← back to Model Arena
data/artifacts/131728b7aeb6/gpt.html
886 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Designer Wallcoverings — Color of the Season Reel</title>
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<style>
:root {
/* Design tokens */
--bg: #0d0d0f;
--surface: #17171c;
--ink: #f5f2ea;
--muted: #8a8578;
--accent: #c9a961; /* warm metallic gold */
--accent-soft: #7d6a45;
--line: rgba(245, 242, 234, 0.12);
--shadow-soft: 0 22px 40px rgba(0, 0, 0, 0.45);
--shadow-subtle: 0 1px 0 rgba(255, 255, 255, 0.04), 0 10px 30px rgba(0, 0, 0, 0.6);
--radius-soft: 18px;
--radius-pill: 999px;
--ease-swift: cubic-bezier(.22,.9,.24,1);
--ease-scene: cubic-bezier(.77,0,.18,1);
--ease-hero: cubic-bezier(.22,1,.36,1);
--font-display: 'Playfair Display', 'Cormorant Garamond', 'EB Garamond', 'Didot', 'Bodoni MT', Georgia, serif;
--font-sans: 'Avenir Next', 'Century Gothic', Futura, 'Segoe UI', sans-serif;
--fs-caption: 12px;
--fs-body: 16px;
--fs-lead: 21px;
--fs-h3: 28px;
--fs-h2: 38px;
--fs-h1: 50px;
--fs-display: 67px;
--reel-width: 360px;
--reel-height: 640px;
--caption-bg: rgba(13, 13, 15, 0.66);
--caption-blur: 20px;
--timeline-height: 3px;
--timeline-bg: rgba(245, 242, 234, 0.12);
--timeline-fill: #f5f2ea;
--scene-duration: 4500ms;
}
/* Entrance keyframes from HyperFrames */
@keyframes fadeUp {
from { opacity: 0; transform: translateY(28px); }
to { opacity: 1; transform: none; }
}
@keyframes scaleIn {
from { opacity: 0; transform: scale(.92); }
to { opacity: 1; transform: none; }
}
@keyframes clipReveal {
from { clip-path: inset(0 100% 0 0); }
to { clip-path: inset(0); }
}
@keyframes blurIn {
from { opacity: 0; filter: blur(12px); }
to { opacity: 1; filter: blur(0); }
}
/* Global layout */
*,
*::before,
*::after {
box-sizing: border-box;
}
html, body {
margin: 0;
padding: 0;
height: 100%;
background: radial-gradient(circle at top, #191922 0, #050507 55%, #000 100%);
color: var(--ink);
font-family: var(--font-sans);
-webkit-font-smoothing: antialiased;
}
body {
display: flex;
align-items: center;
justify-content: center;
}
/* Reel frame */
.reel-shell {
width: min(var(--reel-width), 100vw);
height: min(var(--reel-height), 100vh);
background: radial-gradient(circle at top, #191922 0, #050507 70%, #000 100%);
border-radius: 28px;
box-shadow: var(--shadow-soft);
overflow: hidden;
position: relative;
color: var(--ink);
display: flex;
flex-direction: column;
}
/* Top bar with wordmark */
.reel-header {
position: relative;
z-index: 5;
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 14px 8px;
border-bottom: 1px solid rgba(245, 242, 234, 0.08);
background: linear-gradient(to bottom, rgba(6,6,8,0.9), rgba(6,6,8,0.3));
backdrop-filter: blur(14px);
}
.brand-lockup {
font-family: var(--font-display);
font-size: 13px;
line-height: 1.1;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--ink);
white-space: normal;
max-width: 200px;
}
.brand-lockup span {
display: block;
}
/* Header controls */
.header-controls {
display: flex;
align-items: center;
gap: 10px;
}
.badge-label {
font-family: var(--font-sans);
font-size: 10px;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--muted);
}
/* Play / Pause button */
.play-toggle {
display: inline-flex;
align-items: center;
justify-content: center;
width: 26px;
height: 26px;
border-radius: 999px;
border: 1px solid rgba(201,169,97,0.65);
background: radial-gradient(circle at 30% 0, rgba(255,255,255,0.14), rgba(17,17,20,0.96));
color: var(--ink);
cursor: pointer;
transition: background 160ms var(--ease-swift), transform 160ms var(--ease-swift), box-shadow 160ms var(--ease-swift), border-color 160ms var(--ease-swift);
box-shadow: 0 0 0 1px rgba(0,0,0,0.4), 0 10px 24px rgba(0,0,0,0.9);
}
.play-toggle:hover {
background: radial-gradient(circle at 30% 0, rgba(255,255,255,0.2), rgba(24,24,28,1));
transform: translateY(-1px);
box-shadow: 0 16px 30px rgba(0,0,0,0.85);
}
.play-toggle:active {
transform: translateY(0);
box-shadow: 0 6px 14px rgba(0,0,0,0.75);
}
.play-icon,
.pause-icon {
width: 11px;
height: 11px;
display: block;
fill: none;
stroke: var(--ink);
stroke-width: 1.4;
}
.pause-icon {
display: none;
}
/* Progress bar */
.timeline {
position: relative;
width: 100%;
height: var(--timeline-height);
background: var(--timeline-bg);
overflow: hidden;
}
.timeline-fill {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 0%;
background: linear-gradient(90deg, var(--accent), var(--ink));
transform-origin: left;
transition: width 120ms linear;
}
/* Reel content area */
.reel-main {
position: relative;
flex: 1;
overflow: hidden;
background:
radial-gradient(circle at 0 0, rgba(201,169,97,0.18), transparent 46%),
radial-gradient(circle at 100% 40%, rgba(125,106,69,0.28), transparent 55%),
radial-gradient(circle at 50% 100%, rgba(0,0,0,0.9), #050507 70%);
}
/* Ambient vignette & border */
.reel-vignette {
position: absolute;
inset: 0;
pointer-events: none;
box-shadow: inset 0 0 70px rgba(0,0,0,0.9);
border-radius: inherit;
border: 1px solid rgba(255,255,255,0.02);
}
/* Scenes */
.scene {
position: absolute;
inset: 0;
padding: 22px 18px 20px;
display: flex;
flex-direction: column;
justify-content: space-between;
opacity: 0;
transform: translateX(6%);
transition:
opacity 500ms var(--ease-scene),
transform 500ms var(--ease-scene);
pointer-events: none;
}
.scene.is-active {
opacity: 1;
transform: translateX(0);
pointer-events: auto;
}
.scene.is-exit-left {
opacity: 0;
transform: translateX(-6%);
}
/* Caption band */
.caption-band {
background: rgba(9,9,11,0.78);
border-radius: 999px;
padding: 6px 13px 6px 10px;
border: 1px solid rgba(245,242,234,0.06);
box-shadow: var(--shadow-subtle);
backdrop-filter: blur(14px);
display: inline-flex;
align-items: center;
gap: 8px;
max-width: 100%;
animation: fadeUp 700ms var(--ease-hero) both;
}
.caption-pill {
font-size: var(--fs-caption);
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--muted);
white-space: nowrap;
}
.caption-text {
font-size: 14px;
color: var(--ink);
opacity: 0.92;
}
/* Scene 1: Hook */
.scene-1-headline {
margin-top: 40px;
}
.kicker-label {
display: inline-flex;
align-items: center;
gap: 6px;
font-family: var(--font-sans);
font-size: 11px;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--muted);
margin-bottom: 12px;
}
.kicker-dot {
width: 7px;
height: 7px;
border-radius: 999px;
background: radial-gradient(circle at 30% 0, #fdf6e3, #c9a961);
box-shadow: 0 0 0 1px rgba(201,169,97,0.6), 0 0 14px rgba(201,169,97,0.9);
}
.hook-heading {
font-family: var(--font-display);
font-size: 32px;
line-height: 1.05;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--ink);
margin: 0 0 10px;
}
.hook-subtitle {
font-size: var(--fs-body);
color: var(--muted);
max-width: 20rem;
}
/* Scene 2: Hue Name */
.hue-scene {
align-items: center;
text-align: center;
}
.hue-label {
font-family: var(--font-sans);
font-size: 11px;
letter-spacing: 0.22em;
text-transform: uppercase;
color: var(--muted);
margin-top: 8px;
}
.hue-name-lockup {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 8px;
}
.hue-name {
font-family: var(--font-display);
font-size: 52px;
line-height: 1;
letter-spacing: 0.12em;
text-transform: uppercase;
padding: 10px 16px;
border-radius: 999px;
border: 1px solid rgba(245,242,234,0.12);
box-shadow:
inset 0 0 26px rgba(201,169,97,0.12),
0 26px 60px rgba(0,0,0,0.9);
background:
radial-gradient(circle at 0 0, rgba(201,169,97,0.55), rgba(7,12,12,1)),
radial-gradient(circle at 100% 100%, rgba(39,59,54,0.94), rgba(16,22,21,1));
}
.hue-note {
font-size: 14px;
color: var(--muted);
max-width: 16rem;
}
/* Scene 3: Swatches */
.swatch-scene {
padding-top: 26px;
padding-bottom: 24px;
}
.section-label {
font-size: 11px;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--muted);
margin-bottom: 10px;
}
.swatch-row {
display: grid;
grid-template-columns: repeat(3, minmax(0,1fr));
gap: 10px;
margin-bottom: 14px;
}
.swatch-tile {
position: relative;
aspect-ratio: 3 / 4;
border-radius: 16px;
overflow: hidden;
box-shadow: 0 18px 40px rgba(0,0,0,0.9);
background: #1c2624;
border: 1px solid rgba(245,242,234,0.08);
}
/* Swatch motifs */
.swatch-base {
position: absolute;
inset: 0;
}
/* Swatch 1: Celadon lattice */
.swatch-1 {
background:
radial-gradient(circle at 0 0, rgba(201,169,97,0.22), transparent 60%),
linear-gradient(135deg, #203632, #1a2927);
}
.swatch-1::before,
.swatch-1::after {
content: "";
position: absolute;
inset: 0;
background-image:
linear-gradient(135deg, rgba(245,242,234,0.06) 0, rgba(245,242,234,0.06) 1px, transparent 0, transparent 18px),
linear-gradient(225deg, rgba(245,242,234,0.05) 0, rgba(245,242,234,0.05) 1px, transparent 0, transparent 18px);
background-size: 18px 18px;
mix-blend-mode: screen;
}
.swatch-1::after {
transform: translate(9px, 9px);
opacity: 0.45;
}
/* Swatch 2: Vertical metallic bands */
.swatch-2 {
background:
linear-gradient(90deg,
rgba(16,27,26,1) 0,
rgba(41,64,58,1) 20%,
rgba(16,27,26,1) 40%,
rgba(41,64,58,1) 60%,
rgba(16,27,26,1) 80%,
rgba(41,64,58,1) 100%);
}
.swatch-2::before {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(90deg,
rgba(201,169,97,0.0) 0,
rgba(201,169,97,0.42) 14%,
rgba(201,169,97,0.0) 28%,
rgba(201,169,97,0.45) 44%,
rgba(201,169,97,0.0) 60%,
rgba(201,169,97,0.45) 76%,
rgba(201,169,97,0.0) 100%);
mix-blend-mode: screen;
}
.swatch-2::after {
content: "";
position: absolute;
inset: 0;
background:
linear-gradient(to bottom, rgba(0,0,0,0.5), transparent 30%, transparent 70%, rgba(0,0,0,0.7));
}
/* Swatch 3: Organic brush */
.swatch-3 {
background:
radial-gradient(circle at 10% 0, rgba(201,169,97,0.28), transparent 48%),
radial-gradient(circle at 100% 100%, rgba(17,35,33,1), rgba(7,14,14,1));
}
.swatch-3::before {
content: "";
position: absolute;
inset: -20%;
background-image:
radial-gradient(circle at 10% 20%, rgba(245,242,234,0.08) 0, transparent 40%),
radial-gradient(circle at 60% 0%, rgba(245,242,234,0.05) 0, transparent 50%),
radial-gradient(circle at 40% 80%, rgba(245,242,234,0.06) 0, transparent 50%),
radial-gradient(circle at 110% 60%, rgba(245,242,234,0.08) 0, transparent 45%);
filter: blur(10px);
opacity: 0.8;
}
/* Swatch caption */
.swatch-caption {
font-size: 13px;
color: var(--muted);
max-width: 19rem;
}
/* Scene 4: Styling tip & CTA */
.tip-scene {
padding-top: 26px;
padding-bottom: 28px;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.tip-main {
margin-top: 20px;
}
.tip-heading {
font-family: var(--font-display);
font-size: 28px;
line-height: 1.1;
letter-spacing: 0.08em;
text-transform: uppercase;
margin: 0 0 10px;
}
.tip-body {
font-size: var(--fs-body);
color: var(--muted);
max-width: 20rem;
}
/* CTA panel */
.cta-panel {
margin-top: 26px;
padding: 12px 14px;
border-radius: 18px;
border: 1px solid rgba(245,242,234,0.08);
background:
radial-gradient(circle at 0 0, rgba(201,169,97,0.26), rgba(22,26,24,0.96)),
radial-gradient(circle at 100% 100%, rgba(19,29,27,1), rgba(11,14,14,1));
box-shadow: var(--shadow-subtle);
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
}
.cta-copy {
font-size: 13px;
}
.cta-eyebrow {
font-size: 10px;
letter-spacing: 0.16em;
text-transform: uppercase;
color: rgba(245,242,234,0.78);
margin-bottom: 3px;
}
.cta-main {
font-family: var(--font-display);
font-size: 18px;
letter-spacing: 0.08em;
text-transform: uppercase;
}
/* CTA button */
.cta-button {
flex-shrink: 0;
padding: 8px 14px;
border-radius: 999px;
border: 1px solid rgba(245,242,234,0.5);
background: radial-gradient(circle at 0 0, #f5f2ea, #c9a961);
color: #151515;
font-family: var(--font-sans);
font-size: 11px;
letter-spacing: 0.18em;
text-transform: uppercase;
cursor: pointer;
box-shadow: 0 14px 28px rgba(0,0,0,0.9);
transition: transform 140ms var(--ease-swift), box-shadow 140ms var(--ease-swift), filter 140ms var(--ease-swift);
}
.cta-button:hover {
transform: translateY(-1px);
box-shadow: 0 20px 38px rgba(0,0,0,0.95);
filter: brightness(1.05);
}
.cta-button:active {
transform: translateY(0);
box-shadow: 0 10px 22px rgba(0,0,0,0.9);
}
/* Caption bar at bottom */
.caption-bar {
position: absolute;
left: 12px;
right: 12px;
bottom: 16px;
padding: 8px 14px;
display: flex;
align-items: center;
gap: 10px;
border-radius: 999px;
background: var(--caption-bg);
backdrop-filter: blur(var(--caption-blur));
border: 1px solid rgba(245,242,234,0.06);
box-shadow: var(--shadow-subtle);
font-size: 13px;
}
.caption-dot {
width: 6px;
height: 6px;
border-radius: 999px;
background: var(--accent);
box-shadow: 0 0 0 1px rgba(10,10,10,0.8), 0 0 12px rgba(201,169,97,0.9);
}
.caption-content {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
/* Caption marquee animation */
.caption-scroller {
display: inline-block;
animation: clipReveal 800ms var(--ease-hero) both;
}
/* State: paused */
.reel-shell.is-paused .timeline-fill {
transition: none;
}
/* Utility */
.hide-visually {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0 0 0 0);
white-space: nowrap;
}
</style>
</head>
<body>
<div class="reel-shell" data-playing="true">
<header class="reel-header">
<div class="brand-lockup">
<span>DESIGNER</span>
<span>WALLCOVERINGS</span>
</div>
<div class="header-controls">
<div class="badge-label">COLOR OF THE SEASON</div>
<button class="play-toggle" type="button" aria-label="Pause reel" aria-pressed="true">
<svg class="play-icon" viewBox="0 0 12 12" aria-hidden="true">
<polygon points="3,2 10,6 3,10" fill="currentColor"></polygon>
</svg>
<svg class="pause-icon" viewBox="0 0 12 12" aria-hidden="true">
<rect x="2.5" y="2" width="2.3" height="8" fill="currentColor"></rect>
<rect x="7.2" y="2" width="2.3" height="8" fill="currentColor"></rect>
</svg>
</button>
</div>
</header>
<div class="timeline" aria-hidden="true">
<div class="timeline-fill"></div>
</div>
<main class="reel-main">
<div class="reel-vignette"></div>
<!-- Scene 1: Hook -->
<section class="scene scene-1 is-active" data-scene-index="0" aria-label="Seasonal color hook">
<div>
<div class="scene-1-headline">
<div class="kicker-label">
<span class="kicker-dot"></span>
<span>This season it's all about</span>
</div>
<h1 class="hook-heading">
Quiet luxury<br />
on your walls
</h1>
<p class="hook-subtitle">
A soft celadon that feels like evening light on hand‑troweled plaster.
</p>
</div>
</div>
<div>
<div class="caption-band">
<div class="caption-pill">Scene 1 — Introduction</div>
<div class="caption-text">Watch the hue reveal, then explore three celadon wall textures in motion.</div>
</div>
</div>
</section>
<!-- Scene 2: Hue name -->
<section class="scene hue-scene scene-2" data-scene-index="1" aria-label="Celadon color reveal">
<div class="hue-name-lockup">
<div class="hue-label">Color of the Season</div>
<div class="hue-name">
Celadon
</div>
<p class="hue-note">
A luminous green with porcelain softness, grounded by inky trims and warm metallics.
</p>
</div>
<div class="caption-band">
<div class="caption-pill">Scene 2 — Hue Reveal</div>
<div class="caption-text">Celadon: serene enough for bedrooms, elevated enough for gallery dining rooms.</div>
</div>
</section>
<!-- Scene 3: Pattern swatches -->
<section class="scene swatch-scene scene-3" data-scene-index="2" aria-label="Celadon wallcovering swatches">
<div>
<div class="section-label">Celadon in three wall textures</div>
<div class="swatch-row">
<div class="swatch-tile" aria-hidden="true">
<div class="swatch-base swatch-1"></div>
</div>
<div class="swatch-tile" aria-hidden="true">
<div class="swatch-base swatch-2"></div>
</div>
<div class="swatch-tile" aria-hidden="true">
<div class="swatch-base swatch-3"></div>
</div>
</div>
<p class="swatch-caption">
From tailored lattice to brushed metallic bands and painterly clouds of color — each swatch keeps celadon at the center, never overpowering the room.
</p>
</div>
<div class="caption-band">
<div class="caption-pill">Scene 3 — Textures</div>
<div class="caption-text">Pair a single statement wall with quieter coordinates for layered yet restful rooms.</div>
</div>
</section>
<!-- Scene 4: Styling tip & CTA -->
<section class="scene tip-scene scene-4" data-scene-index="3" aria-label="Styling tips and call to action">
<div class="tip-main">
<div class="section-label">Styling tip</div>
<h2 class="tip-heading">Let celadon breathe</h2>
<p class="tip-body">
Balance the softness with deep near‑black woodwork, linen upholstery, and a single brass moment—a picture light, a tray, a mirror frame.
</p>
</div>
<div class="cta-panel">
<div class="cta-copy">
<div class="cta-eyebrow">Discover the collection</div>
<div class="cta-main">Order a celadon sample set</div>
</div>
<button class="cta-button" type="button">
Request set
</button>
</div>
</section>
<!-- Live captions at bottom -->
<div class="caption-bar" aria-live="polite">
<div class="caption-dot"></div>
<div class="caption-content">
<span class="caption-scroller" id="liveCaption">
This season it's all about quiet luxury on your walls.
</span>
</div>
</div>
</main>
</div>
<script>
(function() {
const shell = document.querySelector('.reel-shell');
const scenes = Array.from(document.querySelectorAll('.scene'));
const progress = document.querySelector('.timeline-fill');
const playToggle = document.querySelector('.play-toggle');
const playIcon = document.querySelector('.play-icon');
const pauseIcon = document.querySelector('.pause-icon');
const liveCaption = document.getElementById('liveCaption');
const sceneDuration = parseInt(getComputedStyle(document.documentElement)
.getPropertyValue('--scene-duration'), 10) || 4500;
const captions = [
'This season it\'s all about quiet luxury on your walls.',
'Celadon: a porcelain-soft green that flatters every light.',
'Three distinct celadon wall textures, from lattice to brushed metallic.',
'Layer celadon with deep trims and one warm metallic accent.'
];
let currentScene = 0;
let isPlaying = true;
let timerId = null;
let progressStart = null;
let progressRequest = null;
function setCaption(index) {
if (!liveCaption) return;
liveCaption.textContent = captions[index] || '';
liveCaption.style.animation = 'none';
// restart clipReveal
requestAnimationFrame(() => {
liveCaption.style.animation = '';
liveCaption.style.animation = 'clipReveal 800ms var(--ease-hero) both';
});
}
function showScene(index, fromIndex) {
scenes.forEach((scene, i) => {
scene.classList.remove('is-exit-left', 'is-active');
if (i === index) {
scene.classList.add('is-active');
} else if (typeof fromIndex === 'number' && i === fromIndex && index > fromIndex) {
scene.classList.add('is-exit-left');
}
});
setCaption(index);
}
function animateProgress(timestamp) {
if (!isPlaying) return;
if (!progressStart) progressStart = timestamp;
const elapsed = timestamp - progressStart;
const pct = Math.min(100, (elapsed / sceneDuration) * 100);
if (progress) progress.style.width = pct + '%';
if (elapsed >= sceneDuration) {
nextScene();
return;
}
progressRequest = requestAnimationFrame(animateProgress);
}
function startProgress() {
cancelAnimationFrame(progressRequest);
progressStart = null;
if (progress) progress.style.width = '0%';
progressRequest = requestAnimationFrame(animateProgress);
}
function nextScene() {
const fromIndex = currentScene;
currentScene = (currentScene + 1) % scenes.length;
showScene(currentScene, fromIndex);
progressStart = null;
if (isPlaying) {
startProgress();
}
}
function togglePlayState(forceState) {
const newState = typeof forceState === 'boolean' ? forceState : !isPlaying;
isPlaying = newState;
shell.dataset.playing = String(isPlaying);
shell.classList.toggle('is-paused', !isPlaying);
if (isPlaying) {
playToggle.setAttribute('aria-label', 'Pause reel');
playToggle.setAttribute('aria-pressed', 'true');
playIcon.style.display = 'none';
pauseIcon.style.display = 'block';
// resume progress from current width
const currentWidth = parseFloat((progress && progress.style.width) || '0');
if (!isNaN(currentWidth) && currentWidth > 0) {
const elapsed = (currentWidth / 100) * sceneDuration;
progressStart = performance.now() - elapsed;
cancelAnimationFrame(progressRequest);
progressRequest = requestAnimationFrame(animateProgress);
} else {
startProgress();
}
} else {
playToggle.setAttribute('aria-label', 'Play reel');
playToggle.setAttribute('aria-pressed', 'false');
playIcon.style.display = 'block';
pauseIcon.style.display = 'none';
cancelAnimationFrame(progressRequest);
progressRequest = null;
}
}
playToggle.addEventListener('click', () => {
togglePlayState();
});
// Kick things off
showScene(currentScene, null);
setCaption(currentScene);
togglePlayState(true); // ensures icons correct + progress running
})();
</script>
</body>
</html>