← back to Model Arena
Enable 🎨 design-tools belt (opendesign/hyperframes/figma) on all loop battles — models fetch real palettes/type/motion for beautiful UI
e6af3f8af3016c819f0cf4131a531bf508f4e813 · 2026-07-25 00:47:43 -0700 · Steve Abrams
Files touched
A data/artifacts/53b12394c732/hf-qwen-coder-32b.htmlA data/artifacts/53b12394c732/hf-qwen-coder-32b.pngA data/artifacts/b72f0e9e751b/claude-code.htmlA data/artifacts/b72f0e9e751b/claude-code.pngA data/artifacts/b72f0e9e751b/gemma3-12b.htmlA data/artifacts/b72f0e9e751b/gemma3-12b.pngA data/artifacts/b72f0e9e751b/gpt.htmlA data/artifacts/b72f0e9e751b/gpt.pngA data/artifacts/b72f0e9e751b/hermes3-8b.htmlA data/artifacts/b72f0e9e751b/hermes3-8b.pngA data/artifacts/b72f0e9e751b/hf-qwen-coder-32b.htmlA data/artifacts/b72f0e9e751b/hf-qwen-coder-32b.pngA data/artifacts/b72f0e9e751b/kimi.htmlA data/artifacts/b72f0e9e751b/kimi.pngA data/artifacts/b72f0e9e751b/qwen3-14b.htmlA data/artifacts/b72f0e9e751b/qwen3-14b.pngA data/artifacts/bde366feb227/claude-code.htmlA data/artifacts/bde366feb227/claude-code.pngA data/artifacts/bde366feb227/gpt.htmlA data/artifacts/bde366feb227/gpt.pngA data/artifacts/bde366feb227/grok.htmlA data/artifacts/bde366feb227/grok.pngA data/artifacts/d7f4f8ca5f8d/claude-code.htmlA data/artifacts/d7f4f8ca5f8d/claude-code.pngA data/artifacts/d7f4f8ca5f8d/gemma3-12b.htmlA data/artifacts/d7f4f8ca5f8d/gemma3-12b.pngA data/artifacts/d7f4f8ca5f8d/gpt.htmlA data/artifacts/d7f4f8ca5f8d/gpt.pngA data/artifacts/d7f4f8ca5f8d/grok.htmlA data/artifacts/d7f4f8ca5f8d/grok.pngA data/artifacts/d7f4f8ca5f8d/hermes3-8b.htmlA data/artifacts/d7f4f8ca5f8d/hermes3-8b.pngA data/artifacts/d7f4f8ca5f8d/kimi.htmlA data/artifacts/d7f4f8ca5f8d/kimi.pngA data/artifacts/d7f4f8ca5f8d/qwen3-14b.htmlA data/artifacts/d7f4f8ca5f8d/qwen3-14b.pngM data/challenges.jsonM data/costlog.jsonlM idea-run/run-next.sh
Diff
commit e6af3f8af3016c819f0cf4131a531bf508f4e813
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Sat Jul 25 00:47:43 2026 -0700
Enable 🎨 design-tools belt (opendesign/hyperframes/figma) on all loop battles — models fetch real palettes/type/motion for beautiful UI
---
data/artifacts/53b12394c732/hf-qwen-coder-32b.html | 131 ++
data/artifacts/53b12394c732/hf-qwen-coder-32b.png | Bin 0 -> 14630 bytes
data/artifacts/b72f0e9e751b/claude-code.html | 425 ++++++
data/artifacts/b72f0e9e751b/claude-code.png | Bin 0 -> 246668 bytes
data/artifacts/b72f0e9e751b/gemma3-12b.html | 214 +++
data/artifacts/b72f0e9e751b/gemma3-12b.png | Bin 0 -> 18532 bytes
data/artifacts/b72f0e9e751b/gpt.html | 1453 ++++++++++++++++++++
data/artifacts/b72f0e9e751b/gpt.png | Bin 0 -> 224864 bytes
data/artifacts/b72f0e9e751b/hermes3-8b.html | 155 +++
data/artifacts/b72f0e9e751b/hermes3-8b.png | Bin 0 -> 145819 bytes
data/artifacts/b72f0e9e751b/hf-qwen-coder-32b.html | 154 +++
data/artifacts/b72f0e9e751b/hf-qwen-coder-32b.png | Bin 0 -> 3032 bytes
data/artifacts/b72f0e9e751b/kimi.html | 812 +++++++++++
data/artifacts/b72f0e9e751b/kimi.png | Bin 0 -> 101858 bytes
data/artifacts/b72f0e9e751b/qwen3-14b.html | 238 ++++
data/artifacts/b72f0e9e751b/qwen3-14b.png | Bin 0 -> 24419 bytes
data/artifacts/bde366feb227/claude-code.html | 439 ++++++
data/artifacts/bde366feb227/claude-code.png | Bin 0 -> 181553 bytes
data/artifacts/bde366feb227/gpt.html | 1358 ++++++++++++++++++
data/artifacts/bde366feb227/gpt.png | Bin 0 -> 236068 bytes
data/artifacts/bde366feb227/grok.html | 629 +++++++++
data/artifacts/bde366feb227/grok.png | Bin 0 -> 88245 bytes
data/artifacts/d7f4f8ca5f8d/claude-code.html | 450 ++++++
data/artifacts/d7f4f8ca5f8d/claude-code.png | Bin 0 -> 243189 bytes
data/artifacts/d7f4f8ca5f8d/gemma3-12b.html | 284 ++++
data/artifacts/d7f4f8ca5f8d/gemma3-12b.png | Bin 0 -> 17205 bytes
data/artifacts/d7f4f8ca5f8d/gpt.html | 613 +++++++++
data/artifacts/d7f4f8ca5f8d/gpt.png | Bin 0 -> 322986 bytes
data/artifacts/d7f4f8ca5f8d/grok.html | 298 ++++
data/artifacts/d7f4f8ca5f8d/grok.png | Bin 0 -> 139575 bytes
data/artifacts/d7f4f8ca5f8d/hermes3-8b.html | 110 ++
data/artifacts/d7f4f8ca5f8d/hermes3-8b.png | Bin 0 -> 9334 bytes
data/artifacts/d7f4f8ca5f8d/kimi.html | 538 ++++++++
data/artifacts/d7f4f8ca5f8d/kimi.png | Bin 0 -> 231943 bytes
data/artifacts/d7f4f8ca5f8d/qwen3-14b.html | 210 +++
data/artifacts/d7f4f8ca5f8d/qwen3-14b.png | Bin 0 -> 78492 bytes
data/challenges.json | 256 ++--
data/costlog.jsonl | 7 +
idea-run/run-next.sh | 2 +-
39 files changed, 8666 insertions(+), 110 deletions(-)
diff --git a/data/artifacts/53b12394c732/hf-qwen-coder-32b.html b/data/artifacts/53b12394c732/hf-qwen-coder-32b.html
new file mode 100644
index 0000000..93127b6
--- /dev/null
+++ b/data/artifacts/53b12394c732/hf-qwen-coder-32b.html
@@ -0,0 +1,131 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Luxury Wallcovering Carousel</title>
+ <style>
+ body {
+ font-family: 'Arial', sans-serif;
+ margin: 0;
+ padding: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100vh;
+ background-color: #f5f5f5;
+ }
+ .carousel-container {
+ position: relative;
+ width: 1080px;
+ height: 1080px;
+ overflow: hidden;
+ border-radius: 20px;
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
+ }
+ .carousel-slide {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ transition: transform 0.5s ease-in-out;
+ }
+ .slide-1 { background-color: #f8e9d3; }
+ .slide-2, .slide-3, .slide-4 { background-color: #ffffff; }
+ .slide-5 { background-color: #f8e9d3; }
+ .carousel-slide h1 {
+ font-size: 40px;
+ color: #333;
+ text-align: center;
+ }
+ .carousel-slide p {
+ font-size: 24px;
+ color: #666;
+ text-align: center;
+ margin-top: 20px;
+ }
+ .pattern { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 80%; height: 80%; background-image: repeating-linear-gradient(45deg, #d3e6fa, #d3e6fa 10px, transparent 10px, transparent 20px); }
+ .wordmark { position: absolute; top: 20px; left: 20px; font-size: 32px; color: #333; text-transform: uppercase; }
+ .controls {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin-top: 10px;
+ }
+ .dot { width: 10px; height: 10px; background-color: #ccc; border-radius: 50%; margin: 0 5px; cursor: pointer; transition: background-color 0.3s ease-in-out; }
+ .dot.active { background-color: #333; }
+ .arrow {
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 12px 8px 0 8px;
+ border-color: #333 transparent transparent transparent;
+ cursor: pointer;
+ margin: 0 10px;
+ }
+ .arrow.right { transform: rotate(180deg); }
+ </style>
+</head>
+<body>
+ <div class="carousel-container">
+ <div class="carousel-slide slide-1" style="transform: translateX(0);">
+ <div class="pattern"></div>
+ <div class="wordmark">Luxury Wallcoverings</div>
+ </div>
+ <div class="carousel-slide slide-2" style="transform: translateX(1080px);">
+ <h1>Pattern 1</h1>
+ <p>Elegant and sophisticated, this pattern adds a touch of luxury to any space.</p>
+ </div>
+ <div class="carousel-slide slide-3" style="transform: translateX(2160px);">
+ <h1>Pattern 2</h1>
+ <p>A modern twist on tradition, perfect for contemporary interiors.</p>
+ </div>
+ <div class="carousel-slide slide-4" style="transform: translateX(3240px);">
+ <h1>Pattern 3</h1>
+ <p>Vibrant and eye-catching, ideal for making a statement in any room.</p>
+ </div>
+ <div class="carousel-slide slide-5" style="transform: translateX(4320px);">
+ <h1>Contact Us</h1>
+ <p>Discover how our wallcoverings can transform your space. Get in touch today!</p>
+ </div>
+ </div>
+ <div class="controls">
+ <div class="arrow left" onclick="moveSlide(-1)"></div>
+ <div class="dot active" onclick="changeSlide(0)"></div>
+ <div class="dot" onclick="changeSlide(1)"></div>
+ <div class="dot" onclick="changeSlide(2)"></div>
+ <div class="dot" onclick="changeSlide(3)"></div>
+ <div class="dot" onclick="changeSlide(4)"></div>
+ <div class="arrow right" onclick="moveSlide(1)"></div>
+ </div>
+ <script>
+ let currentSlide = 0;
+ const slides = document.querySelectorAll('.carousel-slide');
+ const dots = document.querySelectorAll('.dot');
+
+ function changeSlide(index) {
+ if (index >= slides.length || index < 0) return;
+ currentSlide = index;
+ updateSlides();
+ }
+
+ function moveSlide(direction) {
+ changeSlide(currentSlide + direction);
+ }
+
+ function updateSlides() {
+ slides.forEach((slide, index) => {
+ slide.style.transform = `translateX(${(index - currentSlide) * 1080}px)`;
+ });
+ dots.forEach(dot => dot.classList.remove('active'));
+ dots[currentSlide].classList.add('active');
+ }
+
+ document.addEventListener('DOMContentLoaded', () => {
+ updateSlides();
+ });
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/53b12394c732/hf-qwen-coder-32b.png b/data/artifacts/53b12394c732/hf-qwen-coder-32b.png
new file mode 100644
index 0000000..6edc38e
Binary files /dev/null and b/data/artifacts/53b12394c732/hf-qwen-coder-32b.png differ
diff --git a/data/artifacts/b72f0e9e751b/claude-code.html b/data/artifacts/b72f0e9e751b/claude-code.html
new file mode 100644
index 0000000..3a75215
--- /dev/null
+++ b/data/artifacts/b72f0e9e751b/claude-code.html
@@ -0,0 +1,425 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Reel Storyboard · Maison Wallcoverings</title>
+<style>
+ :root{
+ --bg:#0a0a0c;
+ --panel:#121216;
+ --panel-2:#17171d;
+ --line:#26262f;
+ --gold:#c9a24b;
+ --gold-2:#e7cf8f;
+ --ink:#f4f1e9;
+ --muted:#8a8a97;
+ --accent:#b98a5e;
+ --radius:18px;
+ --sans:'Helvetica Neue',Helvetica,Arial,sans-serif;
+ --serif:Georgia,'Times New Roman',serif;
+ }
+ *{box-sizing:border-box;margin:0;padding:0}
+ html,body{height:100%}
+ body{
+ background:
+ radial-gradient(1200px 700px at 80% -10%, #1a1712 0%, transparent 60%),
+ radial-gradient(900px 600px at -10% 110%, #14100c 0%, transparent 55%),
+ var(--bg);
+ color:var(--ink);
+ font-family:var(--sans);
+ min-height:100%;
+ -webkit-font-smoothing:antialiased;
+ display:flex;
+ justify-content:center;
+ padding:34px 20px 60px;
+ }
+ .wrap{
+ width:100%;
+ max-width:1100px;
+ display:grid;
+ grid-template-columns:minmax(300px,360px) 1fr;
+ gap:38px;
+ align-items:start;
+ }
+ header.brand{
+ grid-column:1 / -1;
+ display:flex;
+ align-items:flex-end;
+ justify-content:space-between;
+ border-bottom:1px solid var(--line);
+ padding-bottom:20px;
+ flex-wrap:wrap;
+ gap:14px;
+ }
+ .brand h1{
+ font-family:var(--serif);
+ font-weight:400;
+ font-size:26px;
+ letter-spacing:.14em;
+ text-transform:uppercase;
+ }
+ .brand h1 span{color:var(--gold)}
+ .brand .sub{
+ color:var(--muted);
+ font-size:11px;
+ letter-spacing:.32em;
+ text-transform:uppercase;
+ margin-top:6px;
+ }
+ .badge{
+ font-size:10px;letter-spacing:.28em;text-transform:uppercase;
+ color:var(--gold-2);
+ border:1px solid var(--line);
+ padding:8px 14px;border-radius:40px;
+ background:linear-gradient(180deg,rgba(201,162,75,.08),rgba(201,162,75,0));
+ }
+
+ /* ---------- PHONE ---------- */
+ .stage{display:flex;flex-direction:column;align-items:center;gap:22px;position:sticky;top:24px}
+ .phone{
+ position:relative;
+ width:300px;
+ aspect-ratio:9/16;
+ border-radius:44px;
+ padding:12px;
+ background:linear-gradient(150deg,#2a2a31,#0c0c0f 55%);
+ box-shadow:0 40px 90px -30px rgba(0,0,0,.9),0 0 0 1px #000, inset 0 0 0 2px #303038;
+ }
+ .notch{
+ position:absolute;top:20px;left:50%;transform:translateX(-50%);
+ width:96px;height:22px;background:#000;border-radius:14px;z-index:20;
+ }
+ .screen{
+ position:relative;
+ width:100%;height:100%;
+ border-radius:34px;
+ overflow:hidden;
+ background:#000;
+ }
+ .scene{
+ position:absolute;inset:0;
+ opacity:0;
+ transition:opacity .7s ease;
+ display:flex;align-items:flex-end;
+ background-size:cover;background-position:center;
+ }
+ .scene.active{opacity:1}
+ .scene::before{
+ content:"";position:absolute;inset:0;
+ background:linear-gradient(180deg,rgba(0,0,0,.15) 0%,rgba(0,0,0,0) 35%,rgba(0,0,0,.75) 100%);
+ }
+ .scene .grain{position:absolute;inset:0;opacity:.05;mix-blend-mode:overlay;
+ background-image:radial-gradient(#fff 1px,transparent 1px);background-size:3px 3px}
+
+ .scene .kicker{
+ position:absolute;top:56px;left:22px;
+ font-size:10px;letter-spacing:.34em;text-transform:uppercase;
+ color:rgba(255,255,255,.85);
+ padding:6px 12px;border:1px solid rgba(255,255,255,.35);border-radius:30px;
+ backdrop-filter:blur(4px);
+ }
+ .scene .cap{
+ position:relative;z-index:2;
+ padding:26px 24px 40px;
+ width:100%;
+ }
+ .scene .cap .line{
+ font-family:var(--serif);
+ font-size:27px;line-height:1.15;
+ text-shadow:0 2px 18px rgba(0,0,0,.6);
+ transform:translateY(18px);opacity:0;
+ }
+ .scene .cap .sub{
+ margin-top:10px;
+ font-size:12px;letter-spacing:.06em;
+ color:rgba(255,255,255,.82);
+ transform:translateY(18px);opacity:0;
+ }
+ .scene.active .cap .line{animation:rise .8s .15s forwards cubic-bezier(.2,.8,.2,1)}
+ .scene.active .cap .sub{animation:rise .8s .32s forwards cubic-bezier(.2,.8,.2,1)}
+ @keyframes rise{to{transform:translateY(0);opacity:1}}
+
+ /* swatch grid scene */
+ .swgrid{position:absolute;top:0;left:0;right:0;bottom:0;
+ display:grid;grid-template-columns:repeat(3,1fr);grid-template-rows:repeat(3,1fr);gap:5px;padding:5px}
+ .swgrid div{border-radius:5px;transform:scale(.4);opacity:0}
+ .scene.active .swgrid div{animation:pop .5s forwards cubic-bezier(.2,.9,.3,1.3)}
+ @keyframes pop{to{transform:scale(1);opacity:1}}
+
+ /* CTA scene */
+ .cta-btn{
+ display:inline-block;margin-top:16px;
+ font-size:12px;letter-spacing:.2em;text-transform:uppercase;
+ color:#0a0a0c;background:var(--gold-2);
+ padding:12px 22px;border-radius:40px;font-weight:600;
+ transform:translateY(18px);opacity:0;
+ }
+ .scene.active .cta-btn{animation:rise .8s .5s forwards cubic-bezier(.2,.8,.2,1)}
+
+ /* progress + segments */
+ .segbar{
+ position:absolute;top:20px;left:16px;right:16px;z-index:30;
+ display:flex;gap:5px;height:3px;
+ }
+ .segbar .seg{flex:1;background:rgba(255,255,255,.25);border-radius:3px;overflow:hidden}
+ .segbar .seg i{display:block;height:100%;width:0;background:#fff;border-radius:3px}
+
+ .ui-icons{position:absolute;right:16px;bottom:120px;z-index:25;display:flex;flex-direction:column;gap:20px;align-items:center}
+ .ui-icons div{width:30px;height:30px;border-radius:50%;
+ border:1px solid rgba(255,255,255,.4);display:flex;align-items:center;justify-content:center;
+ color:#fff;font-size:14px;background:rgba(0,0,0,.2)}
+
+ .transport{display:flex;align-items:center;gap:16px}
+ .btn{
+ cursor:pointer;border:1px solid var(--line);background:var(--panel-2);
+ color:var(--ink);border-radius:50px;font-size:13px;
+ padding:12px 20px;letter-spacing:.04em;transition:.2s;
+ display:flex;align-items:center;gap:8px;
+ }
+ .btn:hover{border-color:var(--gold);color:var(--gold-2)}
+ .btn.primary{background:linear-gradient(180deg,var(--gold-2),var(--gold));color:#111;border:none;font-weight:600;padding:14px 28px}
+ .btn.primary:hover{filter:brightness(1.08);color:#111}
+ .timecode{font-variant-numeric:tabular-nums;color:var(--muted);font-size:12px;letter-spacing:.1em}
+
+ /* ---------- EDITOR ---------- */
+ .editor h2{
+ font-family:var(--serif);font-weight:400;font-size:19px;letter-spacing:.05em;
+ margin-bottom:4px;
+ }
+ .editor .hint{color:var(--muted);font-size:12px;margin-bottom:20px}
+ .cards{display:flex;flex-direction:column;gap:14px}
+ .card{
+ background:linear-gradient(180deg,var(--panel),var(--panel-2));
+ border:1px solid var(--line);border-radius:var(--radius);
+ padding:16px 18px;transition:.25s;position:relative;overflow:hidden;
+ }
+ .card::after{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:transparent;transition:.25s}
+ .card.on{border-color:rgba(201,162,75,.5)}
+ .card.on::after{background:linear-gradient(var(--gold-2),var(--gold))}
+ .card-top{display:flex;align-items:center;gap:12px;margin-bottom:12px}
+ .idx{
+ width:30px;height:30px;flex:none;border-radius:9px;
+ background:#000;border:1px solid var(--line);
+ display:flex;align-items:center;justify-content:center;
+ font-family:var(--serif);color:var(--gold-2);font-size:14px;
+ }
+ .card.on .idx{border-color:var(--gold)}
+ .card-top .meta{flex:1;min-width:0}
+ .card-top .name{font-size:12px;letter-spacing:.24em;text-transform:uppercase;color:var(--ink)}
+ .card-top .role{font-size:10px;letter-spacing:.18em;text-transform:uppercase;color:var(--muted);margin-top:3px}
+ .dur{color:var(--muted);font-size:11px;font-variant-numeric:tabular-nums;letter-spacing:.08em}
+ .card textarea{
+ width:100%;background:#0c0c0f;border:1px solid var(--line);
+ color:var(--ink);border-radius:10px;padding:10px 12px;
+ font-family:var(--serif);font-size:15px;line-height:1.4;resize:vertical;min-height:52px;
+ transition:.2s;
+ }
+ .card textarea:focus{outline:none;border-color:var(--gold);box-shadow:0 0 0 3px rgba(201,162,75,.12)}
+ .card .sublbl{display:block;margin:10px 0 6px;font-size:10px;letter-spacing:.18em;text-transform:uppercase;color:var(--muted)}
+ .card input.subedit{
+ width:100%;background:#0c0c0f;border:1px solid var(--line);
+ color:var(--muted);border-radius:10px;padding:8px 12px;font-size:12px;font-family:var(--sans);
+ }
+ .card input.subedit:focus{outline:none;border-color:var(--accent);color:var(--ink)}
+ .goto{cursor:pointer;font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--muted);
+ border:1px solid var(--line);padding:6px 10px;border-radius:30px}
+ .goto:hover{color:var(--gold-2);border-color:var(--gold)}
+
+ .foot{grid-column:1/-1;text-align:center;color:#4c4c57;font-size:11px;letter-spacing:.24em;text-transform:uppercase;margin-top:14px}
+
+ @media(max-width:820px){
+ .wrap{grid-template-columns:1fr;gap:30px}
+ .stage{position:static}
+ }
+</style>
+</head>
+<body>
+<div class="wrap">
+ <header class="brand">
+ <div>
+ <h1>Maison <span>Wallcoverings</span></h1>
+ <div class="sub">Reel Storyboard · 9:16 · 15 sec</div>
+ </div>
+ <div class="badge">Instagram Reel Maker</div>
+ </header>
+
+ <!-- PREVIEW -->
+ <section class="stage">
+ <div class="phone">
+ <div class="notch"></div>
+ <div class="screen">
+ <div class="segbar" id="segbar"></div>
+ <div id="scenes"></div>
+ <div class="ui-icons">
+ <div>♡</div><div>❝</div><div>➤</div>
+ </div>
+ </div>
+ </div>
+ <div class="transport">
+ <button class="btn primary" id="play">▶ Play</button>
+ <button class="btn" id="restart">↺ Restart</button>
+ <span class="timecode" id="tc">0.0 / 15.0s</span>
+ </div>
+ </section>
+
+ <!-- EDITOR -->
+ <section class="editor">
+ <h2>Scene Captions</h2>
+ <p class="hint">Edit the on-screen text for each of the five scenes. Changes appear live in the preview.</p>
+ <div class="cards" id="cards"></div>
+ </section>
+
+ <div class="foot">Maison Wallcoverings — Craft in Every Wall</div>
+</div>
+
+<script>
+const scenes = [
+ { role:"Hook", name:"The Hook", dur:2.6, kicker:"New Collection",
+ bg:"linear-gradient(135deg,#3a2c22,#6d4b32 45%,#1c130d)",
+ line:"Walls that whisper luxury.", sub:"Introducing the Atelier Series ✦" },
+ { role:"Room Reveal", name:"Room Reveal", dur:3.2, kicker:"The Reveal",
+ bg:"linear-gradient(160deg,#1f2b2b,#2e4a48 40%,#0d1615)",
+ line:"One wall changes everything.", sub:"Emerald damask · living room" },
+ { role:"Close-up Texture", name:"Close-Up", dur:2.8, kicker:"Feel It",
+ bg:"linear-gradient(135deg,#4a3a2a,#8a6b3f 50%,#241a10)",
+ line:"Hand-woven. Gold-threaded.", sub:"Grasscloth with real metallic weave" },
+ { role:"Swatch Grid", name:"Swatch Grid", dur:3.0, kicker:"14 Colorways",
+ bg:"#101014", swatches:true,
+ line:"Find your shade.", sub:"Swipe through the full palette" },
+ { role:"CTA", name:"Call to Action", dur:3.4, kicker:"Order Samples",
+ bg:"linear-gradient(150deg,#2a2118,#0a0a0c)", cta:true,
+ line:"Order your free swatch.", sub:"Tap the link in bio →" }
+];
+const swColors = ["#6d4b32","#2e4a48","#8a6b3f","#3a2c3a","#4a5568","#7a3b3b","#3b5a3b","#8a7f5f","#463a5a"];
+
+const scenesEl = document.getElementById('scenes');
+const segbar = document.getElementById('segbar');
+const cardsEl = document.getElementById('cards');
+const tcEl = document.getElementById('tc');
+const playBtn = document.getElementById('play');
+const total = scenes.reduce((a,s)=>a+s.dur,0);
+
+// build scenes
+scenes.forEach((s,i)=>{
+ const d=document.createElement('div');
+ d.className='scene'; d.dataset.i=i;
+ d.style.background=s.bg; d.style.backgroundSize='cover';
+ let inner=`<div class="grain"></div>`;
+ if(s.swatches){
+ inner+=`<div class="swgrid">`+swColors.map((c,k)=>`<div style="background:${c};animation-delay:${k*0.06}s"></div>`).join('')+`</div>`;
+ }
+ inner+=`<div class="kicker">${s.kicker}</div>
+ <div class="cap">
+ <div class="line" data-line>${s.line}</div>
+ <div class="sub" data-sub>${s.sub}</div>
+ ${s.cta?'<span class="cta-btn">Shop Now</span>':''}
+ </div>`;
+ d.innerHTML=inner;
+ scenesEl.appendChild(d);
+
+ const seg=document.createElement('div');
+ seg.className='seg'; seg.innerHTML='<i></i>';
+ segbar.appendChild(seg);
+});
+
+// build editor cards
+scenes.forEach((s,i)=>{
+ const c=document.createElement('div');
+ c.className='card'; c.dataset.i=i;
+ c.innerHTML=`
+ <div class="card-top">
+ <div class="idx">${i+1}</div>
+ <div class="meta">
+ <div class="name">${s.name}</div>
+ <div class="role">${s.role}</div>
+ </div>
+ <span class="dur">${s.dur.toFixed(1)}s</span>
+ <span class="goto" data-goto="${i}">View</span>
+ </div>
+ <textarea data-edit="line" data-i="${i}" maxlength="70">${s.line}</textarea>
+ <span class="sublbl">Sub-caption</span>
+ <input class="subedit" data-edit="sub" data-i="${i}" maxlength="60" value="${s.sub.replace(/"/g,'"')}">
+ `;
+ cardsEl.appendChild(c);
+});
+
+const sceneNodes=[...scenesEl.children];
+const segNodes=[...segbar.querySelectorAll('.seg i')];
+const cardNodes=[...cardsEl.children];
+
+// live editing
+cardsEl.addEventListener('input',e=>{
+ const t=e.target; if(!t.dataset.edit) return;
+ const i=+t.dataset.i;
+ const node=sceneNodes[i].querySelector(t.dataset.edit==='line'?'[data-line]':'[data-sub]');
+ node.textContent=t.value;
+});
+cardsEl.addEventListener('click',e=>{
+ if(e.target.dataset.goto!=null){ jumpTo(+e.target.dataset.goto); }
+});
+
+// playback engine
+let current=0, elapsedInScene=0, playing=false, last=0, raf=null;
+
+function setActive(i){
+ sceneNodes.forEach((n,k)=>n.classList.toggle('active',k===i));
+ cardNodes.forEach((n,k)=>n.classList.toggle('on',k===i));
+ segNodes.forEach((n,k)=>{ n.style.transition='none'; n.style.width=(k<i?'100%':'0%'); });
+}
+setActive(0);
+
+function jumpTo(i){
+ current=i; elapsedInScene=0;
+ setActive(i);
+ updateTC();
+ if(!playing){ // restart the entry animation by re-toggling
+ const n=sceneNodes[i]; n.classList.remove('active'); void n.offsetWidth; n.classList.add('active');
+ }
+}
+
+function updateTC(){
+ let before=0; for(let k=0;k<current;k++) before+=scenes[k].dur;
+ const t=Math.min(before+elapsedInScene,total);
+ tcEl.textContent=t.toFixed(1)+' / '+total.toFixed(1)+'s';
+}
+
+function tick(now){
+ if(!playing) return;
+ const dt=(now-last)/1000; last=now;
+ elapsedInScene+=dt;
+ const dur=scenes[current].dur;
+ const seg=segNodes[current];
+ seg.style.transition='none';
+ seg.style.width=Math.min(elapsedInScene/dur*100,100)+'%';
+ updateTC();
+ if(elapsedInScene>=dur){
+ seg.style.width='100%';
+ current=(current+1)%scenes.length;
+ elapsedInScene=0;
+ if(current===0){ segNodes.forEach(s=>s.style.width='0%'); }
+ setActive(current);
+ }
+ raf=requestAnimationFrame(tick);
+}
+
+function play(){
+ playing=true; playBtn.textContent='❚❚ Pause';
+ last=performance.now();
+ raf=requestAnimationFrame(tick);
+}
+function pause(){
+ playing=false; playBtn.textContent='▶ Play';
+ cancelAnimationFrame(raf);
+}
+playBtn.addEventListener('click',()=>{ playing?pause():play(); });
+document.getElementById('restart').addEventListener('click',()=>{
+ pause(); current=0; elapsedInScene=0;
+ segNodes.forEach(s=>{s.style.transition='none';s.style.width='0%';});
+ setActive(0); updateTC();
+ const n=sceneNodes[0]; n.classList.remove('active'); void n.offsetWidth; n.classList.add('active');
+});
+updateTC();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/b72f0e9e751b/claude-code.png b/data/artifacts/b72f0e9e751b/claude-code.png
new file mode 100644
index 0000000..47e5dd6
Binary files /dev/null and b/data/artifacts/b72f0e9e751b/claude-code.png differ
diff --git a/data/artifacts/b72f0e9e751b/gemma3-12b.html b/data/artifacts/b72f0e9e751b/gemma3-12b.html
new file mode 100644
index 0000000..aba6df8
--- /dev/null
+++ b/data/artifacts/b72f0e9e751b/gemma3-12b.html
@@ -0,0 +1,214 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Wallcovering Reel Storyboard</title>
+ <style>
+ body {
+ font-family: sans-serif;
+ margin: 0;
+ background-color: #121212; /* Luxe dark background */
+ color: #fff;
+ overflow: hidden; /* Prevent scrollbars */
+ }
+
+ .container {
+ display: flex;
+ flex-direction: column;
+ height: 100vh;
+ width: 100%;
+ }
+
+ #phone-frame {
+ background-color: #282828; /* Darker phone frame */
+ border: 1px solid rgba(255, 255, 255, 0.1);
+ padding: 20px;
+ margin: 20px auto;
+ width: calc(100% - 40px); /* Responsive width */
+ max-width: 400px; /* Limit maximum width */
+ height: 568px; /* Standard phone height (9:16) */
+ overflow: hidden;
+ }
+
+ .scene {
+ display: none;
+ height: 100%;
+ position: relative;
+ }
+
+ #reel-preview {
+ width: 100%;
+ height: 100%;
+ object-fit: cover; /* Fill the frame */
+ }
+
+ .caption {
+ position: absolute;
+ bottom: 20px;
+ left: 50%;
+ transform: translateX(-50%);
+ background-color: rgba(0, 0, 0, 0.7);
+ padding: 10px;
+ border-radius: 5px;
+ font-size: 14px;
+ text-align: center;
+ animation: slideIn 0.5s ease-in-out forwards; /* Animate the caption */
+ }
+
+ @keyframes slideIn {
+ from { opacity: 0; }
+ to { opacity: 1; }
+ }
+
+ #progress-bar-container {
+ width: 100%;
+ height: 10px;
+ background-color: #333;
+ margin: 20px auto;
+ }
+
+ #progress-bar {
+ width: 0%;
+ height: 100%;
+ background-color: #f05446; /* Accent color */
+ }
+
+ .controls {
+ text-align: center;
+ margin-top: 20px;
+ }
+
+ button {
+ background-color: transparent;
+ border: 1px solid #fff;
+ padding: 8px 16px;
+ color: #fff;
+ cursor: pointer;
+ margin: 0 10px;
+ font-size: 14px;
+ }
+
+ button:hover {
+ background-color: rgba(255, 255, 255, 0.1);
+ }
+
+
+ </style>
+</head>
+<body>
+
+<div class="container">
+ <h1>Wallcovering Reel Storyboard</h1>
+
+ <div id="phone-frame">
+ <img id="reel-preview" src="" alt="Reel Preview">
+ <div class="scene" data-duration="3" id="scene1"><div class="caption">✨Captivating Walls Await! ✨</div></div>
+ <div class="scene" data-duration="4" id="scene2"><div class="caption">Transform Your Space 🏡</div></div>
+ <div class="scene" data-duration="3" id="scene3"><div class="caption">Textural Details That Elevate. ✨</div></div>
+ <div class="scene" data-duration="5" id="scene4"><div class="caption">Endless Possibilities 🎨</div></div>
+ <div class="scene" data-duration="4" id="scene5"><div class="caption">Shop the Look! Link in Bio 🔗</div></div>
+
+
+ </div>
+
+ <div id="progress-bar-container">
+ <div id="progress-bar"></div>
+ </div>
+
+ <div class="controls">
+ <button id="playPauseBtn">Play</button>
+ <button id="resetBtn">Reset</button>
+ </div>
+</div>
+
+<script>
+ const phoneFrame = document.getElementById('phone-frame');
+ const reelPreview = document.getElementById('reel-preview');
+ const scenes = document.querySelectorAll('.scene');
+ const progressBar = document.getElementById('progress-bar');
+ const playPauseBtn = document.getElementById('playPauseBtn');
+ const resetBtn = document.getElementById('resetBtn');
+
+ let currentSceneIndex = 0;
+ let timer;
+ let isPlaying = false;
+
+
+ // Sample Images (Replace with actual image URLs)
+ const images = [
+ "https://via.placeholder.com/400x568?text=Hook",
+ "https://via.placeholder.com/400x568?text=Room+Reveal",
+ "https://via.placeholder.com/400x568?text=Texture",
+ "https://via.placeholder.com/400x568?text=Swatch+Grid",
+ "https://via.placeholder.com/400x568?text=CTA"
+ ];
+
+
+ function showScene(index) {
+ scenes.forEach(scene => scene.style.display = 'none'); // Hide all scenes
+
+ const scene = document.getElementById(`scene${index + 1}`);
+ reelPreview.src = images[index];
+ scene.style.display = 'block';
+
+ }
+
+ function startTimer() {
+ let totalDuration = 0;
+ scenes.forEach(scene => {
+ totalDuration += parseInt(scene.dataset.duration);
+ });
+
+
+ if (isPlaying) {
+ timer = setTimeout(() => {
+ currentSceneIndex++;
+ if (currentSceneIndex < scenes.length) {
+ showScene(currentSceneIndex);
+ startTimer(); // Restart timer for the next scene
+ } else {
+ currentSceneIndex = 0;
+ showScene(currentSceneIndex);
+ startTimer(); // Loop back to the beginning
+ }
+
+ }, (scenes[currentSceneIndex].dataset.duration *1000));
+ }
+
+
+ }
+
+
+ function playPause() {
+ isPlaying = !isPlaying;
+ if (isPlaying) {
+ playPauseBtn.textContent = 'Pause';
+ startTimer();
+ } else {
+ playPauseBtn.textContent = 'Play';
+ clearTimeout(timer);
+ }
+ }
+
+ function resetStoryboard() {
+ currentSceneIndex = 0;
+ isPlaying = false;
+ playPauseBtn.textContent = "Play";
+ showScene(currentSceneIndex);
+ progressBar.style.width = '0%';
+ clearTimeout(timer)
+
+ }
+
+
+ // Event Listeners
+ playPauseBtn.addEventListener('click', playPause);
+ resetBtn.addEventListener('click', resetStoryboard);
+
+ // Initial Setup
+ showScene(currentSceneIndex);
+</script>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/b72f0e9e751b/gemma3-12b.png b/data/artifacts/b72f0e9e751b/gemma3-12b.png
new file mode 100644
index 0000000..f920d73
Binary files /dev/null and b/data/artifacts/b72f0e9e751b/gemma3-12b.png differ
diff --git a/data/artifacts/b72f0e9e751b/gpt.html b/data/artifacts/b72f0e9e751b/gpt.html
new file mode 100644
index 0000000..5797f46
--- /dev/null
+++ b/data/artifacts/b72f0e9e751b/gpt.html
@@ -0,0 +1,1453 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<title>Reel Storyboard Tool – Wallcovering Brand</title>
+<style>
+ :root {
+ --bg: #050509;
+ --bg-elevated: #111119;
+ --bg-soft: #171721;
+ --accent: #d2b57e;
+ --accent-soft: rgba(210,181,126,0.28);
+ --accent-strong: #f3d9a2;
+ --text-main: #f5f5f7;
+ --text-muted: #a3a3b3;
+ --border-subtle: #272738;
+ --danger: #f87c7c;
+ --phone-radius: 36px;
+ --transition-fast: 160ms ease-out;
+ --shadow-soft: 0 22px 70px rgba(0,0,0,0.7);
+ --font-body: system-ui, -apple-system, BlinkMacSystemFont, "SF Pro Text",
+ "Segoe UI", sans-serif;
+ }
+
+ * {
+ box-sizing: border-box;
+ }
+
+ html, body {
+ height: 100%;
+ margin: 0;
+ padding: 0;
+ background: radial-gradient(circle at top, #1a1a26 0, #050509 52%, #000 100%);
+ color: var(--text-main);
+ font-family: var(--font-body);
+ -webkit-font-smoothing: antialiased;
+ }
+
+ body {
+ display: flex;
+ align-items: stretch;
+ justify-content: center;
+ }
+
+ .app {
+ display: flex;
+ gap: 28px;
+ max-width: 1120px;
+ width: 100%;
+ padding: 22px 26px;
+ }
+
+ @media (max-width: 920px) {
+ .app {
+ flex-direction: column;
+ align-items: center;
+ padding: 18px;
+ gap: 20px;
+ }
+ }
+
+ /* LEFT: PHONE PREVIEW */
+
+ .preview-column {
+ flex: 0 0 auto;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 16px;
+ }
+
+ .branding {
+ text-align: center;
+ }
+
+ .branding-title {
+ letter-spacing: 0.12em;
+ text-transform: uppercase;
+ font-size: 11px;
+ color: var(--accent-strong);
+ }
+
+ .branding-main {
+ margin-top: 4px;
+ font-size: 18px;
+ letter-spacing: 0.06em;
+ text-transform: uppercase;
+ }
+
+ .branding-sub {
+ margin-top: 3px;
+ font-size: 11px;
+ color: var(--text-muted);
+ letter-spacing: 0.11em;
+ text-transform: uppercase;
+ }
+
+ .phone-frame-wrapper {
+ position: relative;
+ padding: 8px;
+ border-radius: calc(var(--phone-radius) + 6px);
+ background: radial-gradient(circle at 20% 0, rgba(210,181,126,0.28), transparent 55%),
+ radial-gradient(circle at 80% 120%, rgba(117,104,84,0.35), transparent 60%),
+ linear-gradient(145deg, #050509, #12121b);
+ box-shadow: var(--shadow-soft);
+ }
+
+ .phone-outline {
+ position: relative;
+ width: 280px;
+ height: calc(280px * 16 / 9);
+ border-radius: var(--phone-radius);
+ background: radial-gradient(circle at 10% 0, #282834, #090910 55%);
+ padding: 10px 6px;
+ box-shadow:
+ inset 0 0 0 1px rgba(255,255,255,0.02),
+ inset 0 0 0 2px rgba(0,0,0,0.8),
+ 0 20px 45px rgba(0,0,0,0.9);
+ overflow: hidden;
+ }
+
+ /* Notch & hardware hints */
+
+ .notch {
+ position: absolute;
+ top: 6px;
+ left: 50%;
+ transform: translateX(-50%);
+ width: 96px;
+ height: 14px;
+ border-radius: 0 0 12px 12px;
+ background: radial-gradient(circle at 50% 0, #2f2f3c, #12121b 70%);
+ box-shadow: 0 1px 3px rgba(0,0,0,0.7);
+ z-index: 3;
+ }
+
+ .notch::before,
+ .notch::after {
+ content: "";
+ position: absolute;
+ top: 4px;
+ border-radius: 999px;
+ }
+ .notch::before {
+ left: 18px;
+ width: 18px;
+ height: 4px;
+ background: radial-gradient(circle, #666674, #11111a);
+ }
+ .notch::after {
+ right: 16px;
+ width: 10px;
+ height: 10px;
+ background: radial-gradient(circle, #44445b, #11111a);
+ }
+
+ .phone-bezel-inner {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ border-radius: calc(var(--phone-radius) - 6px);
+ overflow: hidden;
+ background: #000;
+ }
+
+ /* Reel content */
+
+ .reel-screen {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ background: radial-gradient(circle at 20% -10%, #303046, #050509 55%);
+ color: #f8f8fb;
+ display: flex;
+ flex-direction: column;
+ padding: 14px 11px 12px;
+ }
+
+ /* Faux Instagram UI chrome */
+
+ .reel-status-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ font-size: 9px;
+ color: #d9d9e6;
+ opacity: 0.92;
+ margin-bottom: 6px;
+ }
+ .reel-status-bar span {
+ opacity: 0.9;
+ }
+
+ .reel-progress-bar {
+ width: 100%;
+ height: 3px;
+ border-radius: 999px;
+ background: rgba(255,255,255,0.1);
+ overflow: hidden;
+ margin-bottom: 5px;
+ display: flex;
+ gap: 2px;
+ }
+
+ .reel-progress-segment {
+ flex: 1;
+ background: rgba(255,255,255,0.08);
+ position: relative;
+ overflow: hidden;
+ border-radius: 999px;
+ }
+
+ .reel-progress-segment-fill {
+ position: absolute;
+ top: 0; left: 0; bottom: 0;
+ width: 0%;
+ background: linear-gradient(90deg, #f5f5ff, #e3c893);
+ border-radius: inherit;
+ transition: width 120ms linear;
+ }
+
+ .reel-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ font-size: 9px;
+ margin-bottom: 6px;
+ }
+
+ .reel-profile {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ }
+
+ .reel-avatar {
+ width: 17px;
+ height: 17px;
+ border-radius: 999px;
+ background: radial-gradient(circle at 30% 20%, #f5e7d1, #987a48 40%, #41363f 70%, #0c0b11 100%);
+ border: 1px solid rgba(255,255,255,0.35);
+ box-shadow: 0 0 0 1px rgba(0,0,0,0.7);
+ }
+
+ .reel-handle {
+ display: flex;
+ flex-direction: column;
+ gap: 1px;
+ }
+
+ .reel-handle-main {
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+ font-size: 8px;
+ }
+
+ .reel-handle-sub {
+ font-size: 8px;
+ color: rgba(230,230,240,0.7);
+ }
+
+ .reel-header-icons {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ opacity: 0.95;
+ }
+
+ .reel-header-dot-menu {
+ width: 12px;
+ height: 3px;
+ border-radius: 999px;
+ background: radial-gradient(circle, rgba(255,255,255,0.95) 0, rgba(255,255,255,0.6) 55%, transparent 100%);
+ }
+
+ /* Scene visual */
+
+ .scene-visual {
+ flex: 1;
+ border-radius: 18px;
+ overflow: hidden;
+ position: relative;
+ background: radial-gradient(circle at 10% 0, #3b3b4c, #050509 65%);
+ box-shadow: 0 18px 38px rgba(0,0,0,0.65);
+ border: 1px solid rgba(255,255,255,0.06);
+ }
+
+ .scene-gradient-overlay {
+ position: absolute;
+ inset: 0;
+ background:
+ linear-gradient(135deg, rgba(210,181,126,0.14), transparent 40%),
+ radial-gradient(circle at 80% 120%, rgba(0,0,0,0.85), transparent 60%);
+ mix-blend-mode: screen;
+ opacity: 0.9;
+ pointer-events: none;
+ }
+
+ .scene-panes {
+ position: absolute;
+ inset: 0;
+ display: grid;
+ grid-template-columns: 1.2fr 0.9fr;
+ overflow: hidden;
+ }
+
+ .pane-left,
+ .pane-right {
+ position: relative;
+ }
+
+ .pane-left::before {
+ content: "";
+ position: absolute;
+ inset: 8% 10% 6% 10%;
+ border-radius: 20px;
+ background:
+ linear-gradient(145deg, #1c1c27, #050509 65%),
+ radial-gradient(circle at 10% 0, rgba(210,181,126,0.18), transparent 55%);
+ box-shadow:
+ inset 0 0 0 1px rgba(255,255,255,0.05),
+ 0 16px 34px rgba(0,0,0,0.8);
+ }
+
+ .pane-right::before {
+ content: "";
+ position: absolute;
+ inset: 10% 14% 10% 0;
+ border-radius: 18px;
+ background:
+ linear-gradient(165deg, #13131e, #08060a 55%),
+ radial-gradient(circle at 40% 0, rgba(210,181,126,0.18), transparent 45%);
+ box-shadow:
+ inset 0 0 0 1px rgba(255,255,255,0.03),
+ 0 16px 34px rgba(0,0,0,0.9);
+ }
+
+ .pane-wall-stripes {
+ position: absolute;
+ inset: 14% 10% 16% 14%;
+ background-image:
+ repeating-linear-gradient(
+ 100deg,
+ rgba(255,255,255,0.14) 0,
+ rgba(255,255,255,0.1) 4px,
+ rgba(0,0,0,0.5) 4px,
+ rgba(0,0,0,0.5) 8px
+ );
+ opacity: 0.32;
+ mix-blend-mode: screen;
+ border-radius: 22px;
+ }
+
+ .pane-right-grid {
+ position: absolute;
+ inset: 16% 16% 18% 4%;
+ display: grid;
+ grid-template-columns: 1fr;
+ grid-auto-rows: 1fr;
+ gap: 6px;
+ }
+
+ .pane-swatch {
+ border-radius: 11px;
+ background: conic-gradient(from 210deg, #f7e6d1, #c8a16a, #7e6545, #241e26, #f7e6d1);
+ position: relative;
+ overflow: hidden;
+ }
+
+ .pane-swatch::before {
+ content: "";
+ position: absolute;
+ inset: 12%;
+ border-radius: 9px;
+ background:
+ linear-gradient(145deg, #f2e4cf, #c7a36d 50%, #7a6648 80%);
+ mix-blend-mode: normal;
+ }
+
+ .pane-detail {
+ border-radius: 11px;
+ position: relative;
+ overflow: hidden;
+ background:
+ radial-gradient(circle at 0 0, #f5e5cc, #947a53 40%, #30272f 75%),
+ repeating-linear-gradient(
+ 45deg,
+ rgba(255,255,255,0.32) 0,
+ rgba(255,255,255,0.25) 1px,
+ rgba(140,126,103,0.6) 2px,
+ rgba(140,126,103,0.6) 4px
+ );
+ opacity: 0.95;
+ }
+
+ .pane-detail::before {
+ content: "";
+ position: absolute;
+ inset: 10%;
+ border-radius: 10px;
+ border: 1px dashed rgba(0,0,0,0.35);
+ opacity: 0.32;
+ }
+
+ .pane-glow-orb {
+ position: absolute;
+ width: 80px;
+ height: 80px;
+ border-radius: 50%;
+ right: 10%;
+ bottom: 9%;
+ background: radial-gradient(circle, rgba(255,255,255,0.9), rgba(210,181,126,0.9), transparent 70%);
+ opacity: 0.22;
+ filter: blur(1px);
+ pointer-events: none;
+ }
+
+ .scene-label {
+ position: absolute;
+ top: 10px;
+ left: 12px;
+ padding: 3px 7px 3px 6px;
+ border-radius: 999px;
+ font-size: 8px;
+ text-transform: uppercase;
+ letter-spacing: 0.16em;
+ background: rgba(6,6,10,0.86);
+ color: rgba(245,245,255,0.9);
+ border: 1px solid rgba(255,255,255,0.12);
+ display: inline-flex;
+ align-items: center;
+ gap: 5px;
+ }
+
+ .scene-label-dot {
+ width: 7px;
+ height: 7px;
+ border-radius: 999px;
+ background: radial-gradient(circle, #fce5b8, #c08f43 60%, #433629 100%);
+ box-shadow: 0 0 0 1px rgba(0,0,0,0.6);
+ }
+
+ .scene-timer {
+ position: absolute;
+ top: 10px;
+ right: 10px;
+ padding: 3px 7px;
+ border-radius: 999px;
+ font-size: 8px;
+ text-transform: uppercase;
+ letter-spacing: 0.16em;
+ color: rgba(245,245,255,0.8);
+ background: rgba(7,7,11,0.9);
+ border: 1px solid rgba(255,255,255,0.12);
+ }
+
+ /* Captions overlay */
+
+ .caption-container {
+ position: absolute;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ padding: 10px 10px 9px;
+ pointer-events: none;
+ }
+
+ .caption-backdrop {
+ border-radius: 16px;
+ padding: 7px 7px 6px;
+ background: linear-gradient(to top, rgba(0,0,0,0.92), rgba(0,0,0,0.68), transparent);
+ border: 1px solid rgba(255,255,255,0.08);
+ box-shadow: 0 16px 26px rgba(0,0,0,0.9);
+ pointer-events: auto;
+ }
+
+ .caption-text {
+ font-size: 11px;
+ line-height: 1.4;
+ color: #f5f5ff;
+ max-height: 52px;
+ overflow: hidden;
+ position: relative;
+ }
+
+ .caption-text.fade-in {
+ animation: captionFade 380ms ease-out forwards;
+ }
+
+ @keyframes captionFade {
+ from {
+ opacity: 0;
+ transform: translateY(8px);
+ filter: blur(2px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ filter: blur(0);
+ }
+ }
+
+ .caption-text span.key {
+ color: var(--accent-strong);
+ font-weight: 500;
+ }
+
+ .caption-meta {
+ margin-top: 4px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ font-size: 9px;
+ color: rgba(210,210,230,0.8);
+ }
+
+ .caption-meta-left {
+ display: flex;
+ gap: 7px;
+ align-items: center;
+ }
+
+ .caption-pill {
+ padding: 2px 6px 3px;
+ border-radius: 999px;
+ border: 1px solid rgba(255,255,255,0.16);
+ background: rgba(20,20,35,0.72);
+ font-size: 8px;
+ text-transform: uppercase;
+ letter-spacing: 0.14em;
+ }
+
+ .caption-meta-tag {
+ opacity: 0.7;
+ }
+
+ .caption-meta-ticks {
+ font-size: 8px;
+ letter-spacing: 0.08em;
+ opacity: 0.85;
+ }
+
+ /* Right controls */
+
+ .controls-column {
+ flex: 1;
+ background: radial-gradient(circle at top left, rgba(210,181,126,0.08), transparent 50%),
+ linear-gradient(145deg, #050509, #12121b);
+ border-radius: 22px;
+ border: 1px solid rgba(255,255,255,0.05);
+ padding: 16px 16px 14px;
+ display: flex;
+ flex-direction: column;
+ box-shadow:
+ 0 26px 60px rgba(0,0,0,0.9),
+ inset 0 0 0 1px rgba(255,255,255,0.02);
+ }
+
+ @media (max-width: 920px) {
+ .phone-outline {
+ width: 240px;
+ height: calc(240px * 16 / 9);
+ }
+ .controls-column {
+ width: 100%;
+ max-width: 640px;
+ }
+ }
+
+ .panel-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: baseline;
+ margin-bottom: 10px;
+ }
+
+ .panel-title {
+ font-size: 13px;
+ letter-spacing: 0.18em;
+ text-transform: uppercase;
+ color: var(--text-main);
+ }
+
+ .panel-subtitle {
+ font-size: 11px;
+ color: var(--text-muted);
+ }
+
+ .tagline {
+ font-size: 11px;
+ color: var(--accent-strong);
+ letter-spacing: 0.14em;
+ text-transform: uppercase;
+ margin-bottom: 10px;
+ }
+
+ .scene-timeline {
+ display: flex;
+ gap: 6px;
+ margin-bottom: 10px;
+ }
+
+ .timeline-chip {
+ flex: 1;
+ border-radius: 999px;
+ padding: 6px 7px;
+ border: 1px solid var(--border-subtle);
+ background: rgba(9,9,16,0.9);
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ font-size: 10px;
+ color: var(--text-muted);
+ cursor: pointer;
+ transition: border-color var(--transition-fast),
+ background var(--transition-fast),
+ transform 120ms ease-out,
+ box-shadow 120ms ease-out;
+ }
+
+ .timeline-chip-label {
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+ }
+
+ .timeline-chip-title {
+ text-transform: uppercase;
+ letter-spacing: 0.14em;
+ font-size: 9px;
+ }
+
+ .timeline-chip-desc {
+ font-size: 9px;
+ opacity: 0.8;
+ }
+
+ .timeline-chip-duration {
+ padding: 2px 5px;
+ border-radius: 999px;
+ background: rgba(32,32,48,0.9);
+ font-size: 9px;
+ }
+
+ .timeline-chip.active {
+ border-color: var(--accent-soft);
+ background: radial-gradient(circle at top left, rgba(210,181,126,0.16), rgba(12,12,20,0.98));
+ color: var(--text-main);
+ box-shadow: 0 0 0 1px rgba(210,181,126,0.2);
+ transform: translateY(-1px);
+ }
+
+ .timeline-chip.active .timeline-chip-duration {
+ background: rgba(210,181,126,0.16);
+ }
+
+ .transport-row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 10px;
+ gap: 10px;
+ }
+
+ .transport-left {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ }
+
+ .btn-ghost {
+ border-radius: 999px;
+ border: 1px solid var(--border-subtle);
+ padding: 6px 10px;
+ background: radial-gradient(circle at 0 0, rgba(255,255,255,0.05), transparent 60%);
+ color: var(--text-main);
+ font-size: 11px;
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ cursor: pointer;
+ letter-spacing: 0.12em;
+ text-transform: uppercase;
+ transition: border-color var(--transition-fast),
+ background var(--transition-fast),
+ transform 80ms ease-out,
+ box-shadow 80ms ease-out;
+ }
+
+ .btn-ghost span.icon {
+ width: 9px;
+ height: 9px;
+ border-radius: 999px;
+ background: radial-gradient(circle, #f4e0b9, #ba8b45 55%, #36251b 100%);
+ box-shadow: 0 0 0 1px rgba(0,0,0,0.6);
+ }
+
+ .btn-ghost:hover {
+ border-color: rgba(210,181,126,0.5);
+ background: radial-gradient(circle at 0 0, rgba(210,181,126,0.14), rgba(10,10,18,0.96));
+ box-shadow: 0 0 0 1px rgba(210,181,126,0.25);
+ }
+
+ .btn-ghost:active {
+ transform: translateY(1px);
+ box-shadow: none;
+ }
+
+ .transport-right {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 10px;
+ color: var(--text-muted);
+ }
+
+ .play-toggle {
+ width: 26px;
+ height: 26px;
+ border-radius: 999px;
+ background: radial-gradient(circle at 30% 20%, #f9e6c4, #c39a5b 55%, #3c3022 100%);
+ border: 1px solid rgba(255,255,255,0.4);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: #050509;
+ font-size: 11px;
+ cursor: pointer;
+ box-shadow:
+ 0 0 0 1px rgba(0,0,0,0.8),
+ 0 10px 18px rgba(0,0,0,0.8);
+ transition: transform 60ms ease-out, box-shadow 60ms ease-out, filter 120ms ease-out;
+ }
+
+ .play-toggle.paused {
+ filter: grayscale(0.1) brightness(0.95);
+ opacity: 0.9;
+ }
+
+ .play-toggle:active {
+ transform: translateY(1px) scale(0.97);
+ box-shadow: 0 3px 8px rgba(0,0,0,0.9);
+ }
+
+ .scene-indicator {
+ padding: 2px 7px;
+ border-radius: 999px;
+ border: 1px solid var(--border-subtle);
+ background: rgba(16,16,26,0.9);
+ font-size: 9px;
+ letter-spacing: 0.16em;
+ text-transform: uppercase;
+ }
+
+ .scene-indicator span {
+ color: var(--accent-strong);
+ }
+
+ .duration-label {
+ font-variant-numeric: tabular-nums;
+ }
+
+ .editor {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ margin-top: 4px;
+ }
+
+ .field-group {
+ background: rgba(10,10,16,0.9);
+ border-radius: 16px;
+ border: 1px solid var(--border-subtle);
+ padding: 9px 10px;
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+ }
+
+ .field-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: baseline;
+ }
+
+ .field-title {
+ font-size: 10px;
+ text-transform: uppercase;
+ letter-spacing: 0.18em;
+ color: var(--text-main);
+ }
+
+ .field-badge {
+ font-size: 9px;
+ color: var(--accent-strong);
+ letter-spacing: 0.16em;
+ text-transform: uppercase;
+ padding: 2px 7px;
+ border-radius: 999px;
+ border: 1px solid rgba(210,181,126,0.4);
+ background: rgba(210,181,126,0.14);
+ }
+
+ .field-subtitle {
+ font-size: 10px;
+ color: var(--text-muted);
+ }
+
+ textarea {
+ margin-top: 4px;
+ width: 100%;
+ min-height: 68px;
+ resize: vertical;
+ border-radius: 12px;
+ border: 1px solid rgba(60,60,84,0.9);
+ background: radial-gradient(circle at top, rgba(210,181,126,0.08), rgba(8,8,12,0.98));
+ color: var(--text-main);
+ font-family: inherit;
+ font-size: 11px;
+ padding: 7px 8px;
+ outline: none;
+ box-shadow: inset 0 0 0 1px rgba(0,0,0,0.7);
+ transition: border-color var(--transition-fast),
+ box-shadow var(--transition-fast),
+ background var(--transition-fast);
+ }
+
+ textarea:focus {
+ border-color: rgba(210,181,126,0.7);
+ box-shadow:
+ 0 0 0 1px rgba(210,181,126,0.35),
+ 0 0 0 1px rgba(0,0,0,0.9);
+ background: radial-gradient(circle at top, rgba(210,181,126,0.14), rgba(8,8,12,0.98));
+ }
+
+ .helper-row {
+ display: flex;
+ justify-content: space-between;
+ font-size: 9px;
+ color: var(--text-muted);
+ }
+
+ .helper-row span strong {
+ color: var(--accent-strong);
+ }
+
+ .scene-meta-grid {
+ display: grid;
+ grid-template-columns: 1.2fr 1fr;
+ gap: 8px;
+ }
+
+ @media (max-width: 680px) {
+ .scene-meta-grid {
+ grid-template-columns: 1fr;
+ }
+ }
+
+ .pill-row {
+ display: flex;
+ gap: 6px;
+ flex-wrap: wrap;
+ margin-top: 3px;
+ }
+
+ .mini-pill {
+ font-size: 9px;
+ padding: 3px 6px;
+ border-radius: 999px;
+ border: 1px solid rgba(60,60,84,0.9);
+ color: var(--text-muted);
+ background: rgba(10,10,18,0.96);
+ }
+
+ .mini-pill.highlight {
+ border-color: rgba(210,181,126,0.7);
+ color: var(--accent-strong);
+ background: rgba(210,181,126,0.08);
+ }
+
+ .cta-note {
+ font-size: 10px;
+ color: var(--text-muted);
+ }
+
+ .cta-note span {
+ color: var(--accent-strong);
+ }
+
+ .footer-hint {
+ margin-top: 6px;
+ font-size: 9px;
+ color: var(--text-muted);
+ display: flex;
+ justify-content: space-between;
+ gap: 8px;
+ flex-wrap: wrap;
+ }
+
+ .footer-hint span {
+ opacity: 0.8;
+ }
+
+ .footer-hint span.code {
+ font-family: "SF Mono", ui-monospace, Menlo, Monaco, Consolas, monospace;
+ font-size: 9px;
+ background: rgba(12,12,18,0.9);
+ padding: 2px 4px;
+ border-radius: 5px;
+ border: 1px solid rgba(40,40,62,0.8);
+ }
+</style>
+</head>
+<body>
+<div class="app">
+ <section class="preview-column">
+ <header class="branding">
+ <div class="branding-title">Storyboard</div>
+ <div class="branding-main">Reels for Walls</div>
+ <div class="branding-sub">Vertical 9:16 | Wallcovering launch</div>
+ </header>
+
+ <div class="phone-frame-wrapper">
+ <div class="phone-outline">
+ <div class="notch"></div>
+ <div class="phone-bezel-inner">
+ <div class="reel-screen">
+ <div class="reel-status-bar">
+ <span>9:16 • Preview</span>
+ <span id="clock">00:00</span>
+ </div>
+ <div class="reel-progress-bar" id="progressBar">
+ <div class="reel-progress-segment"><div class="reel-progress-segment-fill"></div></div>
+ <div class="reel-progress-segment"><div class="reel-progress-segment-fill"></div></div>
+ <div class="reel-progress-segment"><div class="reel-progress-segment-fill"></div></div>
+ <div class="reel-progress-segment"><div class="reel-progress-segment-fill"></div></div>
+ <div class="reel-progress-segment"><div class="reel-progress-segment-fill"></div></div>
+ </div>
+ <div class="reel-header">
+ <div class="reel-profile">
+ <div class="reel-avatar"></div>
+ <div class="reel-handle">
+ <div class="reel-handle-main">@atelier.wall</div>
+ <div class="reel-handle-sub">New Collection • Storyboard</div>
+ </div>
+ </div>
+ <div class="reel-header-icons">
+ <div class="reel-header-dot-menu"></div>
+ </div>
+ </div>
+
+ <div class="scene-visual">
+ <div class="scene-gradient-overlay"></div>
+ <div class="scene-panes">
+ <div class="pane-left">
+ <div class="pane-wall-stripes"></div>
+ </div>
+ <div class="pane-right">
+ <div class="pane-right-grid">
+ <div class="pane-swatch"></div>
+ <div class="pane-detail"></div>
+ </div>
+ </div>
+ </div>
+ <div class="pane-glow-orb"></div>
+ <div class="scene-label">
+ <span class="scene-label-dot"></span>
+ <span id="sceneLabelText">Hook • Scene 1</span>
+ </div>
+ <div class="scene-timer" id="sceneTimer">00:00 – 00:02</div>
+
+ <div class="caption-container">
+ <div class="caption-backdrop">
+ <div class="caption-text" id="captionDisplay"></div>
+ <div class="caption-meta">
+ <div class="caption-meta-left">
+ <span class="caption-pill" id="captionScenePill">Hook</span>
+ <span class="caption-meta-tag">Animated captions • 9:16</span>
+ </div>
+ <div class="caption-meta-ticks" id="captionTicks">⏱ • 0.0s</div>
+ </div>
+ </div>
+ </div>
+ </div> <!-- scene-visual -->
+ </div> <!-- reel-screen -->
+ </div>
+ </div>
+ </div>
+ </section>
+
+ <section class="controls-column">
+ <header class="panel-header">
+ <div>
+ <div class="panel-title">Reel Storyboard</div>
+ <div class="panel-subtitle">Plan 5 scenes for your wallcovering launch reel.</div>
+ </div>
+ <div class="tagline">Luxe wall stories, frame by frame</div>
+ </header>
+
+ <div class="scene-timeline" id="sceneTimeline">
+ <!-- Scene chips injected by JS -->
+ </div>
+
+ <div class="transport-row">
+ <div class="transport-left">
+ <button class="btn-ghost" id="resetBtn">
+ <span class="icon"></span>
+ Reset order
+ </button>
+ <span class="scene-indicator" id="sceneIndicator">
+ Scene <span>1</span> / 5
+ </span>
+ </div>
+ <div class="transport-right">
+ <button class="play-toggle paused" id="playToggle" aria-label="Play or pause preview">
+ ▷
+ </button>
+ <span class="duration-label" id="durationLabel">00.0 / 10.0s</span>
+ </div>
+ </div>
+
+ <div class="editor">
+ <div class="field-group">
+ <div class="field-header">
+ <div>
+ <div class="field-title" id="fieldTitle">Hook caption</div>
+ <div class="field-subtitle" id="fieldSubtitle">Stop the scroll in the first second. Lead with transformation.</div>
+ </div>
+ <div class="field-badge" id="fieldBadge">Scene 1 • Hook</div>
+ </div>
+ <textarea id="captionInput"></textarea>
+ <div class="helper-row">
+ <span>Use <strong>*asterisks*</strong> to highlight hero phrases.</span>
+ <span id="charCount">0 / 120</span>
+ </div>
+ </div>
+
+ <div class="scene-meta-grid">
+ <div class="field-group">
+ <div class="field-header">
+ <div class="field-title">Scene timing</div>
+ </div>
+ <div class="field-subtitle">Scenes auto-loop based on durations below (seconds).</div>
+ <div class="pill-row" id="durationPills">
+ <!-- Duration pills injected -->
+ </div>
+ </div>
+
+ <div class="field-group">
+ <div class="field-title">CTA & mood</div>
+ <div class="cta-note">
+ Final frame should invite action:
+ <span>"Save for your renovation", "Tap to order swatches"</span>, or a showroom visit.
+ </div>
+ <div class="pill-row">
+ <div class="mini-pill highlight">Muted glamour</div>
+ <div class="mini-pill">Warm metallics</div>
+ <div class="mini-pill">Textured close-ups</div>
+ </div>
+ </div>
+ </div>
+
+ <div class="footer-hint">
+ <span>Tip: Match each scene to a beat in your audio for seamless transitions.</span>
+ <span>Hook → Reveal → Texture → Swatches → <span class="code">CTA: "Your walls, reimagined."</span></span>
+ </div>
+ </div>
+ </section>
+</div>
+
+<script>
+(function () {
+ const scenes = [
+ {
+ id: 1,
+ key: "Hook",
+ name: "Hook",
+ title: "Hook caption",
+ subtitle: "Stop the scroll in the first second. Lead with transformation.",
+ duration: 2.0,
+ defaultCaption:
+ "*Bare wall* today. Boutique hotel tomorrow. Meet the wallcovering that changes everything."
+ },
+ {
+ id: 2,
+ key: "Reveal",
+ name: "Room reveal",
+ title: "Room reveal",
+ subtitle: "Pull back to show the full space dressed in your hero pattern.",
+ duration: 2.5,
+ defaultCaption:
+ "From *blank* to breathtaking. A single wall, washed in tailored texture and quiet shine."
+ },
+ {
+ id: 3,
+ key: "Texture",
+ name: "Texture detail",
+ title: "Texture close-up",
+ subtitle: "Let them feel the surface through the screen.",
+ duration: 2.0,
+ defaultCaption:
+ "Hand-drawn lines, layered inks, and a soft brushed shimmer you can almost *touch*."
+ },
+ {
+ id: 4,
+ key: "Swatches",
+ name: "Swatch grid",
+ title: "Swatch grid",
+ subtitle: "Show options: tones, scales, or material stories.",
+ duration: 1.8,
+ defaultCaption:
+ "Four curated colorways, designed to shift with sunrise, candlelight, and everything between."
+ },
+ {
+ id: 5,
+ key: "CTA",
+ name: "Call to action",
+ title: "CTA",
+ subtitle: "End with a clear, simple next step.",
+ duration: 1.7,
+ defaultCaption:
+ "*Save this wall* for your renovation board and tap for samples delivered to your studio."
+ }
+ ];
+
+ const sceneTimelineEl = document.getElementById("sceneTimeline");
+ const durationPillsEl = document.getElementById("durationPills");
+ const captionDisplayEl = document.getElementById("captionDisplay");
+ const captionInputEl = document.getElementById("captionInput");
+ const sceneLabelTextEl = document.getElementById("sceneLabelText");
+ const sceneTimerEl = document.getElementById("sceneTimer");
+ const captionScenePillEl = document.getElementById("captionScenePill");
+ const captionTicksEl = document.getElementById("captionTicks");
+ const sceneIndicatorEl = document.getElementById("sceneIndicator");
+ const durationLabelEl = document.getElementById("durationLabel");
+ const playToggleEl = document.getElementById("playToggle");
+ const resetBtnEl = document.getElementById("resetBtn");
+ const fieldTitleEl = document.getElementById("fieldTitle");
+ const fieldSubtitleEl = document.getElementById("fieldSubtitle");
+ const fieldBadgeEl = document.getElementById("fieldBadge");
+ const charCountEl = document.getElementById("charCount");
+ const clockEl = document.getElementById("clock");
+ const progressSegments = Array.from(
+ document.querySelectorAll(".reel-progress-segment-fill")
+ );
+
+ let currentSceneIndex = 0;
+ let isPlaying = false;
+ let startTime = null;
+ let currentSceneStart = 0;
+ let frameReq = null;
+ const maxChars = 120;
+
+ const captionValues = {};
+ scenes.forEach(scene => {
+ captionValues[scene.id] = scene.defaultCaption;
+ });
+
+ function totalDuration() {
+ return scenes.reduce((sum, s) => sum + s.duration, 0);
+ }
+
+ function formatTime(ms) {
+ const sec = ms / 1000;
+ const m = Math.floor(sec / 60);
+ const s = Math.floor(sec % 60);
+ return `${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
+ }
+
+ function formatSeconds(sec) {
+ return sec.toFixed(1).padStart(4, "0");
+ }
+
+ function formatSceneRange(sceneIndex, offsetSec, sceneStartGlobal) {
+ let offset = 0;
+ for (let i = 0; i < sceneIndex; i++) offset += scenes[i].duration;
+ const start = offset;
+ const end = start + scenes[sceneIndex].duration;
+ return `${start.toFixed(1).padStart(4, "0")} – ${end
+ .toFixed(1)
+ .padStart(4, "0")}s`;
+ }
+
+ function renderCaption(scene) {
+ const raw = captionValues[scene.id] || "";
+ const escaped = raw
+ .replace(/&/g, "&")
+ .replace(/</g, "<")
+ .replace(/>/g, ">");
+ const withHighlights = escaped.replace(
+ /\*(.+?)\*/g,
+ '<span class="key">$1</span>'
+ );
+ captionDisplayEl.innerHTML = withHighlights;
+ captionDisplayEl.classList.remove("fade-in");
+ void captionDisplayEl.offsetWidth;
+ captionDisplayEl.classList.add("fade-in");
+ }
+
+ function updateSceneMeta() {
+ const scene = scenes[currentSceneIndex];
+ const sceneNumber = currentSceneIndex + 1;
+ sceneLabelTextEl.textContent = `${scene.key} • Scene ${sceneNumber}`;
+ captionScenePillEl.textContent = scene.key;
+ sceneIndicatorEl.innerHTML = `Scene <span>${sceneNumber}</span> / ${scenes.length}`;
+ fieldTitleEl.textContent = scene.title;
+ fieldSubtitleEl.textContent = scene.subtitle;
+ fieldBadgeEl.textContent = `Scene ${sceneNumber} • ${scene.name}`;
+ captionInputEl.value = captionValues[scene.id] || "";
+ updateCharCount();
+ captionTicksEl.textContent = `⏱ • 0.0s`;
+ updateSceneTimer(0);
+ renderCaption(scene);
+ }
+
+ function updateSceneTimer(offsetSec) {
+ const scene = scenes[currentSceneIndex];
+ sceneTimerEl.textContent = formatSceneRange(
+ currentSceneIndex,
+ offsetSec,
+ 0
+ );
+ }
+
+ function updateTimelineUI() {
+ const chips = Array.from(
+ sceneTimelineEl.querySelectorAll(".timeline-chip")
+ );
+ chips.forEach((chip, idx) => {
+ chip.classList.toggle("active", idx === currentSceneIndex);
+ });
+
+ const total = totalDuration();
+ durationLabelEl.textContent = `${formatSeconds(
+ elapsedMs() / 1000
+ )} / ${total.toFixed(1)}s`;
+ }
+
+ function updateDurationPills() {
+ durationPillsEl.innerHTML = "";
+ scenes.forEach((scene, idx) => {
+ const pill = document.createElement("button");
+ pill.type = "button";
+ pill.className =
+ "mini-pill" + (idx === currentSceneIndex ? " highlight" : "");
+ pill.textContent = `${scene.key} • ${scene.duration.toFixed(1)}s`;
+ durationPillsEl.appendChild(pill);
+ });
+ }
+
+ function buildSceneTimeline() {
+ sceneTimelineEl.innerHTML = "";
+ scenes.forEach((scene, idx) => {
+ const chip = document.createElement("button");
+ chip.type = "button";
+ chip.className =
+ "timeline-chip" + (idx === currentSceneIndex ? " active" : "");
+ chip.dataset.index = idx;
+
+ chip.innerHTML = `
+ <div class="timeline-chip-label">
+ <span class="timeline-chip-title">${scene.key}</span>
+ <span class="timeline-chip-desc">${scene.name}</span>
+ </div>
+ <span class="timeline-chip-duration">${scene.duration.toFixed(
+ 1
+ )}s</span>
+ `;
+ chip.addEventListener("click", () => {
+ jumpToScene(idx);
+ });
+ sceneTimelineEl.appendChild(chip);
+ });
+ }
+
+ function buildDurationPills() {
+ updateDurationPills();
+ }
+
+ function jumpToScene(idx) {
+ currentSceneIndex = idx;
+ currentSceneStart = sceneStartOffset(idx);
+ if (isPlaying) {
+ startTime = performance.now() - currentSceneStart * 1000;
+ }
+ updateSceneMeta();
+ updateTimelineUI();
+ updateProgress(0);
+ }
+
+ function sceneStartOffset(index) {
+ let offset = 0;
+ for (let i = 0; i < index; i++) offset += scenes[i].duration;
+ return offset;
+ }
+
+ function updateProgress(nowMs) {
+ const total = totalDuration();
+ const globalElapsedSec = isPlaying
+ ? (nowMs - startTime) / 1000
+ : currentSceneStart;
+ const loopedElapsed =
+ ((globalElapsedSec % total) + total) % total;
+
+ // determine current scene based on loopedElapsed
+ let acc = 0;
+ let newIndex = 0;
+ for (let i = 0; i < scenes.length; i++) {
+ const sDur = scenes[i].duration;
+ if (loopedElapsed < acc + sDur) {
+ newIndex = i;
+ break;
+ }
+ acc += sDur;
+ }
+
+ if (newIndex !== currentSceneIndex) {
+ currentSceneIndex = newIndex;
+ currentSceneStart = acc;
+ updateSceneMeta();
+ updateDurationPills();
+ }
+
+ const sceneElapsed = loopedElapsed - currentSceneStart;
+ captionTicksEl.textContent = `⏱ • ${sceneElapsed.toFixed(1)}s`;
+ updateSceneTimer(sceneElapsed);
+
+ // update progress bar
+ let running = 0;
+ scenes.forEach((scene, idx) => {
+ const segFill = progressSegments[idx];
+ const segDur = scene.duration;
+ let widthPercent = 0;
+ if (loopedElapsed >= running + segDur) {
+ widthPercent = 100;
+ } else if (loopedElapsed <= running) {
+ widthPercent = 0;
+ } else {
+ const local = loopedElapsed - running;
+ widthPercent = (local / segDur) * 100;
+ }
+ segFill.style.width = `${widthPercent}%`;
+ running += segDur;
+ });
+
+ // status bar clock
+ clockEl.textContent = formatTime(loopedElapsed * 1000);
+
+ durationLabelEl.textContent = `${formatSeconds(
+ loopedElapsed
+ )} / ${total.toFixed(1)}s`;
+ updateTimelineUI();
+ }
+
+ function elapsedMs() {
+ if (!isPlaying) {
+ return currentSceneStart * 1000;
+ }
+ const now = performance.now();
+ return now - startTime;
+ }
+
+ function loop(now) {
+ if (!isPlaying) return;
+ updateProgress(now);
+ frameReq = requestAnimationFrame(loop);
+ }
+
+ function play() {
+ if (isPlaying) return;
+ isPlaying = true;
+ playToggleEl.textContent = "❚❚";
+ playToggleEl.classList.remove("paused");
+ const total = totalDuration();
+ const initialSec =
+ currentSceneStart % total;
+ startTime = performance.now() - initialSec * 1000;
+ frameReq = requestAnimationFrame(loop);
+ }
+
+ function pause() {
+ if (!isPlaying) return;
+ isPlaying = false;
+ playToggleEl.textContent = "▷";
+ playToggleEl.classList.add("paused");
+ cancelAnimationFrame(frameReq);
+ const total = totalDuration();
+ const elapsedSec = (performance.now() - startTime) / 1000;
+ const looped = ((elapsedSec % total) + total) % total;
+ currentSceneStart = looped;
+ updateProgress(performance.now());
+ }
+
+ function togglePlay() {
+ if (isPlaying) pause();
+ else play();
+ }
+
+ function resetOrder() {
+ pause();
+ currentSceneIndex = 0;
+ currentSceneStart = 0;
+ scenes.slice().sort((a, b) => a.id - b.id);
+ buildSceneTimeline();
+ updateSceneMeta();
+ updateDurationPills();
+ progressSegments.forEach(seg => (seg.style.width = "0%"));
+ updateProgress(performance.now());
+ }
+
+ function updateCharCount() {
+ const len = captionInputEl.value.length;
+ charCountEl.textContent = `${len} / ${maxChars}`;
+ charCountEl.style.color =
+ len > maxChars ? "var(--danger)" : "var(--text-muted)";
+ }
+
+ captionInputEl.addEventListener("input", () => {
+ captionValues[scenes[currentSceneIndex].id] = captionInputEl.value;
+ updateCharCount();
+ renderCaption(scenes[currentSceneIndex]);
+ });
+
+ playToggleEl.addEventListener("click", togglePlay);
+ resetBtnEl.addEventListener("click", resetOrder);
+
+ captionInputEl.addEventListener("keydown", e => {
+ if (e.key === "Tab") {
+ e.preventDefault();
+ const nextIndex =
+ (currentSceneIndex + 1) % scenes.length;
+ jumpToScene(nextIndex);
+ captionInputEl.focus();
+ captionInputEl.select();
+ }
+ });
+
+ document.addEventListener("visibilitychange", () => {
+ if (document.hidden) {
+ pause();
+ }
+ });
+
+ // Initialize UI
+ buildSceneTimeline();
+ buildDurationPills();
+ updateSceneMeta();
+ updateProgress(performance.now());
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/b72f0e9e751b/gpt.png b/data/artifacts/b72f0e9e751b/gpt.png
new file mode 100644
index 0000000..0fe27c4
Binary files /dev/null and b/data/artifacts/b72f0e9e751b/gpt.png differ
diff --git a/data/artifacts/b72f0e9e751b/hermes3-8b.html b/data/artifacts/b72f0e9e751b/hermes3-8b.html
new file mode 100644
index 0000000..893da25
--- /dev/null
+++ b/data/artifacts/b72f0e9e751b/hermes3-8b.html
@@ -0,0 +1,155 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Wallcovering Brand Storyboard Tool</title>
+ <style>
+ body {
+ margin: 0;
+ padding: 0;
+ font-family: Arial, sans-serif;
+ color: white;
+ background-color: #000;
+ }
+
+ .container {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100vh;
+ }
+
+ .phone-frame {
+ position: relative;
+ width: 135px;
+ height: 270px;
+ background-color: #333;
+ border-radius: 10px;
+ overflow: hidden;
+ }
+
+ .phone-frame::after {
+ content: '';
+ display: block;
+ position: absolute;
+ top: 20px;
+ right: -15px;
+ width: 0;
+ height: 0;
+ border-top: 135px solid transparent;
+ border-bottom: 135px solid #333;
+ border-right: 15px solid white;
+ }
+
+ .scene {
+ position: absolute;
+ top: 20px;
+ left: 20px;
+ width: 90%;
+ height: 80%;
+ background-position: center;
+ background-repeat: no-repeat;
+ background-size: cover;
+ }
+
+ .scene-text {
+ position: absolute;
+ bottom: 10px;
+ left: 10px;
+ color: white;
+ font-size: 12px;
+ text-shadow: 1px 1px 0 #000;
+ }
+
+ .progress-bar {
+ position: absolute;
+ top: 20px;
+ right: 20px;
+ width: 90%;
+ height: 5px;
+ background-color: #444;
+ border-radius: 5px;
+ box-shadow: 0 2px 6px rgba(255, 255, 255, 0.3);
+ }
+
+ .progress-bar-fill {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 100%;
+ background-color: #ff5f58;
+ width: 20%;
+ border-radius: 5px 5px 0 0;
+ }
+ </style>
+</head>
+<body>
+ <div class="container">
+ <div class="phone-frame">
+ <div class="scene" style="background-image:url('https://picsum.photos/135/270?image=1');"></div>
+ <div class="scene-text">Welcome to Our Brand!</div>
+ </div>
+
+ <div class="phone-frame">
+ <div class="scene" style="background-image:url('https://picsum.photos/135/270?image=10');"></div>
+ <div class="scene-text">Transform Your Space</div>
+ </div>
+
+ <div class="phone-frame">
+ <div class="scene" style="background-image:url('https://picsum.photos/135/270?image=100');"></div>
+ <div class="scene-text">Discover the Texture</div>
+ </div>
+
+ <div class="phone-frame">
+ <div class="scene" style="background-image:url('https://picsum.photos/135/270?image=1010');"></div>
+ <div class="scene-text">Choose Your Swatch</div>
+ </div>
+
+ <div class="phone-frame">
+ <div class="scene" style="background-image:url('https://picsum.photos/135/270?image=10000');"></div>
+ <div class="scene-text">Shop Now!</div>
+ </div>
+
+ <div class="progress-bar">
+ <div class="progress-bar-fill"></div>
+ </div>
+ </div>
+
+ <script>
+ let timer = null;
+ let currentIndex = 0;
+
+ function startTimer() {
+ const frames = document.querySelectorAll('.phone-frame');
+ const duration = 5; // seconds
+
+ timer = setInterval(() => {
+ if (currentIndex >= frames.length) {
+ currentIndex = 0;
+ }
+
+ frames[currentIndex].style.zIndex = '1';
+ frames[currentIndex].querySelector('.scene').style.opacity = '1';
+ frames[currentIndex].querySelector('.scene-text').style.opacity = '1';
+
+ const progressFill = document.querySelector('.progress-bar-fill');
+ const progressWidth = (currentIndex / frames.length) * 100;
+ progressFill.style.width = `${progressWidth}%`;
+
+ currentIndex++;
+
+ }, duration * 1000);
+ }
+
+ startTimer();
+
+ function pausePlay() {
+ clearInterval(timer);
+ startTimer();
+ }
+
+ document.querySelector('.phone-frame').addEventListener('click', pausePlay);
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/b72f0e9e751b/hermes3-8b.png b/data/artifacts/b72f0e9e751b/hermes3-8b.png
new file mode 100644
index 0000000..7308b12
Binary files /dev/null and b/data/artifacts/b72f0e9e751b/hermes3-8b.png differ
diff --git a/data/artifacts/b72f0e9e751b/hf-qwen-coder-32b.html b/data/artifacts/b72f0e9e751b/hf-qwen-coder-32b.html
new file mode 100644
index 0000000..d29440f
--- /dev/null
+++ b/data/artifacts/b72f0e9e751b/hf-qwen-coder-32b.html
@@ -0,0 +1,154 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Instagram Reel Storyboard</title>
+ <style>
+ body, html {
+ margin: 0;
+ padding: 0;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background-color: #121212;
+ color: white;
+ font-family: Arial, sans-serif;
+ }
+ .phone-frame {
+ width: 375px;
+ height: 667px;
+ border-radius: 40px;
+ overflow: hidden;
+ position: relative;
+ box-shadow: 0 10px 20px rgba(0, 0, 0, 0.8);
+ }
+ .screen {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ top: 0;
+ left: 0;
+ background-size: cover;
+ background-position: center;
+ }
+ .scene {
+ display: none;
+ position: relative;
+ }
+ .scene.active {
+ display: block;
+ }
+ .caption {
+ position: absolute;
+ bottom: 20px;
+ left: 20px;
+ right: 20px;
+ font-size: 18px;
+ opacity: 0;
+ transition: opacity 0.5s ease-in-out;
+ }
+ .scene.active .caption {
+ opacity: 1;
+ }
+ .controls {
+ position: absolute;
+ bottom: 10px;
+ left: 20px;
+ right: 20px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+ .progress-bar {
+ width: 100%;
+ height: 5px;
+ background-color: rgba(255, 255, 255, 0.3);
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ }
+ .fill {
+ width: 0;
+ height: 100%;
+ background-color: white;
+ transition: width 6s linear;
+ }
+ </style>
+</head>
+<body>
+ <div class="phone-frame">
+ <div id="screen" class="screen"></div>
+ <div id="controls" class="controls">
+ <button onclick="togglePlay()">Play/Pause</button>
+ <div class="progress-bar">
+ <div id="fill" class="fill"></div>
+ </div>
+ </div>
+ <div id="scene1" class="scene active">
+ <div class="caption">Discover the luxury of elegance.</div>
+ </div>
+ <div id="scene2" class="scene">
+ <div class="caption">Transform your space with our textures.</div>
+ </div>
+ <div id="scene3" class="scene">
+ <div class="caption">Feel the smoothness of each touch.</div>
+ </div>
+ <div id="scene4" class="scene">
+ <div class="caption">Choose your perfect color palette.</div>
+ </div>
+ <div id="scene5" class="scene">
+ <div class="caption">Contact us for a custom design today!</div>
+ </div>
+ </div>
+
+ <script>
+ const scenes = [
+ { image: 'https://via.placeholder.com/375x667?text=Hook', duration: 6 },
+ { image: 'https://via.placeholder.com/375x667?text=Room+Reveal', duration: 6 },
+ { image: 'https://via.placeholder.com/375x667?text=Close-up+Texture', duration: 6 },
+ { image: 'https://via.placeholder.com/375x667?text=Swatch+Grid', duration: 6 },
+ { image: 'https://via.placeholder.com/375x667?text=CTA', duration: 6 }
+ ];
+ let currentScene = 0;
+ let timer;
+ let fillWidth = 0;
+ const screen = document.getElementById('screen');
+ const fill = document.getElementById('fill');
+
+ function updateScene() {
+ scenes.forEach((scene, index) => {
+ document.getElementById(`scene${index + 1}`).classList.toggle('active', index === currentScene);
+ });
+ screen.style.backgroundImage = `url(${scenes[currentScene].image})`;
+ fillWidth = 0;
+ fill.style.width = `${fillWidth}%`;
+ }
+
+ function startTimer() {
+ timer = setInterval(() => {
+ fillWidth += 1 / (6 * 100);
+ fill.style.width = `${fillWidth * 100}%`;
+
+ if (fillWidth >= 1) {
+ currentScene = (currentScene + 1) % scenes.length;
+ updateScene();
+ }
+ }, 10);
+ }
+
+ function togglePlay() {
+ if (timer) {
+ clearInterval(timer);
+ timer = null;
+ } else {
+ startTimer();
+ }
+ }
+
+ updateScene();
+ startTimer();
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/b72f0e9e751b/hf-qwen-coder-32b.png b/data/artifacts/b72f0e9e751b/hf-qwen-coder-32b.png
new file mode 100644
index 0000000..311886c
Binary files /dev/null and b/data/artifacts/b72f0e9e751b/hf-qwen-coder-32b.png differ
diff --git a/data/artifacts/b72f0e9e751b/kimi.html b/data/artifacts/b72f0e9e751b/kimi.html
new file mode 100644
index 0000000..1812e7a
--- /dev/null
+++ b/data/artifacts/b72f0e9e751b/kimi.html
@@ -0,0 +1,812 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Luxe Wallcovering Storyboard</title>
+<style>
+:root {
+ --gold: #d4af37;
+ --gold-light: #f4e5c2;
+ --dark: #0a0a0a;
+ --dark-grey: #1a1a1a;
+ --grey: #2a2a2a;
+ --text: #e8e8e8;
+ --transition: cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+ background: var(--dark);
+ color: var(--text);
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 20px;
+ overflow-x: hidden;
+}
+
+header {
+ text-align: center;
+ margin-bottom: 30px;
+ letter-spacing: 2px;
+}
+
+h1 {
+ font-weight: 300;
+ font-size: 1.5rem;
+ color: var(--gold);
+ text-transform: uppercase;
+ margin-bottom: 8px;
+}
+
+.subtitle {
+ font-size: 0.75rem;
+ color: #666;
+ letter-spacing: 3px;
+}
+
+.workspace {
+ display: flex;
+ gap: 40px;
+ align-items: flex-start;
+ justify-content: center;
+ flex-wrap: wrap;
+ width: 100%;
+ max-width: 1200px;
+}
+
+.phone-container {
+ position: relative;
+ filter: drop-shadow(0 20px 40px rgba(0,0,0,0.8));
+}
+
+.phone-frame {
+ width: 375px;
+ height: 667px;
+ background: var(--dark-grey);
+ border-radius: 40px;
+ padding: 12px;
+ position: relative;
+ box-shadow:
+ 0 0 0 2px #333,
+ inset 0 0 20px rgba(0,0,0,0.5);
+}
+
+.phone-notch {
+ position: absolute;
+ top: 12px;
+ left: 50%;
+ transform: translateX(-50%);
+ width: 120px;
+ height: 25px;
+ background: var(--dark);
+ border-radius: 0 0 20px 20px;
+ z-index: 10;
+}
+
+.screen {
+ width: 100%;
+ height: 100%;
+ background: var(--dark);
+ border-radius: 30px;
+ overflow: hidden;
+ position: relative;
+}
+
+.progress-container {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 3px;
+ background: rgba(255,255,255,0.1);
+ z-index: 100;
+}
+
+.progress-bar {
+ height: 100%;
+ background: var(--gold);
+ width: 0%;
+ transition: width 0.1s linear;
+ box-shadow: 0 0 10px var(--gold);
+}
+
+.scene {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ opacity: 0;
+ transition: opacity 0.8s var(--transition);
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ padding: 40px 30px;
+}
+
+.scene.active {
+ opacity: 1;
+}
+
+/* Scene 1: Hook */
+.scene-hook {
+ background: radial-gradient(circle at 30% 30%, #1a1a2e 0%, #0a0a0a 100%);
+ position: relative;
+ overflow: hidden;
+}
+
+.scene-hook::before {
+ content: '';
+ position: absolute;
+ width: 200%;
+ height: 200%;
+ background: repeating-linear-gradient(
+ 45deg,
+ transparent,
+ transparent 10px,
+ rgba(212, 175, 55, 0.03) 10px,
+ rgba(212, 175, 55, 0.03) 20px
+ );
+ animation: drift 20s linear infinite;
+}
+
+@keyframes drift {
+ 0% { transform: translate(0, 0); }
+ 100% { transform: translate(-50px, -50px); }
+}
+
+.luxury-text {
+ font-size: 2.2rem;
+ font-weight: 300;
+ text-align: center;
+ line-height: 1.2;
+ background: linear-gradient(135deg, var(--gold-light) 0%, var(--gold) 50%, var(--gold-light) 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+ text-transform: uppercase;
+ letter-spacing: 3px;
+ opacity: 0;
+ transform: translateY(30px);
+ transition: all 1s var(--transition);
+}
+
+.scene.active .luxury-text {
+ opacity: 1;
+ transform: translateY(0);
+}
+
+/* Scene 2: Room */
+.scene-room {
+ background: linear-gradient(135deg, #1e1e1e 0%, #2d2d2d 100%);
+ position: relative;
+}
+
+.wall-left {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 50%;
+ height: 100%;
+ background: linear-gradient(90deg, #2a2520 0%, #3e3630 100%);
+ transform: skewY(-5deg);
+ transform-origin: top left;
+}
+
+.wall-right {
+ position: absolute;
+ right: 0;
+ top: 0;
+ width: 50%;
+ height: 100%;
+ background: linear-gradient(-90deg, #2a2520 0%, #3e3630 100%);
+ transform: skewY(5deg);
+ transform-origin: top right;
+}
+
+.wall-pattern {
+ position: absolute;
+ inset: 0;
+ background-image: repeating-linear-gradient(
+ 0deg,
+ transparent,
+ transparent 50px,
+ rgba(212, 175, 55, 0.05) 50px,
+ rgba(212, 175, 55, 0.05) 51px
+ );
+}
+
+.light-beam {
+ position: absolute;
+ top: -20%;
+ left: 20%;
+ width: 60%;
+ height: 80%;
+ background: linear-gradient(180deg, rgba(255,255,255,0.1) 0%, transparent 100%);
+ filter: blur(40px);
+ transform: rotate(-15deg);
+}
+
+/* Scene 3: Texture */
+.scene-texture {
+ background: var(--dark-grey);
+ position: relative;
+}
+
+.texture-pattern {
+ position: absolute;
+ inset: 0;
+ background-color: #1a1a1a;
+ background-image:
+ repeating-linear-gradient(90deg, transparent, transparent 2px, rgba(212,175,55,0.1) 2px, rgba(212,175,55,0.1) 4px),
+ repeating-linear-gradient(0deg, transparent, transparent 20px, rgba(255,255,255,0.02) 20px, rgba(255,255,255,0.02) 21px);
+ background-size: 100% 100%, 100% 100%;
+}
+
+.texture-shine {
+ position: absolute;
+ inset: 0;
+ background: radial-gradient(circle at 50% 50%, rgba(212,175,55,0.2) 0%, transparent 70%);
+ animation: pulse 4s ease-in-out infinite;
+}
+
+@keyframes pulse {
+ 0%, 100% { opacity: 0.3; }
+ 50% { opacity: 0.6; }
+}
+
+/* Scene 4: Swatches */
+.scene-swatches {
+ background: var(--dark);
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 15px;
+ padding: 60px 30px;
+}
+
+.swatch {
+ border-radius: 12px;
+ position: relative;
+ overflow: hidden;
+ box-shadow: 0 4px 15px rgba(0,0,0,0.5);
+ border: 1px solid rgba(255,255,255,0.1);
+ transform: scale(0.9);
+ opacity: 0;
+ transition: all 0.6s var(--transition);
+}
+
+.scene.active .swatch {
+ transform: scale(1);
+ opacity: 1;
+}
+
+.scene.active .swatch:nth-child(1) { transition-delay: 0.1s; }
+.scene.active .swatch:nth-child(2) { transition-delay: 0.2s; }
+.scene.active .swatch:nth-child(3) { transition-delay: 0.3s; }
+.scene.active .swatch:nth-child(4) { transition-delay: 0.4s; }
+
+.swatch-gold { background: linear-gradient(135deg, #d4af37 0%, #f4e5c2 50%, #d4af37 100%); }
+.swatch-bronze { background: linear-gradient(135deg, #8b7355 0%, #d4af37 100%); }
+.swatch-slate { background: linear-gradient(135deg, #2c3e50 0%, #4a5f7f 100%); }
+.swatch-cream { background: linear-gradient(135deg, #f5f5dc 0%, #e8dcc0 100%); }
+
+/* Scene 5: CTA */
+.scene-cta {
+ background: radial-gradient(circle at center, #1a1a2e 0%, #000 100%);
+ text-align: center;
+}
+
+.cta-button {
+ margin-top: 30px;
+ padding: 18px 40px;
+ background: transparent;
+ border: 1px solid var(--gold);
+ color: var(--gold);
+ font-size: 0.9rem;
+ letter-spacing: 3px;
+ text-transform: uppercase;
+ cursor: pointer;
+ position: relative;
+ overflow: hidden;
+ transition: all 0.3s;
+ opacity: 0;
+ transform: translateY(20px);
+}
+
+.scene.active .cta-button {
+ opacity: 1;
+ transform: translateY(0);
+ transition-delay: 0.5s;
+}
+
+.cta-button::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: -100%;
+ width: 100%;
+ height: 100%;
+ background: var(--gold);
+ transition: left 0.3s;
+ z-index: -1;
+}
+
+.cta-button:hover {
+ color: var(--dark);
+}
+
+.cta-button:hover::before {
+ left: 0;
+}
+
+.caption-overlay {
+ position: absolute;
+ bottom: 80px;
+ left: 30px;
+ right: 30px;
+ text-align: center;
+ z-index: 50;
+ pointer-events: none;
+}
+
+.caption-text {
+ font-size: 1.3rem;
+ font-weight: 400;
+ color: white;
+ text-shadow: 0 2px 10px rgba(0,0,0,0.8);
+ letter-spacing: 1px;
+ line-height: 1.4;
+ opacity: 0;
+ transform: translateY(20px);
+ transition: all 0.8s var(--transition);
+}
+
+.scene.active .caption-text {
+ opacity: 1;
+ transform: translateY(0);
+ transition-delay: 0.3s;
+}
+
+.controls-overlay {
+ position: absolute;
+ bottom: 30px;
+ left: 50%;
+ transform: translateX(-50%);
+ z-index: 100;
+ display: flex;
+ gap: 20px;
+ align-items: center;
+}
+
+.play-pause-btn {
+ width: 50px;
+ height: 50px;
+ border-radius: 50%;
+ background: rgba(255,255,255,0.1);
+ backdrop-filter: blur(10px);
+ border: 1px solid rgba(255,255,255,0.2);
+ color: white;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ transition: all 0.3s;
+ font-size: 1.2rem;
+}
+
+.play-pause-btn:hover {
+ background: var(--gold);
+ color: var(--dark);
+ transform: scale(1.1);
+}
+
+.editor-panel {
+ background: var(--dark-grey);
+ padding: 30px;
+ border-radius: 20px;
+ width: 350px;
+ border: 1px solid var(--grey);
+}
+
+.editor-header {
+ font-size: 0.8rem;
+ text-transform: uppercase;
+ letter-spacing: 2px;
+ color: var(--gold);
+ margin-bottom: 20px;
+ border-bottom: 1px solid var(--grey);
+ padding-bottom: 10px;
+}
+
+.scene-editor {
+ margin-bottom: 20px;
+ padding: 15px;
+ background: rgba(0,0,0,0.3);
+ border-radius: 10px;
+ border: 1px solid transparent;
+ transition: all 0.3s;
+}
+
+.scene-editor.active {
+ border-color: var(--gold);
+ background: rgba(212,175,55,0.05);
+}
+
+.scene-label {
+ font-size: 0.7rem;
+ color: #666;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+ margin-bottom: 8px;
+ display: flex;
+ justify-content: space-between;
+}
+
+.scene-number {
+ color: var(--gold);
+ font-weight: bold;
+}
+
+.caption-input {
+ width: 100%;
+ background: transparent;
+ border: none;
+ border-bottom: 1px solid var(--grey);
+ color: var(--text);
+ font-size: 0.95rem;
+ padding: 8px 0;
+ font-family: inherit;
+ transition: border-color 0.3s;
+}
+
+.caption-input:focus {
+ outline: none;
+ border-color: var(--gold);
+}
+
+.transport-controls {
+ display: flex;
+ gap: 10px;
+ margin-top: 20px;
+ padding-top: 20px;
+ border-top: 1px solid var(--grey);
+}
+
+.transport-btn {
+ flex: 1;
+ padding: 12px;
+ background: var(--grey);
+ border: none;
+ color: var(--text);
+ border-radius: 8px;
+ cursor: pointer;
+ font-size: 0.8rem;
+ letter-spacing: 1px;
+ text-transform: uppercase;
+ transition: all 0.3s;
+}
+
+.transport-btn:hover {
+ background: var(--gold);
+ color: var(--dark);
+}
+
+.timeline-indicator {
+ display: flex;
+ gap: 5px;
+ margin-bottom: 20px;
+ justify-content: center;
+}
+
+.timeline-dot {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background: var(--grey);
+ transition: all 0.3s;
+}
+
+.timeline-dot.active {
+ background: var(--gold);
+ transform: scale(1.2);
+ box-shadow: 0 0 10px var(--gold);
+}
+
+@media (max-width: 800px) {
+ .workspace {
+ flex-direction: column;
+ align-items: center;
+ }
+
+ .phone-frame {
+ width: 320px;
+ height: 569px;
+ }
+
+ .editor-panel {
+ width: 100%;
+ max-width: 400px;
+ }
+}
+</style>
+</head>
+<body>
+
+<header>
+ <h1>Atelier Storyboard</h1>
+ <div class="subtitle">Vertical Content Studio</div>
+</header>
+
+<div class="workspace">
+ <div class="phone-container">
+ <div class="phone-frame">
+ <div class="phone-notch"></div>
+ <div class="screen" id="screen">
+ <div class="progress-container">
+ <div class="progress-bar" id="progressBar"></div>
+ </div>
+
+ <!-- Scene 1: Hook -->
+ <div class="scene scene-hook active" data-index="0">
+ <div class="luxury-text" id="caption-0">Transform<br>Your Space</div>
+ </div>
+
+ <!-- Scene 2: Room -->
+ <div class="scene scene-room" data-index="1">
+ <div class="wall-left">
+ <div class="wall-pattern"></div>
+ </div>
+ <div class="wall-right">
+ <div class="wall-pattern"></div>
+ </div>
+ <div class="light-beam"></div>
+ <div class="caption-overlay">
+ <div class="caption-text" id="caption-1">Elegance in Every Roll</div>
+ </div>
+ </div>
+
+ <!-- Scene 3: Texture -->
+ <div class="scene scene-texture" data-index="2">
+ <div class="texture-pattern"></div>
+ <div class="texture-shine"></div>
+ <div class="caption-overlay">
+ <div class="caption-text" id="caption-2">Tactile Luxury</div>
+ </div>
+ </div>
+
+ <!-- Scene 4: Swatches -->
+ <div class="scene scene-swatches" data-index="3">
+ <div class="swatch swatch-gold"></div>
+ <div class="swatch swatch-bronze"></div>
+ <div class="swatch swatch-slate"></div>
+ <div class="swatch swatch-cream"></div>
+ <div class="caption-overlay" style="bottom: 40px;">
+ <div class="caption-text" id="caption-3">Curated Palettes</div>
+ </div>
+ </div>
+
+ <!-- Scene 5: CTA -->
+ <div class="scene scene-cta" data-index="4">
+ <div class="luxury-text" style="font-size: 1.8rem; margin-bottom: 20px;" id="caption-4">Define Your<br>Sanctuary</div>
+ <button class="cta-button">Shop Collection</button>
+ </div>
+
+ <div class="controls-overlay">
+ <button class="play-pause-btn" id="playPauseBtn">❚❚</button>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="editor-panel">
+ <div class="editor-header">Scene Editor</div>
+
+ <div class="timeline-indicator" id="timelineIndicator">
+ <div class="timeline-dot active"></div>
+ <div class="timeline-dot"></div>
+ <div class="timeline-dot"></div>
+ <div class="timeline-dot"></div>
+ <div class="timeline-dot"></div>
+ </div>
+
+ <div class="scene-editor active" data-scene="0">
+ <div class="scene-label">
+ <span>Hook</span>
+ <span class="scene-number">01</span>
+ </div>
+ <input type="text" class="caption-input" value="Transform Your Space" data-scene="0">
+ </div>
+
+ <div class="scene-editor" data-scene="1">
+ <div class="scene-label">
+ <span>Room Reveal</span>
+ <span class="scene-number">02</span>
+ </div>
+ <input type="text" class="caption-input" value="Elegance in Every Roll" data-scene="1">
+ </div>
+
+ <div class="scene-editor" data-scene="2">
+ <div class="scene-label">
+ <span>Texture Close-up</span>
+ <span class="scene-number">03</span>
+ </div>
+ <input type="text" class="caption-input" value="Tactile Luxury" data-scene="2">
+ </div>
+
+ <div class="scene-editor" data-scene="3">
+ <div class="scene-label">
+ <span>Swatch Grid</span>
+ <span class="scene-number">04</span>
+ </div>
+ <input type="text" class="caption-input" value="Curated Palettes" data-scene="3">
+ </div>
+
+ <div class="scene-editor" data-scene="4">
+ <div class="scene-label">
+ <span>Call to Action</span>
+ <span class="scene-number">05</span>
+ </div>
+ <input type="text" class="caption-input" value="Define Your Sanctuary" data-scene="4">
+ </div>
+
+ <div class="transport-controls">
+ <button class="transport-btn" id="resetBtn">Reset</button>
+ <button class="transport-btn" id="prevBtn">Prev</button>
+ <button class="transport-btn" id="nextBtn">Next</button>
+ </div>
+ </div>
+</div>
+
+<script>
+const scenes = [
+ { duration: 4000, type: 'hook' },
+ { duration: 4000, type: 'room' },
+ { duration: 4000, type: 'texture' },
+ { duration: 4000, type: 'swatches' },
+ { duration: 4000, type: 'cta' }
+];
+
+let currentScene = 0;
+let isPlaying = true;
+let startTime = Date.now();
+let sceneStartTime = Date.now();
+let pausedTime = 0;
+let animationFrame;
+
+const screen = document.getElementById('screen');
+const progressBar = document.getElementById('progressBar');
+const playPauseBtn = document.getElementById('playPauseBtn');
+const sceneElements = document.querySelectorAll('.scene');
+const captionInputs = document.querySelectorAll('.caption-input');
+const sceneEditors = document.querySelectorAll('.scene-editor');
+const timelineDots = document.querySelectorAll('.timeline-dot');
+
+function updateScene(index) {
+ sceneElements.forEach((el, i) => {
+ if (i === index) {
+ el.classList.add('active');
+ } else {
+ el.classList.remove('active');
+ }
+ });
+
+ sceneEditors.forEach((el, i) => {
+ if (i === index) {
+ el.classList.add('active');
+ } else {
+ el.classList.remove('active');
+ }
+ });
+
+ timelineDots.forEach((el, i) => {
+ if (i === index) {
+ el.classList.add('active');
+ } else {
+ el.classList.remove('active');
+ }
+ });
+
+ currentScene = index;
+ sceneStartTime = Date.now() - pausedTime;
+ pausedTime = 0;
+}
+
+function nextScene() {
+ const next = (currentScene + 1) % scenes.length;
+ updateScene(next);
+}
+
+function prevScene() {
+ const prev = (currentScene - 1 + scenes.length) % scenes.length;
+ updateScene(prev);
+}
+
+function animate() {
+ if (!isPlaying) {
+ animationFrame = requestAnimationFrame(animate);
+ return;
+ }
+
+ const now = Date.now();
+ const elapsed = now - sceneStartTime;
+ const duration = scenes[currentScene].duration;
+ const progress = Math.min((elapsed / duration) * 100, 100);
+
+ progressBar.style.width = progress + '%';
+
+ if (elapsed >= duration) {
+ nextScene();
+ }
+
+ animationFrame = requestAnimationFrame(animate);
+}
+
+playPauseBtn.addEventListener('click', () => {
+ isPlaying = !isPlaying;
+ playPauseBtn.textContent = isPlaying ? '❚❚' : '▶';
+
+ if (isPlaying) {
+ sceneStartTime = Date.now() - pausedTime;
+ pausedTime = 0;
+ } else {
+ pausedTime = Date.now() - sceneStartTime;
+ }
+});
+
+document.getElementById('resetBtn').addEventListener('click', () => {
+ updateScene(0);
+ sceneStartTime = Date.now();
+ pausedTime = 0;
+ isPlaying = true;
+ playPauseBtn.textContent = '❚❚';
+});
+
+document.getElementById('nextBtn').addEventListener('click', () => {
+ nextScene();
+ sceneStartTime = Date.now();
+ pausedTime = 0;
+});
+
+document.getElementById('prevBtn').addEventListener('click', () => {
+ prevScene();
+ sceneStartTime = Date.now();
+ pausedTime = 0;
+});
+
+captionInputs.forEach(input => {
+ input.addEventListener('input', (e) => {
+ const sceneIndex = parseInt(e.target.dataset.scene);
+ const captionEl = document.getElementById(`caption-${sceneIndex}`);
+ if (captionEl) {
+ if (sceneIndex === 0 || sceneIndex === 4) {
+ captionEl.innerHTML = e.target.value.replace(/\n/g, '<br>');
+ } else {
+ captionEl.textContent = e.target.value;
+ }
+ }
+ });
+});
+
+sceneEditors.forEach((editor, index) => {
+ editor.addEventListener('click', () => {
+ updateScene(index);
+ sceneStartTime = Date.now();
+ pausedTime = 0;
+ });
+});
+
+animate();
+</script>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/b72f0e9e751b/kimi.png b/data/artifacts/b72f0e9e751b/kimi.png
new file mode 100644
index 0000000..e64a544
Binary files /dev/null and b/data/artifacts/b72f0e9e751b/kimi.png differ
diff --git a/data/artifacts/b72f0e9e751b/qwen3-14b.html b/data/artifacts/b72f0e9e751b/qwen3-14b.html
new file mode 100644
index 0000000..57a08e3
--- /dev/null
+++ b/data/artifacts/b72f0e9e751b/qwen3-14b.html
@@ -0,0 +1,238 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title>Instagram Reel Storyboard</title>
+ <style>
+ * {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ }
+ html, body {
+ width: 100%;
+ height: 100%;
+ background: #0f0f0f;
+ color: #fff;
+ font-family: 'Helvetica Neue', sans-serif;
+ overflow: hidden;
+ }
+ .container {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+ .phone-frame {
+ width: 80vw;
+ max-width: 360px;
+ height: 55vw;
+ max-height: 810px;
+ background: #1a1a1a;
+ border: 4px solid #2a2a2a;
+ border-radius: 40px;
+ box-shadow: 0 0 20px rgba(0,0,0,0.5);
+ position: relative;
+ overflow: hidden;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+ .phone-frame::before {
+ content: '';
+ position: absolute;
+ top: 0; left: 0;
+ width: 100%;
+ height: 100%;
+ background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 360 640"><path d="M0 0h360v640H0z" fill="none"/><path d="M0 0h360v640H0z" fill="none"/><path d="M0 0h360v640H0z" fill="none"/><path d="M0 0h360v640H0z" fill="none"/><path d="M0 0h360v640H0z" fill="none"/><path d="M0 0h360v640H0z" fill="none"/><path d="M0 0h360v640H0z" fill="none"/><path d="M0 0h360v640H0z" fill="none"/><path d="M0 0h360v640H0z" fill="none"/><path d="M0 0h360v640H0z" fill="none"/></svg>') no-repeat center;
+ background-size: contain;
+ }
+ .scene {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ background: #1e1e1e;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ transition: opacity 0.5s ease-in-out;
+ opacity: 0;
+ pointer-events: none;
+ }
+ .scene.active {
+ opacity: 1;
+ pointer-events: auto;
+ }
+ .caption {
+ font-size: 24px;
+ font-weight: bold;
+ text-align: center;
+ padding: 10px;
+ background: rgba(0,0,0,0.3);
+ border-radius: 10px;
+ max-width: 80%;
+ animation: fadeIn 1s ease-in-out forwards;
+ }
+ @keyframes fadeIn {
+ from { opacity: 0; transform: translateY(20px); }
+ to { opacity: 1; transform: translateY(0); }
+ }
+ .progress-bar {
+ position: absolute;
+ bottom: 20px;
+ left: 0;
+ width: 90%;
+ height: 8px;
+ background: #333;
+ border-radius: 4px;
+ overflow: hidden;
+ margin: 0 auto;
+ }
+ .progress-fill {
+ height: 100%;
+ width: 0%;
+ background: #6f42c1;
+ transition: width 0.5s ease-in-out;
+ }
+ .controls {
+ position: absolute;
+ top: 20px;
+ left: 50%;
+ transform: translateX(-50%);
+ display: flex;
+ gap: 15px;
+ }
+ .controls button {
+ background: #333;
+ color: #fff;
+ border: none;
+ padding: 10px 15px;
+ border-radius: 50px;
+ font-size: 16px;
+ cursor: pointer;
+ transition: background 0.3s ease;
+ }
+ .controls button:hover {
+ background: #444;
+ }
+ .scene-editor {
+ position: absolute;
+ bottom: 10px;
+ left: 50%;
+ transform: translateX(-50%);
+ background: #1a1a1a;
+ padding: 10px 20px;
+ border-radius: 10px;
+ display: flex;
+ gap: 10px;
+ flex-wrap: wrap;
+ max-width: 90%;
+ }
+ .scene-editor input {
+ flex: 1;
+ min-width: 150px;
+ padding: 6px;
+ background: #2a2a2a;
+ color: #fff;
+ border: none;
+ border-radius: 5px;
+ }
+ </style>
+</head>
+<body>
+ <div class="container">
+ <div class="phone-frame">
+ <div class="scene active" data-index="0">
+ <div class="caption">Hook: Luxe living starts here</div>
+ </div>
+ <div class="scene" data-index="1">
+ <div class="caption">Room reveal: Timeless elegance in every corner</div>
+ </div>
+ <div class="scene" data-index="2">
+ <div class="caption">Texture close-up: Feel the artistry</div>
+ </div>
+ <div class="scene" data-index="3">
+ <div class="caption">Swatch grid: Choose your perfect match</div>
+ </div>
+ <div class="scene" data-index="4">
+ <div class="caption">CTA: Discover the collection now</div>
+ </div>
+ <div class="progress-bar">
+ <div class="progress-fill" style="width: 0%;"></div>
+ </div>
+ <div class="controls">
+ <button id="playPauseBtn">▶️ Play</button>
+ </div>
+ </div>
+ <div class="scene-editor">
+ <input type="text" data-index="0" value="Hook: Luxe living starts here" />
+ <input type="text" data-index="1" value="Room reveal: Timeless elegance in every corner" />
+ <input type="text" data-index="2" value="Texture close-up: Feel the artistry" />
+ <input type="text" data-index="3" value="Swatch grid: Choose your perfect match" />
+ <input type="text" data-index="4" value="CTA: Discover the collection now" />
+ </div>
+ </div>
+ <script>
+ const scenes = document.querySelectorAll('.scene');
+ const inputs = document.querySelectorAll('.scene-editor input');
+ const progressBar = document.querySelector('.progress-fill');
+ const playPauseBtn = document.getElementById('playPauseBtn');
+ let isPlaying = false;
+ let currentSceneIndex = 0;
+ let interval;
+
+ function updateSceneCaptions() {
+ scenes.forEach((scene, index) => {
+ const caption = scene.querySelector('.caption');
+ if (caption) {
+ caption.textContent = inputs[index].value;
+ }
+ });
+ }
+
+ inputs.forEach((input, index) => {
+ input.addEventListener('input', updateSceneCaptions);
+ });
+
+ function showScene(index) {
+ scenes.forEach((scene, i) => {
+ scene.classList.toggle('active', i === index);
+ });
+ currentSceneIndex = index;
+ progressBar.style.width = `${(index / (scenes.length - 1)) * 100}%`;
+ }
+
+ function play() {
+ if (isPlaying) return;
+ isPlaying = true;
+ playPauseBtn.textContent = '⏸️ Pause';
+ interval = setInterval(() => {
+ currentSceneIndex = (currentSceneIndex + 1) % scenes.length;
+ showScene(currentSceneIndex);
+ }, 2000);
+ }
+
+ function pause() {
+ isPlaying = false;
+ playPauseBtn.textContent = '▶️ Play';
+ clearInterval(interval);
+ }
+
+ playPauseBtn.addEventListener('click', () => {
+ if (isPlaying) {
+ pause();
+ } else {
+ play();
+ }
+ });
+
+ // Initialize
+ showScene(currentSceneIndex);
+ updateSceneCaptions();
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/b72f0e9e751b/qwen3-14b.png b/data/artifacts/b72f0e9e751b/qwen3-14b.png
new file mode 100644
index 0000000..ea349ea
Binary files /dev/null and b/data/artifacts/b72f0e9e751b/qwen3-14b.png differ
diff --git a/data/artifacts/bde366feb227/claude-code.html b/data/artifacts/bde366feb227/claude-code.html
new file mode 100644
index 0000000..3946704
--- /dev/null
+++ b/data/artifacts/bde366feb227/claude-code.html
@@ -0,0 +1,439 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Atelier Verdant — Shoppable Post</title>
+<style>
+ :root{
+ --ink:#1a1a1a; --sub:#8a8a8a; --line:#efefef; --accent:#2f4638;
+ --card:#ffffff; --bg:#fafafa;
+ }
+ *{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent}
+ html,body{height:100%}
+ body{
+ font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
+ background:linear-gradient(160deg,#ece9e4,#dfe4de);
+ display:flex;align-items:center;justify-content:center;
+ min-height:100vh;padding:24px 12px;color:var(--ink);
+ }
+ .phone{
+ width:100%;max-width:430px;background:var(--card);
+ border-radius:22px;overflow:hidden;
+ box-shadow:0 20px 60px rgba(40,50,45,.22),0 2px 8px rgba(0,0,0,.06);
+ }
+
+ /* ---------- Post header ---------- */
+ .post-head{display:flex;align-items:center;gap:11px;padding:12px 14px}
+ .avatar{
+ width:38px;height:38px;border-radius:50%;flex-shrink:0;
+ padding:2px;background:conic-gradient(from 210deg,#c9a86a,#7c9a7e,#3a5245,#c9a86a);
+ }
+ .avatar span{
+ display:flex;align-items:center;justify-content:center;
+ width:100%;height:100%;border-radius:50%;
+ background:#2f4638;color:#f4efe6;font-weight:600;font-size:13px;
+ letter-spacing:.5px;border:2px solid #fff;
+ }
+ .who{display:flex;flex-direction:column;line-height:1.25;flex:1;min-width:0}
+ .who b{font-size:13.5px;font-weight:600;display:flex;align-items:center;gap:4px}
+ .who b svg{width:13px;height:13px;color:#3897f0;flex-shrink:0}
+ .who small{font-size:11.5px;color:var(--sub)}
+ .dots{font-size:20px;color:var(--ink);letter-spacing:1px;padding:0 4px;cursor:pointer}
+
+ /* ---------- Room scene (CSS illustrated) ---------- */
+ .scene{
+ position:relative;width:100%;aspect-ratio:1/1;overflow:hidden;
+ background:#d8cfc0;user-select:none;
+ }
+ /* wallpaper wall */
+ .wall{
+ position:absolute;inset:0;
+ background-color:#3a5346;
+ background-image:
+ radial-gradient(circle at 20% 25%, rgba(201,168,106,.35) 0 3px, transparent 4px),
+ radial-gradient(circle at 20% 25%, transparent 13px, rgba(201,168,106,.22) 13px 15px, transparent 16px),
+ radial-gradient(circle at 60% 65%, rgba(201,168,106,.35) 0 3px, transparent 4px),
+ radial-gradient(circle at 60% 65%, transparent 13px, rgba(201,168,106,.22) 13px 15px, transparent 16px),
+ linear-gradient(140deg, rgba(255,255,255,.06), rgba(0,0,0,.14));
+ background-size:120px 120px,120px 120px,120px 120px,120px 120px,100% 100%;
+ background-position:0 0,0 0,60px 60px,60px 60px,0 0;
+ }
+ /* botanical leaf accents */
+ .wall::before{
+ content:"";position:absolute;inset:0;
+ background-image:
+ radial-gradient(ellipse 8px 20px at 35% 15%, rgba(233,222,200,.28) 40%, transparent 60%),
+ radial-gradient(ellipse 8px 20px at 78% 40%, rgba(233,222,200,.24) 40%, transparent 60%),
+ radial-gradient(ellipse 8px 20px at 12% 70%, rgba(233,222,200,.24) 40%, transparent 60%),
+ radial-gradient(ellipse 8px 20px at 88% 85%, rgba(233,222,200,.22) 40%, transparent 60%);
+ transform:rotate(8deg);
+ }
+ /* soft window light */
+ .light{
+ position:absolute;top:-8%;left:-10%;width:70%;height:80%;
+ background:radial-gradient(ellipse at 30% 30%, rgba(255,248,225,.35), transparent 65%);
+ pointer-events:none;
+ }
+ /* floor */
+ .floor{
+ position:absolute;left:0;right:0;bottom:0;height:26%;
+ background:linear-gradient(#c9b59a,#b39c7d);
+ box-shadow:0 -1px 0 rgba(0,0,0,.12) inset;
+ }
+ .baseboard{
+ position:absolute;left:0;right:0;bottom:26%;height:3.5%;
+ background:linear-gradient(#f3ece0,#e2d8c7);
+ }
+ /* console/sideboard */
+ .console{
+ position:absolute;bottom:22%;left:50%;transform:translateX(-50%);
+ width:62%;height:20%;background:linear-gradient(#3c2c22,#2c2018);
+ border-radius:4px 4px 2px 2px;
+ box-shadow:0 12px 22px rgba(0,0,0,.3);
+ }
+ .console::before,.console::after{
+ content:"";position:absolute;bottom:-14px;width:6px;height:16px;
+ background:#241a13;
+ }
+ .console::before{left:11%}.console::after{right:11%}
+ .console .drw{
+ position:absolute;top:38%;left:8%;right:8%;height:2px;background:rgba(255,255,255,.12);
+ }
+ .knob{position:absolute;top:52%;width:5px;height:5px;border-radius:50%;background:#c9a86a}
+ .knob.l{left:32%}.knob.r{right:32%}
+ /* framed art on wall */
+ .frame{
+ position:absolute;top:16%;left:50%;transform:translateX(-50%);
+ width:26%;height:26%;background:#f6f1e7;
+ border:5px solid #d9c9a3;border-radius:2px;
+ box-shadow:0 8px 16px rgba(0,0,0,.25);
+ }
+ .frame::after{
+ content:"";position:absolute;inset:6px;
+ background:linear-gradient(135deg,#7c9a7e,#3a5245 70%);
+ border-radius:1px;
+ }
+ /* vase + lamp on console */
+ .vase{
+ position:absolute;bottom:42%;left:34%;width:9%;height:16%;
+ background:linear-gradient(#b9491f,#8f3213);border-radius:40% 40% 45% 45%/60% 60% 40% 40%;
+ box-shadow:0 6px 10px rgba(0,0,0,.28);
+ }
+ .vase::before{
+ content:"";position:absolute;bottom:70%;left:50%;transform:translateX(-50%);
+ width:120%;height:90%;
+ background:
+ radial-gradient(ellipse 4px 14px at 30% 60%, #6f8f6b 50%, transparent 60%),
+ radial-gradient(ellipse 4px 16px at 55% 40%, #567a52 50%, transparent 60%),
+ radial-gradient(ellipse 4px 13px at 72% 62%, #6f8f6b 50%, transparent 60%);
+ }
+ .lamp{
+ position:absolute;bottom:42%;right:31%;width:12%;height:20%;
+ }
+ .lamp .shade{
+ position:absolute;top:0;left:50%;transform:translateX(-50%);
+ width:100%;height:52%;background:linear-gradient(#f6ead0,#e6d3ad);
+ border-radius:6px 6px 3px 3px;box-shadow:0 4px 10px rgba(0,0,0,.2);
+ }
+ .lamp .stem{position:absolute;bottom:0;left:50%;transform:translateX(-50%);width:8%;height:52%;background:#28201a}
+
+ /* ---------- Product tags ---------- */
+ .tag{
+ position:absolute;width:26px;height:26px;border-radius:50%;
+ background:rgba(255,255,255,.92);border:none;cursor:pointer;
+ display:flex;align-items:center;justify-content:center;
+ box-shadow:0 2px 10px rgba(0,0,0,.35);
+ transform:translate(-50%,-50%);z-index:5;
+ animation:pulse 2.4s ease-out infinite;
+ }
+ .tag::before{
+ content:"";width:8px;height:8px;border-radius:50%;background:#1a1a1a;
+ transition:transform .2s;
+ }
+ .tag:hover::before{transform:scale(1.25)}
+ .tag.active{background:#2f4638;animation:none}
+ .tag.active::before{background:#fff}
+ @keyframes pulse{
+ 0%{box-shadow:0 2px 10px rgba(0,0,0,.35),0 0 0 0 rgba(255,255,255,.6)}
+ 70%{box-shadow:0 2px 10px rgba(0,0,0,.35),0 0 0 12px rgba(255,255,255,0)}
+ 100%{box-shadow:0 2px 10px rgba(0,0,0,.35),0 0 0 0 rgba(255,255,255,0)}
+ }
+ .tag1{top:30%;left:26%}
+ .tag2{top:60%;left:50%}
+ .tag3{top:26%;left:63%}
+
+ /* ---------- Product card popover ---------- */
+ .card{
+ position:absolute;z-index:8;width:220px;
+ background:var(--card);border-radius:14px;overflow:hidden;
+ box-shadow:0 14px 40px rgba(0,0,0,.32);
+ opacity:0;pointer-events:none;transform:translate(-50%,-6px) scale(.94);
+ transition:opacity .22s ease,transform .22s ease;
+ }
+ .card.show{opacity:1;pointer-events:auto;transform:translate(-50%,0) scale(1)}
+ .card .top{display:flex;gap:11px;padding:12px}
+ .swatch{
+ width:52px;height:52px;border-radius:9px;flex-shrink:0;
+ box-shadow:inset 0 0 0 1px rgba(0,0,0,.08);
+ }
+ .sw1{background:
+ radial-gradient(circle at 30% 30%, #c9a86a 0 2px, transparent 3px),
+ radial-gradient(circle at 70% 70%, #c9a86a 0 2px, transparent 3px),
+ #3a5346;background-size:20px 20px}
+ .sw2{background:
+ repeating-linear-gradient(45deg,#8f3213 0 4px,#a8451f 4px 8px)}
+ .sw3{background:
+ linear-gradient(#e6d3ad,#d9c9a3),
+ repeating-linear-gradient(90deg, rgba(120,90,50,.25) 0 1px, transparent 1px 6px);
+ background-blend-mode:multiply}
+ .card .info{min-width:0;display:flex;flex-direction:column;justify-content:center}
+ .card .brand{font-size:9.5px;letter-spacing:1.2px;text-transform:uppercase;color:var(--sub)}
+ .card .name{font-size:13.5px;font-weight:600;margin:2px 0 3px;line-height:1.2}
+ .card .price{font-size:12.5px;color:var(--accent);font-weight:600}
+ .card .price small{color:var(--sub);font-weight:400}
+ .card .view{
+ display:block;width:100%;border:none;border-top:1px solid var(--line);
+ background:#fff;color:var(--accent);font-weight:600;font-size:12.5px;
+ padding:11px;cursor:pointer;letter-spacing:.4px;transition:background .15s;
+ }
+ .card .view:hover{background:#f4f6f4}
+ .card .arrow{
+ position:absolute;width:12px;height:12px;background:#fff;
+ transform:rotate(45deg);top:-6px;left:50%;margin-left:-6px;
+ }
+ .card.below .arrow{top:auto;bottom:-6px}
+
+ /* ---------- Action bar ---------- */
+ .actions{display:flex;align-items:center;gap:16px;padding:11px 14px 6px}
+ .actions svg{width:24px;height:24px;cursor:pointer;stroke:var(--ink);fill:none;stroke-width:1.7}
+ .actions .heart.liked{fill:#ed4956;stroke:#ed4956}
+ .actions .spacer{flex:1}
+ .meta{padding:0 14px}
+ .likes{font-size:13.5px;font-weight:600}
+ .caption{font-size:13.5px;line-height:1.45;margin-top:5px}
+ .caption b{font-weight:600}
+ .caption .tagword{color:#3a5a86}
+ .comments{margin-top:7px;display:flex;flex-direction:column;gap:4px}
+ .comments .c{font-size:13px;line-height:1.4}
+ .comments .c b{font-weight:600}
+ .viewall{font-size:13px;color:var(--sub);margin-top:6px;cursor:pointer}
+ .time{font-size:10.5px;letter-spacing:.4px;color:var(--sub);text-transform:uppercase;margin:9px 0 2px}
+
+ /* add comment row */
+ .addrow{display:flex;align-items:center;gap:10px;padding:11px 14px;border-top:1px solid var(--line);margin-top:10px}
+ .addrow .em{width:24px;height:24px;border-radius:50%;background:#eee;display:flex;align-items:center;justify-content:center;font-size:13px}
+ .addrow input{border:none;flex:1;font-size:13px;outline:none;background:transparent}
+ .addrow .post{color:#b9d0f0;font-weight:600;font-size:13px}
+
+ .toast{
+ position:fixed;left:50%;bottom:34px;transform:translateX(-50%) translateY(20px);
+ background:#1a1a1a;color:#fff;padding:11px 20px;border-radius:30px;
+ font-size:13px;opacity:0;pointer-events:none;transition:.3s;z-index:20;
+ box-shadow:0 8px 24px rgba(0,0,0,.3);
+ }
+ .toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
+</style>
+</head>
+<body>
+ <div class="phone">
+ <!-- header -->
+ <div class="post-head">
+ <div class="avatar"><span>AV</span></div>
+ <div class="who">
+ <b>atelierverdant
+ <svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l2.4 1.8 3 .1 1 2.8 2.4 1.7-.9 2.9.9 2.9-2.4 1.7-1 2.8-3 .1L12 22l-2.4-1.8-3-.1-1-2.8L3.2 15l.9-2.9-.9-2.9 2.4-1.7 1-2.8 3-.1z"/><path d="M10.4 13.7l-1.9-1.9-1.2 1.2 3.1 3.1 5.6-5.6-1.2-1.2z" fill="#fff"/></svg>
+ </b>
+ <small>Designer Wallcoverings · Sponsored</small>
+ </div>
+ <div class="dots">⋯</div>
+ </div>
+
+ <!-- room scene -->
+ <div class="scene" id="scene">
+ <div class="wall"></div>
+ <div class="light"></div>
+ <div class="frame"></div>
+ <div class="baseboard"></div>
+ <div class="floor"></div>
+ <div class="console">
+ <div class="drw"></div><div class="knob l"></div><div class="knob r"></div>
+ </div>
+ <div class="vase"></div>
+ <div class="lamp"><div class="shade"></div><div class="stem"></div></div>
+
+ <!-- tappable tags -->
+ <button class="tag tag1" data-i="0" aria-label="Tagged product"></button>
+ <button class="tag tag2" data-i="1" aria-label="Tagged product"></button>
+ <button class="tag tag3" data-i="2" aria-label="Tagged product"></button>
+
+ <!-- product cards -->
+ <div class="card" id="card0">
+ <div class="arrow"></div>
+ <div class="top">
+ <div class="swatch sw1"></div>
+ <div class="info">
+ <div class="brand">Atelier Verdant</div>
+ <div class="name">Fernwood Emerald</div>
+ <div class="price">$168 <small>/ roll</small></div>
+ </div>
+ </div>
+ <button class="view" data-name="Fernwood Emerald">View Product →</button>
+ </div>
+
+ <div class="card" id="card1">
+ <div class="arrow"></div>
+ <div class="top">
+ <div class="swatch sw2"></div>
+ <div class="info">
+ <div class="brand">Atelier Verdant</div>
+ <div class="name">Terracotta Vessel</div>
+ <div class="price">$92 <small>/ each</small></div>
+ </div>
+ </div>
+ <button class="view" data-name="Terracotta Vessel">View Product →</button>
+ </div>
+
+ <div class="card" id="card2">
+ <div class="arrow"></div>
+ <div class="top">
+ <div class="swatch sw3"></div>
+ <div class="info">
+ <div class="brand">Atelier Verdant</div>
+ <div class="name">Grasscloth Alabaster</div>
+ <div class="price">$144 <small>/ roll</small></div>
+ </div>
+ </div>
+ <button class="view" data-name="Grasscloth Alabaster">View Product →</button>
+ </div>
+ </div>
+
+ <!-- actions -->
+ <div class="actions">
+ <svg class="heart" id="heart" viewBox="0 0 24 24"><path d="M12 21s-7.5-4.6-10-9.3C.4 8.4 2 5 5.3 5c2 0 3.3 1.1 4.2 2.3l.6.9.6-.9C11.6 6.1 13 5 15 5c3.3 0 4.9 3.4 3.3 6.7C19.5 16.4 12 21 12 21z"/></svg>
+ <svg viewBox="0 0 24 24"><path d="M21 11.5a8.4 8.4 0 01-9 8.3 9 9 0 01-3.9-.9L3 20l1.1-4a8.3 8.3 0 01-1-4A8.4 8.4 0 1121 11.5z"/></svg>
+ <svg viewBox="0 0 24 24"><path d="M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z"/></svg>
+ <div class="spacer"></div>
+ <svg viewBox="0 0 24 24"><path d="M6 3h12v18l-6-4-6 4V3z"/></svg>
+ </div>
+
+ <!-- meta -->
+ <div class="meta">
+ <div class="likes" id="likes">2,847 likes</div>
+ <div class="caption">
+ <b>atelierverdant</b> Slow mornings against our <span class="tagword">Fernwood Emerald</span> grasscloth 🌿 A hand-woven botanical that turns any wall into a garden. Tap the dots to shop the room. <span class="tagword">#wallcoverings #interiordesign #botanicalhome</span>
+ </div>
+ <div class="comments">
+ <div class="c"><b>studio.olive</b> The depth on that green is unreal 😍</div>
+ <div class="c"><b>maison_clara</b> Need the Fernwood in my hallway immediately</div>
+ </div>
+ <div class="viewall">View all 134 comments</div>
+ <div class="time">2 hours ago</div>
+ </div>
+
+ <div class="addrow">
+ <div class="em">🙂</div>
+ <input id="cinput" placeholder="Add a comment…" aria-label="Add a comment">
+ <span class="post" id="cpost">Post</span>
+ </div>
+ </div>
+
+ <div class="toast" id="toast"></div>
+
+<script>
+(function(){
+ const scene = document.getElementById('scene');
+ const tags = Array.from(document.querySelectorAll('.tag'));
+ const cards = [0,1,2].map(i=>document.getElementById('card'+i));
+ let open = -1;
+
+ function positionCard(i){
+ const tag = tags[i], card = cards[i];
+ const st = tag.style;
+ // read tag % position from its class-defined left/top via computed
+ const rect = tag.getBoundingClientRect();
+ const srect = scene.getBoundingClientRect();
+ const cx = rect.left - srect.left + rect.width/2;
+ const cy = rect.top - srect.top + rect.height/2;
+ // decide above or below based on vertical space
+ const below = cy < srect.height*0.42;
+ card.classList.toggle('below', below);
+ let left = cx;
+ left = Math.max(115, Math.min(srect.width-115, left));
+ card.style.left = left+'px';
+ if(below){
+ card.style.top = (cy+22)+'px';
+ card.style.bottom = 'auto';
+ }else{
+ card.style.top = 'auto';
+ card.style.bottom = (srect.height-cy+22)+'px';
+ }
+ // point arrow toward the tag
+ const arrow = card.querySelector('.arrow');
+ arrow.style.left = (cx-left+card.offsetWidth/2)+'px';
+ }
+
+ function closeAll(){
+ cards.forEach(c=>c.classList.remove('show'));
+ tags.forEach(t=>t.classList.remove('active'));
+ open = -1;
+ }
+
+ tags.forEach((tag,i)=>{
+ tag.addEventListener('click',e=>{
+ e.stopPropagation();
+ if(open===i){closeAll();return;}
+ closeAll();
+ positionCard(i);
+ // recompute after layout for accurate arrow
+ requestAnimationFrame(()=>positionCard(i));
+ cards[i].classList.add('show');
+ tag.classList.add('active');
+ open=i;
+ });
+ });
+
+ scene.addEventListener('click',e=>{
+ if(!e.target.closest('.card') && !e.target.closest('.tag')) closeAll();
+ });
+
+ const toast = document.getElementById('toast');
+ let tt;
+ function showToast(msg){
+ toast.textContent=msg;toast.classList.add('show');
+ clearTimeout(tt);tt=setTimeout(()=>toast.classList.remove('show'),2000);
+ }
+
+ document.querySelectorAll('.view').forEach(b=>{
+ b.addEventListener('click',e=>{
+ e.stopPropagation();
+ showToast('Opening “'+b.dataset.name+'” →');
+ });
+ });
+
+ // like interactions
+ const heart=document.getElementById('heart');
+ const likes=document.getElementById('likes');
+ let liked=false, base=2847;
+ heart.addEventListener('click',()=>{
+ liked=!liked;heart.classList.toggle('liked',liked);
+ likes.textContent=(base+(liked?1:0)).toLocaleString()+' likes';
+ if(liked) showToast('Liked ❤');
+ });
+
+ // comment
+ const ci=document.getElementById('cinput'), cp=document.getElementById('cpost');
+ function postComment(){
+ const v=ci.value.trim();if(!v)return;
+ const wrap=document.querySelector('.comments');
+ const d=document.createElement('div');d.className='c';
+ d.innerHTML='<b>you</b> '+v.replace(/</g,'<');
+ wrap.appendChild(d);ci.value='';showToast('Comment posted');
+ }
+ cp.addEventListener('click',postComment);
+ ci.addEventListener('keydown',e=>{if(e.key==='Enter')postComment();});
+
+ window.addEventListener('resize',()=>{if(open>=0)positionCard(open);});
+})();
+</script>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/bde366feb227/claude-code.png b/data/artifacts/bde366feb227/claude-code.png
new file mode 100644
index 0000000..011cd74
Binary files /dev/null and b/data/artifacts/bde366feb227/claude-code.png differ
diff --git a/data/artifacts/bde366feb227/gpt.html b/data/artifacts/bde366feb227/gpt.html
new file mode 100644
index 0000000..804d6f4
--- /dev/null
+++ b/data/artifacts/bde366feb227/gpt.html
@@ -0,0 +1,1358 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>Instagram Shoppable Post Mockup - Wallcovering</title>
+<style>
+ :root {
+ --bg: #101015;
+ --card-bg: #111119;
+ --accent: #f2b679;
+ --accent-soft: rgba(242, 182, 121, 0.12);
+ --text-main: #f5f5f7;
+ --text-muted: #a4a4b0;
+ --text-soft: #7b7b88;
+ --border-subtle: #272734;
+ --like-red: #f05a7e;
+ --blue-link: #3897f0;
+ --shadow-soft: 0 24px 60px rgba(0,0,0,0.65);
+ --radius-lg: 18px;
+ --radius-md: 12px;
+ --radius-pill: 999px;
+ --transition-fast: 0.22s ease-out;
+ --transition-med: 0.3s cubic-bezier(.19,1,.22,1);
+ }
+
+ * {
+ box-sizing: border-box;
+ -webkit-tap-highlight-color: transparent;
+ }
+
+ html, body {
+ margin: 0;
+ padding: 0;
+ background: radial-gradient(circle at top, #181828 0, #05050a 52%);
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "SF Pro Text",
+ "Segoe UI", sans-serif;
+ color: var(--text-main);
+ }
+
+ body {
+ min-height: 100vh;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .frame {
+ width: 370px;
+ max-width: 100vw;
+ background: radial-gradient(circle at top left, #202030, #080813 70%);
+ border-radius: 28px;
+ padding: 18px 14px;
+ box-shadow:
+ 0 35px 80px rgba(0,0,0,0.85),
+ 0 0 0 1px rgba(255,255,255,0.02);
+ border: 1px solid rgba(255,255,255,0.03);
+ }
+
+ .ig-shell {
+ background: linear-gradient(145deg, #151521, #0b0b14);
+ border-radius: 24px;
+ overflow: hidden;
+ border: 1px solid rgba(255,255,255,0.06);
+ }
+
+ /* HEADER */
+ .ig-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 10px 14px 8px;
+ }
+ .ig-header-left {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ }
+ .avatar-wrap {
+ width: 32px;
+ height: 32px;
+ padding: 2px;
+ border-radius: 50%;
+ background: conic-gradient(from 180deg, #f9ce6a, #f58c75, #d948a6, #6a5af9, #f9ce6a);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+ .avatar-inner {
+ width: 100%;
+ height: 100%;
+ border-radius: 50%;
+ background: radial-gradient(circle at 30% 20%, #fefefe 0, #dedfe9 32%, #c4c6d2 70%);
+ border: 2px solid #151521;
+ position: relative;
+ overflow: hidden;
+ }
+ .avatar-inner::before {
+ content: "";
+ position: absolute;
+ inset: 16% 8% 22% 22%;
+ border-radius: 40% 60% 60% 40%;
+ background: radial-gradient(circle at 35% 25%, #f6e5df 0, #e4c5b4 32%, #c89b86 65%);
+ }
+ .avatar-inner::after {
+ content: "";
+ position: absolute;
+ inset: 40% 28% 20% 18%;
+ border-radius: 50%;
+ background: radial-gradient(circle at 50% 30%, #2f2c3a 0, #151521 65%);
+ }
+
+ .ig-identity {
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+ }
+ .ig-handle {
+ font-size: 13px;
+ font-weight: 600;
+ letter-spacing: 0.01em;
+ }
+ .ig-meta {
+ font-size: 11px;
+ color: var(--text-soft);
+ }
+ .ig-meta-dot::before {
+ content: "•";
+ margin: 0 4px;
+ }
+
+ .ig-header-right {
+ display: flex;
+ align-items: center;
+ gap: 14px;
+ color: #efefef;
+ }
+ .ig-icon {
+ width: 18px;
+ height: 18px;
+ position: relative;
+ }
+ .ig-icon.more::before,
+ .ig-icon.more::after {
+ content: "";
+ position: absolute;
+ width: 3px;
+ height: 3px;
+ border-radius: 50%;
+ background: #fafafa;
+ left: 50%;
+ transform: translateX(-50%);
+ }
+ .ig-icon.more::before {
+ top: 4px;
+ box-shadow: 0 4px 0 #fafafa, 0 8px 0 #fafafa;
+ }
+
+ .ig-icon.shop {
+ border-radius: 6px;
+ border: 1px solid rgba(255,255,255,0.16);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+ .ig-icon.shop::before {
+ content: "";
+ width: 11px;
+ height: 8px;
+ border: 1.4px solid #fafafa;
+ border-radius: 3px 3px 5px 5px;
+ box-sizing: border-box;
+ position: relative;
+ top: 0.5px;
+ }
+ .ig-icon.shop::after {
+ content: "";
+ position: absolute;
+ top: 2px;
+ left: 4px;
+ right: 4px;
+ height: 3px;
+ border-top: 1.4px solid #fafafa;
+ border-radius: 2px;
+ }
+
+ /* IMAGE AREA - ROOM ILLUSTRATION */
+ .ig-media-wrap {
+ position: relative;
+ background: radial-gradient(circle at top, #202031 0, #060612 72%);
+ border-radius: 18px;
+ margin: 0 10px;
+ overflow: hidden;
+ border: 1px solid rgba(255,255,255,0.06);
+ }
+ .ig-media {
+ position: relative;
+ width: 100%;
+ padding-top: 100%;
+ overflow: hidden;
+ cursor: pointer;
+ }
+
+ /* Room base */
+ .room {
+ position: absolute;
+ inset: 0;
+ padding: 16px 14px 12px;
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-end;
+ background:
+ radial-gradient(circle at top left, rgba(255,255,255,0.12) 0, transparent 55%),
+ radial-gradient(circle at top right, rgba(111, 92, 255,0.16) 0, transparent 55%),
+ linear-gradient(160deg, #151524 0, #070713 70%);
+ }
+
+ .room-wall {
+ position: absolute;
+ inset: 14px 14px 34%;
+ border-radius: 14px;
+ overflow: hidden;
+ background-color: #222132;
+ }
+
+ /* Wallpaper patterns layer */
+ .wallpattern-base {
+ position: absolute;
+ inset: 0;
+ background:
+ radial-gradient(circle at 0% 0%, rgba(255,255,255,0.12) 0, transparent 55%),
+ radial-gradient(circle at 100% 0%, rgba(241,182,121,0.10) 0, transparent 60%),
+ radial-gradient(circle at 100% 100%, rgba(141,188,159,0.25) 0, transparent 70%),
+ radial-gradient(circle at 0% 100%, rgba(19,187,187,0.16) 0, transparent 65%),
+ #232332;
+ opacity: 0.98;
+ }
+
+ .wallpattern-arches {
+ position: absolute;
+ inset: 0;
+ background-image:
+ radial-gradient(circle at 10% 110%, rgba(0,0,0,0.24) 0, transparent 55%),
+ radial-gradient(circle at 50% -30%, rgba(255,255,255,0.12) 0, transparent 60%);
+ mix-blend-mode: soft-light;
+ }
+
+ .wallpattern-lines {
+ position: absolute;
+ inset: 0;
+ background-image:
+ repeating-linear-gradient(
+ 135deg,
+ rgba(255,255,255,0.04) 0,
+ rgba(255,255,255,0.04) 1px,
+ transparent 1px,
+ transparent 7px
+ ),
+ repeating-linear-gradient(
+ -135deg,
+ rgba(13,13,25,0.7) 0,
+ rgba(13,13,25,0.7) 1px,
+ transparent 1px,
+ transparent 8px
+ );
+ opacity: 0.8;
+ }
+
+ .room-floor {
+ position: absolute;
+ left: 6px;
+ right: 6px;
+ bottom: 6px;
+ height: 27%;
+ border-radius: 16px;
+ background:
+ linear-gradient(to top, rgba(0,0,0,0.45), transparent 55%),
+ linear-gradient(180deg, #111019, #07050b 65%);
+ box-shadow: 0 -8px 25px rgba(0,0,0,0.85);
+ }
+
+ .floor-planks {
+ position: absolute;
+ inset: 6px 10px 6px;
+ background-image:
+ linear-gradient(
+ 90deg,
+ rgba(255,255,255,0.04) 0,
+ rgba(255,255,255,0.04) 1px,
+ transparent 1px,
+ transparent 30px
+ );
+ opacity: 0.6;
+ }
+
+ /* Sofa */
+ .sofa {
+ position: absolute;
+ left: 14%;
+ right: 10%;
+ bottom: 13%;
+ height: 26%;
+ display: flex;
+ flex-direction: column;
+ }
+
+ .sofa-base {
+ flex: 1;
+ border-radius: 16px 16px 14px 14px;
+ background:
+ linear-gradient(145deg, #272941 0, #141423 60%, #0c0c18 100%);
+ box-shadow:
+ 0 18px 30px rgba(0,0,0,0.9),
+ 0 -4px 12px rgba(255,255,255,0.02) inset;
+ position: relative;
+ overflow: hidden;
+ }
+
+ .sofa-base::before {
+ content: "";
+ position: absolute;
+ inset: 2px 2px auto 2px;
+ height: 32%;
+ border-radius: 12px 12px 10px 10px;
+ background:
+ linear-gradient(120deg, rgba(255,255,255,0.08), transparent 40%),
+ linear-gradient(145deg, #313454, #19192b 60%);
+ }
+
+ .sofa-arm {
+ position: absolute;
+ right: -4%;
+ top: 10%;
+ bottom: 14%;
+ width: 22%;
+ border-radius: 22px 18px 16px 10px;
+ background: linear-gradient(145deg, #24253d, #11111e);
+ box-shadow:
+ -4px 0 14px rgba(0,0,0,0.8),
+ 0 0 0 1px rgba(255,255,255,0.04) inset;
+ }
+
+ .sofa-cushion-main {
+ position: absolute;
+ left: 18%;
+ right: 22%;
+ top: 16%;
+ bottom: 40%;
+ border-radius: 16px;
+ background:
+ linear-gradient(160deg, #3a3e6a, #20223f 60%, #151524);
+ box-shadow:
+ 0 14px 22px rgba(0,0,0,0.85),
+ 0 0 0 1px rgba(255,255,255,0.04) inset;
+ }
+
+ .sofa-cushion-alt {
+ position: absolute;
+ left: 5%;
+ width: 20%;
+ top: 16%;
+ bottom: 45%;
+ border-radius: 13px;
+ background:
+ linear-gradient(145deg, #f3d9b8, #d9a271);
+ box-shadow: 0 14px 18px rgba(0,0,0,0.75);
+ }
+
+ .throw {
+ position: absolute;
+ right: 20%;
+ bottom: 34%;
+ width: 18%;
+ height: 24%;
+ border-radius: 6px;
+ background:
+ linear-gradient(135deg, #8fe1d9, #4ab7a6);
+ box-shadow: 0 10px 16px rgba(0,0,0,0.7);
+ transform: skewX(-10deg) rotate(-2deg);
+ }
+
+ .throw::after {
+ content: "";
+ position: absolute;
+ inset: 0 0 -18% 0;
+ background:
+ repeating-linear-gradient(
+ 180deg,
+ rgba(255,255,255,0.45) 0,
+ rgba(255,255,255,0.45) 2px,
+ transparent 2px,
+ transparent 4px
+ );
+ opacity: 0.85;
+ border-radius: 0 0 6px 6px;
+ }
+
+ .sofa-shadow {
+ position: absolute;
+ left: 8%;
+ right: 16%;
+ bottom: 8%;
+ height: 24%;
+ background: radial-gradient(circle at 50% 0, rgba(0,0,0,0.9) 0, transparent 70%);
+ opacity: 0.95;
+ }
+
+ /* Coffee table */
+ .table {
+ position: absolute;
+ left: 20%;
+ right: 32%;
+ bottom: 8%;
+ height: 14%;
+ }
+
+ .table-top {
+ position: absolute;
+ left: 10%;
+ right: 10%;
+ top: 0;
+ height: 35%;
+ border-radius: 14px;
+ background:
+ linear-gradient(145deg, #f5f0eb, #e2d1c1);
+ box-shadow: 0 10px 18px rgba(0,0,0,0.6);
+ }
+ .table-legs {
+ position: absolute;
+ left: 16%;
+ right: 16%;
+ bottom: 0;
+ top: 30%;
+ }
+ .table-leg {
+ position: absolute;
+ bottom: 0;
+ width: 3px;
+ border-radius: 999px;
+ background: linear-gradient(180deg, #d0b29c, #8b6245);
+ box-shadow: 0 0 0 1px rgba(0,0,0,0.3);
+ }
+ .table-leg:nth-child(1) { left: 22%; }
+ .table-leg:nth-child(2) { left: 50%; transform: translateX(-50%); }
+ .table-leg:nth-child(3) { right: 22%; }
+
+ .table-decor {
+ position: absolute;
+ left: 18%;
+ right: 18%;
+ top: 10%;
+ height: 60%;
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-end;
+ }
+ .decor-vase {
+ width: 16px;
+ height: 22px;
+ border-radius: 50% 50% 40% 40%;
+ background: radial-gradient(circle at 30% 10%, #ffffff 0, #dfd7ff 30%, #9c91f6 75%);
+ box-shadow: 0 7px 10px rgba(0,0,0,0.5);
+ position: relative;
+ }
+ .decor-vase::after {
+ content: "";
+ position: absolute;
+ left: 50%;
+ top: -10px;
+ width: 1px;
+ height: 12px;
+ background: linear-gradient(180deg, #6bbb7a, #29643a);
+ }
+ .decor-book {
+ width: 18px;
+ height: 8px;
+ border-radius: 3px;
+ background: linear-gradient(145deg, #1f2135, #10111e);
+ box-shadow: 0 5px 7px rgba(0,0,0,0.6);
+ position: relative;
+ }
+ .decor-book::before {
+ content: "";
+ position: absolute;
+ inset: 1px;
+ border-radius: 2px;
+ border-top: 2px solid rgba(255,255,255,0.24);
+ }
+
+ /* Wall art */
+ .wall-art {
+ position: absolute;
+ left: 26%;
+ right: 22%;
+ top: 20%;
+ height: 24%;
+ border-radius: 14px;
+ background:
+ linear-gradient(145deg, #f7f4f1, #e1d9ce);
+ box-shadow:
+ 0 18px 24px rgba(0,0,0,0.7),
+ 0 0 0 1px rgba(0,0,0,0.45);
+ overflow: hidden;
+ }
+ .wall-art-inner {
+ position: absolute;
+ inset: 8% 10%;
+ border-radius: 10px;
+ background:
+ radial-gradient(circle at 15% 20%, #f8d6b0 0, transparent 55%),
+ radial-gradient(circle at 70% 80%, #a3d2f9 0, transparent 55%),
+ radial-gradient(circle at 95% 10%, #f8a0b1 0, transparent 50%),
+ linear-gradient(145deg, #151622, #1e2235);
+ }
+ .wall-art-inner::before {
+ content: "";
+ position: absolute;
+ inset: 12% 30% 18% 6%;
+ border-radius: 999px;
+ border: 2px solid rgba(255,255,255,0.4);
+ }
+ .wall-art-inner::after {
+ content: "";
+ position: absolute;
+ inset: 22% 6% 8% 34%;
+ border-radius: 10px;
+ border: 2px solid rgba(255,255,255,0.4);
+ }
+
+ /* Product tags */
+ .tag {
+ position: absolute;
+ z-index: 4;
+ width: 22px;
+ height: 22px;
+ border-radius: 999px;
+ background: rgba(15,15,25,0.8);
+ border: 1px solid rgba(255,255,255,0.18);
+ box-shadow:
+ 0 0 0 1px rgba(0,0,0,0.5),
+ 0 8px 15px rgba(0,0,0,0.65);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ transition: transform var(--transition-fast), box-shadow var(--transition-fast), background 0.18s ease-out;
+ backdrop-filter: blur(10px);
+ }
+
+ .tag::before,
+ .tag::after {
+ content: "";
+ position: absolute;
+ border-radius: inherit;
+ inset: 2px;
+ }
+ .tag::before {
+ border: 1px solid rgba(255,255,255,0.35);
+ opacity: 0.85;
+ }
+ .tag::after {
+ background: radial-gradient(circle at 30% 20%, rgba(255,255,255,0.7) 0, rgba(255,255,255,0) 55%);
+ mix-blend-mode: screen;
+ }
+
+ .tag-dot {
+ position: relative;
+ width: 6px;
+ height: 6px;
+ border-radius: 999px;
+ background: #ffffff;
+ box-shadow: 0 0 0 3px rgba(21,21,33,0.85);
+ }
+
+ .tag:hover {
+ transform: translateY(-1px) scale(1.03);
+ box-shadow:
+ 0 0 0 1px rgba(255,255,255,0.25),
+ 0 10px 20px rgba(0,0,0,0.85);
+ background: rgba(18,18,32,0.98);
+ }
+
+ .tag[data-target="tag1"] { top: 22%; left: 22%; }
+ .tag[data-target="tag2"] { top: 66%; left: 56%; }
+ .tag[data-target="tag3"] { top: 44%; right: 18%; }
+
+ .tag.active {
+ background: rgba(242,182,121,0.95);
+ border-color: rgba(255,255,255,0.85);
+ }
+ .tag.active .tag-dot {
+ background: #151521;
+ box-shadow: 0 0 0 4px rgba(21,21,33,0.8);
+ }
+
+ /* Swatch pattern (reusable) */
+ .swatch {
+ position: relative;
+ border-radius: 8px;
+ overflow: hidden;
+ background-color: #25253a;
+ }
+ .swatch-main {
+ position: absolute;
+ inset: 0;
+ }
+
+ .swatch.pattern-aurora {
+ background:
+ radial-gradient(circle at 0% 0%, #f7d5aa 0, #f5c495 16%, transparent 55%),
+ radial-gradient(circle at 80% 100%, #89d9bb 0, transparent 50%),
+ #101323;
+ }
+ .swatch.pattern-aurora .swatch-main {
+ background-image:
+ radial-gradient(circle at 0% 120%, rgba(0,0,0,0.42) 0, transparent 60%),
+ repeating-linear-gradient(
+ 135deg,
+ rgba(255,255,255,0.2) 0,
+ rgba(255,255,255,0.2) 1px,
+ transparent 1px,
+ transparent 8px
+ );
+ mix-blend-mode: soft-light;
+ opacity: 0.8;
+ }
+
+ .swatch.pattern-linen {
+ background:
+ linear-gradient(120deg, #f7f1e5, #e2d5c3);
+ }
+ .swatch.pattern-linen .swatch-main {
+ background-image:
+ repeating-linear-gradient(
+ 0deg,
+ rgba(182,160,132,0.45) 0,
+ rgba(182,160,132,0.45) 1px,
+ transparent 1px,
+ transparent 4px
+ ),
+ repeating-linear-gradient(
+ 90deg,
+ rgba(182,160,132,0.45) 0,
+ rgba(182,160,132,0.45) 1px,
+ transparent 1px,
+ transparent 6px
+ );
+ opacity: 0.45;
+ mix-blend-mode: multiply;
+ }
+
+ .swatch.pattern-ink {
+ background:
+ radial-gradient(circle at 50% 0%, #fce4d4 0, transparent 55%),
+ radial-gradient(circle at 0% 100%, #c2f0ff 0, transparent 58%),
+ #111322;
+ }
+ .swatch.pattern-ink .swatch-main {
+ background-image:
+ radial-gradient(circle at 20% 40%, rgba(0,0,0,0.9) 0, transparent 32%),
+ radial-gradient(circle at 70% 70%, rgba(0,0,0,0.8) 0, transparent 30%);
+ mix-blend-mode: normal;
+ opacity: 0.85;
+ }
+
+ /* Product cards */
+ .product-card {
+ position: absolute;
+ min-width: 200px;
+ max-width: 230px;
+ border-radius: 14px;
+ padding: 10px 10px 10px;
+ background: linear-gradient(145deg, rgba(15,15,25,0.97), rgba(17,17,31,0.95));
+ border: 1px solid rgba(255,255,255,0.18);
+ box-shadow:
+ 0 18px 40px rgba(0,0,0,0.9),
+ 0 0 0 1px rgba(0,0,0,0.7);
+ backdrop-filter: blur(14px);
+ display: none;
+ z-index: 5;
+ }
+
+ .product-card.visible {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ animation: popIn var(--transition-med);
+ transform-origin: top left;
+ }
+
+ @keyframes popIn {
+ from {
+ opacity: 0;
+ transform: translateY(4px) scale(0.96);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0) scale(1);
+ }
+ }
+
+ .product-card-main {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ }
+
+ .product-info {
+ display: flex;
+ flex-direction: column;
+ gap: 3px;
+ }
+ .product-name {
+ font-size: 12px;
+ font-weight: 600;
+ letter-spacing: 0.01em;
+ }
+ .product-detail-line {
+ font-size: 11px;
+ color: var(--text-soft);
+ }
+ .product-meta {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ margin-top: 2px;
+ }
+ .price {
+ font-size: 12px;
+ font-weight: 600;
+ color: var(--accent);
+ }
+ .pill {
+ font-size: 10px;
+ padding: 2px 6px;
+ border-radius: 999px;
+ background: rgba(242,182,121,0.08);
+ border: 1px solid rgba(242,182,121,0.25);
+ color: var(--accent);
+ }
+
+ .btn-view {
+ margin-left: auto;
+ font-size: 11px;
+ padding: 4px 10px;
+ border-radius: 999px;
+ border: none;
+ cursor: pointer;
+ background: linear-gradient(145deg, #f2b679, #f59562);
+ color: #141320;
+ font-weight: 600;
+ letter-spacing: 0.03em;
+ text-transform: uppercase;
+ box-shadow:
+ 0 7px 14px rgba(0,0,0,0.7),
+ 0 0 0 1px rgba(0,0,0,0.5);
+ transition: transform 0.15s ease-out, box-shadow 0.15s ease-out, filter 0.15s ease-out;
+ }
+ .btn-view:hover {
+ transform: translateY(-1px);
+ box-shadow:
+ 0 10px 20px rgba(0,0,0,0.85),
+ 0 0 0 1px rgba(0,0,0,0.6);
+ filter: brightness(1.03);
+ }
+ .btn-view:active {
+ transform: translateY(0);
+ box-shadow:
+ 0 5px 10px rgba(0,0,0,0.8),
+ 0 0 0 1px rgba(0,0,0,0.6);
+ }
+
+ .card-topline {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 6px;
+ }
+ .tag-label {
+ font-size: 10px;
+ text-transform: uppercase;
+ letter-spacing: 0.14em;
+ color: var(--text-soft);
+ }
+
+ .close-hit {
+ width: 16px;
+ height: 16px;
+ border-radius: 999px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ margin-left: 4px;
+ opacity: 0.7;
+ transition: opacity 0.18s ease-out, background 0.18s ease-out;
+ }
+ .close-hit:hover {
+ opacity: 1;
+ background: rgba(255,255,255,0.02);
+ }
+ .close-x {
+ width: 9px;
+ height: 9px;
+ position: relative;
+ }
+ .close-x::before,
+ .close-x::after {
+ content: "";
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ width: 100%;
+ height: 1px;
+ background: rgba(255,255,255,0.7);
+ transform-origin: center;
+ }
+ .close-x::before {
+ transform: translate(-50%, -50%) rotate(45deg);
+ }
+ .close-x::after {
+ transform: translate(-50%, -50%) rotate(-45deg);
+ }
+
+ .card-layout {
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+ }
+ .card-body {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ }
+
+ .card-swatch-wrap {
+ width: 54px;
+ height: 54px;
+ flex: 0 0 auto;
+ border-radius: 13px;
+ padding: 3px;
+ background: radial-gradient(circle at 10% 0, rgba(255,255,255,0.4), transparent 40%);
+ box-shadow:
+ 0 10px 20px rgba(0,0,0,0.7),
+ 0 0 0 1px rgba(255,255,255,0.08);
+ }
+ .card-swatch-inner {
+ width: 100%;
+ height: 100%;
+ border-radius: 10px;
+ overflow: hidden;
+ position: relative;
+ }
+
+ /* Card placements relative to tags */
+ #card1 { top: 24%; left: 22%; transform: translate(-2px, 20px); }
+ #card2 { bottom: 14%; left: 36%; transform: translate(-6px, 0); }
+ #card3 { top: 26%; right: 18%; transform: translate(-40%, 16px); }
+
+ /* IG Controls */
+ .ig-controls {
+ padding: 8px 14px 0;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+ .ig-actions-left {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ }
+ .control-icon {
+ width: 22px;
+ height: 22px;
+ position: relative;
+ cursor: pointer;
+ }
+ .control-icon.heart::before {
+ content: "";
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ width: 11px;
+ height: 10px;
+ transform: translate(-50%, -50%) rotate(-45deg);
+ border-radius: 6px 6px 0 0;
+ background: #fefefe;
+ }
+ .control-icon.heart::after {
+ content: "";
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ width: 11px;
+ height: 10px;
+ transform: translate(-50%, -50%) rotate(45deg);
+ border-radius: 6px 6px 0 0;
+ background: #fefefe;
+ }
+ .control-icon.comment::before {
+ content: "";
+ position: absolute;
+ inset: 4px 4px 7px 4px;
+ border-radius: 50% 50% 45% 45%;
+ border: 1.6px solid #fefefe;
+ }
+ .control-icon.comment::after {
+ content: "";
+ position: absolute;
+ left: 40%;
+ bottom: 4px;
+ width: 6px;
+ height: 6px;
+ border-radius: 0 0 6px 0;
+ border-right: 1.6px solid #fefefe;
+ border-bottom: 1.6px solid #fefefe;
+ }
+ .control-icon.share::before {
+ content: "";
+ position: absolute;
+ inset: 5px 7px;
+ border-radius: 4px;
+ border: 1.5px solid #fefefe;
+ }
+ .control-icon.share::after {
+ content: "";
+ position: absolute;
+ left: 50%;
+ top: 3px;
+ width: 10px;
+ height: 8px;
+ border-radius: 10px 10px 0 0;
+ border: 1.5px solid #fefefe;
+ border-bottom: none;
+ transform: translateX(-50%);
+ }
+ .control-icon.save::before {
+ content: "";
+ position: absolute;
+ inset: 4px 5px;
+ border-radius: 3px 3px 2px 2px;
+ border: 1.5px solid #fefefe;
+ }
+ .control-icon.save::after {
+ content: "";
+ position: absolute;
+ left: 10px;
+ bottom: 5px;
+ width: 5px;
+ height: 5px;
+ background: #fefefe;
+ clip-path: polygon(0 0, 100% 0, 100% 100%, 50% 70%, 0 100%);
+ }
+
+ .ig-indicator {
+ font-size: 11px;
+ color: var(--text-soft);
+ }
+ .dots {
+ display: inline-flex;
+ gap: 3px;
+ margin-left: 6px;
+ }
+ .dot {
+ width: 4px;
+ height: 4px;
+ border-radius: 999px;
+ background: rgba(255,255,255,0.28);
+ }
+ .dot.active {
+ width: 9px;
+ background: #fefefe;
+ }
+
+ /* IG Meta section */
+ .ig-meta-section {
+ padding: 4px 14px 10px;
+ }
+ .likes-row {
+ font-size: 12px;
+ font-weight: 600;
+ margin-bottom: 4px;
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ }
+ .likes-avatars {
+ display: flex;
+ }
+ .likes-avatar {
+ width: 16px;
+ height: 16px;
+ border-radius: 50%;
+ border: 1px solid #12121c;
+ background: radial-gradient(circle at 30% 20%, #ffffff 0, #d8daf0 45%, #9a9fcb);
+ box-shadow: 0 0 0 1px rgba(0,0,0,0.4);
+ }
+ .likes-avatar + .likes-avatar {
+ margin-left: -6px;
+ }
+
+ .caption {
+ font-size: 12px;
+ line-height: 1.5;
+ }
+ .caption b {
+ font-weight: 600;
+ }
+ .caption .tag-accent {
+ color: var(--accent);
+ font-weight: 500;
+ }
+ .caption .more {
+ color: var(--text-soft);
+ }
+
+ .view-comments {
+ margin-top: 4px;
+ font-size: 12px;
+ color: var(--text-soft);
+ }
+ .comment {
+ margin-top: 2px;
+ font-size: 12px;
+ }
+ .comment b {
+ font-weight: 600;
+ }
+ .timestamp {
+ margin-top: 6px;
+ font-size: 10px;
+ letter-spacing: 0.16em;
+ text-transform: uppercase;
+ color: var(--text-soft);
+ }
+ .shop-link {
+ color: var(--blue-link);
+ font-weight: 500;
+ cursor: pointer;
+ }
+
+ /* Tap hint */
+ .hint {
+ position: absolute;
+ inset: 12px 10px auto auto;
+ background: rgba(0,0,0,0.55);
+ border-radius: 999px;
+ padding: 4px 8px;
+ font-size: 10px;
+ display: inline-flex;
+ align-items: center;
+ gap: 5px;
+ color: var(--text-muted);
+ border: 1px solid rgba(255,255,255,0.16);
+ backdrop-filter: blur(12px);
+ z-index: 6;
+ }
+ .hint-dot {
+ width: 8px;
+ height: 8px;
+ border-radius: 999px;
+ border: 1px solid rgba(255,255,255,0.5);
+ position: relative;
+ }
+ .hint-dot::before {
+ content: "";
+ position: absolute;
+ inset: 2px;
+ border-radius: inherit;
+ background: #ffffff;
+ }
+
+ @media (max-width: 400px) {
+ .frame {
+ border-radius: 0;
+ box-shadow: none;
+ border: none;
+ }
+ }
+</style>
+</head>
+<body>
+<div class="frame">
+ <div class="ig-shell">
+ <!-- Header -->
+ <div class="ig-header">
+ <div class="ig-header-left">
+ <div class="avatar-wrap">
+ <div class="avatar-inner"></div>
+ </div>
+ <div class="ig-identity">
+ <div class="ig-handle">LumenWall Studio</div>
+ <div class="ig-meta">
+ Tokyo, Japan
+ <span class="ig-meta-dot"></span>
+ <span>Sponsored</span>
+ </div>
+ </div>
+ </div>
+ <div class="ig-header-right">
+ <div class="ig-icon shop" aria-hidden="true"></div>
+ <div class="ig-icon more" aria-hidden="true"></div>
+ </div>
+ </div>
+
+ <!-- Media -->
+ <div class="ig-media-wrap">
+ <div class="ig-media" id="media">
+ <div class="room">
+ <div class="room-wall">
+ <div class="wallpattern-base"></div>
+ <div class="wallpattern-arches"></div>
+ <div class="wallpattern-lines"></div>
+ </div>
+ <div class="room-floor">
+ <div class="floor-planks"></div>
+ </div>
+
+ <div class="sofa">
+ <div class="sofa-base">
+ <div class="sofa-arm"></div>
+ <div class="sofa-cushion-main"></div>
+ <div class="sofa-cushion-alt"></div>
+ <div class="throw"></div>
+ </div>
+ <div class="sofa-shadow"></div>
+ </div>
+
+ <div class="table">
+ <div class="table-top"></div>
+ <div class="table-decor">
+ <div class="decor-vase"></div>
+ <div class="decor-book"></div>
+ </div>
+ <div class="table-legs">
+ <div class="table-leg"></div>
+ <div class="table-leg"></div>
+ <div class="table-leg"></div>
+ </div>
+ </div>
+
+ <div class="wall-art">
+ <div class="wall-art-inner"></div>
+ </div>
+
+ <!-- Tap hint -->
+ <div class="hint" id="tapHint">
+ <span class="hint-dot"></span>
+ <span>Tap to view pieces</span>
+ </div>
+
+ <!-- Product tags -->
+ <button class="tag" type="button" data-target="card1" aria-label="View wallcovering">
+ <span class="tag-dot"></span>
+ </button>
+ <button class="tag" type="button" data-target="card2" aria-label="View sofa upholstery">
+ <span class="tag-dot"></span>
+ </button>
+ <button class="tag" type="button" data-target="card3" aria-label="View art wallcovering panel">
+ <span class="tag-dot"></span>
+ </button>
+
+ <!-- Product Cards -->
+ <div class="product-card" id="card1">
+ <div class="card-layout">
+ <div class="card-topline">
+ <span class="tag-label">Signature Wallcovering</span>
+ <div class="close-hit" data-close="card1" aria-label="Close wallcovering details">
+ <div class="close-x"></div>
+ </div>
+ </div>
+ <div class="card-body">
+ <div class="card-swatch-wrap">
+ <div class="card-swatch-inner swatch pattern-aurora">
+ <div class="swatch-main"></div>
+ </div>
+ </div>
+ <div class="product-info">
+ <div class="product-name">Aurora Gradient Mural</div>
+ <div class="product-detail-line">Peel + paste vinyl · 27 in repeat</div>
+ <div class="product-meta">
+ <span class="price">$168 / roll</span>
+ <span class="pill">Limited edition</span>
+ </div>
+ </div>
+ <button class="btn-view" type="button">View</button>
+ </div>
+ </div>
+ </div>
+
+ <div class="product-card" id="card2">
+ <div class="card-layout">
+ <div class="card-topline">
+ <span class="tag-label">Texture Companion</span>
+ <div class="close-hit" data-close="card2" aria-label="Close upholstery details">
+ <div class="close-x"></div>
+ </div>
+ </div>
+ <div class="card-body">
+ <div class="card-swatch-wrap">
+ <div class="card-swatch-inner swatch pattern-linen">
+ <div class="swatch-main"></div>
+ </div>
+ </div>
+ <div class="product-info">
+ <div class="product-name">Cloudline Linen Weave</div>
+ <div class="product-detail-line">Grasscloth-style wallcovering</div>
+ <div class="product-meta">
+ <span class="price">$132 / roll</span>
+ <span class="pill">Matte texture</span>
+ </div>
+ </div>
+ <button class="btn-view" type="button">View</button>
+ </div>
+ </div>
+ </div>
+
+ <div class="product-card" id="card3">
+ <div class="card-layout">
+ <div class="card-topline">
+ <span class="tag-label">Art Panel</span>
+ <div class="close-hit" data-close="card3" aria-label="Close wall panel details">
+ <div class="close-x"></div>
+ </div>
+ </div>
+ <div class="card-body">
+ <div class="card-swatch-wrap">
+ <div class="card-swatch-inner swatch pattern-ink">
+ <div class="swatch-main"></div>
+ </div>
+ </div>
+ <div class="product-info">
+ <div class="product-name">Ink Bloom Panel Set</div>
+ <div class="product-detail-line">Triptych wallcovering panels</div>
+ <div class="product-meta">
+ <span class="price">$420 / set</span>
+ <span class="pill">Made to measure</span>
+ </div>
+ </div>
+ <button class="btn-view" type="button">View</button>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <!-- Controls -->
+ <div class="ig-controls">
+ <div class="ig-actions-left">
+ <div class="control-icon heart" aria-hidden="true"></div>
+ <div class="control-icon comment" aria-hidden="true"></div>
+ <div class="control-icon share" aria-hidden="true"></div>
+ </div>
+ <div class="control-icon save" aria-hidden="true"></div>
+ </div>
+
+ <!-- Meta -->
+ <div class="ig-meta-section">
+ <div class="likes-row">
+ <div class="likes-avatars">
+ <div class="likes-avatar"></div>
+ <div class="likes-avatar"></div>
+ <div class="likes-avatar"></div>
+ </div>
+ <span>1,284 likes</span>
+ </div>
+ <div class="caption">
+ <b>lumenwall.studio</b>
+ Evening light on our
+ <span class="tag-accent">Aurora Gradient</span>
+ mural, paired with soft linen texture and a custom inked panel set.
+ <span class="more">More</span>
+ </div>
+ <div class="view-comments">View all 32 comments</div>
+ <div class="comment"><b>case.form</b> That gradient is unreal. Does it come in cool tones?</div>
+ <div class="comment"><b>lumenwall.studio</b> Yes – tap the tags to explore the full palette.</div>
+ <div class="timestamp">2 hours ago · <span class="shop-link" id="shopLink">Shop collection</span></div>
+ </div>
+ </div>
+</div>
+
+<script>
+(function() {
+ const tags = Array.from(document.querySelectorAll('.tag'));
+ const cards = Array.from(document.querySelectorAll('.product-card'));
+ const hint = document.getElementById('tapHint');
+ const media = document.getElementById('media');
+ const shopLink = document.getElementById('shopLink');
+
+ function hideAllCards() {
+ cards.forEach(c => c.classList.remove('visible'));
+ tags.forEach(t => t.classList.remove('active'));
+ }
+
+ function showCard(id) {
+ const card = document.getElementById(id);
+ if (!card) return;
+ const tag = tags.find(t => t.dataset.target === id);
+ hideAllCards();
+ card.classList.add('visible');
+ if (tag) tag.classList.add('active');
+ if (hint) hint.style.display = 'none';
+ }
+
+ tags.forEach(tag => {
+ tag.addEventListener('click', function(e) {
+ e.stopPropagation();
+ const targetId = this.dataset.target;
+ const card = document.getElementById(targetId);
+ const isVisible = card && card.classList.contains('visible');
+ if (isVisible) {
+ hideAllCards();
+ } else {
+ showCard(targetId);
+ }
+ });
+ });
+
+ cards.forEach(card => {
+ card.addEventListener('click', e => e.stopPropagation());
+ });
+
+ document.addEventListener('click', function(e) {
+ if (!media.contains(e.target)) {
+ hideAllCards();
+ }
+ });
+
+ document.querySelectorAll('.close-hit').forEach(btn => {
+ btn.addEventListener('click', function(e) {
+ e.stopPropagation();
+ const id = this.getAttribute('data-close');
+ const card = document.getElementById(id);
+ if (card) card.classList.remove('visible');
+ const tag = tags.find(t => t.dataset.target === id);
+ if (tag) tag.classList.remove('active');
+ });
+ });
+
+ if (shopLink) {
+ shopLink.addEventListener('click', function(e) {
+ e.preventDefault();
+ showCard('card1');
+ });
+ }
+
+ let hintTimeout = setTimeout(() => {
+ if (hint) hint.style.opacity = '0.9';
+ }, 800);
+
+ media.addEventListener('click', function() {
+ if (hint) hint.style.display = 'none';
+ clearTimeout(hintTimeout);
+ });
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/bde366feb227/gpt.png b/data/artifacts/bde366feb227/gpt.png
new file mode 100644
index 0000000..8b12bab
Binary files /dev/null and b/data/artifacts/bde366feb227/gpt.png differ
diff --git a/data/artifacts/bde366feb227/grok.html b/data/artifacts/bde366feb227/grok.html
new file mode 100644
index 0000000..c5073cf
--- /dev/null
+++ b/data/artifacts/bde366feb227/grok.html
@@ -0,0 +1,629 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Maison Murale — Shoppable Post</title>
+<style>
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
+ body {
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
+ background: #0a0a0a;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ min-height: 100vh;
+ padding: 24px 12px;
+ color: #262626;
+ }
+ .phone {
+ width: 390px;
+ max-width: 100%;
+ background: #fff;
+ border-radius: 28px;
+ overflow: hidden;
+ box-shadow: 0 25px 80px rgba(0,0,0,.55), 0 0 0 1px rgba(255,255,255,.06);
+ }
+ /* IG header */
+ .ig-header {
+ display: flex;
+ align-items: center;
+ padding: 12px 14px;
+ gap: 10px;
+ border-bottom: 1px solid #efefef;
+ }
+ .avatar {
+ width: 34px; height: 34px;
+ border-radius: 50%;
+ background: conic-gradient(from 210deg, #c9a87c, #8b6f4e, #e8d5b5, #a68b5b, #c9a87c);
+ display: grid; place-items: center;
+ flex-shrink: 0;
+ position: relative;
+ }
+ .avatar::after {
+ content: "";
+ width: 28px; height: 28px;
+ border-radius: 50%;
+ background: linear-gradient(145deg, #2c2420, #4a3f35);
+ display: block;
+ }
+ .avatar-initial {
+ position: absolute;
+ font-size: 11px; font-weight: 600; color: #e8d5b5;
+ letter-spacing: .5px;
+ }
+ .user-meta { flex: 1; min-width: 0; }
+ .username { font-size: 13.5px; font-weight: 600; line-height: 1.2; }
+ .sponsored { font-size: 11px; color: #8e8e8e; }
+ .more-btn {
+ background: none; border: none; cursor: pointer;
+ padding: 6px; font-size: 18px; letter-spacing: 2px; color: #262626;
+ }
+ /* Media / room */
+ .media {
+ position: relative;
+ width: 100%;
+ aspect-ratio: 1 / 1;
+ overflow: hidden;
+ background: #d4c4a8;
+ cursor: default;
+ }
+ /* CSS room illustration */
+ .room {
+ position: absolute; inset: 0;
+ background:
+ linear-gradient(180deg, #e8dfd0 0%, #ddd2c0 40%, #cbbba3 100%);
+ }
+ /* Wallpaper pattern on back wall */
+ .wall {
+ position: absolute;
+ left: 0; right: 0; top: 0; bottom: 28%;
+ background-color: #f3ebe0;
+ background-image:
+ radial-gradient(ellipse 18px 28px at 30px 40px, transparent 40%, rgba(139,111,78,.18) 41%, rgba(139,111,78,.18) 55%, transparent 56%),
+ radial-gradient(ellipse 14px 22px at 70px 90px, transparent 40%, rgba(166,139,91,.14) 41%, rgba(166,139,91,.14) 52%, transparent 53%),
+ radial-gradient(ellipse 16px 24px at 110px 35px, transparent 40%, rgba(139,111,78,.16) 41%, rgba(139,111,78,.16) 54%, transparent 55%),
+ radial-gradient(ellipse 12px 20px at 50px 140px, transparent 40%, rgba(120,95,60,.12) 41%, rgba(120,95,60,.12) 50%, transparent 51%),
+ repeating-linear-gradient(
+ 0deg,
+ transparent,
+ transparent 47px,
+ rgba(139,111,78,.07) 47px,
+ rgba(139,111,78,.07) 48px
+ ),
+ repeating-linear-gradient(
+ 90deg,
+ transparent,
+ transparent 55px,
+ rgba(139,111,78,.05) 55px,
+ rgba(139,111,78,.05) 56px
+ );
+ background-size: 120px 160px, 100px 140px, 130px 150px, 90px 120px, 48px 48px, 56px 56px;
+ }
+ /* Soft botanical vine motif overlay */
+ .wall::before {
+ content: "";
+ position: absolute; inset: 0;
+ opacity: .45;
+ background-image:
+ radial-gradient(circle at 20% 30%, rgba(90,110,70,.2) 0 3px, transparent 4px),
+ radial-gradient(circle at 22% 34%, rgba(90,110,70,.15) 0 5px, transparent 6px),
+ radial-gradient(circle at 55% 55%, rgba(90,110,70,.18) 0 3px, transparent 4px),
+ radial-gradient(circle at 58% 50%, rgba(90,110,70,.12) 0 7px, transparent 8px),
+ radial-gradient(circle at 78% 22%, rgba(90,110,70,.2) 0 2px, transparent 3px),
+ radial-gradient(circle at 80% 26%, rgba(90,110,70,.14) 0 6px, transparent 7px),
+ radial-gradient(circle at 35% 70%, rgba(90,110,70,.16) 0 4px, transparent 5px),
+ radial-gradient(circle at 88% 68%, rgba(90,110,70,.15) 0 3px, transparent 4px);
+ background-size: 100% 100%;
+ }
+ /* Floor */
+ .floor {
+ position: absolute;
+ left: 0; right: 0; bottom: 0; height: 30%;
+ background: linear-gradient(180deg, #b8956a 0%, #a07d55 30%, #8c6c48 100%);
+ transform: perspective(400px) rotateX(8deg);
+ transform-origin: top center;
+ }
+ .floor::before {
+ content: "";
+ position: absolute; inset: 0;
+ background: repeating-linear-gradient(
+ 90deg,
+ transparent 0 48px,
+ rgba(0,0,0,.08) 48px 49px
+ );
+ }
+ /* Baseboard */
+ .baseboard {
+ position: absolute;
+ left: 0; right: 0; bottom: 28%;
+ height: 10px;
+ background: linear-gradient(180deg, #f5f0e8, #e0d6c8);
+ box-shadow: 0 2px 4px rgba(0,0,0,.1);
+ z-index: 2;
+ }
+ /* Window light */
+ .window-light {
+ position: absolute;
+ top: 8%; right: 6%;
+ width: 28%; height: 38%;
+ background: linear-gradient(135deg, rgba(255,252,245,.55), rgba(255,248,230,.15));
+ border: 3px solid rgba(245,240,230,.7);
+ border-radius: 2px;
+ box-shadow: inset 0 0 40px rgba(255,250,240,.4), 0 8px 30px rgba(200,180,140,.15);
+ z-index: 2;
+ }
+ .window-light::before {
+ content: "";
+ position: absolute; inset: 0;
+ background:
+ linear-gradient(90deg, transparent 48%, rgba(245,240,230,.6) 48% 52%, transparent 52%),
+ linear-gradient(0deg, transparent 48%, rgba(245,240,230,.6) 48% 52%, transparent 52%);
+ }
+ /* Light rays on floor */
+ .sun-rays {
+ position: absolute;
+ bottom: 0; right: 5%;
+ width: 40%; height: 32%;
+ background: linear-gradient(160deg, rgba(255,248,220,.35), transparent 70%);
+ clip-path: polygon(40% 0, 100% 0, 85% 100%, 0% 100%);
+ z-index: 1;
+ pointer-events: none;
+ }
+ /* Console table */
+ .console {
+ position: absolute;
+ bottom: 22%; left: 50%;
+ transform: translateX(-50%);
+ width: 52%; height: 14%;
+ z-index: 3;
+ }
+ .console-top {
+ position: absolute; top: 0; left: 0; right: 0;
+ height: 12px;
+ background: linear-gradient(180deg, #5c4030, #3d2a1f);
+ border-radius: 2px 2px 0 0;
+ box-shadow: 0 2px 6px rgba(0,0,0,.25);
+ }
+ .console-leg {
+ position: absolute; top: 12px;
+ width: 6px; height: calc(100% - 12px);
+ background: linear-gradient(90deg, #4a3224, #2e1e14);
+ }
+ .console-leg.l { left: 8%; }
+ .console-leg.r { right: 8%; }
+ /* Vase on console */
+ .vase {
+ position: absolute;
+ bottom: 34%; left: 42%;
+ width: 28px; height: 48px;
+ background: linear-gradient(90deg, #c4b8a4, #e8e0d4 40%, #b8ac98);
+ border-radius: 40% 40% 30% 30% / 20% 20% 60% 60%;
+ z-index: 4;
+ box-shadow: 2px 4px 8px rgba(0,0,0,.15);
+ }
+ .vase::before {
+ content: "";
+ position: absolute;
+ top: -18px; left: 50%; transform: translateX(-50%);
+ width: 4px; height: 22px;
+ background: #5a6e48;
+ border-radius: 2px;
+ box-shadow: 6px 4px 0 -1px #6a7e55, -5px 8px 0 -1px #4a5e3a, 3px -2px 0 -1px #7a8e60;
+ }
+ .vase::after {
+ content: "";
+ position: absolute;
+ top: -28px; left: 50%; transform: translateX(-30%);
+ width: 22px; height: 16px;
+ background: radial-gradient(ellipse, #7a9a5a 0%, #5a7a40 60%, transparent 70%);
+ border-radius: 50%;
+ }
+ /* Framed art / second wall moment */
+ .frame {
+ position: absolute;
+ top: 18%; left: 10%;
+ width: 22%; height: 28%;
+ background: #faf6f0;
+ border: 5px solid #3d2a1f;
+ box-shadow: 3px 4px 12px rgba(0,0,0,.18);
+ z-index: 3;
+ }
+ .frame::before {
+ content: "";
+ position: absolute; inset: 8px;
+ background:
+ linear-gradient(160deg, #d4c8b0, #e8dfd0),
+ radial-gradient(circle at 40% 40%, rgba(90,110,70,.25) 0 20%, transparent 50%);
+ background-blend-mode: multiply;
+ }
+ /* Armchair suggestion */
+ .chair {
+ position: absolute;
+ bottom: 18%; right: 8%;
+ width: 26%; height: 22%;
+ z-index: 3;
+ }
+ .chair-back {
+ position: absolute; top: 0; left: 10%; right: 10%;
+ height: 55%;
+ background: linear-gradient(180deg, #6b4f3a, #5a3f2c);
+ border-radius: 40% 40% 8% 8% / 30% 30% 10% 10%;
+ box-shadow: inset 0 4px 8px rgba(255,255,255,.08);
+ }
+ .chair-seat {
+ position: absolute; bottom: 15%; left: 0; right: 0;
+ height: 35%;
+ background: linear-gradient(180deg, #7a5a42, #5c4030);
+ border-radius: 8px 8px 4px 4px;
+ }
+ .chair-leg {
+ position: absolute; bottom: 0;
+ width: 5px; height: 18%;
+ background: #2e1e14;
+ }
+ .chair-leg.l { left: 15%; }
+ .chair-leg.r { right: 15%; }
+ /* Product tags */
+ .tag {
+ position: absolute;
+ z-index: 10;
+ width: 28px; height: 28px;
+ border-radius: 50%;
+ background: rgba(255,255,255,.92);
+ border: none;
+ cursor: pointer;
+ box-shadow: 0 2px 10px rgba(0,0,0,.28);
+ display: grid; place-items: center;
+ transition: transform .2s ease, box-shadow .2s ease;
+ padding: 0;
+ }
+ .tag::after {
+ content: "";
+ width: 9px; height: 9px;
+ border-radius: 50%;
+ background: #262626;
+ transition: transform .2s ease;
+ }
+ .tag:hover, .tag.active {
+ transform: scale(1.12);
+ box-shadow: 0 3px 16px rgba(0,0,0,.35);
+ }
+ .tag.active::after {
+ background: #c9a87c;
+ }
+ .tag .pulse {
+ position: absolute; inset: -4px;
+ border-radius: 50%;
+ border: 2px solid rgba(255,255,255,.7);
+ animation: pulse 2.2s ease-out infinite;
+ pointer-events: none;
+ }
+ @keyframes pulse {
+ 0% { transform: scale(.85); opacity: .8; }
+ 100% { transform: scale(1.55); opacity: 0; }
+ }
+ .tag-1 { top: 32%; left: 48%; }
+ .tag-2 { top: 55%; left: 18%; }
+ .tag-3 { top: 42%; right: 22%; left: auto; }
+ /* Product card popup */
+ .product-card {
+ position: absolute;
+ z-index: 20;
+ width: 220px;
+ background: #fff;
+ border-radius: 12px;
+ box-shadow: 0 12px 40px rgba(0,0,0,.28), 0 0 0 1px rgba(0,0,0,.04);
+ padding: 12px;
+ display: none;
+ animation: cardIn .22s ease;
+ bottom: 16px; left: 50%;
+ transform: translateX(-50%);
+ }
+ .product-card.show { display: block; }
+ @keyframes cardIn {
+ from { opacity: 0; transform: translateX(-50%) translateY(8px); }
+ to { opacity: 1; transform: translateX(-50%) translateY(0); }
+ }
+ .pc-inner { display: flex; gap: 12px; align-items: center; }
+ .swatch {
+ width: 56px; height: 56px;
+ border-radius: 8px;
+ flex-shrink: 0;
+ box-shadow: inset 0 0 0 1px rgba(0,0,0,.06);
+ position: relative;
+ overflow: hidden;
+ }
+ .swatch-a {
+ background-color: #f3ebe0;
+ background-image:
+ radial-gradient(ellipse 8px 12px at 14px 18px, transparent 40%, rgba(139,111,78,.35) 41%, rgba(139,111,78,.35) 55%, transparent 56%),
+ radial-gradient(ellipse 6px 10px at 36px 38px, transparent 40%, rgba(90,110,70,.3) 41%, rgba(90,110,70,.3) 52%, transparent 53%);
+ background-size: 40px 50px;
+ }
+ .swatch-b {
+ background-color: #e8e4dc;
+ background-image:
+ repeating-linear-gradient(45deg, transparent, transparent 4px, rgba(100,90,70,.12) 4px 5px),
+ radial-gradient(circle at 30% 40%, rgba(70,90,60,.25) 0 3px, transparent 4px),
+ radial-gradient(circle at 70% 60%, rgba(70,90,60,.2) 0 2px, transparent 3px);
+ }
+ .swatch-c {
+ background:
+ linear-gradient(135deg, #2c2420 25%, transparent 25%) -10px 0,
+ linear-gradient(225deg, #2c2420 25%, transparent 25%) -10px 0,
+ linear-gradient(315deg, #2c2420 25%, transparent 25%),
+ linear-gradient(45deg, #2c2420 25%, transparent 25%);
+ background-size: 12px 12px;
+ background-color: #c9a87c;
+ }
+ .pc-info { flex: 1; min-width: 0; }
+ .pc-brand { font-size: 10px; text-transform: uppercase; letter-spacing: 1px; color: #8e8e8e; margin-bottom: 2px; }
+ .pc-name { font-size: 13px; font-weight: 600; line-height: 1.25; margin-bottom: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
+ .pc-price { font-size: 13px; color: #262626; font-weight: 500; }
+ .pc-view {
+ display: block;
+ width: 100%;
+ margin-top: 10px;
+ padding: 9px;
+ background: #262626;
+ color: #fff;
+ border: none;
+ border-radius: 8px;
+ font-size: 12.5px;
+ font-weight: 600;
+ cursor: pointer;
+ letter-spacing: .3px;
+ transition: background .15s;
+ }
+ .pc-view:hover { background: #000; }
+ .pc-close {
+ position: absolute; top: 6px; right: 8px;
+ background: none; border: none;
+ font-size: 16px; color: #8e8e8e;
+ cursor: pointer; line-height: 1; padding: 4px;
+ }
+ /* Actions row */
+ .actions {
+ display: flex;
+ align-items: center;
+ padding: 10px 14px 6px;
+ gap: 14px;
+ }
+ .actions button {
+ background: none; border: none; cursor: pointer;
+ padding: 0; display: flex; align-items: center;
+ }
+ .actions svg { width: 24px; height: 24px; }
+ .actions .spacer { flex: 1; }
+ .liked svg path { fill: #ed4956; stroke: #ed4956; }
+ /* Likes & caption */
+ .likes {
+ padding: 0 14px;
+ font-size: 13.5px; font-weight: 600;
+ }
+ .caption {
+ padding: 6px 14px 2px;
+ font-size: 13.5px; line-height: 1.4;
+ }
+ .caption .un { font-weight: 600; margin-right: 4px; }
+ .caption .more { color: #8e8e8e; cursor: pointer; }
+ .comments-preview {
+ padding: 4px 14px;
+ font-size: 13.5px; color: #8e8e8e;
+ cursor: pointer;
+ }
+ .comment {
+ padding: 2px 14px;
+ font-size: 13.5px; line-height: 1.35;
+ }
+ .comment .un { font-weight: 600; margin-right: 4px; }
+ .timestamp {
+ padding: 8px 14px 4px;
+ font-size: 10px; color: #8e8e8e;
+ text-transform: uppercase; letter-spacing: .2px;
+ }
+ /* Add comment bar */
+ .add-comment {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 12px 14px;
+ border-top: 1px solid #efefef;
+ margin-top: 4px;
+ }
+ .add-comment .sm-avatar {
+ width: 28px; height: 28px;
+ border-radius: 50%;
+ background: linear-gradient(135deg, #ddd, #bbb);
+ flex-shrink: 0;
+ }
+ .add-comment span {
+ flex: 1; font-size: 13.5px; color: #8e8e8e;
+ }
+ .shop-badge {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+ font-size: 11px;
+ font-weight: 600;
+ color: #262626;
+ background: rgba(255,255,255,.92);
+ padding: 5px 10px;
+ border-radius: 6px;
+ position: absolute;
+ bottom: 14px; left: 12px;
+ z-index: 5;
+ box-shadow: 0 2px 8px rgba(0,0,0,.15);
+ pointer-events: none;
+ }
+ .shop-badge svg { width: 12px; height: 12px; }
+</style>
+</head>
+<body>
+<div class="phone">
+ <header class="ig-header">
+ <div class="avatar"><span class="avatar-initial">M</span></div>
+ <div class="user-meta">
+ <div class="username">maisonmurale</div>
+ <div class="sponsored">Sponsored</div>
+ </div>
+ <button class="more-btn" aria-label="More">•••</button>
+ </header>
+
+ <div class="media" id="media">
+ <div class="room">
+ <div class="wall"></div>
+ <div class="window-light"></div>
+ <div class="sun-rays"></div>
+ <div class="frame"></div>
+ <div class="baseboard"></div>
+ <div class="floor"></div>
+ <div class="console">
+ <div class="console-top"></div>
+ <div class="console-leg l"></div>
+ <div class="console-leg r"></div>
+ </div>
+ <div class="vase"></div>
+ <div class="chair">
+ <div class="chair-back"></div>
+ <div class="chair-seat"></div>
+ <div class="chair-leg l"></div>
+ <div class="chair-leg r"></div>
+ </div>
+ </div>
+
+ <div class="shop-badge">
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M6 6h15l-1.5 9h-12z"/><circle cx="9" cy="20" r="1"/><circle cx="18" cy="20" r="1"/><path d="M6 6L5 3H2"/></svg>
+ Shop
+ </div>
+
+ <button class="tag tag-1" data-product="0" aria-label="View product"><span class="pulse"></span></button>
+ <button class="tag tag-2" data-product="1" aria-label="View product"><span class="pulse"></span></button>
+ <button class="tag tag-3" data-product="2" aria-label="View product"><span class="pulse"></span></button>
+
+ <div class="product-card" id="productCard">
+ <button class="pc-close" id="pcClose" aria-label="Close">×</button>
+ <div class="pc-inner">
+ <div class="swatch" id="pcSwatch"></div>
+ <div class="pc-info">
+ <div class="pc-brand">Maison Murale</div>
+ <div class="pc-name" id="pcName"></div>
+ <div class="pc-price" id="pcPrice"></div>
+ </div>
+ </div>
+ <button class="pc-view">View</button>
+ </div>
+ </div>
+
+ <div class="actions" id="actions">
+ <button class="like-btn" id="likeBtn" aria-label="Like">
+ <svg viewBox="0 0 24 24" fill="none" stroke="#262626" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>
+ </button>
+ <button aria-label="Comment">
+ <svg viewBox="0 0 24 24" fill="none" stroke="#262626" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
+ </button>
+ <button aria-label="Share">
+ <svg viewBox="0 0 24 24" fill="none" stroke="#262626" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>
+ </button>
+ <div class="spacer"></div>
+ <button aria-label="Save">
+ <svg viewBox="0 0 24 24" fill="none" stroke="#262626" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"/></svg>
+ </button>
+ </div>
+
+ <div class="likes" id="likeCount">12,847 likes</div>
+ <div class="caption">
+ <span class="un">maisonmurale</span>Soft morning light, quiet botanicals. Our <strong>Hearth & Vine</strong> collection turns bare walls into a lived-in sanctuary. Tap the tags to explore each pattern. <span class="more">more</span>
+ </div>
+ <div class="comments-preview">View all 234 comments</div>
+ <div class="comment"><span class="un">atelier.lena</span>The scale of that vine print is perfection 🤍</div>
+ <div class="comment"><span class="un">design.by.cole</span>Need this for the reading nook project</div>
+ <div class="timestamp">2 hours ago</div>
+
+ <div class="add-comment">
+ <div class="sm-avatar"></div>
+ <span>Add a comment…</span>
+ </div>
+</div>
+
+<script>
+(function () {
+ var products = [
+ {
+ name: "Hearth Vine — Cream",
+ price: "from $148 / roll",
+ swatch: "swatch-a"
+ },
+ {
+ name: "Olive Branch Damask",
+ price: "from $162 / roll",
+ swatch: "swatch-b"
+ },
+ {
+ name: "Gilded Lattice Noir",
+ price: "from $178 / roll",
+ swatch: "swatch-c"
+ }
+ ];
+
+ var card = document.getElementById("productCard");
+ var pcName = document.getElementById("pcName");
+ var pcPrice = document.getElementById("pcPrice");
+ var pcSwatch = document.getElementById("pcSwatch");
+ var tags = document.querySelectorAll(".tag");
+ var activeIdx = null;
+
+ function openCard(idx) {
+ var p = products[idx];
+ pcName.textContent = p.name;
+ pcPrice.textContent = p.price;
+ pcSwatch.className = "swatch " + p.swatch;
+ card.classList.add("show");
+ tags.forEach(function (t, i) {
+ t.classList.toggle("active", i === idx);
+ });
+ activeIdx = idx;
+ }
+
+ function closeCard() {
+ card.classList.remove("show");
+ tags.forEach(function (t) { t.classList.remove("active"); });
+ activeIdx = null;
+ }
+
+ tags.forEach(function (tag) {
+ tag.addEventListener("click", function (e) {
+ e.stopPropagation();
+ var idx = parseInt(tag.getAttribute("data-product"), 10);
+ if (activeIdx === idx) {
+ closeCard();
+ } else {
+ openCard(idx);
+ }
+ });
+ });
+
+ document.getElementById("pcClose").addEventListener("click", function (e) {
+ e.stopPropagation();
+ closeCard();
+ });
+
+ document.getElementById("media").addEventListener("click", function (e) {
+ if (!e.target.closest(".tag") && !e.target.closest(".product-card")) {
+ closeCard();
+ }
+ });
+
+ var liked = false;
+ var baseLikes = 12847;
+ document.getElementById("likeBtn").addEventListener("click", function () {
+ liked = !liked;
+ this.classList.toggle("liked", liked);
+ document.getElementById("likeCount").textContent =
+ (baseLikes + (liked ? 1 : 0)).toLocaleString() + " likes";
+ });
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/bde366feb227/grok.png b/data/artifacts/bde366feb227/grok.png
new file mode 100644
index 0000000..26e7206
Binary files /dev/null and b/data/artifacts/bde366feb227/grok.png differ
diff --git a/data/artifacts/d7f4f8ca5f8d/claude-code.html b/data/artifacts/d7f4f8ca5f8d/claude-code.html
new file mode 100644
index 0000000..8918f9e
--- /dev/null
+++ b/data/artifacts/d7f4f8ca5f8d/claude-code.html
@@ -0,0 +1,450 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
+<title>Atelier — Wallpaper Swatch Match</title>
+<style>
+ :root{
+ --bg1:#1c1b1a; --bg2:#26221f; --ink:#e9e2d4; --muted:#9c9385;
+ --gold:#c9a24b; --gold-soft:#b8955a; --frame:#3a332b;
+ --cell:60px;
+ }
+ *{box-sizing:border-box; -webkit-tap-highlight-color:transparent;}
+ html,body{height:100%;}
+ body{
+ margin:0; min-height:100%;
+ font-family:"Georgia","Times New Roman",serif;
+ color:var(--ink);
+ background:
+ radial-gradient(1200px 700px at 50% -10%, #2f2a25 0%, transparent 60%),
+ linear-gradient(160deg, var(--bg1), var(--bg2));
+ display:flex; flex-direction:column; align-items:center;
+ justify-content:flex-start; gap:14px; padding:20px 14px 40px;
+ }
+ header{ text-align:center; margin-top:6px; }
+ h1{
+ margin:0; font-weight:400; letter-spacing:.32em;
+ font-size:clamp(18px,5.5vw,30px); text-transform:uppercase;
+ color:var(--ink);
+ }
+ h1 .amp{ color:var(--gold); }
+ .subtitle{
+ margin:6px 0 0; font-size:11px; letter-spacing:.42em;
+ text-transform:uppercase; color:var(--muted);
+ }
+ .hud{
+ display:flex; gap:10px; align-items:stretch; width:min(94vw,460px);
+ justify-content:center;
+ }
+ .stat{
+ flex:1; background:linear-gradient(180deg,#2b2620,#211d18);
+ border:1px solid var(--frame); border-radius:12px;
+ padding:9px 6px; text-align:center;
+ box-shadow: inset 0 1px 0 rgba(255,255,255,.04);
+ }
+ .stat .label{
+ font-size:9.5px; letter-spacing:.28em; text-transform:uppercase; color:var(--muted);
+ }
+ .stat .value{
+ font-size:clamp(18px,5vw,24px); color:var(--gold); margin-top:3px; letter-spacing:.04em;
+ font-variant-numeric:tabular-nums;
+ }
+ .btn{
+ flex:1; background:linear-gradient(180deg,#332b21,#241d16);
+ border:1px solid var(--gold-soft); border-radius:12px;
+ color:var(--gold); cursor:pointer; font-family:inherit;
+ letter-spacing:.2em; text-transform:uppercase; font-size:12px;
+ transition:transform .12s ease, background .2s ease;
+ display:flex; align-items:center; justify-content:center;
+ }
+ .btn:hover{ background:linear-gradient(180deg,#3d3325,#2a2118); }
+ .btn:active{ transform:scale(.96); }
+
+ .frame{
+ padding:12px; border-radius:18px;
+ background:linear-gradient(180deg,#322b22,#231e18);
+ border:1px solid var(--frame);
+ box-shadow:
+ 0 18px 40px rgba(0,0,0,.55),
+ inset 0 0 0 1px rgba(201,162,75,.18),
+ inset 0 2px 0 rgba(255,255,255,.04);
+ }
+ .board{
+ position:relative;
+ width:min(88vw,432px); aspect-ratio:1/1;
+ border-radius:10px;
+ background:
+ repeating-linear-gradient(45deg, rgba(255,255,255,.015) 0 8px, transparent 8px 16px),
+ #17140f;
+ box-shadow: inset 0 0 26px rgba(0,0,0,.6);
+ touch-action:none; overflow:hidden;
+ }
+
+ .tile{
+ position:absolute; border-radius:8px;
+ background-repeat:no-repeat; background-position:center; background-size:100% 100%;
+ box-shadow:
+ inset 0 0 0 1px rgba(0,0,0,.32),
+ inset 0 0 0 3px rgba(255,255,255,.05),
+ 0 2px 5px rgba(0,0,0,.35);
+ cursor:pointer;
+ transition:top .34s cubic-bezier(.2,.85,.3,1), left .34s cubic-bezier(.2,.85,.3,1),
+ transform .16s ease, box-shadow .18s ease;
+ will-change:top,left,transform;
+ }
+ .tile.sel{
+ z-index:6; transform:scale(.88);
+ box-shadow:
+ 0 0 0 3px var(--gold),
+ 0 0 18px rgba(201,162,75,.7),
+ inset 0 0 0 3px rgba(255,255,255,.12);
+ }
+ .tile.clearing{
+ z-index:5; animation:shimmer .44s ease forwards;
+ }
+ @keyframes shimmer{
+ 0%{ transform:scale(1); filter:brightness(1); }
+ 35%{ transform:scale(1.14); filter:brightness(1.9) saturate(1.5);
+ box-shadow:0 0 26px rgba(255,240,205,.95), inset 0 0 0 3px rgba(255,255,255,.5); }
+ 100%{ transform:scale(.1) rotate(12deg); filter:brightness(2.4); opacity:0; }
+ }
+
+ /* ——— luxe wallpaper swatches (CSS-drawn) ——— */
+ /* 0 · Damask — deep forest */
+ .t0{ background-color:#3a4a3f;
+ background-image:
+ radial-gradient(ellipse 42% 26% at 50% 20%, #93a795 0 44%, transparent 47%),
+ radial-gradient(ellipse 20% 34% at 50% 55%, #b4c4b0 0 46%, transparent 49%),
+ radial-gradient(ellipse 30% 16% at 25% 62%, #93a795 0 46%, transparent 49%),
+ radial-gradient(ellipse 30% 16% at 75% 62%, #93a795 0 46%, transparent 49%),
+ radial-gradient(circle at 50% 87%, #b4c4b0 0 11%, transparent 13%);
+ }
+ /* 1 · Floral — dusty rose */
+ .t1{ background-color:#b0868a;
+ background-image:
+ radial-gradient(circle at 50% 27%, #e4cdcf 0 15%, transparent 17%),
+ radial-gradient(circle at 27% 55%, #e4cdcf 0 15%, transparent 17%),
+ radial-gradient(circle at 73% 55%, #e4cdcf 0 15%, transparent 17%),
+ radial-gradient(circle at 50% 78%, #e4cdcf 0 15%, transparent 17%),
+ radial-gradient(circle at 50% 52%, #f2e4dd 0 12%, transparent 14%);
+ }
+ /* 2 · Geometric weave — antique gold */
+ .t2{ background-color:#b7994f;
+ background-image:
+ repeating-linear-gradient(45deg, rgba(255,248,220,.55) 0 4px, transparent 4px 11px),
+ repeating-linear-gradient(-45deg, rgba(90,68,26,.6) 0 4px, transparent 4px 11px);
+ }
+ /* 3 · Trellis lattice — slate blue */
+ .t3{ background-color:#5d7083;
+ background-image:
+ repeating-linear-gradient(45deg, transparent 0 11px, rgba(190,205,216,.9) 11px 13px),
+ repeating-linear-gradient(-45deg, transparent 0 11px, rgba(190,205,216,.9) 11px 13px);
+ }
+ /* 4 · Pearl medallion — mauve/plum */
+ .t4{ background-color:#856576;
+ background-image:
+ radial-gradient(circle at 50% 50%, #decad3 0 23%, transparent 25%),
+ radial-gradient(circle at 50% 50%, #a9899a 0 34%, transparent 36%),
+ radial-gradient(circle at 12% 12%, #c2a6b3 0 12%, transparent 14%),
+ radial-gradient(circle at 88% 88%, #c2a6b3 0 12%, transparent 14%),
+ radial-gradient(circle at 88% 12%, #c2a6b3 0 12%, transparent 14%),
+ radial-gradient(circle at 12% 88%, #c2a6b3 0 12%, transparent 14%);
+ }
+ /* 5 · Quatrefoil — warm caramel taupe */
+ .t5{ background-color:#9c7c58;
+ background-image:
+ radial-gradient(circle at 30% 30%, #cdb18b 0 21%, transparent 23%),
+ radial-gradient(circle at 70% 30%, #cdb18b 0 21%, transparent 23%),
+ radial-gradient(circle at 30% 70%, #cdb18b 0 21%, transparent 23%),
+ radial-gradient(circle at 70% 70%, #cdb18b 0 21%, transparent 23%),
+ radial-gradient(circle at 50% 50%, #e0cbaa 0 12%, transparent 14%);
+ }
+
+ footer{ font-size:10.5px; letter-spacing:.26em; text-transform:uppercase; color:var(--muted); }
+</style>
+</head>
+<body>
+ <header>
+ <h1>Atelier <span class="amp">·</span> Swatch Match</h1>
+ <p class="subtitle">Line up three fine wallpapers</p>
+ </header>
+
+ <div class="hud">
+ <div class="stat"><div class="label">Score</div><div class="value" id="score">0</div></div>
+ <div class="stat"><div class="label">Moves</div><div class="value" id="moves">0</div></div>
+ <button class="btn" id="restart">Restart</button>
+ </div>
+
+ <div class="frame">
+ <div class="board" id="board"></div>
+ </div>
+
+ <footer>Swap adjacent swatches to make a match</footer>
+
+<script>
+(function(){
+ const N = 6, TYPES = 6, GAP = 4;
+ const TR = "top .34s cubic-bezier(.2,.85,.3,1), left .34s cubic-bezier(.2,.85,.3,1), transform .16s ease, box-shadow .18s ease";
+ const board = document.getElementById('board');
+ const scoreEl = document.getElementById('score');
+ const movesEl = document.getElementById('moves');
+
+ let grid = []; // grid[r][c] = tileId | null
+ let tiles = {}; // id -> {type, el, r, c}
+ let nextId = 1;
+ let selected = null; // tileId
+ let score = 0, moves = 0;
+ let busy = false;
+
+ const sleep = ms => new Promise(res => setTimeout(res, ms));
+ const randType = () => Math.floor(Math.random() * TYPES);
+ const cell = () => board.clientWidth / N;
+
+ function createTile(type){
+ const id = nextId++;
+ const el = document.createElement('div');
+ el.className = 'tile t' + type;
+ el.dataset.id = id;
+ board.appendChild(el);
+ tiles[id] = { type, el, r:null, c:null };
+ return id;
+ }
+
+ function placeNow(id, r, c){
+ // instant placement (used for spawning above the board)
+ const cs = cell();
+ const t = tiles[id];
+ t.el.style.transition = 'none';
+ t.el.style.width = (cs - GAP) + 'px';
+ t.el.style.height = (cs - GAP) + 'px';
+ t.el.style.left = (c * cs + GAP/2) + 'px';
+ t.el.style.top = (r * cs + GAP/2) + 'px';
+ t.r = r; t.c = c;
+ void t.el.offsetWidth; // commit reflow so the next move animates
+ }
+
+ function layout(instant){
+ const cs = cell();
+ for(let r=0;r<N;r++){
+ for(let c=0;c<N;c++){
+ const id = grid[r][c];
+ if(id == null) continue;
+ const t = tiles[id];
+ t.el.style.transition = instant ? 'none' : TR;
+ t.el.style.width = (cs - GAP) + 'px';
+ t.el.style.height = (cs - GAP) + 'px';
+ t.el.style.left = (c * cs + GAP/2) + 'px';
+ t.el.style.top = (r * cs + GAP/2) + 'px';
+ t.r = r; t.c = c;
+ }
+ }
+ if(instant){
+ void board.offsetWidth;
+ for(const id in tiles) tiles[id].el.style.transition = TR;
+ }
+ }
+
+ // ——— match detection ———
+ function typeGridFromGrid(){
+ const g = [];
+ for(let r=0;r<N;r++){ g[r]=[]; for(let c=0;c<N;c++){ const id=grid[r][c]; g[r][c]= id==null?-1:tiles[id].type; } }
+ return g;
+ }
+ function findMatchesIn(g){
+ const set = new Set();
+ // rows
+ for(let r=0;r<N;r++){
+ let run=1;
+ for(let c=1;c<=N;c++){
+ if(c<N && g[r][c]!==-1 && g[r][c]===g[r][c-1]) run++;
+ else { if(run>=3) for(let k=c-run;k<c;k++) set.add(r+','+k); run=1; }
+ }
+ }
+ // cols
+ for(let c=0;c<N;c++){
+ let run=1;
+ for(let r=1;r<=N;r++){
+ if(r<N && g[r][c]!==-1 && g[r][c]===g[r-1][c]) run++;
+ else { if(run>=3) for(let k=r-run;k<r;k++) set.add(k+','+c); run=1; }
+ }
+ }
+ return set;
+ }
+ function findMatches(){ return findMatchesIn(typeGridFromGrid()); }
+
+ function collapse(){
+ for(let c=0;c<N;c++){
+ const kept = [];
+ for(let r=N-1;r>=0;r--){ if(grid[r][c]!=null) kept.push(grid[r][c]); }
+ let i = 0, above = 1;
+ for(let r=N-1;r>=0;r--){
+ if(i < kept.length){ grid[r][c] = kept[i++]; }
+ else {
+ const id = createTile(randType());
+ placeNow(id, -(above++), c); // spawn above, will fall on next layout()
+ grid[r][c] = id;
+ }
+ }
+ }
+ }
+
+ async function resolve(){
+ busy = true;
+ let combo = 0;
+ let matched = findMatches();
+ while(matched.size){
+ combo++;
+ score += matched.size * 10 * combo;
+ matched.forEach(k=>{
+ const [r,c] = k.split(',').map(Number);
+ const id = grid[r][c];
+ if(id!=null) tiles[id].el.classList.add('clearing');
+ });
+ updateHUD();
+ await sleep(440);
+ matched.forEach(k=>{
+ const [r,c] = k.split(',').map(Number);
+ const id = grid[r][c];
+ if(id!=null){ tiles[id].el.remove(); delete tiles[id]; grid[r][c]=null; }
+ });
+ collapse();
+ layout(false);
+ await sleep(360);
+ matched = findMatches();
+ }
+ ensurePlayable();
+ busy = false;
+ }
+
+ // ——— interaction ———
+ function tileIdFromEvent(e){
+ const el = e.target.closest('.tile');
+ if(!el) return null;
+ return parseInt(el.dataset.id, 10);
+ }
+
+ function select(id){
+ if(busy || id==null || !tiles[id]) return;
+ if(selected == null){
+ selected = id; tiles[id].el.classList.add('sel'); return;
+ }
+ if(selected === id){
+ tiles[id].el.classList.remove('sel'); selected = null; return;
+ }
+ const a = tiles[selected], b = tiles[id];
+ const adjacent = Math.abs(a.r-b.r) + Math.abs(a.c-b.c) === 1;
+ if(adjacent){
+ const prev = selected;
+ tiles[prev].el.classList.remove('sel');
+ selected = null;
+ attemptSwap(prev, id);
+ } else {
+ tiles[selected].el.classList.remove('sel');
+ selected = id; tiles[id].el.classList.add('sel');
+ }
+ }
+
+ async function attemptSwap(a, b){
+ busy = true;
+ const ta = tiles[a], tb = tiles[b];
+ const ar=ta.r, ac=ta.c, br=tb.r, bc=tb.c;
+ grid[ar][ac] = b; grid[br][bc] = a;
+ ta.r=br; ta.c=bc; tb.r=ar; tb.c=ac;
+ layout(false);
+ await sleep(340);
+
+ if(findMatches().size === 0){
+ // no match — revert
+ grid[ar][ac] = a; grid[br][bc] = b;
+ ta.r=ar; ta.c=ac; tb.r=br; tb.c=bc;
+ layout(false);
+ await sleep(340);
+ busy = false;
+ } else {
+ moves++; updateHUD();
+ await resolve();
+ }
+ }
+
+ board.addEventListener('click', e=>{
+ const id = tileIdFromEvent(e);
+ if(id!=null) select(id);
+ });
+
+ // ——— setup / helpers ———
+ function updateHUD(){ scoreEl.textContent = score; movesEl.textContent = moves; }
+
+ function buildBoard(){
+ // clear
+ board.innerHTML = '';
+ tiles = {}; grid = [];
+ selected = null; nextId = 1;
+ for(let r=0;r<N;r++){
+ grid[r]=[];
+ for(let c=0;c<N;c++){
+ let type;
+ do { type = randType(); }
+ while(
+ (c>=2 && tiles[grid[r][c-1]].type===type && tiles[grid[r][c-2]].type===type) ||
+ (r>=2 && tiles[grid[r-1][c]].type===type && tiles[grid[r-2][c]].type===type)
+ );
+ const id = createTile(type);
+ grid[r][c] = id;
+ }
+ }
+ layout(true);
+ ensurePlayable();
+ }
+
+ function hasMoves(){
+ const g = typeGridFromGrid();
+ const trySwap = (r1,c1,r2,c2)=>{
+ const t=g[r1][c1]; g[r1][c1]=g[r2][c2]; g[r2][c2]=t;
+ const ok = findMatchesIn(g).size>0;
+ const t2=g[r1][c1]; g[r1][c1]=g[r2][c2]; g[r2][c2]=t2;
+ return ok;
+ };
+ for(let r=0;r<N;r++) for(let c=0;c<N;c++){
+ if(c<N-1 && trySwap(r,c,r,c+1)) return true;
+ if(r<N-1 && trySwap(r,c,r+1,c)) return true;
+ }
+ return false;
+ }
+
+ function ensurePlayable(){
+ let guard = 0;
+ while(!hasMoves() && guard++ < 20){
+ // reshuffle types among existing tiles until a move exists & no instant matches
+ const ids = [];
+ for(let r=0;r<N;r++) for(let c=0;c<N;c++) ids.push(grid[r][c]);
+ const types = ids.map(id=>tiles[id].type);
+ for(let i=types.length-1;i>0;i--){ const j=Math.floor(Math.random()*(i+1)); [types[i],types[j]]=[types[j],types[i]]; }
+ let k=0;
+ for(let r=0;r<N;r++) for(let c=0;c<N;c++){
+ const id=grid[r][c]; const t=types[k++];
+ tiles[id].type=t; tiles[id].el.className='tile t'+t;
+ }
+ if(findMatches().size>0) continue; // avoid pre-made matches, loop again
+ }
+ }
+
+ document.getElementById('restart').addEventListener('click', ()=>{
+ if(busy) return;
+ score = 0; moves = 0; updateHUD();
+ buildBoard();
+ });
+
+ let resizeTimer;
+ window.addEventListener('resize', ()=>{
+ clearTimeout(resizeTimer);
+ resizeTimer = setTimeout(()=>layout(true), 80);
+ });
+
+ // start
+ buildBoard();
+ updateHUD();
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/d7f4f8ca5f8d/claude-code.png b/data/artifacts/d7f4f8ca5f8d/claude-code.png
new file mode 100644
index 0000000..21e27e3
Binary files /dev/null and b/data/artifacts/d7f4f8ca5f8d/claude-code.png differ
diff --git a/data/artifacts/d7f4f8ca5f8d/gemma3-12b.html b/data/artifacts/d7f4f8ca5f8d/gemma3-12b.html
new file mode 100644
index 0000000..02d9011
--- /dev/null
+++ b/data/artifacts/d7f4f8ca5f8d/gemma3-12b.html
@@ -0,0 +1,284 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Luxe Match</title>
+ <style>
+ body {
+ font-family: sans-serif;
+ background-color: #f2e9d8; /* Muted beige */
+ margin: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100vh;
+ }
+
+ .game-container {
+ width: 360px;
+ border: 2px solid #c8b7a0; /* Soft gray */
+ padding: 20px;
+ background-color: white;
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+ }
+
+ .grid {
+ display: grid;
+ grid-template-columns: repeat(6, 50px);
+ grid-gap: 5px;
+ }
+
+ .tile {
+ width: 50px;
+ height: 50px;
+ background-color: #e7d2c1; /* Light tan */
+ border: 1px solid #ddd;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-size: 24px;
+ cursor: pointer;
+ }
+
+ .tile.matched {
+ animation: shimmer 0.5s forwards;
+ background-color: #ffeadc; /* Lighter tan */
+ }
+
+
+ @keyframes shimmer {
+ 0% { transform: scale(1); }
+ 25% { transform: scale(1.1); }
+ 75% { transform: scale(1.1); }
+ 100% { transform: scale(1); }
+ }
+
+ #controls {
+ margin-top: 20px;
+ text-align: center;
+ }
+
+ button {
+ padding: 8px 16px;
+ background-color: #d4a97f; /* Warm brown */
+ color: white;
+ border: none;
+ cursor: pointer;
+ font-size: 14px;
+ }
+
+ /* Wallpaper patterns (CSS drawn) - Example, can be expanded greatly*/
+ .tile.pattern-damask { background-image: url("data:image/svg+xml,%3Csvg width='50' height='50' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23c8b7a0' stroke='%23ddd' stroke-width='1'%3E%3Crect x='5' y='5' width='40' height='40'/%3E%3Crect x='15' y='15' width='20' height='20'/%3E%3Crect x='25' y='25' width='20' height='20'/%3E%3C/g%3E%3C/svg%3E"); }
+ .tile.pattern-floral { background-image: url("data:image/svg+xml,%3Csvg width='50' height='50' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23c8b7a0' stroke='%23ddd' stroke-width='1'%3E%3Ccircle cx='25' cy='25' r='15'/%3E%3C/g%3E%3C/svg%3E"); }
+ .tile.pattern-geometric { background-image: url("data:image/svg+xml,%3Csvg width='50' height='50' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23c8b7a0' stroke='%23ddd' stroke-width='1'%3E%3Crect x='10' y='10' width='30' height='30'/%3E%3Crect x='20' y='20' width='10' height='10'/%3E%3C/g%3E%3C/svg%3E"); }
+
+ </style>
+</head>
+<body>
+
+ <div class="game-container">
+ <h2>Luxe Match</h2>
+ <div id="grid" class="grid"></div>
+ <div id="controls">
+ <p>Moves: <span id="move-count">0</span></p>
+ <button id="restart-button">Restart</button>
+ </div>
+ </div>
+
+ <script>
+ const gridElement = document.getElementById('grid');
+ const moveCountSpan = document.getElementById('move-count');
+ const restartButton = document.getElementById('restart-button');
+
+ const gridSize = 6;
+ let grid = [];
+ let moves = 0;
+
+ const patterns = ["pattern-damask", "pattern-floral", "pattern-geometric"];
+
+
+ function createGrid() {
+ grid = [];
+ for (let i = 0; i < gridSize; i++) {
+ grid[i] = [];
+ for (let j = 0; j < gridSize; j++) {
+ const patternIndex = Math.floor(Math.random() * patterns.length);
+ grid[i][j] = patternIndex;
+ }
+ }
+ }
+
+ function renderGrid() {
+ gridElement.innerHTML = '';
+ for (let i = 0; i < gridSize; i++) {
+ for (let j = 0; j < gridSize; j++) {
+ const tile = document.createElement('div');
+ tile.classList.add('tile', patterns[grid[i][j]]); // Add pattern class
+ tile.dataset.row = i;
+ tile.dataset.col = j;
+ tile.addEventListener('click', tileClickHandler);
+ gridElement.appendChild(tile);
+ }
+ }
+ }
+
+ function tileClickHandler(event) {
+ const row = parseInt(event.target.dataset.row);
+ const col = parseInt(event.target.dataset.col);
+ swapTiles(row, col, null); // Initially, no second tile selected
+ }
+
+
+ let firstTileClicked = null;
+
+ function swapTiles(row1, col1, row2, col2) {
+ if (firstTileClicked === null) {
+ firstTileClicked = { row: row1, col: col1 };
+ return;
+ }
+
+ const secondTile = { row: row1, col: col1 };
+
+ // Check if adjacent to the first tile. Not Diagonal
+ if (Math.abs(firstTileClicked.row - secondTile.row) + Math.abs(firstTileClicked.col - secondTile.col) !== 1) {
+ return;
+ }
+
+
+ moves++;
+ moveCountSpan.textContent = moves;
+
+ // Swap the tiles in the grid array
+ const temp = grid[firstTileClicked.row][firstTileClicked.col];
+ grid[firstTileClicked.row][firstTileClicked.col] = grid[secondTile.row][secondTile.col];
+ grid[secondTile.row][secondTile.col] = temp;
+
+ renderGrid(); // Re-render the entire grid after swapping
+
+
+ if (checkForMatches()) {
+ clearMatchedTiles();
+ } else {
+ // Swap back if no match found
+ const temp2 = grid[firstTileClicked.row][firstTileClicked.col];
+ grid[firstTileClicked.row][firstTileClicked.col] = grid[secondTile.row][secondTile.col];
+ grid[secondTile.row][secondTile.col] = temp2;
+ renderGrid();
+
+ }
+
+
+ firstTileClicked = null; // Reset for next click
+ }
+
+ function checkForMatches() {
+ let hasMatch = false;
+
+ // Check horizontal matches
+ for (let i = 0; i < gridSize; i++) {
+ for (let j = 0; j < gridSize - 2; j++) {
+ if (grid[i][j] === grid[i][j + 1] && grid[i][j] === grid[i][j + 2]) {
+ hasMatch = true;
+ break;
+ }
+ }
+ if(hasMatch) break;
+ }
+
+ // Check vertical matches
+ if(!hasMatch){
+ for (let j = 0; j < gridSize; j++) {
+ for (let i = 0; i < gridSize - 2; i++) {
+ if (grid[i][j] === grid[i + 1][j] && grid[i][j] === grid[i + 2][j]) {
+ hasMatch = true;
+ break;
+ }
+ }
+ if(hasMatch) break;
+ }
+ }
+
+ return hasMatch;
+
+ }
+
+ function clearMatchedTiles() {
+ let matchedTiles = [];
+
+ // Find horizontal matches
+ for (let i = 0; i < gridSize; i++) {
+ for (let j = 0; j < gridSize - 2; j++) {
+ if (grid[i][j] === grid[i][j + 1] && grid[i][j] === grid[i][j + 2]) {
+ matchedTiles.push({ row: i, col: j });
+ matchedTiles.push({ row: i, col: j + 1 });
+ matchedTiles.push({ row: i, col: j + 2 });
+ }
+ }
+ }
+
+ // Find vertical matches
+ for (let j = 0; j < gridSize; j++) {
+ for (let i = 0; i < gridSize - 2; i++) {
+ if (grid[i][j] === grid[i + 1][j] && grid[i][j] === grid[i + 2][j]) {
+ matchedTiles.push({ row: i, col: j });
+ matchedTiles.push({ row: i + 1, col: j });
+ matchedTiles.push({ row: i + 2, col: j });
+ }
+ }
+ }
+
+ // Remove duplicates from matched tiles (important for correct clearing)
+ matchedTiles = [...new Set(matchedTiles)];
+
+
+ for (const tile of matchedTiles) {
+ grid[tile.row][tile.col] = -1; // Mark as cleared
+
+ const gridTileElement = document.querySelector(`.tile[data-row="${tile.row}"][data-col="${tile.col}"]`);
+ if(gridTileElement){
+ gridTileElement.classList.add('matched');
+ }
+ }
+
+ setTimeout(() => {
+ // Shift Tiles Down or Left
+ for (let i = 0; i < gridSize; i++) {
+ for (let j = 0; j < gridSize; j++) {
+ if(grid[i][j] === -1){
+ // Shift down
+ let k = i;
+ while(k > 0 && grid[k-1][j] !== -1 ){
+ grid[k][j] = grid[k-1][j];
+ k--;
+ }
+
+ if(k === 0){
+ const patternIndex = Math.floor(Math.random() * patterns.length);
+ grid[k][j] = patternIndex;
+ }
+
+
+ }
+ }
+ }
+
+ renderGrid(); // Re-render the entire grid after clearing and shifting
+ }, 500); // Delay to allow shimmer animation to complete before shifting
+ }
+
+
+
+ restartButton.addEventListener('click', () => {
+ createGrid();
+ moves = 0;
+ moveCountSpan.textContent = moves;
+ renderGrid();
+ });
+
+ createGrid();
+ renderGrid();
+ </script>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/d7f4f8ca5f8d/gemma3-12b.png b/data/artifacts/d7f4f8ca5f8d/gemma3-12b.png
new file mode 100644
index 0000000..7e8a036
Binary files /dev/null and b/data/artifacts/d7f4f8ca5f8d/gemma3-12b.png differ
diff --git a/data/artifacts/d7f4f8ca5f8d/gpt.html b/data/artifacts/d7f4f8ca5f8d/gpt.html
new file mode 100644
index 0000000..ea50b54
--- /dev/null
+++ b/data/artifacts/d7f4f8ca5f8d/gpt.html
@@ -0,0 +1,613 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="utf-8" />
+<title>Luxury Wallpaper Match</title>
+<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+<style>
+:root{
+ --bg:#151519;
+ --panel:#202028;
+ --panel-soft:#252632;
+ --accent:#d7c6a1;
+ --accent-soft:#bfae8b;
+ --text:#f3f0ea;
+ --text-soft:#ccc6ba;
+ --grid-gap:6px;
+ --tile-size:64px;
+ --border-radius:10px;
+ --shadow-soft:0 18px 40px rgba(0,0,0,0.55);
+}
+*{box-sizing:border-box;margin:0;padding:0;}
+html,body{
+ height:100%;
+ background:radial-gradient(circle at top, #262635 0%, #121019 55%, #05040a 100%);
+ color:var(--text);
+ font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
+}
+body{
+ display:flex;
+ align-items:center;
+ justify-content:center;
+}
+.app-wrap{
+ background:radial-gradient(circle at top left, #303045 0, #1a1a24 45%, #111016 100%);
+ padding:20px 22px 22px;
+ border-radius:18px;
+ box-shadow:var(--shadow-soft);
+ border:1px solid rgba(255,255,255,0.06);
+ max-width:460px;
+ width:100%;
+}
+.header{
+ display:flex;
+ justify-content:space-between;
+ align-items:center;
+ margin-bottom:12px;
+}
+.title-block{
+ display:flex;
+ flex-direction:column;
+ gap:2px;
+}
+.title{
+ font-size:20px;
+ letter-spacing:.06em;
+ text-transform:uppercase;
+}
+.subtitle{
+ font-size:11px;
+ letter-spacing:.16em;
+ text-transform:uppercase;
+ color:var(--text-soft);
+}
+.controls{
+ display:flex;
+ align-items:center;
+ gap:10px;
+}
+.info-pill{
+ background:linear-gradient(135deg,#29293a,#202029);
+ border-radius:999px;
+ padding:6px 10px;
+ font-size:11px;
+ display:flex;
+ align-items:center;
+ gap:6px;
+ border:1px solid rgba(255,255,255,0.08);
+}
+.info-label{
+ text-transform:uppercase;
+ letter-spacing:.12em;
+ color:var(--text-soft);
+ font-size:10px;
+}
+.info-val{
+ font-variant-numeric:tabular-nums;
+ color:var(--accent);
+}
+button{
+ border:none;
+ cursor:pointer;
+ background:linear-gradient(135deg,#d7c6a1,#b49b6c);
+ color:#1d1408;
+ font-size:11px;
+ padding:6px 12px;
+ border-radius:999px;
+ text-transform:uppercase;
+ letter-spacing:.16em;
+ font-weight:600;
+ box-shadow:0 0 0 1px rgba(0,0,0,.4),0 7px 18px rgba(0,0,0,.55);
+ transition:transform .1s ease, box-shadow .1s ease, filter .15s ease;
+}
+button:active{
+ transform:translateY(1px) scale(.98);
+ box-shadow:0 4px 10px rgba(0,0,0,.6);
+ filter:brightness(.96);
+}
+.status-row{
+ display:flex;
+ justify-content:space-between;
+ margin-bottom:10px;
+ font-size:11px;
+ color:var(--text-soft);
+}
+.status-row span strong{color:var(--accent-soft);}
+.board-wrap{
+ background:radial-gradient(circle at top, #2b2b3c 0, #171720 40%, #0e0d13 100%);
+ border-radius:16px;
+ padding:14px;
+ border:1px solid rgba(255,255,255,0.08);
+ box-shadow:inset 0 0 0 1px rgba(0,0,0,0.5);
+ position:relative;
+}
+.grid{
+ display:grid;
+ grid-template-columns:repeat(6,var(--tile-size));
+ grid-template-rows:repeat(6,var(--tile-size));
+ gap:var(--grid-gap);
+ touch-action:none;
+}
+.tile{
+ position:relative;
+ width:var(--tile-size);
+ height:var(--tile-size);
+ border-radius:12px;
+ overflow:hidden;
+ cursor:pointer;
+ transform-origin:center;
+ box-shadow:0 5px 15px rgba(0,0,0,0.7);
+ transition:transform .15s ease, box-shadow .15s ease, filter .15s ease;
+}
+.tile::before,
+.tile::after{
+ content:"";
+ position:absolute;
+ inset:0;
+}
+.tile-base{
+ position:absolute;
+ inset:0;
+ border-radius:inherit;
+}
+.tile.selected{
+ transform:translateY(-2px) scale(1.03);
+ box-shadow:0 10px 22px rgba(0,0,0,0.8);
+}
+.tile.hint{
+ animation:hintPulse 1.1s ease-in-out 0s 2;
+}
+@keyframes hintPulse{
+ 0%,100%{transform:scale(1);}
+ 50%{transform:scale(1.05);}
+}
+.tile.matched{
+ animation:shimmer .6s ease-out forwards;
+ pointer-events:none;
+}
+@keyframes shimmer{
+ 0%{
+ transform:scale(1);
+ box-shadow:0 6px 16px rgba(0,0,0,0.8);
+ }
+ 40%{
+ filter:brightness(1.8);
+ box-shadow:0 0 26px rgba(255,255,255,0.6);
+ }
+ 100%{
+ opacity:0;
+ transform:scale(0.5);
+ filter:brightness(.7);
+ box-shadow:none;
+ }
+}
+.overlay-shine{
+ position:absolute;
+ inset:-20%;
+ background:conic-gradient(from 220deg,rgba(255,255,255,0.35),transparent 20%,transparent 60%,rgba(0,0,0,0.35));
+ mix-blend-mode:soft-light;
+ opacity:.35;
+ pointer-events:none;
+}
+.tile.gentle-glow{
+ animation:gentleGlow 4s ease-in-out infinite;
+}
+@keyframes gentleGlow{
+ 0%,100%{box-shadow:0 5px 15px rgba(0,0,0,0.7);}
+ 50%{box-shadow:0 7px 22px rgba(0,0,0,0.85);}
+}
+/* Palette & wallpaper patterns */
+.tile[data-type="0"] .tile-base{
+ background:
+ radial-gradient(circle at 12% 18%,rgba(255,255,255,0.22) 0,transparent 40%),
+ repeating-radial-gradient(circle at 50% 40%,rgba(255,255,255,0.13) 0,rgba(255,255,255,0.13) 2px,transparent 2px,transparent 6px),
+ linear-gradient(135deg,#4d4254,#31253a);
+}
+.tile[data-type="1"] .tile-base{
+ background:
+ radial-gradient(circle at 20% 15%,rgba(255,255,255,0.24) 0,transparent 36%),
+ repeating-linear-gradient(45deg,rgba(255,255,255,0.10) 0,rgba(255,255,255,0.10) 2px,transparent 2px,transparent 8px),
+ linear-gradient(135deg,#465458,#27333a);
+}
+.tile[data-type="2"] .tile-base{
+ background:
+ radial-gradient(circle at 78% 20%,rgba(255,255,255,0.22) 0,transparent 36%),
+ repeating-linear-gradient(135deg,rgba(255,255,255,0.14) 0,rgba(255,255,255,0.14) 1px,transparent 1px,transparent 7px),
+ linear-gradient(135deg,#59513f,#3a3225);
+}
+.tile[data-type="3"] .tile-base{
+ background:
+ radial-gradient(circle at 20% 80%,rgba(255,255,255,0.18) 0,transparent 40%),
+ repeating-radial-gradient(circle at 20% 25%,rgba(255,255,255,0.16) 0,rgba(255,255,255,0.16) 1.5px,transparent 1.5px,transparent 6px),
+ linear-gradient(135deg,#455662,#293540);
+}
+.tile[data-type="4"] .tile-base{
+ background:
+ radial-gradient(circle at 10% 10%,rgba(255,255,255,0.29) 0,transparent 36%),
+ repeating-linear-gradient(90deg,rgba(255,255,255,0.12) 0,rgba(255,255,255,0.12) 1px,transparent 1px,transparent 6px),
+ linear-gradient(135deg,#584952,#362633);
+}
+.tile[data-type="5"] .tile-base{
+ background:
+ radial-gradient(circle at 80% 82%,rgba(255,255,255,0.2) 0,transparent 40%),
+ repeating-linear-gradient(45deg,rgba(255,255,255,0.11) 0,rgba(255,255,255,0.11) 1px,transparent 1px,transparent 5px),
+ linear-gradient(135deg,#535049,#302f2b);
+}
+/* Damask / floral / geometric overlay patterns */
+.tile[data-type="0"]::before{
+ background-image:
+ radial-gradient(circle at 50% 25%,rgba(255,255,255,0.25) 0,transparent 55%),
+ radial-gradient(circle at 25% 70%,rgba(255,255,255,0.18) 0,transparent 55%),
+ radial-gradient(circle at 75% 70%,rgba(255,255,255,0.18) 0,transparent 55%);
+ background-size:40px 40px;
+ mix-blend-mode:soft-light;
+ opacity:.4;
+}
+.tile[data-type="1"]::before{
+ background-image:
+ radial-gradient(circle,rgba(255,255,255,0.16) 2px,transparent 2px),
+ radial-gradient(circle,rgba(255,255,255,0.10) 2px,transparent 2px);
+ background-position:0 0, 10px 10px;
+ background-size:20px 20px;
+ mix-blend-mode:soft-light;
+ opacity:.55;
+}
+.tile[data-type="2"]::before{
+ background-image:
+ linear-gradient(135deg,rgba(255,255,255,0.26) 1px,transparent 1px),
+ linear-gradient(225deg,rgba(255,255,255,0.18) 1px,transparent 1px);
+ background-size:10px 10px;
+ mix-blend-mode:soft-light;
+ opacity:.6;
+}
+.tile[data-type="3"]::before{
+ background-image:
+ radial-gradient(circle at 50% 30%,rgba(255,255,255,0.22) 0,transparent 55%),
+ radial-gradient(circle at 30% 70%,rgba(255,255,255,0.17) 0,transparent 45%),
+ radial-gradient(circle at 70% 70%,rgba(255,255,255,0.17) 0,transparent 45%);
+ background-size:44px 44px;
+ mix-blend-mode:soft-light;
+ opacity:.42;
+}
+.tile[data-type="4"]::before{
+ background-image:
+ radial-gradient(circle,rgba(255,255,255,0.26) 0,rgba(255,255,255,0.26) 1px,transparent 1px),
+ radial-gradient(circle,rgba(255,255,255,0.18) 0,rgba(255,255,255,0.18) 1px,transparent 1px);
+ background-size:14px 14px;
+ background-position:0 0,7px 7px;
+ mix-blend-mode:soft-light;
+ opacity:.5;
+}
+.tile[data-type="5"]::before{
+ background-image:
+ linear-gradient(135deg,rgba(255,255,255,0.2) 0,rgba(255,255,255,0.2) 1px,transparent 1px),
+ linear-gradient(225deg,rgba(255,255,255,0.12) 0,rgba(255,255,255,0.12) 1px,transparent 1px);
+ background-size:12px 12px;
+ mix-blend-mode:soft-light;
+ opacity:.5;
+}
+/* Highlight edge / inner glow */
+.tile::after{
+ background:
+ radial-gradient(circle at 10% 0,rgba(255,255,255,0.45) 0,transparent 55%),
+ radial-gradient(circle at 90% 100%,rgba(0,0,0,0.6) 0,transparent 60%);
+ mix-blend-mode:soft-light;
+ opacity:.55;
+ pointer-events:none;
+}
+.footer-note{
+ margin-top:10px;
+ font-size:10px;
+ letter-spacing:.12em;
+ text-transform:uppercase;
+ color:var(--text-soft);
+ text-align:right;
+ opacity:.8;
+}
+.footer-note span{
+ color:var(--accent-soft);
+}
+@media (max-width:480px){
+ :root{--tile-size:52px;--grid-gap:5px;}
+ .app-wrap{max-width:92vw;padding:16px;}
+ .title{font-size:18px;}
+ .subtitle{font-size:10px;}
+ .status-row{font-size:10px;}
+}
+</style>
+</head>
+<body>
+<div class="app-wrap">
+ <div class="header">
+ <div class="title-block">
+ <div class="title">Maison Match</div>
+ <div class="subtitle">Swap luxe wallpapers into gentle harmony</div>
+ </div>
+ <div class="controls">
+ <div class="info-pill">
+ <span class="info-label">Score</span>
+ <span class="info-val" id="score">0</span>
+ </div>
+ <div class="info-pill">
+ <span class="info-label">Moves</span>
+ <span class="info-val" id="moves">0</span>
+ </div>
+ <button id="restartBtn">Restart</button>
+ </div>
+ </div>
+ <div class="status-row">
+ <span>Line up <strong>3 or more</strong> matching swatches.</span>
+ <span>Swap <strong>adjacent</strong> tiles only.</span>
+ </div>
+ <div class="board-wrap">
+ <div id="grid" class="grid" aria-label="Wallpaper matching board"></div>
+ <div class="overlay-shine"></div>
+ </div>
+ <div class="footer-note">
+ <span>Tip</span> — Pause, breathe, and move with intention.
+ </div>
+</div>
+<script>
+(function(){
+ const size = 6;
+ const types = 6;
+ const gridEl = document.getElementById('grid');
+ const scoreEl = document.getElementById('score');
+ const movesEl = document.getElementById('moves');
+ const restartBtn = document.getElementById('restartBtn');
+
+ let board = [];
+ let selected = null;
+ let animating = false;
+ let score = 0;
+ let moves = 0;
+
+ function idx(r,c){return r*size+c;}
+
+ function randomType(){
+ return Math.floor(Math.random()*types);
+ }
+
+ function createEmptyBoard(){
+ board = new Array(size*size).fill(0);
+ }
+
+ function hasMatchAt(r,c,arr){
+ const t = arr[idx(r,c)];
+ if(t==null) return false;
+ let count=1;
+ for(let x=c-1;x>=0 && arr[idx(r,x)]===t;x--) count++;
+ for(let x=c+1;x<size && arr[idx(r,x)]===t;x++) count++;
+ if(count>=3) return true;
+ count=1;
+ for(let y=r-1;y>=0 && arr[idx(y,c)]===t;y--) count++;
+ for(let y=r+1;y<size && arr[idx(y,c)]===t;y++) count++;
+ return count>=3;
+ }
+
+ function generateBoard(){
+ createEmptyBoard();
+ for(let r=0;r<size;r++){
+ for(let c=0;c<size;c++){
+ let t;
+ do{
+ t=randomType();
+ board[idx(r,c)]=t;
+ }while(hasMatchAt(r,c,board));
+ }
+ }
+ }
+
+ function renderBoard(){
+ gridEl.innerHTML='';
+ for(let i=0;i<board.length;i++){
+ const tile=document.createElement('div');
+ tile.className='tile gentle-glow';
+ tile.dataset.index=i;
+ tile.dataset.type=board[i];
+ gridEl.appendChild(tile);
+ }
+ }
+
+ function updateScore(delta){
+ score+=delta;
+ scoreEl.textContent=score;
+ }
+ function updateMoves(){
+ moves++;
+ movesEl.textContent=moves;
+ }
+
+ function getRC(index){
+ return {r:Math.floor(index/size), c:index%size};
+ }
+
+ function areAdjacent(a,b){
+ const A=getRC(a), B=getRC(b);
+ return (Math.abs(A.r-B.r)+Math.abs(A.c-B.c))===1;
+ }
+
+ function findMatches(arr){
+ const matches = new Set();
+ // rows
+ for(let r=0;r<size;r++){
+ let run=[0];
+ for(let c=1;c<=size;c++){
+ const prevIdx=idx(r,c-1);
+ const curIdx=c<size?idx(r,c):-1;
+ if(c<size && arr[prevIdx]!=null && arr[prevIdx]===arr[curIdx]){
+ run.push(c);
+ }else{
+ if(run.length>=3){
+ for(const col of run) matches.add(idx(r,col));
+ }
+ run=[c];
+ }
+ }
+ }
+ // cols
+ for(let c=0;c<size;c++){
+ let run=[0];
+ for(let r=1;r<=size;r++){
+ const prevIdx=idx(r-1,c);
+ const curIdx=r<size?idx(r,c):-1;
+ if(r<size && arr[prevIdx]!=null && arr[prevIdx]===arr[curIdx]){
+ run.push(r);
+ }else{
+ if(run.length>=3){
+ for(const row of run) matches.add(idx(row,c));
+ }
+ run=[r];
+ }
+ }
+ }
+ return matches;
+ }
+
+ function applyGravity(){
+ for(let c=0;c<size;c++){
+ let writeRow=size-1;
+ for(let r=size-1;r>=0;r--){
+ const i=idx(r,c);
+ if(board[i]!=null){
+ board[idx(writeRow,c)]=board[i];
+ if(writeRow!==r) board[i]=null;
+ writeRow--;
+ }
+ }
+ for(let r=writeRow;r>=0;r--){
+ board[idx(r,c)]=randomType();
+ }
+ }
+ }
+
+ function refreshTiles(){
+ const tiles = gridEl.children;
+ for(let i=0;i<board.length;i++){
+ const t = tiles[i];
+ t.dataset.type = board[i];
+ t.classList.remove('matched');
+ }
+ }
+
+ function resolveMatches(){
+ const tiles = gridEl.children;
+ const matches = findMatches(board);
+ if(matches.size===0){
+ animating=false;
+ return;
+ }
+ matches.forEach(i=>{
+ tiles[i].classList.add('matched');
+ board[i]=null;
+ });
+ updateScore(matches.size*10);
+ setTimeout(()=>{
+ applyGravity();
+ refreshTiles();
+ setTimeout(()=>{
+ resolveMatches();
+ },160);
+ },420);
+ }
+
+ function deselect(){
+ if(selected==null) return;
+ const t = gridEl.querySelector('.tile.selected');
+ if(t) t.classList.remove('selected');
+ selected=null;
+ }
+
+ function attemptSwap(i1,i2){
+ if(animating) return;
+ if(!areAdjacent(i1,i2)){ deselect(); return; }
+
+ const tiles = gridEl.children;
+ animating=true;
+
+ [board[i1],board[i2]] = [board[i2],board[i1]];
+ tiles[i1].dataset.type=board[i1];
+ tiles[i2].dataset.type=board[i2];
+
+ updateMoves();
+
+ const matches = findMatches(board);
+ if(matches.size===0){
+ // revert if no match
+ setTimeout(()=>{
+ [board[i1],board[i2]] = [board[i2],board[i1]];
+ tiles[i1].dataset.type=board[i1];
+ tiles[i2].dataset.type=board[i2];
+ animating=false;
+ },160);
+ }else{
+ setTimeout(()=>resolveMatches(),80);
+ }
+ deselect();
+ }
+
+ function onTileSelect(index){
+ if(animating) return;
+ const tile = gridEl.children[index];
+ if(!selected){
+ selected=index;
+ tile.classList.add('selected');
+ }else if(selected===index){
+ deselect();
+ }else{
+ const prev=selected;
+ deselect();
+ attemptSwap(prev,index);
+ }
+ }
+
+ // Mouse & touch
+ let touchStartIndex=null;
+ function eventIndexFromTarget(t){
+ const el=t.closest('.tile');
+ return el?parseInt(el.dataset.index,10):null;
+ }
+
+ gridEl.addEventListener('mousedown',e=>{
+ const idx = eventIndexFromTarget(e.target);
+ if(idx==null) return;
+ onTileSelect(idx);
+ });
+
+ gridEl.addEventListener('touchstart',e=>{
+ const t=e.changedTouches[0];
+ const target=document.elementFromPoint(t.clientX,t.clientY);
+ const i=eventIndexFromTarget(target);
+ if(i==null) return;
+ e.preventDefault();
+ touchStartIndex=i;
+ onTileSelect(i);
+ },{passive:false});
+
+ gridEl.addEventListener('touchend',e=>{
+ const t=e.changedTouches[0];
+ const endTarget=document.elementFromPoint(t.clientX,t.clientY);
+ const endIdx=eventIndexFromTarget(endTarget);
+ if(endIdx==null || touchStartIndex==null) {touchStartIndex=null;return;}
+ if(endIdx!==touchStartIndex){
+ attemptSwap(touchStartIndex,endIdx);
+ }
+ touchStartIndex=null;
+ });
+
+ restartBtn.addEventListener('click',()=>{
+ animating=false;
+ selected=null;
+ score=0;moves=0;
+ scoreEl.textContent='0';
+ movesEl.textContent='0';
+ generateBoard();
+ renderBoard();
+ });
+
+ generateBoard();
+ renderBoard();
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/d7f4f8ca5f8d/gpt.png b/data/artifacts/d7f4f8ca5f8d/gpt.png
new file mode 100644
index 0000000..32a78f2
Binary files /dev/null and b/data/artifacts/d7f4f8ca5f8d/gpt.png differ
diff --git a/data/artifacts/d7f4f8ca5f8d/grok.html b/data/artifacts/d7f4f8ca5f8d/grok.html
new file mode 100644
index 0000000..0e37795
--- /dev/null
+++ b/data/artifacts/d7f4f8ca5f8d/grok.html
@@ -0,0 +1,298 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
+<title>Luxe Match</title>
+<style>
+*{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent}
+:root{
+--bg:#1a1816;--panel:#242120;--cream:#e8e0d4;--champagne:#c4a882;
+--rose:#a67c7c;--sage:#7a8a72;--slate:#6a7a8a;--taupe:#8a7a6a;
+--gold:#b8a078;--text:#d4cdc2;--muted:#8a8278;--shimmer:#f5efe6
+}
+html,body{height:100%;overflow:hidden;font-family:Georgia,"Times New Roman",serif;background:var(--bg);color:var(--text)}
+body{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100%}
+.wrap{display:flex;flex-direction:column;align-items:center;gap:14px;padding:16px;max-width:100%}
+h1{font-weight:400;font-size:1.35rem;letter-spacing:.28em;text-transform:uppercase;color:var(--gold);text-shadow:0 1px 0 #000}
+.bar{display:flex;gap:20px;align-items:center;font-size:.85rem;letter-spacing:.12em;color:var(--muted)}
+.bar span b{color:var(--cream);font-weight:400;font-size:1.05rem}
+button{background:transparent;border:1px solid var(--gold);color:var(--gold);padding:8px 20px;font-family:inherit;font-size:.75rem;letter-spacing:.2em;text-transform:uppercase;cursor:pointer;border-radius:2px;transition:background .25s,color .25s}
+button:hover{background:var(--gold);color:var(--bg)}
+.board-wrap{position:relative;padding:10px;background:var(--panel);border:1px solid #3a3530;border-radius:4px;box-shadow:0 12px 40px rgba(0,0,0,.45),inset 0 1px 0 #3a3530}
+.board{display:grid;grid-template-columns:repeat(6,1fr);gap:5px;width:min(78vw,420px);height:min(78vw,420px);touch-action:none}
+.tile{position:relative;border-radius:3px;cursor:pointer;overflow:hidden;transition:transform .15s,box-shadow .2s;border:1px solid rgba(0,0,0,.25)}
+.tile::after{content:"";position:absolute;inset:0;background:linear-gradient(135deg,rgba(255,255,255,.12) 0%,transparent 45%,rgba(0,0,0,.08) 100%);pointer-events:none}
+.tile.selected{transform:scale(.92);box-shadow:0 0 0 2px var(--gold),0 0 16px rgba(184,160,120,.5);z-index:2}
+.tile.swap-a,.tile.swap-b{transition:transform .28s ease}
+.tile.clearing{animation:shimmer .55s ease forwards;pointer-events:none;z-index:3}
+@keyframes shimmer{
+0%{filter:brightness(1);transform:scale(1);opacity:1}
+40%{filter:brightness(1.8);box-shadow:0 0 24px var(--shimmer);transform:scale(1.06)}
+100%{filter:brightness(2.2);transform:scale(.3);opacity:0}
+}
+.tile.drop{transition:transform .32s cubic-bezier(.2,.8,.3,1)}
+/* Pattern bases */
+.p0{background-color:#2c2824}
+.p1{background-color:#3a3028}
+.p2{background-color:#2a322c}
+.p3{background-color:#2a2e36}
+.p4{background-color:#362a2a}
+.p5{background-color:#322e28}
+/* Damask — ornate cross */
+.p0{background-image:
+radial-gradient(ellipse 30% 30% at 50% 50%,var(--champagne) 0%,transparent 70%),
+radial-gradient(ellipse 12% 40% at 50% 20%,var(--gold) 0%,transparent 70%),
+radial-gradient(ellipse 12% 40% at 50% 80%,var(--gold) 0%,transparent 70%),
+radial-gradient(ellipse 40% 12% at 20% 50%,var(--gold) 0%,transparent 70%),
+radial-gradient(ellipse 40% 12% at 80% 50%,var(--gold) 0%,transparent 70%),
+radial-gradient(circle at 50% 50%,transparent 28%,rgba(196,168,130,.25) 30%,transparent 32%)}
+/* Floral — soft blooms */
+.p1{background-image:
+radial-gradient(circle at 50% 50%,var(--rose) 0 8%,transparent 9%),
+radial-gradient(circle at 50% 28%,var(--rose) 0 6%,transparent 7%),
+radial-gradient(circle at 50% 72%,var(--rose) 0 6%,transparent 7%),
+radial-gradient(circle at 28% 50%,var(--rose) 0 6%,transparent 7%),
+radial-gradient(circle at 72% 50%,var(--rose) 0 6%,transparent 7%),
+radial-gradient(circle at 35% 35%,rgba(166,124,124,.5) 0 5%,transparent 6%),
+radial-gradient(circle at 65% 35%,rgba(166,124,124,.5) 0 5%,transparent 6%),
+radial-gradient(circle at 35% 65%,rgba(166,124,124,.5) 0 5%,transparent 6%),
+radial-gradient(circle at 65% 65%,rgba(166,124,124,.5) 0 5%,transparent 6%)}
+/* Geometric diamonds */
+.p2{background-image:
+linear-gradient(45deg,transparent 42%,var(--sage) 43%,var(--sage) 57%,transparent 58%),
+linear-gradient(-45deg,transparent 42%,var(--sage) 43%,var(--sage) 57%,transparent 58%),
+linear-gradient(45deg,transparent 46%,rgba(122,138,114,.4) 47%,rgba(122,138,114,.4) 53%,transparent 54%),
+linear-gradient(-45deg,transparent 46%,rgba(122,138,114,.4) 47%,rgba(122,138,114,.4) 53%,transparent 54%)}
+/* Art deco arcs */
+.p3{background-image:
+repeating-radial-gradient(ellipse at 50% 100%,transparent 0,transparent 8%,var(--slate) 8.5%,var(--slate) 10%,transparent 10.5%),
+repeating-radial-gradient(ellipse at 50% 0%,transparent 0,transparent 8%,rgba(106,122,138,.6) 8.5%,rgba(106,122,138,.6) 10%,transparent 10.5%),
+linear-gradient(180deg,transparent 48%,var(--slate) 49%,var(--slate) 51%,transparent 52%)}
+/* Herringbone / chevron */
+.p4{background-image:
+linear-gradient(135deg,var(--taupe) 25%,transparent 25.5%),
+linear-gradient(225deg,var(--taupe) 25%,transparent 25.5%),
+linear-gradient(315deg,var(--taupe) 25%,transparent 25.5%),
+linear-gradient(45deg,var(--taupe) 25%,transparent 25.5%);
+background-size:14px 14px;background-position:0 0,7px 0,7px -7px,0 7px}
+/* Fleur lattice */
+.p5{background-image:
+radial-gradient(circle at 0 0,var(--gold) 0 2px,transparent 2.5px),
+radial-gradient(circle at 100% 0,var(--gold) 0 2px,transparent 2.5px),
+radial-gradient(circle at 0 100%,var(--gold) 0 2px,transparent 2.5px),
+radial-gradient(circle at 100% 100%,var(--gold) 0 2px,transparent 2.5px),
+radial-gradient(circle at 50% 50%,var(--champagne) 0 3px,transparent 3.5px),
+linear-gradient(0deg,transparent 49%,rgba(184,160,120,.35) 50%,transparent 51%),
+linear-gradient(90deg,transparent 49%,rgba(184,160,120,.35) 50%,transparent 51%)}
+.hint{font-size:.7rem;letter-spacing:.1em;color:var(--muted);opacity:.7;margin-top:2px}
+</style>
+</head>
+<body>
+<div class="wrap">
+<h1>Luxe Match</h1>
+<div class="bar">
+<span>Score <b id="score">0</b></span>
+<span>Moves <b id="moves">0</b></span>
+<button id="restart" type="button">Restart</button>
+</div>
+<div class="board-wrap"><div class="board" id="board"></div></div>
+<p class="hint">Tap adjacent swatches to swap · match 3+</p>
+</div>
+<script>
+(function(){
+const N=6, TYPES=6;
+const boardEl=document.getElementById('board');
+const scoreEl=document.getElementById('score');
+const movesEl=document.getElementById('moves');
+let grid=[], selected=null, locked=false, score=0, moves=0;
+
+function rnd(){return Math.floor(Math.random()*TYPES)}
+function idx(r,c){return r*N+c}
+function rc(i){return [Math.floor(i/N),i%N]}
+
+function createTile(type,i){
+ const d=document.createElement('div');
+ d.className='tile p'+type;
+ d.dataset.i=i;
+ d.dataset.type=type;
+ return d;
+}
+
+function noMatchAt(r,c,type,g){
+ if(c>=2&&g[r][c-1]===type&&g[r][c-2]===type)return false;
+ if(r>=2&&g[r-1][c]===type&&g[r-2][c]===type)return false;
+ return true;
+}
+
+function fillInitial(){
+ grid=[];
+ for(let r=0;r<N;r++){
+ grid[r]=[];
+ for(let c=0;c<N;c++){
+ let t,guard=0;
+ do{t=rnd();guard++}while(!noMatchAt(r,c,t,grid)&&guard<40);
+ grid[r][c]=t;
+ }
+ }
+}
+
+function render(){
+ boardEl.innerHTML='';
+ for(let r=0;r<N;r++)for(let c=0;c<N;c++){
+ boardEl.appendChild(createTile(grid[r][c],idx(r,c)));
+ }
+}
+
+function tileAt(i){return boardEl.children[i]}
+
+function findMatches(){
+ const m=new Set();
+ for(let r=0;r<N;r++){
+ let run=1;
+ for(let c=1;c<=N;c++){
+ if(c<N&&grid[r][c]===grid[r][c-1])run++;
+ else{if(run>=3)for(let k=c-run;k<c;k++)m.add(idx(r,k));run=1}
+ }
+ }
+ for(let c=0;c<N;c++){
+ let run=1;
+ for(let r=1;r<=N;r++){
+ if(r<N&&grid[r][c]===grid[r-1][c])run++;
+ else{if(run>=3)for(let k=r-run;k<r;k++)m.add(idx(k,c));run=1}
+ }
+ }
+ return m;
+}
+
+function adjacent(a,b){
+ const [r1,c1]=rc(a),[r2,c2]=rc(b);
+ return Math.abs(r1-r2)+Math.abs(c1-c2)===1;
+}
+
+function swapData(a,b){
+ const [r1,c1]=rc(a),[r2,c2]=rc(b);
+ const t=grid[r1][c1];grid[r1][c1]=grid[r2][c2];grid[r2][c2]=t;
+}
+
+function syncTile(i){
+ const [r,c]=rc(i);
+ const el=tileAt(i);
+ el.className='tile p'+grid[r][c];
+ el.dataset.type=grid[r][c];
+ el.dataset.i=i;
+}
+
+async function animateSwap(a,b){
+ const ea=tileAt(a),eb=tileAt(b);
+ const ra=ea.getBoundingClientRect(),rb=eb.getBoundingClientRect();
+ const dx=rb.left-ra.left,dy=rb.top-ra.top;
+ ea.style.transform=`translate(${dx}px,${dy}px)`;
+ eb.style.transform=`translate(${-dx}px,${-dy}px)`;
+ ea.classList.add('swap-a');eb.classList.add('swap-b');
+ await wait(280);
+ ea.style.transform='';eb.style.transform='';
+ ea.classList.remove('swap-a');eb.classList.remove('swap-b');
+ syncTile(a);syncTile(b);
+}
+
+function wait(ms){return new Promise(r=>setTimeout(r,ms))}
+
+async function clearAndCascade(matches){
+ const arr=[...matches];
+ score+=arr.length*10+(arr.length>3?(arr.length-3)*15:0);
+ scoreEl.textContent=score;
+ arr.forEach(i=>tileAt(i).classList.add('clearing'));
+ await wait(550);
+ arr.forEach(i=>{const[r,c]=rc(i);grid[r][c]=-1});
+
+ for(let c=0;c<N;c++){
+ let write=N-1;
+ for(let r=N-1;r>=0;r--){
+ if(grid[r][c]!==-1){
+ if(r!==write){grid[write][c]=grid[r][c];grid[r][c]=-1}
+ write--;
+ }
+ }
+ for(let r=write;r>=0;r--)grid[r][c]=rnd();
+ }
+ render();
+ await wait(40);
+ const more=findMatches();
+ if(more.size)await clearAndCascade(more);
+}
+
+async function trySwap(a,b){
+ if(locked||!adjacent(a,b))return;
+ locked=true;
+ clearSelect();
+ swapData(a,b);
+ await animateSwap(a,b);
+ const matches=findMatches();
+ if(matches.size===0){
+ swapData(a,b);
+ await animateSwap(a,b);
+ locked=false;
+ return;
+ }
+ moves++;movesEl.textContent=moves;
+ await clearAndCascade(matches);
+ locked=false;
+}
+
+function clearSelect(){
+ if(selected!==null){const el=tileAt(selected);if(el)el.classList.remove('selected')}
+ selected=null;
+}
+
+function onPick(i){
+ if(locked)return;
+ if(selected===null){
+ selected=i;tileAt(i).classList.add('selected');
+ }else if(selected===i){
+ clearSelect();
+ }else if(adjacent(selected,i)){
+ trySwap(selected,i);
+ }else{
+ clearSelect();
+ selected=i;tileAt(i).classList.add('selected');
+ }
+}
+
+boardEl.addEventListener('click',e=>{
+ const t=e.target.closest('.tile');
+ if(!t)return;
+ onPick(+t.dataset.i);
+});
+
+let touchStart=null;
+boardEl.addEventListener('touchstart',e=>{
+ const t=e.target.closest('.tile');
+ if(!t)return;
+ touchStart=+t.dataset.i;
+},{passive:true});
+boardEl.addEventListener('touchend',e=>{
+ if(touchStart===null)return;
+ const touch=e.changedTouches[0];
+ const el=document.elementFromPoint(touch.clientX,touch.clientY);
+ const t=el&&el.closest?el.closest('.tile'):null;
+ if(t){
+ const end=+t.dataset.i;
+ if(end===touchStart)onPick(end);
+ else if(adjacent(touchStart,end)){clearSelect();trySwap(touchStart,end)}
+ else onPick(end);
+ }
+ touchStart=null;
+},{passive:true});
+
+function restart(){
+ locked=false;selected=null;score=0;moves=0;
+ scoreEl.textContent='0';movesEl.textContent='0';
+ fillInitial();render();
+}
+document.getElementById('restart').addEventListener('click',restart);
+restart();
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/d7f4f8ca5f8d/grok.png b/data/artifacts/d7f4f8ca5f8d/grok.png
new file mode 100644
index 0000000..4dc5dec
Binary files /dev/null and b/data/artifacts/d7f4f8ca5f8d/grok.png differ
diff --git a/data/artifacts/d7f4f8ca5f8d/hermes3-8b.html b/data/artifacts/d7f4f8ca5f8d/hermes3-8b.html
new file mode 100644
index 0000000..7aee35b
--- /dev/null
+++ b/data/artifacts/d7f4f8ca5f8d/hermes3-8b.html
@@ -0,0 +1,110 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Luxury Tile Puzzle</title>
+ <style>
+ * {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+ }
+
+ body {
+ background-color: #f5f5f5;
+ font-family: Arial, sans-serif;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100vh;
+ }
+
+ .container {
+ text-align: center;
+ }
+
+ h1 {
+ color: #8b0000;
+ margin-bottom: 20px;
+ }
+
+ canvas {
+ border: 2px solid #8b0000;
+ display: inline-block;
+ cursor: pointer;
+ }
+
+ .info {
+ margin-top: 10px;
+ }
+
+ .score {
+ color: #8b0000;
+ font-weight: bold;
+ }
+
+ button {
+ background-color: #8b0000;
+ color: white;
+ border: none;
+ padding: 5px 15px;
+ margin-right: 10px;
+ cursor: pointer;
+ outline: none;
+ }
+ </style>
+</head>
+<body>
+ <div class="container">
+ <h1>Luxury Tile Puzzle</h1>
+ <canvas id="gameCanvas" width="300" height="300"></canvas>
+ <div class="info">
+ <span class="score">Score: </span><span id="scoreDisplay">0</span>
+ </div>
+ <button id="restartButton">Restart</button>
+ </div>
+
+ <script>
+ const canvas = document.getElementById('gameCanvas');
+ const ctx = canvas.getContext('2d');
+
+ let tiles = generateTiles();
+ let gameBoard = createGameBoard(tiles);
+ let score = 0;
+
+ drawCanvas(gameBoard, ctx);
+
+ function generateTiles() {
+ // Generate luxury wallpaper swatches
+ return [];
+ }
+
+ function createGameBoard(tiles) {
+ // Create the initial 6x6 game board
+ return [];
+ }
+
+ function drawCanvas(board, context) {
+ // Draw the current state of the game board
+ }
+
+ canvas.addEventListener('click', (event) => {
+ // Handle mouse click events to move tiles around
+ });
+
+ document.getElementById('restartButton').addEventListener('click', () => {
+ // Restart the game
+ });
+
+ function findMatches() {
+ // Find and remove matching rows
+ return score;
+ }
+
+ setInterval(() => {
+ // Update game state periodically (e.g., for matches found)
+ }, 1000);
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/d7f4f8ca5f8d/hermes3-8b.png b/data/artifacts/d7f4f8ca5f8d/hermes3-8b.png
new file mode 100644
index 0000000..5724d72
Binary files /dev/null and b/data/artifacts/d7f4f8ca5f8d/hermes3-8b.png differ
diff --git a/data/artifacts/d7f4f8ca5f8d/kimi.html b/data/artifacts/d7f4f8ca5f8d/kimi.html
new file mode 100644
index 0000000..2b196f4
--- /dev/null
+++ b/data/artifacts/d7f4f8ca5f8d/kimi.html
@@ -0,0 +1,538 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Luxe Wallpaper Match</title>
+<style>
+* {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ user-select: none;
+ -webkit-user-select: none;
+}
+
+body {
+ font-family: 'Georgia', 'Times New Roman', serif;
+ background: linear-gradient(135deg, #f5f2ed 0%, #e8e4dc 100%);
+ min-height: 100vh;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ color: #4a4a4a;
+ overflow: hidden;
+ touch-action: none;
+}
+
+.game-container {
+ background: rgba(255, 255, 255, 0.6);
+ backdrop-filter: blur(10px);
+ border-radius: 16px;
+ padding: 24px;
+ box-shadow:
+ 0 10px 40px rgba(0,0,0,0.08),
+ 0 2px 8px rgba(0,0,0,0.04),
+ inset 0 0 0 1px rgba(255,255,255,0.8);
+ max-width: 500px;
+ width: 90vw;
+}
+
+header {
+ text-align: center;
+ margin-bottom: 20px;
+}
+
+h1 {
+ font-size: 24px;
+ font-weight: 400;
+ letter-spacing: 3px;
+ color: #5c4a3a;
+ margin-bottom: 16px;
+ text-transform: uppercase;
+}
+
+.stats {
+ display: flex;
+ justify-content: space-around;
+ align-items: center;
+ gap: 20px;
+}
+
+.stat {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 4px;
+}
+
+.stat span:first-child {
+ font-size: 11px;
+ text-transform: uppercase;
+ letter-spacing: 2px;
+ color: #8a7a6a;
+}
+
+.stat span:last-child {
+ font-size: 20px;
+ color: #5c4a3a;
+ font-weight: 600;
+}
+
+button {
+ background: #5c4a3a;
+ color: #f5f2ed;
+ border: none;
+ padding: 8px 20px;
+ border-radius: 20px;
+ font-family: inherit;
+ font-size: 11px;
+ letter-spacing: 1px;
+ text-transform: uppercase;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ box-shadow: 0 2px 8px rgba(92,74,58,0.2);
+}
+
+button:hover {
+ background: #4a3a2a;
+ transform: translateY(-1px);
+ box-shadow: 0 4px 12px rgba(92,74,58,0.3);
+}
+
+.grid {
+ display: grid;
+ grid-template-columns: repeat(6, 1fr);
+ grid-template-rows: repeat(6, 1fr);
+ gap: 8px;
+ aspect-ratio: 1;
+ background: rgba(255,255,255,0.4);
+ padding: 12px;
+ border-radius: 12px;
+ box-shadow: inset 0 2px 8px rgba(0,0,0,0.05);
+}
+
+.tile {
+ position: relative;
+ border-radius: 6px;
+ cursor: pointer;
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
+ box-shadow:
+ inset 0 0 12px rgba(0,0,0,0.08),
+ 0 2px 4px rgba(0,0,0,0.1);
+ overflow: hidden;
+}
+
+.tile::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: linear-gradient(135deg, rgba(255,255,255,0.4) 0%, transparent 50%, rgba(0,0,0,0.05) 100%);
+ pointer-events: none;
+}
+
+.tile:hover {
+ transform: translateY(-2px);
+ box-shadow:
+ inset 0 0 12px rgba(0,0,0,0.08),
+ 0 4px 8px rgba(0,0,0,0.15);
+}
+
+.tile.selected {
+ box-shadow:
+ inset 0 0 12px rgba(0,0,0,0.08),
+ 0 0 0 3px #d4af37,
+ 0 4px 12px rgba(0,0,0,0.2);
+ z-index: 10;
+ transform: scale(1.05);
+}
+
+/* Pattern 0: Damask Gold */
+.pattern-0 {
+ background-color: #f4e8d0;
+ background-image:
+ radial-gradient(circle at 50% 50%, rgba(184, 134, 11, 0.25) 0%, transparent 50%),
+ radial-gradient(circle at 0% 0%, rgba(184, 134, 11, 0.2) 0%, transparent 40%),
+ radial-gradient(circle at 100% 0%, rgba(184, 134, 11, 0.2) 0%, transparent 40%),
+ radial-gradient(circle at 0% 100%, rgba(184, 134, 11, 0.2) 0%, transparent 40%),
+ radial-gradient(circle at 100% 100%, rgba(184, 134, 11, 0.2) 0%, transparent 40%);
+ border: 1px solid #e6d5b8;
+}
+
+/* Pattern 1: Floral Rose */
+.pattern-1 {
+ background-color: #e8d5d5;
+ background-image:
+ radial-gradient(circle at 30% 30%, rgba(188, 143, 143, 0.7) 0%, transparent 35%),
+ radial-gradient(circle at 70% 30%, rgba(188, 143, 143, 0.7) 0%, transparent 35%),
+ radial-gradient(circle at 50% 70%, rgba(180, 130, 130, 0.6) 0%, transparent 45%),
+ radial-gradient(circle at 50% 50%, rgba(160, 110, 110, 0.3) 0%, transparent 70%);
+ border: 1px solid #d4b8b8;
+}
+
+/* Pattern 2: Geometric Navy */
+.pattern-2 {
+ background-color: #3d4550;
+ background-image:
+ linear-gradient(45deg, transparent 45%, rgba(255,255,255,0.15) 45%, rgba(255,255,255,0.15) 55%, transparent 55%),
+ linear-gradient(-45deg, transparent 45%, rgba(255,255,255,0.15) 45%, rgba(255,255,255,0.15) 55%, transparent 55%);
+ background-size: 14px 14px;
+ border: 1px solid #2d3748;
+}
+
+/* Pattern 3: Lattice Sage */
+.pattern-3 {
+ background-color: #c5d5c0;
+ background-image:
+ linear-gradient(90deg, transparent 46%, rgba(255,255,255,0.5) 46%, rgba(255,255,255,0.5) 54%, transparent 54%),
+ linear-gradient(0deg, transparent 46%, rgba(255,255,255,0.5) 46%, rgba(255,255,255,0.5) 54%, transparent 54%),
+ linear-gradient(90deg, transparent 20%, rgba(154, 170, 144, 0.3) 20%, rgba(154, 170, 144, 0.3) 25%, transparent 25%),
+ linear-gradient(0deg, transparent 20%, rgba(154, 170, 144, 0.3) 20%, rgba(154, 170, 144, 0.3) 25%, transparent 25%);
+ border: 1px solid #b0c4a8;
+}
+
+/* Pattern 4: Pinstripe Burgundy */
+.pattern-4 {
+ background-color: #722f37;
+ background-image:
+ repeating-linear-gradient(90deg, transparent, transparent 6px, rgba(255,255,255,0.12) 6px, rgba(255,255,255,0.12) 12px),
+ radial-gradient(ellipse at 50% 50%, rgba(255,255,255,0.1) 0%, transparent 70%);
+ border: 1px solid #5c2028;
+}
+
+/* Pattern 5: Medallion Teal */
+.pattern-5 {
+ background-color: #4a7c7e;
+ background-image:
+ radial-gradient(circle at 50% 50%, rgba(255,255,255,0.25) 0%, transparent 25%),
+ radial-gradient(circle at 50% 50%, rgba(255,255,255,0.15) 30%, transparent 60%),
+ conic-gradient(from 0deg, transparent 0deg, rgba(255,255,255,0.15) 30deg, transparent 60deg, transparent 120deg, rgba(255,255,255,0.15) 150deg, transparent 180deg, transparent 240deg, rgba(255,255,255,0.15) 270deg, transparent 300deg, transparent 360deg);
+ border: 1px solid #3a6364;
+}
+
+@keyframes shimmer {
+ 0% {
+ filter: brightness(1) opacity(1);
+ transform: scale(1) rotate(0deg);
+ }
+ 25% {
+ filter: brightness(2) opacity(0.9);
+ background-color: #ffd700;
+ transform: scale(1.1) rotate(2deg);
+ }
+ 50% {
+ filter: brightness(2.5) opacity(0.8);
+ background-color: #ffed4e;
+ transform: scale(1.2) rotate(-2deg);
+ }
+ 75% {
+ filter: brightness(2) opacity(0.9);
+ background-color: #ffd700;
+ transform: scale(1.1) rotate(1deg);
+ }
+ 100% {
+ filter: brightness(1) opacity(0);
+ transform: scale(0) rotate(0deg);
+ }
+}
+
+.clearing {
+ animation: shimmer 0.6s ease-in-out forwards;
+ z-index: 20;
+ pointer-events: none;
+}
+
+@media (max-width: 500px) {
+ .game-container {
+ padding: 16px;
+ }
+ h1 {
+ font-size: 20px;
+ }
+ .grid {
+ gap: 6px;
+ padding: 8px;
+ }
+}
+</style>
+</head>
+<body>
+<div class="game-container">
+ <header>
+ <h1>Luxe Match</h1>
+ <div class="stats">
+ <div class="stat">
+ <span>Score</span>
+ <span id="score">0</span>
+ </div>
+ <button onclick="game.restart()">Restart</button>
+ <div class="stat">
+ <span>Moves</span>
+ <span id="moves">0</span>
+ </div>
+ </div>
+ </header>
+ <div class="grid" id="grid"></div>
+</div>
+
+<script>
+class Game {
+ constructor() {
+ this.size = 6;
+ this.types = 6;
+ this.grid = [];
+ this.score = 0;
+ this.moves = 0;
+ this.selected = null;
+ this.busy = false;
+ this.touchStartX = 0;
+ this.touchStartY = 0;
+ this.init();
+ this.setupTouch();
+ }
+
+ init() {
+ this.grid = [];
+ for (let r = 0; r < this.size; r++) {
+ this.grid[r] = [];
+ for (let c = 0; c < this.size; c++) {
+ this.grid[r][c] = this.randomType();
+ }
+ }
+
+ while (this.findMatches().length > 0) {
+ const matches = this.findMatches();
+ matches.forEach(m => {
+ this.grid[m.r][m.c] = this.randomType();
+ });
+ }
+
+ this.render();
+ this.updateStats();
+ }
+
+ randomType() {
+ return Math.floor(Math.random() * this.types);
+ }
+
+ findMatches() {
+ const matches = [];
+ const seen = new Set();
+
+ for (let r = 0; r < this.size; r++) {
+ for (let c = 0; c < this.size - 2; c++) {
+ const type = this.grid[r][c];
+ if (type === -1) continue;
+ let count = 1;
+ while (c + count < this.size && this.grid[r][c + count] === type) {
+ count++;
+ }
+ if (count >= 3) {
+ for (let i = 0; i < count; i++) {
+ const key = `${r},${c + i}`;
+ if (!seen.has(key)) {
+ seen.add(key);
+ matches.push({r, c: c + i});
+ }
+ }
+ }
+ c += count - 1;
+ }
+ }
+
+ for (let c = 0; c < this.size; c++) {
+ for (let r = 0; r < this.size - 2; r++) {
+ const type = this.grid[r][c];
+ if (type === -1) continue;
+ let count = 1;
+ while (r + count < this.size && this.grid[r + count][c] === type) {
+ count++;
+ }
+ if (count >= 3) {
+ for (let i = 0; i < count; i++) {
+ const key = `${r + i},${c}`;
+ if (!seen.has(key)) {
+ seen.add(key);
+ matches.push({r: r + i, c});
+ }
+ }
+ }
+ r += count - 1;
+ }
+ }
+
+ return matches;
+ }
+
+ async handleMatches() {
+ if (this.busy) return;
+ const matches = this.findMatches();
+ if (matches.length === 0) {
+ this.busy = false;
+ return;
+ }
+
+ this.busy = true;
+ this.score += matches.length * 10;
+ this.updateStats();
+
+ const cells = document.querySelectorAll('.tile');
+ matches.forEach(m => {
+ const index = m.r * this.size + m.c;
+ if (cells[index]) {
+ cells[index].classList.add('clearing');
+ }
+ });
+
+ await new Promise(resolve => setTimeout(resolve, 600));
+
+ matches.forEach(m => {
+ this.grid[m.r][m.c] = -1;
+ });
+
+ this.applyGravity();
+ this.fillEmpty();
+ this.render();
+
+ setTimeout(() => this.handleMatches(), 100);
+ }
+
+ applyGravity() {
+ for (let c = 0; c < this.size; c++) {
+ let writeRow = this.size - 1;
+ for (let r = this.size - 1; r >= 0; r--) {
+ if (this.grid[r][c] !== -1) {
+ this.grid[writeRow][c] = this.grid[r][c];
+ if (writeRow !== r) {
+ this.grid[r][c] = -1;
+ }
+ writeRow--;
+ }
+ }
+ }
+ }
+
+ fillEmpty() {
+ for (let r = 0; r < this.size; r++) {
+ for (let c = 0; c < this.size; c++) {
+ if (this.grid[r][c] === -1) {
+ this.grid[r][c] = this.randomType();
+ }
+ }
+ }
+ }
+
+ swap(r1, c1, r2, c2) {
+ if (this.busy) return;
+
+ const temp = this.grid[r1][c1];
+ this.grid[r1][c1] = this.grid[r2][c2];
+ this.grid[r2][c2] = temp;
+
+ this.moves++;
+ this.updateStats();
+ this.render();
+
+ const hasMatches = this.findMatches().length > 0;
+
+ if (!hasMatches) {
+ setTimeout(() => {
+ const temp = this.grid[r1][c1];
+ this.grid[r1][c1] = this.grid[r2][c2];
+ this.grid[r2][c2] = temp;
+ this.render();
+ this.busy = false;
+ }, 300);
+ } else {
+ this.handleMatches();
+ }
+ }
+
+ handleClick(r, c) {
+ if (this.busy) return;
+
+ if (!this.selected) {
+ this.selected = {r, c};
+ this.render();
+ } else {
+ const {r: r1, c: c1} = this.selected;
+ const dist = Math.abs(r - r1) + Math.abs(c - c1);
+
+ if (dist === 1) {
+ this.selected = null;
+ this.swap(r1, c1, r, c);
+ } else if (dist === 0) {
+ this.selected = null;
+ this.render();
+ } else {
+ this.selected = {r, c};
+ this.render();
+ }
+ }
+ }
+
+ render() {
+ const grid = document.getElementById('grid');
+ grid.innerHTML = '';
+
+ for (let r = 0; r < this.size; r++) {
+ for (let c = 0; c < this.size; c++) {
+ const tile = document.createElement('div');
+ tile.className = `tile pattern-${this.grid[r][c]}`;
+ tile.dataset.r = r;
+ tile.dataset.c = c;
+
+ if (this.selected && this.selected.r === r && this.selected.c === c) {
+ tile.classList.add('selected');
+ }
+
+ tile.addEventListener('click', () => this.handleClick(r, c));
+ grid.appendChild(tile);
+ }
+ }
+ }
+
+ setupTouch() {
+ const grid = document.getElementById('grid');
+
+ grid.addEventListener('touchstart', (e) => {
+ this.touchStartX = e.touches[0].clientX;
+ this.touchStartY = e.touches[0].clientY;
+ }, {passive: false});
+
+ grid.addEventListener('touchend', (e) => {
+ e.preventDefault();
+ const touchEndX = e.changedTouches[0].clientX;
+ const touchEndY = e.changedTouches[0].clientY;
+ const dx = touchEndX - this.touchStartX;
+ const dy = touchEndY - this.touchStartY;
+
+ if (Math.abs(dx) < 10 && Math.abs(dy) < 10) {
+ const element = document.elementFromPoint(touchEndX, touchEndY);
+ if (element && element.classList.contains('tile')) {
+ const r = parseInt(element.dataset.r);
+ const c = parseInt(element.dataset.c);
+ this.handleClick(r, c);
+ }
+ }
+ }, {passive: false});
+ }
+
+ updateStats() {
+ document.getElementById('score').textContent = this.score;
+ document.getElementById('moves').textContent = this.moves;
+ }
+
+ restart() {
+ this.score = 0;
+ this.moves = 0;
+ this.selected = null;
+ this.busy = false;
+ this.init();
+ }
+}
+
+const game = new Game();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/d7f4f8ca5f8d/kimi.png b/data/artifacts/d7f4f8ca5f8d/kimi.png
new file mode 100644
index 0000000..67d3e10
Binary files /dev/null and b/data/artifacts/d7f4f8ca5f8d/kimi.png differ
diff --git a/data/artifacts/d7f4f8ca5f8d/qwen3-14b.html b/data/artifacts/d7f4f8ca5f8d/qwen3-14b.html
new file mode 100644
index 0000000..d51079f
--- /dev/null
+++ b/data/artifacts/d7f4f8ca5f8d/qwen3-14b.html
@@ -0,0 +1,210 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title>Luxury Tile Match</title>
+ <style>
+ * {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ }
+ body {
+ background: #f8f4f0;
+ font-family: 'Georgia', serif;
+ color: #3a2d28;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ height: 100vh;
+ overflow: hidden;
+ }
+ h1 {
+ margin-bottom: 10px;
+ }
+ #game {
+ display: grid;
+ grid-template-columns: repeat(6, 80px);
+ grid-template-rows: repeat(6, 80px);
+ gap: 4px;
+ margin-bottom: 10px;
+ }
+ .tile {
+ background-size: 200% 200%;
+ background-position: 0% 0%;
+ width: 80px;
+ height: 80px;
+ cursor: pointer;
+ user-select: none;
+ transition: transform 0.2s, opacity 0.3s;
+ }
+ .tile[data-type="damask"] {
+ background-image: linear-gradient(45deg, #e6d8d1 25%, #d6cfc1 25%, #d6cfc1 50%, #e6d8d1 50%, #e6d8d1 75%, #d6cfc1 75%, #d6cfc1 100%);
+ }
+ .tile[data-type="floral"] {
+ background-image: radial-gradient(circle at 30% 30%, #f2e6e2 0%, #e0d4d0 100%);
+ background-image: radial-gradient(circle at 70% 70%, #f8f4f0 0%, #e6d8d1 100%), linear-gradient(135deg, #e0d4d0 25%, #f2e6e2 75%);
+ }
+ .tile[data-type="geometric"] {
+ background-image: repeating-linear-gradient(45deg, #e6d8d1 0%, #d6cfc1 25%, #e6d8d1 50%);
+ }
+ .tile.selected {
+ transform: scale(1.1);
+ z-index: 1;
+ }
+ .tile.matching {
+ opacity: 0.5;
+ }
+ #info {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 5px;
+ }
+ #score, #moves {
+ font-size: 18px;
+ font-weight: bold;
+ }
+ button {
+ padding: 10px 20px;
+ font-size: 16px;
+ background-color: #d6cfc1;
+ border: none;
+ border-radius: 8px;
+ cursor: pointer;
+ transition: background-color 0.2s;
+ }
+ button:hover {
+ background-color: #e6d8d1;
+ }
+ </style>
+</head>
+<body>
+ <h1>Luxury Tile Match</h1>
+ <div id="game"></div>
+ <div id="info">
+ <div id="score">Score: 0</div>
+ <div id="moves">Moves: 0</div>
+ <button onclick="restartGame()">Restart</button>
+ </div>
+ <script>
+ const game = document.getElementById('game');
+ const scoreEl = document.getElementById('score');
+ const movesEl = document.getElementById('moves');
+ let score = 0;
+ let moves = 0;
+ let selected = null;
+ let tiles = [];
+
+ const tileTypes = ['damask', 'floral', 'geometric'];
+
+ function createTile(type) {
+ const tile = document.createElement('div');
+ tile.className = 'tile';
+ tile.dataset.type = type;
+ return tile;
+ }
+
+ function initGame() {
+ game.innerHTML = '';
+ tiles = [];
+ score = 0;
+ moves = 0;
+ scoreEl.textContent = 'Score: 0';
+ movesEl.textContent = 'Moves: 0';
+
+ for (let i = 0; i < 36; i++) {
+ const type = tileTypes[Math.floor(Math.random() * tileTypes.length)];
+ const tile = createTile(type);
+ game.appendChild(tile);
+ tiles.push(tile);
+ }
+
+ checkMatches();
+ }
+
+ function getTilePos(el) {
+ const rect = el.getBoundingClientRect();
+ const x = Math.floor((rect.left + window.scrollX) / 84);
+ const y = Math.floor((rect.top + window.scrollY) / 84);
+ return { x, y };
+ }
+
+ function findAdjacentTiles(tile) {
+ const { x, y } = getTilePos(tile);
+ const neighbors = [];
+ if (x > 0) neighbors.push(tiles[x - 1 + y * 6]);
+ if (x < 5) neighbors.push(tiles[x + 1 + y * 6]);
+ if (y > 0) neighbors.push(tiles[x + (y - 1) * 6]);
+ if (y < 5) neighbors.push(tiles[x + (y + 1) * 6]);
+ return neighbors;
+ }
+
+ function checkMatches() {
+ const matches = {};
+ tiles.forEach((tile, index) => {
+ const type = tile.dataset.type;
+ const { x, y } = getTilePos(tile);
+ const key = `${x},${y}`;
+ if (!matches[key]) matches[key] = [];
+ matches[key].push(index);
+ });
+
+ Object.values(matches).forEach(group => {
+ if (group.length >= 3) {
+ group.forEach(i => {
+ tiles[i].classList.add('matching');
+ });
+ }
+ });
+
+ setTimeout(() => {
+ Object.values(matches).forEach(group => {
+ if (group.length >= 3) {
+ group.forEach(i => {
+ tiles[i].remove();
+ });
+ }
+ });
+ score += group.length * 10;
+ scoreEl.textContent = 'Score: ' + score;
+ initGame();
+ }, 500);
+ }
+
+ function restartGame() {
+ initGame();
+ }
+
+ game.addEventListener('click', e => {
+ const tile = e.target;
+ if (!tile.classList.contains('tile')) return;
+
+ if (selected === null) {
+ selected = tile;
+ tile.classList.add('selected');
+ } else if (selected === tile) {
+ selected.classList.remove('selected');
+ selected = null;
+ } else {
+ const neighbors = findAdjacentTiles(selected);
+ if (neighbors.includes(tile)) {
+ moves++;
+ movesEl.textContent = 'Moves: ' + moves;
+ selected.classList.remove('selected');
+ selected = null;
+ checkMatches();
+ } else {
+ selected.classList.remove('selected');
+ selected = tile;
+ tile.classList.add('selected');
+ }
+ }
+ });
+
+ initGame();
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/d7f4f8ca5f8d/qwen3-14b.png b/data/artifacts/d7f4f8ca5f8d/qwen3-14b.png
new file mode 100644
index 0000000..bfb08aa
Binary files /dev/null and b/data/artifacts/d7f4f8ca5f8d/qwen3-14b.png differ
diff --git a/data/challenges.json b/data/challenges.json
index 184b10f..efc96b3 100644
--- a/data/challenges.json
+++ b/data/challenges.json
@@ -14428,13 +14428,15 @@
},
{
"model": "hf-qwen-coder-32b",
- "status": "running",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
+ "seconds": 66,
+ "cost": 0,
"started_at": "2026-07-25T07:41:41.794Z",
- "finished_at": null,
- "queued_at": "2026-07-25T07:39:01.077Z"
+ "finished_at": "2026-07-25T07:42:48.069Z",
+ "queued_at": "2026-07-25T07:39:01.077Z",
+ "bytes": 4989,
+ "thumb": true
},
{
"model": "claude-code",
@@ -14484,7 +14486,8 @@
"bytes": 25399,
"thumb": true
}
- ]
+ ],
+ "judging": true
},
{
"id": "b72f0e9e751b",
@@ -14497,33 +14500,39 @@
"runs": [
{
"model": "qwen3-14b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:39:01.151Z"
+ "seconds": 43,
+ "cost": 0,
+ "started_at": "2026-07-25T07:42:48.072Z",
+ "finished_at": "2026-07-25T07:43:30.739Z",
+ "queued_at": "2026-07-25T07:39:01.151Z",
+ "bytes": 6764,
+ "thumb": true
},
{
"model": "gemma3-12b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:39:01.153Z"
+ "seconds": 42,
+ "cost": 0,
+ "started_at": "2026-07-25T07:43:30.747Z",
+ "finished_at": "2026-07-25T07:44:12.710Z",
+ "queued_at": "2026-07-25T07:39:01.153Z",
+ "bytes": 6093,
+ "thumb": true
},
{
"model": "hermes3-8b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:39:01.155Z"
+ "seconds": 18,
+ "cost": 0,
+ "started_at": "2026-07-25T07:44:12.719Z",
+ "finished_at": "2026-07-25T07:44:30.975Z",
+ "queued_at": "2026-07-25T07:39:01.155Z",
+ "bytes": 4718,
+ "thumb": true
},
{
"model": "qwen25-7b",
@@ -14539,43 +14548,51 @@
},
{
"model": "hf-qwen-coder-32b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:39:01.160Z"
+ "seconds": 54,
+ "cost": 0,
+ "started_at": "2026-07-25T07:44:30.980Z",
+ "finished_at": "2026-07-25T07:45:25.158Z",
+ "queued_at": "2026-07-25T07:39:01.160Z",
+ "bytes": 4751,
+ "thumb": true
},
{
"model": "claude-code",
- "status": "running",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
+ "seconds": 82,
+ "cost": 0,
"started_at": "2026-07-25T07:41:05.454Z",
- "finished_at": null,
- "queued_at": "2026-07-25T07:39:01.163Z"
+ "finished_at": "2026-07-25T07:42:27.546Z",
+ "queued_at": "2026-07-25T07:39:01.163Z",
+ "bytes": 15442,
+ "thumb": true
},
{
"model": "kimi",
- "status": "running",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
+ "seconds": 116,
+ "cost": 0.0182,
"started_at": "2026-07-25T07:40:59.590Z",
- "finished_at": null,
- "queued_at": "2026-07-25T07:39:01.166Z"
+ "finished_at": "2026-07-25T07:42:55.117Z",
+ "queued_at": "2026-07-25T07:39:01.166Z",
+ "bytes": 18220,
+ "thumb": true
},
{
"model": "gpt",
- "status": "running",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
+ "seconds": 99,
+ "cost": 0.156,
"started_at": "2026-07-25T07:40:56.989Z",
- "finished_at": null,
- "queued_at": "2026-07-25T07:39:01.168Z"
+ "finished_at": "2026-07-25T07:42:36.451Z",
+ "queued_at": "2026-07-25T07:39:01.168Z",
+ "bytes": 37564,
+ "thumb": true
},
{
"model": "grok",
@@ -14589,7 +14606,8 @@
"bytes": 18401,
"thumb": true
}
- ]
+ ],
+ "judging": true
},
{
"id": "d7f4f8ca5f8d",
@@ -14602,33 +14620,39 @@
"runs": [
{
"model": "qwen3-14b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:39:01.227Z"
+ "seconds": 38,
+ "cost": 0,
+ "started_at": "2026-07-25T07:45:25.166Z",
+ "finished_at": "2026-07-25T07:46:02.946Z",
+ "queued_at": "2026-07-25T07:39:01.227Z",
+ "bytes": 5563,
+ "thumb": true
},
{
"model": "gemma3-12b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:39:01.229Z"
+ "seconds": 67,
+ "cost": 0,
+ "started_at": "2026-07-25T07:46:02.951Z",
+ "finished_at": "2026-07-25T07:47:09.777Z",
+ "queued_at": "2026-07-25T07:39:01.229Z",
+ "bytes": 9937,
+ "thumb": true
},
{
"model": "hermes3-8b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:39:01.232Z"
+ "seconds": 11,
+ "cost": 0,
+ "started_at": "2026-07-25T07:47:09.782Z",
+ "finished_at": "2026-07-25T07:47:21.017Z",
+ "queued_at": "2026-07-25T07:39:01.232Z",
+ "bytes": 2748,
+ "thumb": true
},
{
"model": "qwen25-7b",
@@ -14644,53 +14668,61 @@
},
{
"model": "hf-qwen-coder-32b",
- "status": "queued",
+ "status": "running",
"error": null,
"seconds": null,
"cost": null,
- "started_at": null,
+ "started_at": "2026-07-25T07:47:21.024Z",
"finished_at": null,
"queued_at": "2026-07-25T07:39:01.237Z"
},
{
"model": "claude-code",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:39:01.239Z"
+ "seconds": 204,
+ "cost": 0,
+ "started_at": "2026-07-25T07:42:27.550Z",
+ "finished_at": "2026-07-25T07:45:51.943Z",
+ "queued_at": "2026-07-25T07:39:01.239Z",
+ "bytes": 15116,
+ "thumb": true
},
{
"model": "kimi",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:39:01.241Z"
+ "seconds": 181,
+ "cost": 0.028,
+ "started_at": "2026-07-25T07:42:55.123Z",
+ "finished_at": "2026-07-25T07:45:55.841Z",
+ "queued_at": "2026-07-25T07:39:01.241Z",
+ "bytes": 13289,
+ "thumb": true
},
{
"model": "gpt",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:39:01.244Z"
+ "seconds": 60,
+ "cost": 0.0723,
+ "started_at": "2026-07-25T07:42:36.461Z",
+ "finished_at": "2026-07-25T07:43:36.080Z",
+ "queued_at": "2026-07-25T07:39:01.244Z",
+ "bytes": 16356,
+ "thumb": true
},
{
"model": "grok",
- "status": "running",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
+ "seconds": 60,
+ "cost": 0.0641,
"started_at": "2026-07-25T07:41:46.420Z",
- "finished_at": null,
- "queued_at": "2026-07-25T07:39:01.246Z"
+ "finished_at": "2026-07-25T07:42:46.921Z",
+ "queued_at": "2026-07-25T07:39:01.246Z",
+ "bytes": 11117,
+ "thumb": true
}
]
},
@@ -14757,43 +14789,49 @@
},
{
"model": "claude-code",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:39:01.315Z"
+ "seconds": 98,
+ "cost": 0,
+ "started_at": "2026-07-25T07:45:51.946Z",
+ "finished_at": "2026-07-25T07:47:29.655Z",
+ "queued_at": "2026-07-25T07:39:01.315Z",
+ "bytes": 17961,
+ "thumb": true
},
{
"model": "kimi",
- "status": "queued",
+ "status": "running",
"error": null,
"seconds": null,
"cost": null,
- "started_at": null,
+ "started_at": "2026-07-25T07:45:55.845Z",
"finished_at": null,
"queued_at": "2026-07-25T07:39:01.318Z"
},
{
"model": "gpt",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:39:01.320Z"
+ "seconds": 121,
+ "cost": 0.1515,
+ "started_at": "2026-07-25T07:43:36.087Z",
+ "finished_at": "2026-07-25T07:45:36.644Z",
+ "queued_at": "2026-07-25T07:39:01.320Z",
+ "bytes": 34064,
+ "thumb": true
},
{
"model": "grok",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:39:01.322Z"
+ "seconds": 102,
+ "cost": 0.1137,
+ "started_at": "2026-07-25T07:42:46.938Z",
+ "finished_at": "2026-07-25T07:44:29.131Z",
+ "queued_at": "2026-07-25T07:39:01.322Z",
+ "bytes": 20418,
+ "thumb": true
}
]
}
diff --git a/data/costlog.jsonl b/data/costlog.jsonl
index 96163d1..377c2a2 100644
--- a/data/costlog.jsonl
+++ b/data/costlog.jsonl
@@ -200,3 +200,10 @@
{"ts":"2026-07-25T07:40:56.981Z","provider":"openai","model":"gpt-5.1","task":"model-arena","input_tokens":176,"output_tokens":10508,"cost_usd":0.14742}
{"ts":"2026-07-25T07:40:59.586Z","provider":"moonshot","model":"kimi-k2.5","task":"model-arena","input_tokens":178,"output_tokens":7263,"cost_usd":0.018264}
{"ts":"2026-07-25T07:41:46.410Z","provider":"xai","model":"grok-4.5","task":"model-arena","input_tokens":374,"output_tokens":6050,"cost_usd":0.091872}
+{"ts":"2026-07-25T07:42:36.447Z","provider":"openai","model":"gpt-5.1","task":"model-arena","input_tokens":166,"output_tokens":11124,"cost_usd":0.156027}
+{"ts":"2026-07-25T07:42:46.917Z","provider":"xai","model":"grok-4.5","task":"model-arena","input_tokens":360,"output_tokens":4202,"cost_usd":0.06411}
+{"ts":"2026-07-25T07:42:55.113Z","provider":"moonshot","model":"kimi-k2.5","task":"model-arena","input_tokens":171,"output_tokens":7248,"cost_usd":0.018223}
+{"ts":"2026-07-25T07:43:36.075Z","provider":"openai","model":"gpt-5.1","task":"model-arena","input_tokens":154,"output_tokens":5144,"cost_usd":0.072286}
+{"ts":"2026-07-25T07:44:29.126Z","provider":"xai","model":"grok-4.5","task":"model-arena","input_tokens":364,"output_tokens":7510,"cost_usd":0.113742}
+{"ts":"2026-07-25T07:45:36.642Z","provider":"openai","model":"gpt-5.1","task":"model-arena","input_tokens":161,"output_tokens":10798,"cost_usd":0.151454}
+{"ts":"2026-07-25T07:45:55.839Z","provider":"moonshot","model":"kimi-k2.5","task":"model-arena","input_tokens":156,"output_tokens":11151,"cost_usd":0.027971}
diff --git a/idea-run/run-next.sh b/idea-run/run-next.sh
index 0830e7c..49979a8 100755
--- a/idea-run/run-next.sh
+++ b/idea-run/run-next.sh
@@ -16,7 +16,7 @@ TITLE="${LINE%%|*}"; PROMPT="${LINE#*|}"
python3 - "$TITLE" "$PROMPT" > /tmp/dwaa-payload.json <<'PY'
import json,sys
json.dump({"title":sys.argv[1],"prompt":sys.argv[2],
- "models":["qwen3-14b","gemma3-12b","hermes3-8b","qwen25-7b","hf-qwen-coder-32b","claude-code","kimi","gpt","grok"]},
+ "models":["qwen3-14b","gemma3-12b","hermes3-8b","qwen25-7b","hf-qwen-coder-32b","claude-code","kimi","gpt","grok"],"designTools":true},
sys.stdout)
PY
← 8ebb3f7 Refocus loop to DW games+social by BRAND/STYLE/COLOR (16 ide
·
back to Model Arena
·
Beauty gate: auto-remix winners scoring <7 (make it more bea 3e64ec7 →