← back to Model Arena
auto-save: 2026-07-25T04:03:25 (4 files) — data/challenges.json data/costlog.jsonl data/artifacts/98e38ea3773f/ data/artifacts/a17a50ae57ef/
770df13be825cb01eb77ed17f77824f0a167ba0f · 2026-07-25 04:03:34 -0700 · Steve Abrams
Files touched
A data/artifacts/98e38ea3773f/claude-code.htmlA data/artifacts/98e38ea3773f/claude-code.pngA data/artifacts/98e38ea3773f/gemma3-12b.htmlA data/artifacts/98e38ea3773f/gemma3-12b.pngA data/artifacts/98e38ea3773f/gpt.htmlA data/artifacts/98e38ea3773f/gpt.pngA data/artifacts/98e38ea3773f/grok.htmlA data/artifacts/98e38ea3773f/grok.pngA data/artifacts/98e38ea3773f/hermes3-8b.htmlA data/artifacts/98e38ea3773f/hermes3-8b.pngA data/artifacts/98e38ea3773f/kimi.htmlA data/artifacts/98e38ea3773f/kimi.pngA data/artifacts/98e38ea3773f/qwen25-7b.htmlA data/artifacts/98e38ea3773f/qwen25-7b.pngA data/artifacts/98e38ea3773f/qwen3-14b.htmlA data/artifacts/98e38ea3773f/qwen3-14b.pngA data/artifacts/a17a50ae57ef/qwen25-7b.htmlA data/artifacts/a17a50ae57ef/qwen25-7b.pngM data/challenges.jsonM data/costlog.jsonl
Diff
commit 770df13be825cb01eb77ed17f77824f0a167ba0f
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Sat Jul 25 04:03:34 2026 -0700
auto-save: 2026-07-25T04:03:25 (4 files) — data/challenges.json data/costlog.jsonl data/artifacts/98e38ea3773f/ data/artifacts/a17a50ae57ef/
---
data/artifacts/98e38ea3773f/claude-code.html | 638 ++++++++++++
data/artifacts/98e38ea3773f/claude-code.png | Bin 0 -> 61932 bytes
data/artifacts/98e38ea3773f/gemma3-12b.html | 306 ++++++
data/artifacts/98e38ea3773f/gemma3-12b.png | Bin 0 -> 37306 bytes
data/artifacts/98e38ea3773f/gpt.html | 1387 ++++++++++++++++++++++++++
data/artifacts/98e38ea3773f/gpt.png | Bin 0 -> 206792 bytes
data/artifacts/98e38ea3773f/grok.html | 1139 +++++++++++++++++++++
data/artifacts/98e38ea3773f/grok.png | Bin 0 -> 85629 bytes
data/artifacts/98e38ea3773f/hermes3-8b.html | 147 +++
data/artifacts/98e38ea3773f/hermes3-8b.png | Bin 0 -> 22067 bytes
data/artifacts/98e38ea3773f/kimi.html | 835 ++++++++++++++++
data/artifacts/98e38ea3773f/kimi.png | Bin 0 -> 64189 bytes
data/artifacts/98e38ea3773f/qwen25-7b.html | 137 +++
data/artifacts/98e38ea3773f/qwen25-7b.png | Bin 0 -> 16333 bytes
data/artifacts/98e38ea3773f/qwen3-14b.html | 468 +++++++++
data/artifacts/98e38ea3773f/qwen3-14b.png | Bin 0 -> 29384 bytes
data/artifacts/a17a50ae57ef/qwen25-7b.html | 146 +++
data/artifacts/a17a50ae57ef/qwen25-7b.png | Bin 0 -> 15253 bytes
data/challenges.json | 163 +--
data/costlog.jsonl | 3 +
20 files changed, 5305 insertions(+), 64 deletions(-)
diff --git a/data/artifacts/98e38ea3773f/claude-code.html b/data/artifacts/98e38ea3773f/claude-code.html
new file mode 100644
index 0000000..3ee64fd
--- /dev/null
+++ b/data/artifacts/98e38ea3773f/claude-code.html
@@ -0,0 +1,638 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Designer Wallcoverings — Palette Atelier</title>
+<style>
+ :root{
+ /* ——— design tokens ——— */
+ --bg:#0d0d0f;
+ --surface:#17171c;
+ --surface-2:#1e1e24;
+ --ink:#f5f2ea;
+ --muted:#8a8578;
+ --accent:#c9a961;
+ --accent-deep:#7d6a45;
+ --line:rgba(201,169,97,.22);
+ --hair:rgba(245,242,234,.10);
+ --shadow:0 8px 24px rgba(0,0,0,.45);
+ --shadow-hi:0 16px 48px rgba(0,0,0,.55);
+ --glow:0 0 24px rgba(201,169,97,.35);
+ --ease:cubic-bezier(.22,1,.36,1);
+ --serif:'Cormorant Garamond','Playfair Display','EB Garamond','Didot','Bodoni MT',Georgia,serif;
+ --sans:-apple-system,'Segoe UI','Helvetica Neue',Arial,sans-serif;
+ --sp-1:4px;--sp-2:8px;--sp-3:12px;--sp-4:16px;--sp-5:24px;--sp-6:32px;--sp-7:48px;--sp-8:64px;--sp-9:96px;
+ }
+
+ *{box-sizing:border-box;margin:0;padding:0}
+ html,body{background:var(--bg);color:var(--ink);font-family:var(--sans);-webkit-font-smoothing:antialiased}
+ body{
+ min-height:100vh;
+ background:
+ radial-gradient(1200px 600px at 80% -10%, rgba(201,169,97,.07), transparent 60%),
+ radial-gradient(900px 500px at -10% 110%, rgba(125,106,69,.08), transparent 55%),
+ var(--bg);
+ padding-top:78px;
+ }
+
+ ::selection{background:var(--accent);color:var(--bg)}
+
+ /* ——— top bar / wordmark lockup ——— */
+ .topbar{
+ position:fixed;top:0;left:0;right:0;height:78px;z-index:50;
+ display:flex;align-items:center;justify-content:space-between;
+ padding:0 var(--sp-7);
+ background:rgba(13,13,15,.72);
+ backdrop-filter:blur(14px);
+ border-bottom:1px solid var(--hair);
+ }
+ .wordmark{display:flex;flex-direction:column;line-height:1.02}
+ .wordmark .name{
+ font-family:var(--serif);
+ font-weight:600;
+ font-size:25px;
+ letter-spacing:.18em;
+ text-transform:uppercase;
+ color:var(--ink);
+ white-space:nowrap;
+ }
+ .wordmark .sub{
+ font-family:var(--sans);
+ font-size:9.5px;letter-spacing:.34em;text-transform:uppercase;
+ color:var(--accent);margin-top:5px;padding-left:3px;
+ }
+ .topbar .util{
+ font-family:var(--sans);font-size:11px;letter-spacing:.15em;text-transform:uppercase;
+ color:var(--muted);display:flex;gap:var(--sp-5);align-items:center;
+ }
+ .topbar .util b{color:var(--ink);font-weight:600}
+ @media(max-width:720px){
+ .topbar{padding:0 var(--sp-5)}
+ .wordmark .name{font-size:20px;letter-spacing:.16em}
+ .topbar .util{display:none}
+ }
+
+ /* ——— layout ——— */
+ .wrap{max-width:1200px;margin:0 auto;padding:var(--sp-9) var(--sp-7) var(--sp-8)}
+ @media(max-width:720px){.wrap{padding:var(--sp-7) var(--sp-5) var(--sp-7)}}
+
+ .eyebrow{
+ font-size:12px;letter-spacing:.28em;text-transform:uppercase;color:var(--accent);
+ margin-bottom:var(--sp-4);
+ opacity:0;animation:fadeUp .7s var(--ease) .05s both;
+ }
+ h1.lede{
+ font-family:var(--serif);font-weight:500;font-size:clamp(42px,6vw,67px);
+ line-height:1.02;letter-spacing:.005em;color:var(--ink);
+ max-width:14ch;
+ opacity:0;animation:fadeUp .7s var(--ease) .14s both;
+ }
+ h1.lede em{font-style:italic;color:var(--accent)}
+ .intro{
+ font-family:var(--sans);font-size:16px;line-height:1.7;color:var(--muted);
+ max-width:52ch;margin-top:var(--sp-5);
+ opacity:0;animation:fadeUp .7s var(--ease) .23s both;
+ }
+
+ .divider{height:1px;background:var(--hair);margin:var(--sp-8) 0 var(--sp-7)}
+
+ /* ——— studio grid ——— */
+ .studio{
+ display:grid;grid-template-columns:minmax(280px,340px) 1fr;gap:var(--sp-8);align-items:start;
+ opacity:0;animation:fadeUp .7s var(--ease) .32s both;
+ }
+ @media(max-width:900px){.studio{grid-template-columns:1fr;gap:var(--sp-7)}}
+
+ .panel-label{
+ font-size:12px;letter-spacing:.2em;text-transform:uppercase;color:var(--muted);
+ margin-bottom:var(--sp-5);display:flex;align-items:center;gap:var(--sp-3);
+ }
+ .panel-label::after{content:"";flex:1;height:1px;background:var(--hair)}
+
+ /* ——— wheel ——— */
+ .wheel-card{
+ background:var(--surface);border:1px solid var(--hair);border-radius:14px;
+ padding:var(--sp-6);box-shadow:var(--shadow);
+ }
+ .wheel-stage{position:relative;width:236px;height:236px;margin:var(--sp-2) auto var(--sp-6);touch-action:none;cursor:crosshair}
+ .wheel{
+ position:absolute;inset:0;border-radius:50%;
+ background:conic-gradient(from 0deg,
+ hsl(0,62%,52%),hsl(30,60%,52%),hsl(60,58%,50%),hsl(90,52%,48%),
+ hsl(120,48%,46%),hsl(150,46%,46%),hsl(180,48%,48%),hsl(210,54%,52%),
+ hsl(240,52%,56%),hsl(270,48%,54%),hsl(300,52%,52%),hsl(330,58%,52%),hsl(360,62%,52%));
+ -webkit-mask:radial-gradient(circle at center, transparent 0 44%, #000 45% 100%);
+ mask:radial-gradient(circle at center, transparent 0 44%, #000 45% 100%);
+ box-shadow:inset 0 0 0 1px rgba(0,0,0,.4);
+ }
+ .wheel-core{
+ position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
+ width:44%;height:44%;border-radius:50%;
+ border:1px solid var(--hair);
+ display:flex;flex-direction:column;align-items:center;justify-content:center;
+ text-align:center;background:var(--surface-2);
+ transition:background .35s var(--ease);
+ }
+ .wheel-core .hval{font-family:var(--serif);font-size:34px;line-height:1;color:var(--ink)}
+ .wheel-core .hlab{font-size:9.5px;letter-spacing:.22em;text-transform:uppercase;color:var(--muted);margin-top:6px}
+ .knob{
+ position:absolute;width:26px;height:26px;border-radius:50%;
+ border:2px solid var(--ink);box-shadow:0 2px 10px rgba(0,0,0,.6),var(--glow);
+ transform:translate(-50%,-50%);pointer-events:none;transition:box-shadow .2s var(--ease);
+ }
+
+ /* segmented harmony control */
+ .seg{display:flex;border:1px solid var(--line);border-radius:11px;overflow:hidden;background:var(--surface-2)}
+ .seg button{
+ flex:1;appearance:none;border:0;background:transparent;color:var(--muted);
+ font-family:var(--sans);font-size:11px;letter-spacing:.14em;text-transform:uppercase;
+ padding:12px 6px;cursor:pointer;transition:all .25s var(--ease);position:relative;
+ }
+ .seg button+button{border-left:1px solid var(--hair)}
+ .seg button.on{color:var(--bg);background:var(--accent);font-weight:600}
+ .seg button:not(.on):hover{color:var(--ink)}
+
+ .hint{font-size:12px;color:var(--muted);margin-top:var(--sp-5);line-height:1.6;letter-spacing:.02em}
+
+ /* ——— palette swatches ——— */
+ .palette{display:grid;grid-template-columns:repeat(5,1fr);gap:var(--sp-4)}
+ @media(max-width:640px){.palette{grid-template-columns:repeat(2,1fr)}}
+ .swatch{
+ border:1px solid var(--hair);border-radius:14px;overflow:hidden;background:var(--surface);
+ cursor:pointer;box-shadow:var(--shadow);
+ transition:transform .3s var(--ease),box-shadow .3s var(--ease),border-color .3s var(--ease);
+ }
+ .swatch:hover{transform:translateY(-6px);box-shadow:var(--shadow-hi);border-color:var(--line)}
+ .swatch .chip{height:150px;transition:background .45s var(--ease);position:relative}
+ .swatch .chip::after{
+ content:"COPY";position:absolute;bottom:10px;right:12px;
+ font-size:9px;letter-spacing:.2em;color:rgba(255,255,255,.0);
+ padding:3px 7px;border:1px solid rgba(255,255,255,0);border-radius:20px;
+ transition:.3s var(--ease);
+ }
+ .swatch:hover .chip::after{color:rgba(255,255,255,.85);border-color:rgba(255,255,255,.4);background:rgba(0,0,0,.18)}
+ .swatch .meta{padding:var(--sp-4) var(--sp-4) var(--sp-5)}
+ .swatch .role{font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--muted)}
+ .swatch .nm{font-family:var(--serif);font-size:22px;line-height:1.1;margin:6px 0 4px;color:var(--ink)}
+ .swatch .hex{font-family:var(--sans);font-size:12px;letter-spacing:.12em;color:var(--accent)}
+
+ /* ——— room preview ——— */
+ .room-block{margin-top:var(--sp-8)}
+ .room{
+ position:relative;height:300px;border-radius:14px;overflow:hidden;
+ border:1px solid var(--hair);box-shadow:var(--shadow);
+ background:var(--c1);transition:background .5s var(--ease);
+ }
+ .room .upper{position:absolute;inset:0 0 42% 0;background:var(--c1);transition:background .5s var(--ease)}
+ .room .lower{position:absolute;left:0;right:0;bottom:0;height:42%;background:var(--c2);transition:background .5s var(--ease)}
+ .room .rail{position:absolute;left:0;right:0;bottom:42%;height:5px;background:var(--c4);box-shadow:0 1px 6px rgba(0,0,0,.4);transition:background .5s var(--ease)}
+ .room .base{position:absolute;left:0;right:0;bottom:0;height:20px;background:var(--c3);transition:background .5s var(--ease)}
+ .room .floor{position:absolute;left:0;right:0;bottom:0;height:0}
+ /* framed panel */
+ .room .frame{
+ position:absolute;top:44px;left:9%;width:150px;height:118px;border-radius:3px;
+ background:var(--c0);border:6px solid var(--c4);
+ box-shadow:0 12px 30px rgba(0,0,0,.5);transition:background .5s var(--ease),border-color .5s var(--ease);
+ }
+ .room .frame::before{
+ content:"";position:absolute;inset:14px;border:1px solid rgba(0,0,0,.15);border-radius:2px;
+ background:repeating-linear-gradient(135deg,transparent 0 12px,rgba(0,0,0,.06) 12px 13px);
+ }
+ /* console + lamp */
+ .room .console{position:absolute;bottom:20px;right:11%;width:180px;height:58px;background:var(--c3);border-radius:3px 3px 0 0;box-shadow:0 -6px 20px rgba(0,0,0,.35);transition:background .5s var(--ease)}
+ .room .vase{position:absolute;bottom:78px;right:15%;width:26px;height:52px;border-radius:40% 40% 50% 50%;background:var(--c4);box-shadow:var(--glow);transition:background .5s var(--ease)}
+ .room .glow{position:absolute;top:0;right:8%;width:220px;height:220px;border-radius:50%;background:radial-gradient(circle,rgba(255,240,210,.10),transparent 70%);pointer-events:none}
+ .room .tag{
+ position:absolute;top:16px;right:18px;font-size:10px;letter-spacing:.24em;text-transform:uppercase;
+ color:rgba(255,255,255,.55);background:rgba(0,0,0,.28);padding:6px 12px;border-radius:20px;border:1px solid rgba(255,255,255,.14);
+ }
+
+ /* ——— actions ——— */
+ .actions{display:flex;flex-wrap:wrap;gap:var(--sp-4);align-items:center;margin-top:var(--sp-7)}
+ .btn{
+ appearance:none;border:1px solid var(--accent);background:var(--accent);color:var(--bg);
+ font-family:var(--sans);font-size:12px;letter-spacing:.18em;text-transform:uppercase;font-weight:600;
+ padding:15px 30px;border-radius:30px;cursor:pointer;transition:all .25s var(--ease);
+ }
+ .btn:hover{box-shadow:var(--glow);transform:translateY(-2px)}
+ .btn.ghost{background:transparent;color:var(--ink);border-color:var(--line)}
+ .btn.ghost:hover{border-color:var(--accent);color:var(--accent);box-shadow:none}
+ .stamp{font-size:12px;color:var(--muted);letter-spacing:.04em}
+ .stamp b{color:var(--ink)}
+
+ footer{margin-top:var(--sp-9);padding-top:var(--sp-5);border-top:1px solid var(--hair);
+ font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--muted);display:flex;justify-content:space-between;flex-wrap:wrap;gap:var(--sp-3)}
+
+ /* ——— toast overlay ——— */
+ .toast{
+ position:fixed;left:50%;bottom:36px;transform:translate(-50%,26px);
+ background:var(--surface);border:1px solid var(--line);color:var(--ink);
+ padding:14px 24px;border-radius:30px;box-shadow:var(--shadow-hi);
+ font-size:12px;letter-spacing:.14em;text-transform:uppercase;z-index:90;
+ opacity:0;pointer-events:none;transition:all .4s var(--ease);display:flex;gap:12px;align-items:center;
+ }
+ .toast.show{opacity:1;transform:translate(-50%,0)}
+ .toast .dot{width:14px;height:14px;border-radius:50%;box-shadow:var(--glow)}
+
+ @keyframes fadeUp{from{opacity:0;transform:translateY(28px)}to{opacity:1;transform:none}}
+</style>
+</head>
+<body>
+
+ <header class="topbar">
+ <div class="wordmark">
+ <span class="name">Designer Wallcoverings</span>
+ <span class="sub">Palette Atelier</span>
+ </div>
+ <div class="util">
+ <span>Harmony <b id="uMode">Analogous</b></span>
+ <span>Base <b id="uHue">210°</b></span>
+ </div>
+ </header>
+
+ <main class="wrap">
+ <p class="eyebrow">Colour Studio · Nº 05</p>
+ <h1 class="lede">Compose a <em>curated</em> wallcovering palette.</h1>
+ <p class="intro">Turn the wheel to set your base hue, then let the atelier build a five-tone
+ scheme — light neutral, soft ground, statement, ink and metallic accent — each named in the
+ language of interiors. Tap any tone to copy its hex, preview it in a room, and export a share card.</p>
+
+ <div class="divider"></div>
+
+ <section class="studio">
+ <!-- controls -->
+ <div>
+ <div class="panel-label">The Wheel</div>
+ <div class="wheel-card">
+ <div class="wheel-stage" id="stage">
+ <div class="wheel"></div>
+ <div class="wheel-core" id="core">
+ <span class="hval" id="coreHue">210</span>
+ <span class="hlab">Base Hue</span>
+ </div>
+ <div class="knob" id="knob"></div>
+ </div>
+ <div class="seg" role="tablist">
+ <button data-mode="analogous" class="on">Analogous</button>
+ <button data-mode="complementary">Complementary</button>
+ <button data-mode="triadic">Triadic</button>
+ </div>
+ <p class="hint">Drag the ring or click a hue. The harmony toggle re-voices the scheme
+ around your chosen colour.</p>
+ </div>
+ </div>
+
+ <!-- palette + room -->
+ <div>
+ <div class="panel-label">The Scheme — Five Tones</div>
+ <div class="palette" id="palette"></div>
+
+ <div class="room-block">
+ <div class="panel-label">Room Preview</div>
+ <div class="room" id="room">
+ <div class="upper"></div>
+ <div class="rail"></div>
+ <div class="lower"></div>
+ <div class="frame"></div>
+ <div class="glow"></div>
+ <div class="console"></div>
+ <div class="vase"></div>
+ <div class="base"></div>
+ <span class="tag">In Situ</span>
+ </div>
+ </div>
+
+ <div class="actions">
+ <button class="btn" id="exportBtn">Export 1080 × 1080 Card</button>
+ <button class="btn ghost" id="shuffleBtn">Surprise Me</button>
+ <span class="stamp">Scheme <b id="stampName">—</b></span>
+ </div>
+ </div>
+ </section>
+
+ <footer>
+ <span>Designer Wallcoverings — Atelier Edition</span>
+ <span>Self-contained · No network</span>
+ </footer>
+ </main>
+
+ <div class="toast" id="toast"><span class="dot" id="toastDot"></span><span id="toastMsg">Copied</span></div>
+
+ <canvas id="exportCanvas" width="1080" height="1080" style="display:none"></canvas>
+
+<script>
+(function(){
+ "use strict";
+
+ /* ————— colour math ————— */
+ function hslToRgb(h,s,l){
+ h=((h%360)+360)%360; s/=100; l/=100;
+ const c=(1-Math.abs(2*l-1))*s, x=c*(1-Math.abs((h/60)%2-1)), m=l-c/2;
+ let r=0,g=0,b=0;
+ if(h<60){r=c;g=x;} else if(h<120){r=x;g=c;} else if(h<180){g=c;b=x;}
+ else if(h<240){g=x;b=c;} else if(h<300){r=x;b=c;} else {r=c;b=x;}
+ return [Math.round((r+m)*255),Math.round((g+m)*255),Math.round((b+m)*255)];
+ }
+ function hslToHex(h,s,l){
+ const [r,g,b]=hslToRgb(h,s,l);
+ return "#"+[r,g,b].map(v=>v.toString(16).padStart(2,"0")).join("").toUpperCase();
+ }
+ function textOn(h,s,l){ return l>58 ? "#141414" : "#f5f2ea"; }
+
+ /* ————— designer naming ————— */
+ const FAMILIES=[
+ {max:15 ,names:{hi:["Blush","Petal","Shell Pink"],mid:["Rosewood","Terracotta","Madder"],lo:["Oxblood","Bordeaux","Garnet"]}},
+ {max:45 ,names:{hi:["Alabaster","Bone","Oyster"],mid:["Clay","Amber","Sienna"],lo:["Bitter Chocolate","Espresso","Umber"]}},
+ {max:70 ,names:{hi:["Chalk","Cream","Vellum"],mid:["Ochre","Honey","Brass"],lo:["Bronze","Antique Gold","Olive Bronze"]}},
+ {max:100,names:{hi:["Linen","Parchment","Oatmeal"],mid:["Chartreuse","Moss","Fennel"],lo:["Loden","Bronze Green","Cypress"]}},
+ {max:160,names:{hi:["Eggshell","Celadon","Sea Foam"],mid:["Sage","Verdigris","Jade"],lo:["Forest","Malachite","Pine"]}},
+ {max:200,names:{hi:["Celadon","Mist","Aqua Chalk"],mid:["Celadon","Teal","Eucalyptus"],lo:["Deep Teal","Spruce","Peacock"]}},
+ {max:250,names:{hi:["Dove","Powder","Porcelain Blue"],mid:["Slate Blue","Denim","Wedgwood"],lo:["Ink","Navy","Midnight"]}},
+ {max:290,names:{hi:["Wisteria","Lavender Ash","Heather"],mid:["Amethyst","Iris","Violet"],lo:["Aubergine","Damson","Indigo"]}},
+ {max:345,names:{hi:["Orchid Chalk","Mauve","Thistle"],mid:["Plum","Magenta","Fuchsia Grey"],lo:["Prune","Boysenberry","Dark Plum"]}},
+ {max:360,names:{hi:["Blush","Petal","Shell Pink"],mid:["Rosewood","Terracotta","Madder"],lo:["Oxblood","Bordeaux","Garnet"]}}
+ ];
+ const NEUTRAL={hi:["Alabaster","Chalk","Oyster","Bone","Porcelain"],mid:["Greige","Dove","Fog","Stone","Ash"],lo:["Charcoal","Onyx","Ink","Graphite","Slate"]};
+
+ function nameFor(h,s,l,seed){
+ const band = l>=80 ? "hi" : (l<=28 ? "lo" : "mid");
+ const pool = s<=15 ? NEUTRAL[band] : (FAMILIES.find(f=>h<f.max)||FAMILIES[0]).names[band];
+ return pool[Math.abs(seed)%pool.length];
+ }
+
+ /* ————— palette generation ————— */
+ const OFFSETS={
+ analogous:{soft:-20, accent:32},
+ complementary:{soft:-10, accent:180},
+ triadic:{soft:120, accent:240}
+ };
+ // roles: light neutral, soft ground, statement, ink, accent
+ const ROLES=[
+ {key:"soft", role:"Light Neutral", l:88, s:13},
+ {key:"soft", role:"Soft Ground", l:75, s:17},
+ {key:"base", role:"Statement", l:50, s:38},
+ {key:"base", role:"Ink", l:16, s:26},
+ {key:"accent", role:"Metallic Accent",l:47, s:52}
+ ];
+
+ let state={hue:210, mode:"analogous", seedShift:0};
+
+ function buildPalette(){
+ const off=OFFSETS[state.mode];
+ return ROLES.map((r,i)=>{
+ let h=state.hue;
+ if(r.key==="soft"&&i===1) h=state.hue+off.soft;
+ if(r.key==="accent") h=state.hue+off.accent;
+ h=((h%360)+360)%360;
+ const hex=hslToHex(h,r.s,r.l);
+ const nm=nameFor(h,r.s,r.l, Math.round(state.hue)+i*7+state.seedShift);
+ return {h,s:r.s,l:r.l,hex,name:nm,role:r.role};
+ });
+ }
+
+ /* ————— render ————— */
+ const paletteEl=document.getElementById("palette");
+ const roomEl=document.getElementById("room");
+ const coreEl=document.getElementById("core");
+ const coreHueEl=document.getElementById("coreHue");
+ const stampName=document.getElementById("stampName");
+ const uMode=document.getElementById("uMode");
+ const uHue=document.getElementById("uHue");
+ let current=[];
+
+ function render(){
+ current=buildPalette();
+ // swatches
+ paletteEl.innerHTML="";
+ current.forEach((c,i)=>{
+ const div=document.createElement("div");
+ div.className="swatch";
+ div.style.animation=`fadeUp .55s var(--ease) ${i*0.06}s both`;
+ div.innerHTML=
+ `<div class="chip" style="background:${c.hex}"></div>
+ <div class="meta">
+ <div class="role">${c.role}</div>
+ <div class="nm">${c.name}</div>
+ <div class="hex">${c.hex}</div>
+ </div>`;
+ div.addEventListener("click",()=>copyHex(c));
+ paletteEl.appendChild(div);
+ });
+ // room vars: c0 light, c1 soft ground, c2 statement, c3 ink, c4 accent
+ roomEl.style.setProperty("--c0",current[0].hex);
+ roomEl.style.setProperty("--c1",current[1].hex);
+ roomEl.style.setProperty("--c2",current[2].hex);
+ roomEl.style.setProperty("--c3",current[3].hex);
+ roomEl.style.setProperty("--c4",current[4].hex);
+ // core swatch bg = statement
+ coreEl.style.background=current[2].hex;
+ coreEl.querySelector(".hval").style.color=textOn(current[2].h,current[2].s,current[2].l);
+ coreEl.querySelector(".hlab").style.color=textOn(current[2].h,current[2].s,current[2].l);
+ coreHueEl.textContent=Math.round(state.hue);
+ // stamp / util
+ const modeName=state.mode.charAt(0).toUpperCase()+state.mode.slice(1);
+ stampName.textContent=`${current[2].name} · ${modeName}`;
+ uMode.textContent=modeName;
+ uHue.textContent=Math.round(state.hue)+"°";
+ positionKnob();
+ }
+
+ /* ————— wheel interaction ————— */
+ const stage=document.getElementById("stage");
+ const knob=document.getElementById("knob");
+ function positionKnob(){
+ const rect=stage.getBoundingClientRect();
+ const R=rect.width*0.375; // ring radius (between mask hole & edge)
+ const a=state.hue*Math.PI/180; // 0 at top, clockwise
+ const cx=rect.width/2, cy=rect.height/2;
+ const x=cx+R*Math.sin(a), y=cy-R*Math.cos(a);
+ knob.style.left=x+"px"; knob.style.top=y+"px";
+ knob.style.background=hslToHex(state.hue,60,52);
+ }
+ function hueFromEvent(e){
+ const rect=stage.getBoundingClientRect();
+ const px=(e.touches?e.touches[0].clientX:e.clientX)-rect.left-rect.width/2;
+ const py=(e.touches?e.touches[0].clientY:e.clientY)-rect.top-rect.height/2;
+ let deg=Math.atan2(px,-py)*180/Math.PI; // top=0 clockwise
+ deg=((deg%360)+360)%360;
+ state.hue=Math.round(deg);
+ render();
+ }
+ let dragging=false;
+ function down(e){dragging=true;hueFromEvent(e);e.preventDefault();}
+ function move(e){if(dragging)hueFromEvent(e);}
+ function up(){dragging=false;}
+ stage.addEventListener("mousedown",down);
+ window.addEventListener("mousemove",move);
+ window.addEventListener("mouseup",up);
+ stage.addEventListener("touchstart",down,{passive:false});
+ window.addEventListener("touchmove",move,{passive:false});
+ window.addEventListener("touchend",up);
+
+ /* ————— harmony toggle ————— */
+ document.querySelectorAll(".seg button").forEach(b=>{
+ b.addEventListener("click",()=>{
+ document.querySelectorAll(".seg button").forEach(x=>x.classList.remove("on"));
+ b.classList.add("on");
+ state.mode=b.dataset.mode;
+ render();
+ });
+ });
+
+ /* ————— copy hex ————— */
+ const toast=document.getElementById("toast");
+ const toastMsg=document.getElementById("toastMsg");
+ const toastDot=document.getElementById("toastDot");
+ let toastT;
+ function showToast(msg,color){
+ toastMsg.textContent=msg;
+ toastDot.style.background=color||"var(--accent)";
+ toast.classList.add("show");
+ clearTimeout(toastT);
+ toastT=setTimeout(()=>toast.classList.remove("show"),1600);
+ }
+ function copyHex(c){
+ const t=c.hex;
+ const done=()=>showToast(`${c.name} · ${t} copied`,c.hex);
+ if(navigator.clipboard&&navigator.clipboard.writeText){
+ navigator.clipboard.writeText(t).then(done).catch(()=>fallbackCopy(t,done));
+ } else fallbackCopy(t,done);
+ }
+ function fallbackCopy(t,done){
+ const ta=document.createElement("textarea");
+ ta.value=t;ta.style.position="fixed";ta.style.opacity="0";
+ document.body.appendChild(ta);ta.select();
+ try{document.execCommand("copy");}catch(e){}
+ document.body.removeChild(ta);done();
+ }
+
+ /* ————— surprise ————— */
+ document.getElementById("shuffleBtn").addEventListener("click",()=>{
+ state.hue=Math.floor(Math.random()*360);
+ state.seedShift=Math.floor(Math.random()*97);
+ const modes=["analogous","complementary","triadic"];
+ state.mode=modes[Math.floor(Math.random()*3)];
+ document.querySelectorAll(".seg button").forEach(x=>x.classList.toggle("on",x.dataset.mode===state.mode));
+ render();
+ showToast("New scheme drawn","var(--accent)");
+ });
+
+ /* ————— export 1080×1080 card ————— */
+ document.getElementById("exportBtn").addEventListener("click",exportCard);
+ function exportCard(){
+ const cv=document.getElementById("exportCanvas");
+ const g=cv.getContext("2d");
+ const W=1080,H=1080;
+ // ground
+ g.fillStyle="#0d0d0f";g.fillRect(0,0,W,H);
+ // subtle vignette
+ const rg=g.createRadialGradient(W*0.8,-60,80,W*0.5,H*0.5,900);
+ rg.addColorStop(0,"rgba(201,169,97,0.10)");rg.addColorStop(1,"rgba(13,13,15,0)");
+ g.fillStyle=rg;g.fillRect(0,0,W,H);
+
+ // header wordmark
+ g.textBaseline="alphabetic";
+ g.fillStyle="#f5f2ea";
+ g.font='600 44px "Cormorant Garamond","Playfair Display",Didot,Georgia,serif';
+ g.textAlign="left";
+ g.save();
+ g.translate(90,120);
+ // letter-spaced draw
+ drawTracked(g,"DESIGNER WALLCOVERINGS",0,0,7);
+ g.restore();
+ g.fillStyle="#c9a961";
+ g.font='500 17px -apple-system,"Helvetica Neue",Arial,sans-serif';
+ drawTracked(g,"PALETTE ATELIER",92,152,6);
+
+ // scheme title
+ const modeName=state.mode.charAt(0).toUpperCase()+state.mode.slice(1);
+ g.fillStyle="#f5f2ea";
+ g.font='500 58px "Cormorant Garamond",Didot,Georgia,serif';
+ g.textAlign="left";
+ g.fillText(current[2].name+" Scheme",90,250);
+ g.fillStyle="#8a8578";
+ g.font='400 20px -apple-system,"Helvetica Neue",Arial,sans-serif';
+ drawTracked(g,modeName.toUpperCase()+" · BASE HUE "+Math.round(state.hue)+"°",92,290,4);
+
+ // big swatch stack
+ const top=360, boxH=560, gap=18, n=5;
+ const boxW=(W-180-gap*(n-1))/n;
+ current.forEach((c,i)=>{
+ const x=90+i*(boxW+gap);
+ // chip
+ g.fillStyle=c.hex;
+ roundRect(g,x,top,boxW,boxH*0.62,10);g.fill();
+ // label plate
+ g.fillStyle="#17171c";
+ roundRect(g,x,top+boxH*0.62+8,boxW,boxH*0.30,10);g.fill();
+ g.strokeStyle="rgba(245,242,234,0.10)";g.lineWidth=1;
+ roundRect(g,x,top+boxH*0.62+8,boxW,boxH*0.30,10);g.stroke();
+ // role
+ g.fillStyle="#8a8578";g.textAlign="center";
+ g.font='400 12px -apple-system,Arial,sans-serif';
+ g.fillText(c.role.toUpperCase(),x+boxW/2,top+boxH*0.62+42);
+ // name
+ g.fillStyle="#f5f2ea";
+ g.font='500 27px "Cormorant Garamond",Didot,Georgia,serif';
+ wrapCenter(g,c.name,x+boxW/2,top+boxH*0.62+80,boxW-16,26);
+ // hex
+ g.fillStyle="#c9a961";
+ g.font='400 15px -apple-system,Arial,sans-serif';
+ g.fillText(c.hex,x+boxW/2,top+boxH*0.62+150);
+ });
+
+ // footer line
+ g.strokeStyle="rgba(245,242,234,0.10)";g.lineWidth=1;
+ g.beginPath();g.moveTo(90,1000);g.lineTo(W-90,1000);g.stroke();
+ g.fillStyle="#8a8578";g.textAlign="left";
+ g.font='400 15px -apple-system,Arial,sans-serif';
+ drawTracked(g,"DESIGNER WALLCOVERINGS — ATELIER EDITION",92,1035,3);
+ g.textAlign="right";
+ drawTracked(g,"DESIGNERWALLCOVERINGS.COM",W-90-tracked(g,"DESIGNERWALLCOVERINGS.COM",3),1035,3);
+
+ // download
+ try{
+ const url=cv.toDataURL("image/png");
+ const a=document.createElement("a");
+ a.href=url;
+ a.download="DW-palette-"+current[2].name.replace(/\s+/g,"")+"-"+Math.round(state.hue)+".png";
+ document.body.appendChild(a);a.click();document.body.removeChild(a);
+ showToast("1080 × 1080 card exported","var(--accent)");
+ }catch(e){ showToast("Export unavailable here","var(--accent)"); }
+ }
+
+ // canvas helpers
+ function roundRect(ctx,x,y,w,h,r){
+ ctx.beginPath();ctx.moveTo(x+r,y);
+ ctx.arcTo(x+w,y,x+w,y+h,r);ctx.arcTo(x+w,y+h,x,y+h,r);
+ ctx.arcTo(x,y+h,x,y,r);ctx.arcTo(x,y,x+w,y,r);ctx.closePath();
+ }
+ function drawTracked(ctx,text,x,y,tr){
+ const prev=ctx.textAlign;ctx.textAlign="left";
+ let cx=x;
+ for(const ch of text){ctx.fillText(ch,cx,y);cx+=ctx.measureText(ch).width+tr;}
+ ctx.textAlign=prev;
+ }
+ function tracked(ctx,text,tr){
+ let w=0;for(const ch of text)w+=ctx.measureText(ch).width+tr;return w-tr;
+ }
+ function wrapCenter(ctx,text,cx,y,maxW,lh){
+ const words=text.split(" ");let line="";const lines=[];
+ for(const w of words){
+ const test=line?line+" "+w:w;
+ if(ctx.measureText(test).width>maxW&&line){lines.push(line);line=w;}
+ else line=test;
+ }
+ if(line)lines.push(line);
+ lines.forEach((ln,i)=>ctx.fillText(ln,cx,y+i*lh));
+ }
+
+ // init
+ render();
+ window.addEventListener("resize",positionKnob);
+ setTimeout(positionKnob,60);
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/98e38ea3773f/claude-code.png b/data/artifacts/98e38ea3773f/claude-code.png
new file mode 100644
index 0000000..3840a13
Binary files /dev/null and b/data/artifacts/98e38ea3773f/claude-code.png differ
diff --git a/data/artifacts/98e38ea3773f/gemma3-12b.html b/data/artifacts/98e38ea3773f/gemma3-12b.html
new file mode 100644
index 0000000..27dd7bd
--- /dev/null
+++ b/data/artifacts/98e38ea3773f/gemma3-12b.html
@@ -0,0 +1,306 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Designer Wallcoverings Palette Builder</title>
+ <style>
+ :root {
+ --bg: #faf8f4;
+ --surface: #ffffff;
+ --text: #1c1a17;
+ --muted: #9b948a;
+ --accent: #b0472e;
+ --line: #ddd;
+ --shadow: rgba(0, 0, 0, 0.12);
+ --ease: cubic-bezier(.22,1,.36,1);
+ }
+
+ body {
+ margin: 0;
+ font-family: system-ui, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
+ background-color: var(--bg);
+ color: var(--text);
+ overflow-x: hidden; /* Prevent horizontal scroll */
+ }
+
+ /* Type Scale */
+ .caption { font-size: 12px; }
+ body { font-size: 16px; }
+ .lead { font-size: 21px; }
+ h3 { font-size: 28px; }
+ h2 { font-size: 38px; }
+ h1 { font-size: 50px; }
+ .display { font-size: 67px; }
+
+ /* Layout */
+ .container {
+ padding: 96px;
+ max-width: 1200px;
+ margin: 0 auto;
+ }
+
+ .wordmark {
+ position: fixed;
+ top: 0;
+ left: 0;
+ padding: 32px;
+ font-family: 'Playfair Display', Georgia, serif;
+ font-size: calc(1em + 1rem); /* ~48px */
+ letter-spacing: .18em;
+ text-transform: uppercase;
+ color: var(--text);
+ z-index: 1000; /* Ensure it's above everything else */
+ }
+
+ .palette-section {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
+ gap: 24px;
+ margin-top: 96px;
+ }
+
+ .swatch {
+ width: 100%;
+ aspect-ratio: 1 / 1;
+ background-color: var(--surface);
+ border-radius: 14px;
+ box-shadow: 0 8px 24px var(--shadow);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-size: 16px;
+ cursor: pointer;
+ transition: transform .2s var(--ease), box-shadow .2s var(--ease);
+ }
+
+ .swatch:hover {
+ transform: scale(1.05);
+ box-shadow: 0 16px 48px var(--shadow);
+ }
+
+ .room-preview {
+ background-color: var(--surface);
+ padding: 32px;
+ border-radius: 14px;
+ margin-top: 32px;
+ text-align: center;
+ }
+
+ .export-button {
+ display: inline-block;
+ background-color: var(--accent);
+ color: white;
+ padding: 16px 32px;
+ border-radius: 14px;
+ text-transform: uppercase;
+ font-size: 12px;
+ letter-spacing: .15em;
+ text-decoration: none;
+ transition: background-color .2s var(--ease);
+ }
+
+ .export-button:hover {
+ background-color: #a03c26; /* Darker shade */
+ }
+
+ .control-panel{
+ margin-top: 32px;
+ display: flex;
+ gap: 16px;
+ align-items: center;
+ }
+
+ .control-button {
+ background-color: var(--surface);
+ border: 1px solid var(--line);
+ padding: 8px 16px;
+ border-radius: 8px;
+ cursor: pointer;
+ font-size: 12px;
+ text-transform: uppercase;
+ letter-spacing: .15em;
+ transition: background-color .2s var(--ease);
+ }
+
+ .control-button:hover {
+ background-color: #f7efe6; /* Lighten on hover */
+ }
+
+ /* Animations - Minimal, subtle */
+ @keyframes fadeUp {
+ from { opacity: 0; transform: translateY(28px); }
+ to { opacity: 1; transform: none; }
+ }
+
+ </style>
+</head>
+<body>
+ <div class="wordmark">DESIGNER WALLCOVERINGS</div>
+
+ <div class="container">
+ <h1>Curated Wallcovering Palettes</h1>
+
+ <div class="palette-section" id="paletteSection">
+ <!-- Swatches will be generated here -->
+ </div>
+
+ <div class="room-preview" id="roomPreview">
+ <h2>Room Preview</h2>
+ <p>Visualize your palette in a room setting. (Placeholder)</p>
+ </div>
+
+ <div class="control-panel">
+ <button class="control-button" id="analogousButton">Analogous</button>
+ <button class="control-button" id="complementaryButton">Complementary</button>
+ <button class="control-button" id="triadicButton">Triadic</button>
+ </div>
+
+ <a href="#" class="export-button" id="exportButton">Export as 1080x1080</a>
+ </div>
+
+ <script>
+ const paletteSection = document.getElementById('paletteSection');
+ const roomPreview = document.getElementById('roomPreview');
+ const exportButton = document.getElementById('exportButton');
+ const analogousButton = document.getElementById('analogousButton');
+ const complementaryButton = document.getElementById('complementaryButton');
+ const triadicButton = document.getElementById('triadicButton');
+
+
+ const hues = ['#e6b8af', '#f2d5c4', '#a7cab3', '#91b0ba', '#d9ccd3']; // Base hues for palettes
+ let currentHueIndex = 0;
+
+ // Palette Styles (Analogous, Complementary, Triadic)
+ const paletteStyles = {
+ analogous: ['Alabaster', 'Linen', 'Sandstone'],
+ complementary: ['Greige', 'Ink', 'Celadon'],
+ triadic: ['Brass', 'Saffron', 'Olive']
+ };
+
+ let currentStyle = 'analogous';
+
+
+ function generatePalette(hueIndex, style) {
+ const hue = hues[hueIndex];
+ paletteSection.innerHTML = ''; // Clear existing swatches
+
+ const paletteColors = [];
+ const colorNames = [];
+
+ switch (style) {
+ case 'analogous':
+ //Analogous Color Scheme - 3 colors near each other on the wheel
+ paletteColors = [hue, darken(hue, 20), lighten(hue, 20)];
+ colorNames = paletteStyles.analogous;
+ break;
+ case 'complementary':
+ //Complementary Color Scheme - Opposite color on the wheel
+ const complementHue = (hueIndex + 5) % hues.length; //Simple Complement
+ paletteColors = [hue, hues[complementHue], lighten(hues[complementHue],20)];
+ colorNames = paletteStyles.complementary;
+ break;
+ case 'triadic':
+ //Triadic Color Scheme - Evenly spaced colors on the wheel
+ const firstColor = (hueIndex + 4) % hues.length;
+ const secondColor = (hueIndex + 2) % hues.length;
+ paletteColors = [hues[firstColor], hues[secondColor], hues[hueIndex]];
+
+ colorNames = paletteStyles.triadic;
+
+ break;
+ default:
+ paletteColors = [hue, darken(hue, 20), lighten(hue, 20)];
+ colorNames = paletteStyles.analogous;
+ }
+
+
+
+ for (let i = 0; i < paletteColors.length; i++) {
+ const swatch = document.createElement('div');
+ swatch.classList.add('swatch');
+ swatch.style.backgroundColor = paletteColors[i];
+ swatch.title = colorNames[i]; //Tooltip for the color name
+
+ swatch.addEventListener('click', function() {
+ navigator.clipboard.writeText(paletteColors[i]); //Copy hex on click
+ });
+
+ paletteSection.appendChild(swatch);
+ }
+ }
+
+
+ function darken(color, amount) {
+ const rgb = hexToRgb(color);
+ const r = Math.max(0, Math.min(255, rgb.r - amount));
+ const g = Math.max(0, Math.min(255, rgb.g - amount));
+ const b = Math.max(0, Math.min(255, rgb.b - amount));
+ return rgbToHex({ r: r, g: g, b: b });
+ }
+
+ function lighten(color, amount) {
+ const rgb = hexToRgb(color);
+ const r = Math.max(0, Math.min(255, rgb.r + amount));
+ const g = Math.max(0, Math.min(255, rgb.g + amount));
+ const b = Math.max(0, Math.min(255, rgb.b + amount));
+ return rgbToHex({ r: r, g: g, b: b });
+ }
+
+ function hexToRgb(hex) {
+ hex = hex.substring(1);
+ const r = parseInt(hex.substring(0, 2), 16);
+ const g = parseInt(hex.substring(2, 4), 16);
+ const b = parseInt(hex.substring(4, 6), 16);
+ return { r: r, g: g, b: b };
+ }
+
+ function rgbToHex(rgb) {
+ const hex = "#" + ((rgb.r < 10 ? "0" : "") + rgb.r.toString(16)) +
+ ((rgb.g < 10 ? "0" : "") + rgb.g.toString(16)) +
+ ((rgb.b < 10 ? "0" : "") + rgb.b.toString(16));
+ return hex;
+ }
+
+
+ // Initial Palette Generation
+ generatePalette(currentHueIndex, currentStyle);
+
+ analogousButton.addEventListener('click', () => {
+ currentStyle = 'analogous';
+ generatePalette(currentHueIndex, currentStyle);
+ });
+
+ complementaryButton.addEventListener('click', () => {
+ currentStyle = 'complementary';
+ generatePalette(currentHueIndex, currentStyle);
+ });
+
+ triadicButton.addEventListener('click', () => {
+ currentStyle = 'triadic';
+ generatePalette(currentHueIndex, currentStyle);
+ });
+
+
+ exportButton.addEventListener('click', (event) =>{
+ // Create a canvas element
+ const canvas = document.createElement('canvas');
+ canvas.width = 260; // Set to your swatch width
+ canvas.height = 260;
+
+ const ctx = canvas.getContext('2d');
+ ctx.fillStyle = paletteSection.children[0].style.backgroundColor; // Use first swatch background
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+
+ // Create a link element
+ const link = document.createElement('a');
+ link.download = 'wallcovering-palette.png';
+ link.href = canvas.toDataURL(); // Convert to data URL
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ });
+
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/98e38ea3773f/gemma3-12b.png b/data/artifacts/98e38ea3773f/gemma3-12b.png
new file mode 100644
index 0000000..4f5fc1f
Binary files /dev/null and b/data/artifacts/98e38ea3773f/gemma3-12b.png differ
diff --git a/data/artifacts/98e38ea3773f/gpt.html b/data/artifacts/98e38ea3773f/gpt.html
new file mode 100644
index 0000000..f6bb453
--- /dev/null
+++ b/data/artifacts/98e38ea3773f/gpt.html
@@ -0,0 +1,1387 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<title>Designer Wallcoverings – Palette Builder</title>
+<style>
+:root {
+ /* Design tokens */
+ --bg: #0d0d0f;
+ --surface: #17171c;
+ --surface-soft: #1e1f25;
+ --ink: #f5f2ea;
+ --muted: #8a8578;
+ --accent: #c9a961; /* brass */
+ --accent-deep: #7d6a45;
+ --line: rgba(245, 242, 234, 0.12);
+ --line-soft: rgba(245, 242, 234, 0.06);
+ --shadow-soft: 0 18px 45px rgba(0, 0, 0, 0.55);
+ --shadow-subtle: 0 12px 30px rgba(0, 0, 0, 0.4);
+
+ --radius-card: 18px;
+ --radius-pill: 999px;
+
+ --font-display: 'Playfair Display', Georgia, 'Times New Roman', serif;
+ --font-sans: 'Avenir Next', 'Helvetica Neue', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
+
+ --fs-caption: 12px;
+ --fs-body: 16px;
+ --fs-lead: 21px;
+ --fs-h3: 28px;
+ --fs-h2: 38px;
+ --fs-h1: 50px;
+
+ --ease-smooth: cubic-bezier(.22,.9,.24,1);
+ --ease-hero: cubic-bezier(.22,1,.36,1);
+
+ --wheel-size: 240px;
+}
+
+/* Global reset */
+*, *::before, *::after {
+ box-sizing: border-box;
+}
+html, body {
+ margin: 0;
+ padding: 0;
+ background: radial-gradient(circle at top, #181820 0, var(--bg) 52%, #050507 100%);
+ color: var(--ink);
+ font-family: var(--font-sans);
+ -webkit-font-smoothing: antialiased;
+ text-rendering: optimizeLegibility;
+}
+body {
+ min-height: 100vh;
+}
+
+/* Layout */
+.app-shell {
+ max-width: 1120px;
+ margin: 0 auto;
+ padding: 88px 32px 40px;
+}
+@media (max-width: 768px) {
+ .app-shell {
+ padding: 80px 20px 32px;
+ }
+}
+
+/* Top bar */
+.top-bar {
+ position: fixed;
+ inset: 0 0 auto 0;
+ height: 64px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0 32px;
+ background: linear-gradient(to bottom, rgba(13,13,15,0.96), rgba(13,13,15,0.9));
+ backdrop-filter: blur(18px);
+ border-bottom: 1px solid rgba(255,255,255,0.04);
+ z-index: 20;
+}
+@media (max-width: 768px) {
+ .top-bar {
+ padding: 0 18px;
+ }
+}
+.wordmark {
+ font-family: var(--font-display);
+ font-size: 17px;
+ line-height: 1.2;
+ letter-spacing: 0.18em;
+ text-transform: uppercase;
+ color: var(--ink);
+ white-space: normal;
+ max-width: 260px;
+}
+.top-meta {
+ display: flex;
+ align-items: center;
+ gap: 18px;
+ font-size: 11px;
+ letter-spacing: 0.18em;
+ text-transform: uppercase;
+ color: var(--muted);
+}
+.pill-label {
+ border-radius: var(--radius-pill);
+ padding: 6px 14px;
+ border: 1px solid rgba(201,169,97,0.4);
+ background: radial-gradient(circle at top left, rgba(201,169,97,0.16), transparent 55%);
+ color: var(--accent);
+}
+
+/* Typography */
+h1, h2, h3 {
+ font-family: var(--font-display);
+ letter-spacing: -0.02em;
+ margin: 0;
+}
+.page-title {
+ font-size: var(--fs-h1);
+ line-height: 1.05;
+ margin-bottom: 10px;
+}
+.lede {
+ font-size: var(--fs-lead);
+ max-width: 44rem;
+ color: var(--muted);
+ line-height: 1.6;
+}
+.label {
+ font-size: 11px;
+ letter-spacing: 0.18em;
+ text-transform: uppercase;
+ color: var(--muted);
+}
+
+/* Cards & surfaces */
+.card {
+ background: radial-gradient(circle at top, rgba(255,255,255,0.02), transparent 55%),
+ linear-gradient(to bottom, rgba(23,23,28,0.96), rgba(9,9,11,0.98));
+ border-radius: var(--radius-card);
+ border: 1px solid var(--line-soft);
+ box-shadow: var(--shadow-soft);
+ padding: 22px 22px 20px;
+ position: relative;
+ overflow: hidden;
+}
+.card::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ pointer-events: none;
+ background: linear-gradient(135deg, rgba(201,169,97,0.16), transparent 55%);
+ mix-blend-mode: soft-light;
+ opacity: 0.45;
+}
+.card-inner {
+ position: relative;
+ z-index: 1;
+}
+.grid {
+ display: grid;
+ grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
+ gap: 26px;
+ margin-top: 22px;
+}
+@media (max-width: 900px) {
+ .grid {
+ grid-template-columns: minmax(0, 1fr);
+ }
+}
+
+/* Controls */
+.controls {
+ display: flex;
+ flex-direction: column;
+ gap: 18px;
+}
+.mode-toggle {
+ display: inline-flex;
+ align-items: center;
+ border-radius: var(--radius-pill);
+ border: 1px solid var(--line);
+ background: rgba(10,10,13,0.9);
+ padding: 2px;
+ gap: 2px;
+}
+.mode-btn {
+ flex: 1;
+ border: none;
+ background: transparent;
+ color: var(--muted);
+ font-family: var(--font-sans);
+ font-size: 11px;
+ letter-spacing: 0.18em;
+ text-transform: uppercase;
+ padding: 9px 10px;
+ border-radius: calc(var(--radius-pill) - 1px);
+ cursor: pointer;
+ transition: background 160ms var(--ease-smooth), color 160ms var(--ease-smooth), transform 160ms var(--ease-smooth), box-shadow 160ms var(--ease-smooth);
+}
+.mode-btn[data-active="true"] {
+ background: radial-gradient(circle at top, rgba(201,169,97,0.33), rgba(201,169,97,0.2) 40%, rgba(13,13,15,0.95) 100%);
+ color: var(--ink);
+ box-shadow: 0 0 0 1px rgba(201,169,97,0.7), 0 0 22px rgba(201,169,97,0.24);
+ transform: translateY(-0.5px);
+}
+
+/* Hue wheel */
+.wheel-wrapper {
+ display: grid;
+ grid-template-columns: auto minmax(0, 1fr);
+ gap: 24px;
+ align-items: center;
+}
+@media (max-width: 720px) {
+ .wheel-wrapper {
+ grid-template-columns: minmax(0, 1fr);
+ }
+}
+.hue-wheel {
+ width: var(--wheel-size);
+ height: var(--wheel-size);
+ border-radius: 50%;
+ position: relative;
+ border: 1px solid var(--line);
+ box-shadow: var(--shadow-subtle);
+ background:
+ conic-gradient(
+ hsl(0,70%,52%),
+ hsl(30,70%,50%),
+ hsl(60,70%,50%),
+ hsl(90,60%,48%),
+ hsl(150,60%,50%),
+ hsl(200,70%,55%),
+ hsl(260,70%,60%),
+ hsl(300,70%,55%),
+ hsl(330,70%,52%),
+ hsl(360,70%,52%)
+ );
+ cursor: crosshair;
+ overflow: visible;
+}
+.hue-wheel::before {
+ content: '';
+ position: absolute;
+ inset: 12%;
+ border-radius: 50%;
+ background: radial-gradient(circle at top, rgba(0,0,0,0.12), rgba(0,0,0,0.85));
+ border: 1px solid rgba(255,255,255,0.04);
+}
+.wheel-knob {
+ position: absolute;
+ width: 22px;
+ height: 22px;
+ border-radius: 999px;
+ border: 2px solid var(--ink);
+ background: #000;
+ box-shadow: 0 0 0 3px rgba(0,0,0,0.7), 0 0 18px rgba(0,0,0,0.5);
+ transform: translate(-50%, -50%);
+ pointer-events: none;
+}
+
+/* Hue readout */
+.hue-meta {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+}
+.hue-angle {
+ font-family: var(--font-display);
+ font-size: 32px;
+ letter-spacing: 0.06em;
+ text-transform: uppercase;
+}
+.hue-chip-row {
+ display: flex;
+ align-items: center;
+ gap: 14px;
+}
+.hue-chip {
+ width: 32px;
+ height: 32px;
+ border-radius: 999px;
+ border: 1px solid rgba(255,255,255,0.4);
+ box-shadow: 0 0 0 1px rgba(0,0,0,0.7), 0 0 12px rgba(0,0,0,0.7);
+}
+.hue-name {
+ font-size: 13px;
+ letter-spacing: 0.18em;
+ text-transform: uppercase;
+ color: var(--muted);
+}
+
+/* Palette swatches */
+.palette-card {
+ display: flex;
+ flex-direction: column;
+ gap: 18px;
+}
+.swatch-row {
+ display: grid;
+ grid-template-columns: repeat(5, minmax(0, 1fr));
+ gap: 10px;
+}
+@media (max-width: 520px) {
+ .swatch-row {
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ }
+}
+.swatch {
+ position: relative;
+ border-radius: 14px;
+ overflow: hidden;
+ border: 1px solid rgba(255,255,255,0.06);
+ cursor: pointer;
+ min-height: 110px;
+ display: flex;
+ align-items: flex-end;
+ padding: 10px 11px;
+ transition: transform 150ms var(--ease-smooth), box-shadow 150ms var(--ease-smooth), border-color 150ms var(--ease-smooth), background-position 260ms var(--ease-smooth);
+ box-shadow: 0 10px 26px rgba(0,0,0,0.6);
+}
+.swatch:hover {
+ transform: translateY(-3px);
+ box-shadow: 0 16px 40px rgba(0,0,0,0.7);
+ border-color: rgba(201,169,97,0.7);
+}
+.swatch-meta {
+ position: relative;
+ z-index: 1;
+}
+.swatch-name {
+ font-family: var(--font-display);
+ font-size: 15px;
+ line-height: 1.2;
+}
+.swatch-hex {
+ font-size: 11px;
+ letter-spacing: 0.18em;
+ text-transform: uppercase;
+ opacity: 0.85;
+ margin-top: 2px;
+}
+
+/* Motifs */
+.motif-overlay {
+ position: absolute;
+ inset: 0;
+ opacity: 0.7;
+ mix-blend-mode: soft-light;
+ pointer-events: none;
+}
+
+/* Different motifs for visual distinction */
+.motif-linen {
+ background-image:
+ linear-gradient(to bottom, rgba(255,255,255,0.12) 1px, transparent 1px),
+ linear-gradient(to right, rgba(255,255,255,0.08) 1px, transparent 1px);
+ background-size: 100% 18px, 22px 100%;
+}
+.motif-brush {
+ background-image:
+ linear-gradient(135deg, rgba(255,255,255,0.12) 8%, transparent 8%, transparent 50%, rgba(255,255,255,0.08) 55%, transparent 55%);
+ background-size: 40px 40px;
+}
+.motif-geo {
+ background-image:
+ radial-gradient(circle at 0 0, rgba(255,255,255,0.16) 0, rgba(255,255,255,0.16) 2px, transparent 2px),
+ radial-gradient(circle at 100% 100%, rgba(255,255,255,0.12) 0, rgba(255,255,255,0.12) 2px, transparent 2px);
+ background-size: 22px 22px;
+}
+.motif-stripe {
+ background-image:
+ linear-gradient(120deg, rgba(255,255,255,0.08) 16%, transparent 16%, transparent 50%, rgba(255,255,255,0.04) 52%, transparent 52%);
+ background-size: 26px 26px;
+}
+.motif-marble {
+ background-image:
+ radial-gradient(circle at 10% 0, rgba(255,255,255,0.2), transparent 55%),
+ radial-gradient(circle at 90% 80%, rgba(255,255,255,0.22), transparent 55%);
+ filter: blur(0.2px);
+}
+
+/* Palette footer */
+.palette-footer {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 10px;
+ margin-top: 4px;
+ font-size: 12px;
+ color: var(--muted);
+}
+@media (max-width: 520px) {
+ .palette-footer {
+ flex-direction: column;
+ align-items: flex-start;
+ }
+}
+.copy-hint {
+ font-size: 11px;
+ letter-spacing: 0.16em;
+ text-transform: uppercase;
+}
+
+/* Room preview */
+.preview-card {
+ margin-top: 18px;
+}
+.preview-strip {
+ border-radius: 14px;
+ overflow: hidden;
+ border: 1px solid rgba(255,255,255,0.08);
+ background: #111115;
+ box-shadow: 0 14px 36px rgba(0,0,0,0.7);
+}
+.preview-inner {
+ display: grid;
+ grid-template-columns: 7fr 5fr;
+ min-height: 190px;
+}
+@media (max-width: 720px) {
+ .preview-inner {
+ grid-template-columns: minmax(0, 1.1fr);
+ }
+}
+.preview-wall {
+ position: relative;
+ overflow: hidden;
+}
+.preview-wall::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ mix-blend-mode: soft-light;
+ background-image:
+ linear-gradient(to bottom, rgba(255,255,255,0.1) 1px, transparent 1px),
+ linear-gradient(to right, rgba(255,255,255,0.05) 1px, transparent 1px);
+ background-size: 100% 22px, 26px 100%;
+ opacity: 0.75;
+}
+.preview-wall-panels {
+ position: absolute;
+ inset: 0;
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+}
+.preview-panel {
+ border-right: 1px solid rgba(0,0,0,0.3);
+}
+.preview-panel:last-child {
+ border-right: none;
+}
+.preview-floor {
+ background: radial-gradient(circle at top, rgba(255,255,255,0.06), rgba(0,0,0,1));
+ position: relative;
+}
+.preview-floor::before {
+ content: '';
+ position: absolute;
+ inset: 40% 10% 0 0;
+ background-image: linear-gradient(120deg, rgba(0,0,0,0.7) 0, rgba(0,0,0,0.2) 30%, rgba(0,0,0,0.9) 100%);
+ border-radius: 120px 30px 0 0;
+ box-shadow: 0 -18px 40px rgba(0,0,0,0.84);
+}
+.preview-sofa {
+ position: absolute;
+ inset: 36% 10% 0 10%;
+ border-radius: 18px 18px 8px 8px;
+ box-shadow: 0 18px 32px rgba(0,0,0,0.85);
+ background:
+ linear-gradient(to bottom, rgba(255,255,255,0.12), transparent 38%),
+ linear-gradient(135deg, rgba(0,0,0,0.7), rgba(0,0,0,0.98));
+ border: 1px solid rgba(255,255,255,0.12);
+}
+.preview-cushions {
+ position: absolute;
+ inset: 8% 14% 36% 16%;
+ display: flex;
+ gap: 6px;
+}
+.preview-cushion {
+ flex: 1;
+ border-radius: 9px;
+ border: 1px solid rgba(255,255,255,0.18);
+ box-shadow: 0 6px 10px rgba(0,0,0,0.7);
+ background:
+ linear-gradient(to bottom, rgba(255,255,255,0.2), transparent 32%),
+ linear-gradient(130deg, rgba(0,0,0,0.7), rgba(0,0,0,0.97));
+}
+.preview-meta {
+ padding: 18px 18px 16px 18px;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+}
+.preview-heading {
+ font-family: var(--font-display);
+ font-size: 21px;
+ letter-spacing: 0.12em;
+ text-transform: uppercase;
+}
+.preview-body {
+ font-size: 13px;
+ color: var(--muted);
+ line-height: 1.6;
+}
+.tag-row {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ margin-top: 10px;
+}
+.tag {
+ border-radius: 999px;
+ padding: 5px 10px;
+ border: 1px solid rgba(255,255,255,0.08);
+ font-size: 11px;
+ letter-spacing: 0.16em;
+ text-transform: uppercase;
+ color: var(--muted);
+}
+
+/* Buttons */
+.btn-row {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10px;
+ align-items: center;
+}
+.btn {
+ position: relative;
+ border-radius: var(--radius-pill);
+ border: 1px solid rgba(201,169,97,0.7);
+ background: radial-gradient(circle at top, rgba(201,169,97,0.46), rgba(201,169,97,0.24) 40%, rgba(13,13,15,0.95) 100%);
+ color: var(--ink);
+ font-family: var(--font-sans);
+ font-size: 11px;
+ letter-spacing: 0.18em;
+ text-transform: uppercase;
+ padding: 10px 18px 9px;
+ cursor: pointer;
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ box-shadow: 0 16px 36px rgba(0,0,0,0.8);
+ transition: transform 130ms var(--ease-smooth), box-shadow 130ms var(--ease-smooth), background 130ms var(--ease-smooth);
+}
+.btn:hover {
+ transform: translateY(-1px);
+ box-shadow: 0 20px 42px rgba(0,0,0,0.9);
+}
+.btn:active {
+ transform: translateY(0);
+ box-shadow: 0 12px 26px rgba(0,0,0,0.85);
+}
+.btn-outline {
+ border-color: rgba(255,255,255,0.4);
+ background: rgba(10,10,13,0.8);
+ color: var(--muted);
+ box-shadow: 0 10px 24px rgba(0,0,0,0.75);
+}
+.btn-outline:hover {
+ background: rgba(20,20,25,0.96);
+}
+
+/* Toast */
+.toast {
+ position: fixed;
+ inset: auto 0 26px 0;
+ display: flex;
+ justify-content: center;
+ pointer-events: none;
+ z-index: 40;
+}
+.toast-inner {
+ min-width: 260px;
+ max-width: 340px;
+ border-radius: 999px;
+ background: rgba(13,13,15,0.96);
+ border: 1px solid rgba(201,169,97,0.7);
+ box-shadow: 0 18px 40px rgba(0,0,0,0.9);
+ padding: 9px 18px 10px;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ font-size: 12px;
+ letter-spacing: 0.16em;
+ text-transform: uppercase;
+ color: var(--ink);
+}
+.toast-icon {
+ width: 14px;
+ height: 14px;
+ border-radius: 999px;
+ border: 1px solid rgba(201,169,97,0.9);
+ background: radial-gradient(circle at top, rgba(201,169,97,0.9), rgba(120,94,38,0.8));
+}
+
+/* Export overlay */
+.overlay {
+ position: fixed;
+ inset: 0;
+ background: radial-gradient(circle at top, rgba(0,0,0,0.76), rgba(0,0,0,0.96));
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 20px;
+ z-index: 50;
+}
+.overlay-panel {
+ max-width: 520px;
+ width: 100%;
+ border-radius: 20px;
+ background: linear-gradient(to bottom right, #17171c, #050507);
+ border: 1px solid var(--line);
+ box-shadow: 0 24px 60px rgba(0,0,0,0.95);
+ padding: 22px 22px 18px;
+ position: relative;
+}
+.overlay-panel::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: radial-gradient(circle at top left, rgba(201,169,97,0.26), transparent 55%);
+ mix-blend-mode: soft-light;
+ opacity: 0.9;
+}
+.overlay-content {
+ position: relative;
+ z-index: 1;
+}
+.overlay-title {
+ font-family: var(--font-display);
+ font-size: 28px;
+ margin-bottom: 6px;
+}
+.overlay-body {
+ font-size: 14px;
+ color: var(--muted);
+ line-height: 1.6;
+}
+.overlay-footer {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-top: 18px;
+ gap: 10px;
+ font-size: 11px;
+ color: var(--muted);
+}
+
+/* Hidden export canvas container */
+#exportCanvas {
+ display: none;
+}
+</style>
+</head>
+<body>
+<header class="top-bar">
+ <div class="wordmark">DESIGNER<br>WALLCOVERINGS</div>
+ <div class="top-meta">
+ <span>PALETTE BUILDER</span>
+ <span class="pill-label">SOCIAL-READY 1080×1080</span>
+ </div>
+</header>
+
+<main class="app-shell">
+ <section>
+ <h1 class="page-title">Curate a wallcovering story.</h1>
+ <p class="lede">Pick a hue, choose a relationship, and we’ll pour it into five-room harmony – from alabaster to ink, brass to evening celadon – ready to share as a 1080×1080 card.</p>
+ </section>
+
+ <section class="grid">
+ <!-- Left: Controls -->
+ <article class="card">
+ <div class="card-inner controls">
+ <div>
+ <div class="label">1 · Choose hue</div>
+ <div class="wheel-wrapper" style="margin-top:10px;">
+ <div class="hue-wheel" id="hueWheel">
+ <div class="wheel-knob" id="wheelKnob"></div>
+ </div>
+ <div class="hue-meta">
+ <div class="hue-angle" id="hueAngle">214°</div>
+ <div class="hue-chip-row">
+ <div class="hue-chip" id="hueChip"></div>
+ <div>
+ <div class="hue-name" id="hueDescriptor">Ink & Brass</div>
+ <div class="label" style="margin-top:4px;">Base wall hue</div>
+ </div>
+ </div>
+ <p style="font-size:13px; color:var(--muted); line-height:1.7; max-width:26rem;margin-top:8px;">
+ Drag around the wheel to dial your anchor hue. We’ll keep the values refined – no neon, no mud – so the palette stays gallery-ready.
+ </p>
+ </div>
+ </div>
+ </div>
+
+ <div>
+ <div class="label">2 · Palette relationship</div>
+ <div class="mode-toggle" style="margin-top:8px;">
+ <button class="mode-btn" data-mode="analogous" data-active="true">Analogous</button>
+ <button class="mode-btn" data-mode="complementary">Complementary</button>
+ <button class="mode-btn" data-mode="triadic">Triadic</button>
+ </div>
+ </div>
+ </div>
+ </article>
+
+ <!-- Right: Palette & preview -->
+ <article class="card">
+ <div class="card-inner palette-card">
+ <div>
+ <div class="label">3 · Curated five-swatch palette</div>
+ <div class="swatch-row" id="swatchRow">
+ <!-- Swatches injected by JS -->
+ </div>
+ <div class="palette-footer">
+ <span class="copy-hint">Tap a swatch to copy its hex.</span>
+ <div class="btn-row">
+ <button class="btn-outline btn" id="shuffleNamesBtn" type="button">Rename palette</button>
+ <button class="btn" id="exportBtn" type="button">
+ <span style="width:10px;height:10px;border-radius:50%;border:1px solid currentColor;display:inline-block;box-shadow:0 0 0 1px rgba(0,0,0,0.6);"></span>
+ Export 1080×1080
+ </button>
+ </div>
+ </div>
+ </div>
+
+ <div class="preview-card">
+ <div class="label" style="margin-bottom:8px;">4 · Room preview</div>
+ <div class="preview-strip">
+ <div class="preview-inner">
+ <div class="preview-wall" id="previewWall">
+ <div class="preview-wall-panels" id="previewPanels"></div>
+ <div class="preview-floor">
+ <div class="preview-sofa" id="previewSofa"></div>
+ <div class="preview-cushions" id="previewCushions"></div>
+ </div>
+ </div>
+ <div class="preview-meta">
+ <div>
+ <div class="preview-heading" id="previewTitle">Nocturne with Brass</div>
+ <p class="preview-body" id="previewCopy">
+ A tailored mix of alabaster, greige, celadon and ink, anchored with a soft brass highlight – designed for quiet confidence on gallery walls.
+ </p>
+ </div>
+ <div>
+ <div class="tag-row" id="tagRow">
+ <!-- Tags injected -->
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </article>
+ </section>
+</main>
+
+<!-- Toast container -->
+<div id="toast" style="display:none;" aria-live="polite"></div>
+
+<!-- Export overlay template (hidden by default) -->
+<div id="overlay" style="display:none;"></div>
+
+<canvas id="exportCanvas" width="1080" height="1080"></canvas>
+
+<script>
+(function() {
+ const TAU = Math.PI * 2;
+
+ /* Palette names */
+ const swatchNamesBase = ["Alabaster", "Greige", "Celadon", "Ink", "Brass"];
+ const paletteTitleTemplates = [
+ "{primary} with {metal}",
+ "Evening {stone}",
+ "{herb} Study",
+ "{ink} & Light",
+ "Quiet {stone}",
+ ];
+ const descriptorPairs = [
+ ["Alabaster", "Brass"],
+ ["Smoke", "Gold"],
+ ["Ink", "Brass"],
+ ["Chalk", "Gilt"],
+ ["Porcelain", "Bronze"],
+ ];
+ const tagsSource = [
+ "Wallcovering Story",
+ "Livable Luxury",
+ "Soft Contrast",
+ "Analog Harmony",
+ "Triadic Focus",
+ "Complement Pairing",
+ "Social-Ready"
+ ];
+
+ /* DOM refs */
+ const hueWheel = document.getElementById('hueWheel');
+ const wheelKnob = document.getElementById('wheelKnob');
+ const hueAngleEl = document.getElementById('hueAngle');
+ const hueChip = document.getElementById('hueChip');
+ const hueDescriptorEl = document.getElementById('hueDescriptor');
+ const swatchRow = document.getElementById('swatchRow');
+ const modeButtons = Array.from(document.querySelectorAll('.mode-btn'));
+ const previewWall = document.getElementById('previewWall');
+ const previewPanels = document.getElementById('previewPanels');
+ const previewSofa = document.getElementById('previewSofa');
+ const previewCushions = document.getElementById('previewCushions');
+ const previewTitle = document.getElementById('previewTitle');
+ const previewCopy = document.getElementById('previewCopy');
+ const tagRow = document.getElementById('tagRow');
+ const toastRoot = document.getElementById('toast');
+ const shuffleNamesBtn = document.getElementById('shuffleNamesBtn');
+ const exportBtn = document.getElementById('exportBtn');
+ const overlayRoot = document.getElementById('overlay');
+ const exportCanvas = document.getElementById('exportCanvas');
+ const ctx = exportCanvas.getContext('2d');
+
+ let currentHue = 214; // starting hue
+ let currentMode = 'analogous';
+ let currentSwatches = [];
+ let currentNames = swatchNamesBase.slice();
+ let currentPaletteTitle = "Nocturne with Brass";
+
+ function hslToHex(h, s, l) {
+ s /= 100;
+ l /= 100;
+ const k = n => (n + h / 30) % 12;
+ const a = s * Math.min(l, 1 - l);
+ const f = n => {
+ const v = l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));
+ return Math.round(255 * v).toString(16).padStart(2, '0');
+ };
+ return `#${f(0)}${f(8)}${f(4)}`;
+ }
+
+ /* Descriptor based on hue */
+ function descriptorForHue(h) {
+ if (h >= 200 && h <= 260) return "Ink & Brass";
+ if (h >= 40 && h <= 80) return "Warm Sand & Gilt";
+ if (h >= 90 && h <= 160) return "Celadon Evening";
+ if (h >= 0 && h < 30) return "Rouge Salon";
+ if (h >= 300 || h < 10) return "Velvet Plum";
+ if (h >= 160 && h < 200) return "Olive Study";
+ if (h > 260 && h < 300) return "Twilight Mauve";
+ return "Gallery Neutral";
+ }
+
+ function computePalette(hue, mode) {
+ const offsets = {
+ analogous: [-18, -6, 0, 10, 22],
+ complementary: [-22, -10, 0, 180, 195],
+ triadic: [-4, 0, 120, 180, 240]
+ }[mode];
+
+ const baseS = 26;
+ const baseL = 26;
+
+ const stops = offsets.map((off, idx) => {
+ let h = (hue + off + 360) % 360;
+
+ let s = baseS;
+ let l = baseL;
+ if (idx === 0) { s = 10; l = 92; } // Alabaster
+ if (idx === 1) { s = 9; l = 65; } // Greige
+ if (idx === 2) { s = 20; l = 52; } // Celadon / mid
+ if (idx === 3) { s = 25; l = 16; } // Ink
+ if (idx === 4) { s = 52; l = 52; } // Brass / accent
+
+ const hex = hslToHex(h, s, l);
+ return {
+ h, s, l, hex
+ };
+ });
+ return stops;
+ }
+
+ function placeKnob(angleDeg) {
+ const rect = hueWheel.getBoundingClientRect();
+ const radius = rect.width / 2;
+ const cx = radius;
+ const cy = radius;
+ const angleRad = (angleDeg - 90) * Math.PI / 180;
+ const r = radius - 6;
+ const x = cx + r * Math.cos(angleRad);
+ const y = cy + r * Math.sin(angleRad);
+ wheelKnob.style.left = `${x}px`;
+ wheelKnob.style.top = `${y}px`;
+ }
+
+ function angleFromEvent(e) {
+ const rect = hueWheel.getBoundingClientRect();
+ const cx = rect.left + rect.width / 2;
+ const cy = rect.top + rect.height / 2;
+ const x = ('touches' in e ? e.touches[0].clientX : e.clientX) - cx;
+ const y = ('touches' in e ? e.touches[0].clientY : e.clientY) - cy;
+ const radians = Math.atan2(y, x);
+ let deg = radians * 180 / Math.PI + 90;
+ if (deg < 0) deg += 360;
+ return deg;
+ }
+
+ function updateHue(h) {
+ currentHue = Math.round(h) % 360;
+ hueAngleEl.textContent = `${currentHue}°`;
+ const baseHex = hslToHex(currentHue, 40, 50);
+ hueChip.style.background = baseHex;
+ hueDescriptorEl.textContent = descriptorForHue(currentHue);
+ regeneratePalette();
+ }
+
+ function motifClassForIndex(i) {
+ return [
+ "motif-linen",
+ "motif-marble",
+ "motif-geo",
+ "motif-brush",
+ "motif-stripe"
+ ][i % 5];
+ }
+
+ function regeneratePalette() {
+ currentSwatches = computePalette(currentHue, currentMode);
+ renderSwatches();
+ renderPreview();
+ }
+
+ function renderSwatches() {
+ swatchRow.innerHTML = "";
+ currentSwatches.forEach((sw, idx) => {
+ const swatch = document.createElement('button');
+ swatch.type = "button";
+ swatch.className = "swatch";
+ swatch.dataset.hex = sw.hex;
+ swatch.style.background = sw.hex;
+ swatch.style.color = sw.l < 40 ? "rgba(245,242,234,0.9)" : "#050507";
+ const motif = document.createElement('div');
+ motif.className = `motif-overlay ${motifClassForIndex(idx)}`;
+ const meta = document.createElement('div');
+ meta.className = "swatch-meta";
+ const nameEl = document.createElement('div');
+ nameEl.className = "swatch-name";
+ nameEl.textContent = currentNames[idx] || swatchNamesBase[idx] || `Shade ${idx+1}`;
+ const hexEl = document.createElement('div');
+ hexEl.className = "swatch-hex";
+ hexEl.textContent = sw.hex.toUpperCase();
+ meta.appendChild(nameEl);
+ meta.appendChild(hexEl);
+ swatch.appendChild(motif);
+ swatch.appendChild(meta);
+ swatchRow.appendChild(swatch);
+ });
+ }
+
+ function renderPreview() {
+ previewPanels.innerHTML = "";
+ const wallColor = currentSwatches[2]?.hex || "#181820";
+ const panelColors = [
+ currentSwatches[1]?.hex || wallColor,
+ wallColor,
+ currentSwatches[3]?.hex || wallColor,
+ currentSwatches[0]?.hex || wallColor
+ ];
+ panelColors.forEach((hex, idx) => {
+ const div = document.createElement('div');
+ div.className = "preview-panel";
+ div.style.background = hex;
+ div.style.boxShadow = idx === 1
+ ? "inset 0 0 80px rgba(0,0,0,0.55)"
+ : "inset 0 0 40px rgba(0,0,0,0.4)";
+ previewPanels.appendChild(div);
+ });
+
+ const sofaColor = currentSwatches[0]?.hex || "#dcd6c8";
+ const cushion1 = currentSwatches[3]?.hex || "#22242b";
+ const cushion2 = currentSwatches[4]?.hex || "#c9a961";
+ const cushion3 = currentSwatches[2]?.hex || "#6a7b73";
+
+ previewSofa.style.background = `
+ linear-gradient(to bottom, rgba(255,255,255,0.12), transparent 38%),
+ linear-gradient(135deg, ${sofaColor}, #000000)
+ `;
+ previewCushions.innerHTML = "";
+ [cushion1, cushion2, cushion3].forEach((hex, idx) => {
+ const c = document.createElement('div');
+ c.className = "preview-cushion";
+ c.style.background = `
+ linear-gradient(to bottom, rgba(255,255,255,0.18), transparent 32%),
+ linear-gradient(135deg, ${hex}, #000000)
+ `;
+ if (idx === 1) {
+ c.style.boxShadow = "0 10px 16px rgba(0,0,0,0.95)";
+ }
+ previewCushions.appendChild(c);
+ });
+
+ // Title and copy
+ previewTitle.innerHTML = currentPaletteTitle;
+ const primary = currentNames[2] || "Celadon";
+ const metal = currentNames[4] || "Brass";
+ const stone = currentNames[1] || "Greige";
+ const ink = currentNames[3] || "Ink";
+ const herb = currentNames[2] || "Celadon";
+ const template = paletteTitleTemplates[Math.floor(Math.random() * paletteTitleTemplates.length)];
+ currentPaletteTitle = template
+ .replace("{primary}", primary)
+ .replace("{metal}", metal)
+ .replace("{stone}", stone)
+ .replace("{ink}", ink)
+ .replace("{herb}", herb);
+ previewTitle.innerHTML = currentPaletteTitle;
+
+ previewCopy.innerHTML =
+ `A composed mix of ${currentNames.join(", ").toLowerCase()} – tuned for high contrast without harshness, and ready to pull across walls, upholstery and small brass moments.`;
+
+ // Tags
+ tagRow.innerHTML = "";
+ shuffleArray(tagsSource.slice()).slice(0,3).forEach(tag => {
+ const span = document.createElement('span');
+ span.className = "tag";
+ span.textContent = tag;
+ tagRow.appendChild(span);
+ });
+ }
+
+ function shuffleArray(arr) {
+ const a = arr.slice();
+ for (let i = a.length - 1; i > 0; i--) {
+ const j = Math.floor(Math.random() * (i + 1));
+ [a[i], a[j]] = [a[j], a[i]];
+ }
+ return a;
+ }
+
+ function showToast(message) {
+ toastRoot.innerHTML = "";
+ const inner = document.createElement('div');
+ inner.className = "toast-inner";
+ inner.innerHTML = `<div class="toast-icon"></div><span>${message}</span>`;
+ toastRoot.appendChild(inner);
+ toastRoot.style.display = "flex";
+ inner.style.opacity = "0";
+ inner.style.transform = "translateY(12px)";
+ requestAnimationFrame(() => {
+ inner.style.transition = "opacity 260ms var(--ease-hero), transform 260ms var(--ease-hero)";
+ inner.style.opacity = "1";
+ inner.style.transform = "translateY(0)";
+ });
+ setTimeout(() => {
+ inner.style.opacity = "0";
+ inner.style.transform = "translateY(10px)";
+ setTimeout(() => {
+ toastRoot.style.display = "none";
+ }, 260);
+ }, 1450);
+ }
+
+ function copyHex(hex) {
+ if (navigator.clipboard && navigator.clipboard.writeText) {
+ navigator.clipboard.writeText(hex).then(() => {
+ showToast(`${hex.toUpperCase()} copied`);
+ });
+ } else {
+ const temp = document.createElement('textarea');
+ temp.value = hex;
+ document.body.appendChild(temp);
+ temp.select();
+ document.execCommand('copy');
+ document.body.removeChild(temp);
+ showToast(`${hex.toUpperCase()} copied`);
+ }
+ }
+
+ function randomiseNames() {
+ const sets = [
+ ["Alabaster", "Warm Greige", "Celadon Mist", "Midnight Ink", "Soft Brass"],
+ ["Chalk", "Stone", "Sage", "Ink", "Old Gold"],
+ ["Porcelain", "Fog", "Olive Leaf", "Night Blue", "Antique Brass"],
+ ["Ivory", "Greige", "Willow", "Ink", "Brushed Brass"],
+ ];
+ currentNames = sets[Math.floor(Math.random() * sets.length)];
+ renderSwatches();
+ renderPreview();
+ }
+
+ function openOverlay(message) {
+ overlayRoot.innerHTML = "";
+ overlayRoot.style.display = "flex";
+ overlayRoot.className = "overlay";
+ const panel = document.createElement('div');
+ panel.className = "overlay-panel";
+ const content = document.createElement('div');
+ content.className = "overlay-content";
+ content.innerHTML = `
+ <div class="label">Export complete</div>
+ <h2 class="overlay-title">Your square is ready.</h2>
+ <p class="overlay-body">
+ We’ve rendered a 1080×1080 card with your current palette and room story. Save it directly from your browser’s download prompt – perfect for moodboards, decks and social.
+ </p>
+ <div class="overlay-footer">
+ <span>${message}</span>
+ <button class="btn-outline btn" type="button" id="overlayCloseBtn">Close</button>
+ </div>
+ `;
+ panel.appendChild(content);
+ overlayRoot.appendChild(panel);
+
+ const btn = content.querySelector('#overlayCloseBtn');
+ btn.addEventListener('click', () => {
+ overlayRoot.style.display = "none";
+ });
+ }
+
+ /* Export to 1080x1080 canvas */
+ function exportCard() {
+ const w = exportCanvas.width;
+ const h = exportCanvas.height;
+
+ // Background
+ const grad = ctx.createLinearGradient(0, 0, 0, h);
+ grad.addColorStop(0, "#050507");
+ grad.addColorStop(0.45, "#121218");
+ grad.addColorStop(1, "#050507");
+ ctx.fillStyle = grad;
+ ctx.fillRect(0, 0, w, h);
+
+ // Inner frame
+ const margin = 80;
+ const innerW = w - margin * 2;
+ const innerH = h - margin * 2;
+ const x0 = margin;
+ const y0 = margin;
+
+ ctx.strokeStyle = "rgba(255,255,255,0.14)";
+ ctx.lineWidth = 1;
+ ctx.strokeRect(x0 + 0.5, y0 + 0.5, innerW - 1, innerH - 1);
+
+ // Palette bar
+ const swW = innerW / 5 - 8;
+ const swH = 220;
+ const swY = y0 + 32;
+ ctx.font = "14px " + getComputedStyle(document.body).fontFamily;
+ ctx.textBaseline = "top";
+
+ currentSwatches.forEach((sw, idx) => {
+ const swX = x0 + idx * (swW + 8);
+ const radius = 26;
+ drawRoundedRect(ctx, swX, swY, swW, swH, radius, sw.hex);
+
+ // Names + hex
+ ctx.fillStyle = sw.l < 40 ? "rgba(245,242,234,0.95)" : "#050507";
+ ctx.font = "19px " + getComputedStyle(document.body).fontFamily.replace(/,? -apple-system[^,]*/g, '');
+ ctx.fillText(currentNames[idx] || swatchNamesBase[idx], swX + 18, swY + swH - 70);
+ ctx.font = "11px " + getComputedStyle(document.body).fontFamily;
+ ctx.fillText(sw.hex.toUpperCase(), swX + 18, swY + swH - 48);
+ });
+
+ // Room strip simplified
+ const roomY = swY + swH + 40;
+ const roomH = 260;
+ const wallColor = currentSwatches[2]?.hex || "#181820";
+ const floorColor = "#050507";
+
+ // Wall
+ const wallGrad = ctx.createLinearGradient(0, roomY, 0, roomY + roomH * 0.7);
+ wallGrad.addColorStop(0, lighten(wallColor, 0.08));
+ wallGrad.addColorStop(1, darken(wallColor, 0.08));
+ ctx.fillStyle = wallGrad;
+ ctx.fillRect(x0 + 10, roomY, innerW - 20, roomH * 0.7);
+
+ // Floor
+ const floorY = roomY + roomH * 0.7;
+ const floorGrad = ctx.createLinearGradient(0, floorY, 0, floorY + roomH * 0.3);
+ floorGrad.addColorStop(0, lighten(floorColor, 0.04));
+ floorGrad.addColorStop(1, floorColor);
+ ctx.fillStyle = floorGrad;
+ ctx.fillRect(x0 + 10, floorY, innerW - 20, roomH * 0.3);
+
+ // Sofa block
+ const sofaColor = currentSwatches[0]?.hex || "#dcd6c8";
+ const sofaX = x0 + 90;
+ const sofaY = floorY - 40;
+ const sofaW = innerW - 220;
+ const sofaH = 90;
+ drawRoundedRect(ctx, sofaX, sofaY, sofaW, sofaH, 20, sofaColor);
+
+ // Cushions (3 blocks)
+ const cW = 52;
+ const cH = 50;
+ const cY = sofaY - 28;
+ const cColors = [
+ currentSwatches[3]?.hex || "#22242b",
+ currentSwatches[4]?.hex || "#c9a961",
+ currentSwatches[2]?.hex || "#6a7b73"
+ ];
+ cColors.forEach((col, idx) => {
+ const cX = sofaX + 60 + idx * (cW + 18);
+ drawRoundedRect(ctx, cX, cY, cW, cH, 12, col);
+ });
+
+ // Text block
+ ctx.fillStyle = "rgba(245,242,234,0.94)";
+ ctx.font = "22px " + getComputedStyle(document.body).fontFamily.replace(/,? -apple-system[^,]*/g, '');
+ const titleLines = wrapText(ctx, stripHTML(currentPaletteTitle), innerW * 0.45);
+ let textX = x0 + innerW - innerW * 0.45;
+ let textY = roomY + 22;
+ titleLines.forEach(line => {
+ ctx.fillText(line, textX, textY);
+ textY += 26;
+ });
+
+ ctx.font = "13px " + getComputedStyle(document.body).fontFamily;
+ ctx.fillStyle = "rgba(138,133,120,0.96)";
+ const copyLines = wrapText(ctx, stripHTML(previewCopy.innerHTML), innerW * 0.45);
+ textY += 10;
+ copyLines.forEach(line => {
+ ctx.fillText(line, textX, textY);
+ textY += 19;
+ });
+
+ // Signature
+ ctx.font = "11px " + getComputedStyle(document.body).fontFamily;
+ ctx.fillStyle = "rgba(138,133,120,0.92)";
+ ctx.fillText("DESIGNER WALLCOVERINGS · PALETTE BUILDER", x0 + 14, h - margin - 18);
+
+ // Download
+ exportCanvas.toBlob(function(blob) {
+ const url = URL.createObjectURL(blob);
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = "designer-wallcoverings-palette.png";
+ document.body.appendChild(a);
+ a.click();
+ document.body.removeChild(a);
+ URL.revokeObjectURL(url);
+ openOverlay("Downloaded as PNG · drop straight into your deck or feed.");
+ }, "image/png");
+ }
+
+ function drawRoundedRect(ctx, x, y, w, h, r, fill) {
+ ctx.beginPath();
+ ctx.moveTo(x + r, y);
+ ctx.lineTo(x + w - r, y);
+ ctx.quadraticCurveTo(x + w, y, x + w, y + r);
+ ctx.lineTo(x + w, y + h - r);
+ ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
+ ctx.lineTo(x + r, y + h);
+ ctx.quadraticCurveTo(x, y + h, x, y + h - r);
+ ctx.lineTo(x, y + r);
+ ctx.quadraticCurveTo(x, y, x + r, y);
+ ctx.closePath();
+ ctx.fillStyle = fill;
+ ctx.fill();
+ }
+
+ function hexToRgb(hex) {
+ const h = hex.replace('#','');
+ const bigint = parseInt(h, 16);
+ return { r: (bigint >> 16) & 255, g: (bigint >> 8) & 255, b: bigint & 255 };
+ }
+
+ function rgbToHex(r,g,b) {
+ return "#" + [r,g,b].map(v => v.toString(16).padStart(2,'0')).join('');
+ }
+
+ function lighten(hex, amount) {
+ const rgb = hexToRgb(hex);
+ return rgbToHex(
+ Math.min(255, rgb.r + 255*amount),
+ Math.min(255, rgb.g + 255*amount),
+ Math.min(255, rgb.b + 255*amount)
+ );
+ }
+
+ function darken(hex, amount) {
+ const rgb = hexToRgb(hex);
+ return rgbToHex(
+ Math.max(0, rgb.r - 255*amount),
+ Math.max(0, rgb.g - 255*amount),
+ Math.max(0, rgb.b - 255*amount)
+ );
+ }
+
+ function wrapText(ctx, text, maxWidth) {
+ const words = text.split(/\s+/);
+ const lines = [];
+ let line = "";
+ words.forEach(word => {
+ const test = line ? line + " " + word : word;
+ const width = ctx.measureText(test).width;
+ if (width > maxWidth && line) {
+ lines.push(line);
+ line = word;
+ } else {
+ line = test;
+ }
+ });
+ if (line) lines.push(line);
+ return lines;
+ }
+
+ function stripHTML(str) {
+ const tmp = document.createElement('div');
+ tmp.innerHTML = str;
+ return tmp.textContent || tmp.innerText || "";
+ }
+
+ /* Events */
+ let dragging = false;
+
+ function startDrag(e) {
+ dragging = true;
+ document.body.style.userSelect = "none";
+ const angle = angleFromEvent(e);
+ placeKnob(angle);
+ updateHue(angle);
+ }
+ function moveDrag(e) {
+ if (!dragging) return;
+ const angle = angleFromEvent(e);
+ placeKnob(angle);
+ updateHue(angle);
+ }
+ function endDrag() {
+ dragging = false;
+ document.body.style.userSelect = "";
+ }
+
+ hueWheel.addEventListener('mousedown', startDrag);
+ window.addEventListener('mousemove', moveDrag);
+ window.addEventListener('mouseup', endDrag);
+
+ hueWheel.addEventListener('touchstart', function(e) {
+ e.preventDefault();
+ startDrag(e);
+ }, { passive:false });
+ window.addEventListener('touchmove', function(e) {
+ if (!dragging) return;
+ e.preventDefault();
+ moveDrag(e);
+ }, { passive:false });
+ window.addEventListener('touchend', endDrag);
+
+ modeButtons.forEach(btn => {
+ btn.addEventListener('click', () => {
+ currentMode = btn.dataset.mode;
+ modeButtons.forEach(b => b.dataset.active = (b === btn).toString());
+ regeneratePalette();
+ });
+ });
+
+ swatchRow.addEventListener('click', e => {
+ const btn = e.target.closest('.swatch');
+ if (!btn) return;
+ const hex = btn.dataset.hex;
+ if (!hex) return;
+ copyHex(hex);
+ });
+
+ shuffleNamesBtn.addEventListener('click', () => {
+ randomiseNames();
+ showToast("Palette names refreshed");
+ });
+
+ exportBtn.addEventListener('click', () => {
+ exportCard();
+ });
+
+ /* Init */
+ window.addEventListener('load', () => {
+ const rect = hueWheel.getBoundingClientRect();
+ hueWheel.style.setProperty('--wheel-size', rect.width + 'px');
+ placeKnob(currentHue);
+ regeneratePalette();
+ });
+
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/98e38ea3773f/gpt.png b/data/artifacts/98e38ea3773f/gpt.png
new file mode 100644
index 0000000..e328ab5
Binary files /dev/null and b/data/artifacts/98e38ea3773f/gpt.png differ
diff --git a/data/artifacts/98e38ea3773f/grok.html b/data/artifacts/98e38ea3773f/grok.html
new file mode 100644
index 0000000..9f49e10
--- /dev/null
+++ b/data/artifacts/98e38ea3773f/grok.html
@@ -0,0 +1,1139 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Designer Wallcoverings — Palette Builder</title>
+<style>
+:root {
+ --bg: #0d0d0f;
+ --surface: #17171c;
+ --surface-2: #1e1e24;
+ --ink: #f5f2ea;
+ --muted: #8a8578;
+ --accent: #c9a961;
+ --accent-dim: #7d6a45;
+ --line: rgba(245, 242, 234, 0.12);
+ --line-strong: rgba(245, 242, 234, 0.22);
+ --shadow: 0 12px 40px rgba(0, 0, 0, 0.45);
+ --shadow-soft: 0 4px 16px rgba(0, 0, 0, 0.28);
+ --ease: cubic-bezier(.22, .9, .24, 1);
+ --ease-out: cubic-bezier(.22, 1, .36, 1);
+ --serif: 'Didot', 'Bodoni MT', 'Playfair Display', Georgia, 'Times New Roman', serif;
+ --sans: 'Avenir Next', 'Century Gothic', Futura, 'Segoe UI', sans-serif;
+ --mono: 'SF Mono', 'Cascadia Code', Consolas, Menlo, monospace;
+ --r-tight: 6px;
+ --r-card: 14px;
+ --bar-h: 64px;
+ --measure: 1120px;
+}
+
+*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
+
+html { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
+
+body {
+ font-family: var(--sans);
+ font-size: 16px;
+ line-height: 1.6;
+ color: var(--ink);
+ background: var(--bg);
+ min-height: 100vh;
+}
+
+/* ——— Top bar ——— */
+.topbar {
+ position: fixed;
+ top: 0; left: 0; right: 0;
+ height: var(--bar-h);
+ z-index: 100;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0 28px;
+ background: rgba(13, 13, 15, 0.92);
+ backdrop-filter: blur(12px);
+ border-bottom: 1px solid var(--line);
+}
+
+.wordmark {
+ font-family: var(--serif);
+ font-size: 13px;
+ font-weight: 400;
+ letter-spacing: 0.18em;
+ text-transform: uppercase;
+ color: var(--ink);
+ line-height: 1.35;
+ max-width: 280px;
+ white-space: normal;
+}
+
+.topbar-meta {
+ font-family: var(--sans);
+ font-size: 10px;
+ letter-spacing: 0.16em;
+ text-transform: uppercase;
+ color: var(--muted);
+}
+
+/* ——— Layout ——— */
+main {
+ max-width: var(--measure);
+ margin: 0 auto;
+ padding: calc(var(--bar-h) + 48px) 28px 96px;
+}
+
+.hero {
+ margin-bottom: 48px;
+ max-width: 540px;
+}
+
+.hero-eyebrow {
+ font-size: 11px;
+ letter-spacing: 0.18em;
+ text-transform: uppercase;
+ color: var(--accent);
+ margin-bottom: 16px;
+}
+
+.hero h1 {
+ font-family: var(--serif);
+ font-size: 38px;
+ font-weight: 400;
+ line-height: 1.12;
+ letter-spacing: -0.02em;
+ color: var(--ink);
+ margin-bottom: 14px;
+}
+
+.hero p {
+ color: var(--muted);
+ font-size: 16px;
+ line-height: 1.65;
+ max-width: 42ch;
+}
+
+/* ——— Studio grid ——— */
+.studio {
+ display: grid;
+ grid-template-columns: 300px 1fr;
+ gap: 32px;
+ align-items: start;
+}
+
+@media (max-width: 860px) {
+ .studio { grid-template-columns: 1fr; }
+}
+
+.panel {
+ background: var(--surface);
+ border: 1px solid var(--line);
+ border-radius: var(--r-card);
+ padding: 28px;
+ box-shadow: var(--shadow-soft);
+}
+
+.panel-label {
+ font-size: 11px;
+ letter-spacing: 0.16em;
+ text-transform: uppercase;
+ color: var(--muted);
+ margin-bottom: 20px;
+}
+
+/* ——— Hue wheel ——— */
+.wheel-wrap {
+ position: relative;
+ width: 220px;
+ height: 220px;
+ margin: 0 auto 24px;
+}
+
+.wheel-canvas {
+ width: 220px;
+ height: 220px;
+ border-radius: 50%;
+ cursor: crosshair;
+ display: block;
+ box-shadow: inset 0 0 0 1px var(--line-strong), var(--shadow-soft);
+}
+
+.wheel-knob {
+ position: absolute;
+ width: 18px;
+ height: 18px;
+ border-radius: 50%;
+ border: 2px solid var(--ink);
+ box-shadow: 0 0 0 1px rgba(0,0,0,0.4), 0 2px 8px rgba(0,0,0,0.5);
+ transform: translate(-50%, -50%);
+ pointer-events: none;
+ transition: box-shadow 0.2s var(--ease);
+}
+
+.hue-readout {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 24px;
+ padding-bottom: 20px;
+ border-bottom: 1px solid var(--line);
+}
+
+.hue-swatch {
+ width: 36px;
+ height: 36px;
+ border-radius: var(--r-tight);
+ border: 1px solid var(--line-strong);
+ box-shadow: var(--shadow-soft);
+}
+
+.hue-meta {
+ text-align: right;
+}
+
+.hue-meta .deg {
+ font-family: var(--serif);
+ font-size: 28px;
+ line-height: 1;
+ color: var(--ink);
+}
+
+.hue-meta .label {
+ font-size: 10px;
+ letter-spacing: 0.14em;
+ text-transform: uppercase;
+ color: var(--muted);
+ margin-top: 4px;
+}
+
+/* ——— Harmony toggle ——— */
+.harmony {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 6px;
+ margin-bottom: 8px;
+}
+
+.harmony button {
+ font-family: var(--sans);
+ font-size: 10px;
+ letter-spacing: 0.14em;
+ text-transform: uppercase;
+ color: var(--muted);
+ background: transparent;
+ border: 1px solid var(--line);
+ border-radius: var(--r-tight);
+ padding: 12px 6px;
+ cursor: pointer;
+ transition: color 0.25s var(--ease), border-color 0.25s var(--ease), background 0.25s var(--ease);
+}
+
+.harmony button:hover {
+ color: var(--ink);
+ border-color: var(--line-strong);
+}
+
+.harmony button.active {
+ color: var(--bg);
+ background: var(--accent);
+ border-color: var(--accent);
+}
+
+/* ——— Palette column ——— */
+.palette-head {
+ display: flex;
+ align-items: baseline;
+ justify-content: space-between;
+ margin-bottom: 20px;
+ gap: 16px;
+}
+
+.palette-head h2 {
+ font-family: var(--serif);
+ font-size: 28px;
+ font-weight: 400;
+ letter-spacing: -0.02em;
+ line-height: 1.15;
+}
+
+.palette-actions {
+ display: flex;
+ gap: 8px;
+ flex-shrink: 0;
+}
+
+.btn {
+ font-family: var(--sans);
+ font-size: 10px;
+ letter-spacing: 0.14em;
+ text-transform: uppercase;
+ color: var(--ink);
+ background: transparent;
+ border: 1px solid var(--line-strong);
+ border-radius: var(--r-tight);
+ padding: 10px 14px;
+ cursor: pointer;
+ transition: background 0.25s var(--ease), border-color 0.25s var(--ease), color 0.25s var(--ease), transform 0.2s var(--ease);
+}
+
+.btn:hover {
+ border-color: var(--accent);
+ color: var(--accent);
+}
+
+.btn:active { transform: scale(0.97); }
+
+.btn-primary {
+ background: var(--accent);
+ color: var(--bg);
+ border-color: var(--accent);
+}
+
+.btn-primary:hover {
+ background: #d4b56e;
+ color: var(--bg);
+ border-color: #d4b56e;
+}
+
+/* Swatches */
+.swatches {
+ display: grid;
+ grid-template-columns: repeat(5, 1fr);
+ gap: 12px;
+ margin-bottom: 32px;
+}
+
+@media (max-width: 640px) {
+ .swatches { grid-template-columns: repeat(2, 1fr); }
+ .swatches .swatch:last-child { grid-column: span 2; }
+}
+
+.swatch {
+ position: relative;
+ border-radius: var(--r-tight);
+ overflow: hidden;
+ cursor: pointer;
+ border: 1px solid var(--line);
+ transition: transform 0.3s var(--ease-out), box-shadow 0.3s var(--ease);
+ background: var(--surface-2);
+}
+
+.swatch:hover {
+ transform: translateY(-3px);
+ box-shadow: var(--shadow);
+ border-color: var(--line-strong);
+}
+
+.swatch:focus-visible {
+ outline: 1px solid var(--accent);
+ outline-offset: 3px;
+}
+
+.swatch-chip {
+ height: 120px;
+ width: 100%;
+ transition: filter 0.3s var(--ease);
+}
+
+.swatch-meta {
+ padding: 12px 12px 14px;
+ background: var(--surface);
+}
+
+.swatch-name {
+ font-family: var(--serif);
+ font-size: 15px;
+ letter-spacing: 0.01em;
+ color: var(--ink);
+ margin-bottom: 4px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.swatch-hex {
+ font-family: var(--mono);
+ font-size: 11px;
+ letter-spacing: 0.04em;
+ color: var(--muted);
+ text-transform: uppercase;
+}
+
+.swatch.copied .swatch-meta {
+ background: var(--accent);
+}
+
+.swatch.copied .swatch-name,
+.swatch.copied .swatch-hex {
+ color: var(--bg);
+}
+
+/* Room preview */
+.room-section {
+ margin-top: 8px;
+}
+
+.room-label {
+ font-size: 11px;
+ letter-spacing: 0.16em;
+ text-transform: uppercase;
+ color: var(--muted);
+ margin-bottom: 14px;
+}
+
+.room {
+ position: relative;
+ height: 220px;
+ border-radius: var(--r-card);
+ border: 1px solid var(--line);
+ overflow: hidden;
+ box-shadow: var(--shadow-soft);
+ background: #1a1a1e;
+}
+
+.room-wall {
+ position: absolute;
+ inset: 0;
+ transition: background 0.5s var(--ease-out);
+}
+
+.room-wainscot {
+ position: absolute;
+ left: 0; right: 0; bottom: 0;
+ height: 38%;
+ border-top: 1px solid rgba(255,255,255,0.08);
+ transition: background 0.5s var(--ease-out);
+}
+
+.room-rail {
+ position: absolute;
+ left: 0; right: 0;
+ bottom: 38%;
+ height: 6px;
+ background: linear-gradient(180deg, rgba(0,0,0,0.15), rgba(0,0,0,0.05));
+ border-top: 1px solid rgba(255,255,255,0.12);
+ border-bottom: 1px solid rgba(0,0,0,0.2);
+ transition: background-color 0.5s var(--ease-out);
+}
+
+.room-floor {
+ position: absolute;
+ left: 0; right: 0; bottom: 0;
+ height: 14%;
+ background:
+ repeating-linear-gradient(
+ 90deg,
+ transparent 0 48px,
+ rgba(0,0,0,0.08) 48px 49px
+ ),
+ linear-gradient(180deg, rgba(0,0,0,0.12), rgba(0,0,0,0.28));
+ transition: background-color 0.5s var(--ease-out);
+}
+
+.room-window {
+ position: absolute;
+ top: 18%;
+ right: 12%;
+ width: 22%;
+ height: 36%;
+ border: 1px solid rgba(255,255,255,0.18);
+ background: linear-gradient(160deg, rgba(200,210,230,0.22), rgba(140,160,190,0.08));
+ box-shadow: inset 0 0 20px rgba(255,255,255,0.06);
+}
+
+.room-window::before,
+.room-window::after {
+ content: '';
+ position: absolute;
+ background: rgba(255,255,255,0.18);
+}
+
+.room-window::before {
+ left: 50%; top: 0; bottom: 0;
+ width: 1px;
+ transform: translateX(-50%);
+}
+
+.room-window::after {
+ top: 50%; left: 0; right: 0;
+ height: 1px;
+ transform: translateY(-50%);
+}
+
+.room-accent-bar {
+ position: absolute;
+ left: 8%;
+ top: 22%;
+ width: 4px;
+ height: 28%;
+ border-radius: 2px;
+ transition: background 0.5s var(--ease-out);
+ opacity: 0.85;
+}
+
+.room-plinth {
+ position: absolute;
+ left: 10%;
+ bottom: 14%;
+ width: 18%;
+ height: 22%;
+ border-radius: 2px 2px 0 0;
+ transition: background 0.5s var(--ease-out);
+ box-shadow: 0 -2px 12px rgba(0,0,0,0.15);
+}
+
+/* Toast overlay */
+.toast {
+ position: fixed;
+ bottom: 32px;
+ left: 50%;
+ transform: translateX(-50%) translateY(20px);
+ background: var(--surface);
+ color: var(--ink);
+ border: 1px solid var(--line-strong);
+ border-radius: var(--r-tight);
+ padding: 12px 22px;
+ font-size: 11px;
+ letter-spacing: 0.14em;
+ text-transform: uppercase;
+ box-shadow: var(--shadow);
+ opacity: 0;
+ pointer-events: none;
+ transition: opacity 0.35s var(--ease), transform 0.35s var(--ease);
+ z-index: 200;
+}
+
+.toast.show {
+ opacity: 1;
+ transform: translateX(-50%) translateY(0);
+}
+
+/* Export overlay */
+.overlay {
+ position: fixed;
+ inset: 0;
+ background: rgba(8, 8, 10, 0.72);
+ backdrop-filter: blur(8px);
+ z-index: 300;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 24px;
+ opacity: 0;
+ pointer-events: none;
+ transition: opacity 0.35s var(--ease);
+}
+
+.overlay.open {
+ opacity: 1;
+ pointer-events: auto;
+}
+
+.overlay-card {
+ background: var(--surface);
+ border: 1px solid var(--line-strong);
+ border-radius: var(--r-card);
+ padding: 28px;
+ max-width: 420px;
+ width: 100%;
+ box-shadow: var(--shadow);
+ transform: translateY(12px);
+ transition: transform 0.4s var(--ease-out);
+}
+
+.overlay.open .overlay-card {
+ transform: translateY(0);
+}
+
+.overlay-card h3 {
+ font-family: var(--serif);
+ font-size: 24px;
+ font-weight: 400;
+ margin-bottom: 8px;
+}
+
+.overlay-card p {
+ color: var(--muted);
+ font-size: 14px;
+ margin-bottom: 20px;
+}
+
+.overlay-actions {
+ display: flex;
+ gap: 10px;
+ justify-content: flex-end;
+}
+
+/* Hidden export canvas host */
+#exportCanvas { display: none; }
+
+footer {
+ margin-top: 64px;
+ padding-top: 24px;
+ border-top: 1px solid var(--line);
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 16px;
+ flex-wrap: wrap;
+}
+
+footer span {
+ font-size: 10px;
+ letter-spacing: 0.16em;
+ text-transform: uppercase;
+ color: var(--muted);
+}
+</style>
+</head>
+<body>
+
+<header class="topbar">
+ <div class="wordmark">Designer<br>Wallcoverings</div>
+ <div class="topbar-meta">Palette Atelier</div>
+</header>
+
+<main>
+ <section class="hero">
+ <div class="hero-eyebrow">Curated for interiors</div>
+ <h1>Compose a wallcovering palette</h1>
+ <p>Select a base hue. We assemble five designer finishes — walls, trim, metal, and ink — ready for mood boards and client cards.</p>
+ </section>
+
+ <div class="studio">
+ <aside class="panel">
+ <div class="panel-label">Base Hue</div>
+ <div class="wheel-wrap" id="wheelWrap">
+ <canvas class="wheel-canvas" id="wheel" width="440" height="440"></canvas>
+ <div class="wheel-knob" id="knob"></div>
+ </div>
+ <div class="hue-readout">
+ <div class="hue-swatch" id="hueSwatch"></div>
+ <div class="hue-meta">
+ <div class="deg" id="hueDeg">28°</div>
+ <div class="label">Warm Brass</div>
+ </div>
+ </div>
+ <div class="panel-label">Harmony</div>
+ <div class="harmony" role="tablist">
+ <button type="button" class="active" data-mode="analogous" role="tab" aria-selected="true">Analogous</button>
+ <button type="button" data-mode="complementary" role="tab" aria-selected="false">Complement</button>
+ <button type="button" data-mode="triadic" role="tab" aria-selected="false">Triadic</button>
+ </div>
+ </aside>
+
+ <section>
+ <div class="palette-head">
+ <h2 id="paletteTitle">Brass Atelier</h2>
+ <div class="palette-actions">
+ <button type="button" class="btn" id="btnShuffle" title="Reshuffle names within family">Reshuffle</button>
+ <button type="button" class="btn btn-primary" id="btnExport">Export 1080²</button>
+ </div>
+ </div>
+
+ <div class="swatches" id="swatches" aria-label="Palette swatches"></div>
+
+ <div class="room-section">
+ <div class="room-label">Live room preview</div>
+ <div class="room" id="room" aria-hidden="true">
+ <div class="room-wall" id="roomWall"></div>
+ <div class="room-window"></div>
+ <div class="room-accent-bar" id="roomAccent"></div>
+ <div class="room-plinth" id="roomPlinth"></div>
+ <div class="room-wainscot" id="roomWainscot"></div>
+ <div class="room-rail" id="roomRail"></div>
+ <div class="room-floor" id="roomFloor"></div>
+ </div>
+ </div>
+ </section>
+ </div>
+
+ <footer>
+ <span>Designer Wallcoverings · Interior Atelier</span>
+ <span>Click a swatch to copy hex</span>
+ </footer>
+</main>
+
+<div class="toast" id="toast" role="status" aria-live="polite">Hex copied</div>
+
+<div class="overlay" id="overlay" aria-hidden="true">
+ <div class="overlay-card" role="dialog" aria-labelledby="ovTitle">
+ <h3 id="ovTitle">Card ready</h3>
+ <p id="ovBody">Your 1080×1080 palette card has been prepared. Download the PNG for social or client decks.</p>
+ <div class="overlay-actions">
+ <button type="button" class="btn" id="ovClose">Close</button>
+ <button type="button" class="btn btn-primary" id="ovDownload">Download PNG</button>
+ </div>
+ </div>
+</div>
+
+<canvas id="exportCanvas" width="1080" height="1080"></canvas>
+
+<script>
+(function () {
+ 'use strict';
+
+ /* ——— Designer name banks ——— */
+ const NAMES = {
+ light: ['Alabaster', 'Porcelain', 'Chalk', 'Linen', 'Ivory Dust', 'Parchment', 'Cloudlime', 'Bone'],
+ soft: ['Greige', 'Putty', 'Dove', 'Doeskin', 'Mushroom', 'Clay Silk', 'Stonewash', 'Fawn'],
+ mid: ['Celadon', 'Sagewash', 'Moss Tea', 'Olive Haze', 'Sea Glass', 'Verdigris', 'Lichen', 'Bayleaf'],
+ deep: ['Ink', 'Nocturne', 'Graphite', 'Espresso', 'Soot', 'Indigo Ash', 'Oxblood', 'Char'],
+ metal: ['Brass', 'Antique Gold', 'Champagne', 'Bronze', 'Gilt', 'Copper Leaf', 'Pewter', 'Ormolu']
+ };
+
+ const TITLE_FRAGMENTS = [
+ 'Atelier', 'Salon', 'Gallery', 'Suite', 'Library', 'Conservatory', 'Study', 'Cabinet'
+ ];
+
+ const HUE_LABELS = [
+ [0, 'Crimson Ember'], [15, 'Terra Cotta'], [28, 'Warm Brass'], [40, 'Honey Oak'],
+ [55, 'Ochre Field'], [75, 'Olive Grove'], [100, 'Celadon Leaf'], [140, 'Botanical'],
+ [170, 'Seafoam'], [195, 'Horizon Blue'], [220, 'Delft'], [250, 'Violet Ink'],
+ [280, 'Amethyst'], [310, 'Mulberry'], [340, 'Rosewood'], [360, 'Crimson Ember']
+ ];
+
+ let hue = 28;
+ let mode = 'analogous';
+ let palette = [];
+ let nameSeed = 0;
+ let exportBlob = null;
+
+ const wheel = document.getElementById('wheel');
+ const ctx = wheel.getContext('2d');
+ const knob = document.getElementById('knob');
+ const hueSwatch = document.getElementById('hueSwatch');
+ const hueDeg = document.getElementById('hueDeg');
+ const hueMetaLabel = hueDeg.nextElementSibling;
+ const swatchesEl = document.getElementById('swatches');
+ const paletteTitle = document.getElementById('paletteTitle');
+ const toast = document.getElementById('toast');
+ const overlay = document.getElementById('overlay');
+ const exportCanvas = document.getElementById('exportCanvas');
+
+ /* ——— Color math ——— */
+ function hslToRgb(h, s, l) {
+ h = ((h % 360) + 360) % 360;
+ s = Math.max(0, Math.min(100, s)) / 100;
+ l = Math.max(0, Math.min(100, l)) / 100;
+ const c = (1 - Math.abs(2 * l - 1)) * s;
+ const x = c * (1 - Math.abs((h / 60) % 2 - 1));
+ const m = l - c / 2;
+ let r = 0, g = 0, b = 0;
+ if (h < 60) { r = c; g = x; }
+ else if (h < 120) { r = x; g = c; }
+ else if (h < 180) { g = c; b = x; }
+ else if (h < 240) { g = x; b = c; }
+ else if (h < 300) { r = x; b = c; }
+ else { r = c; b = x; }
+ return [
+ Math.round((r + m) * 255),
+ Math.round((g + m) * 255),
+ Math.round((b + m) * 255)
+ ];
+ }
+
+ function rgbToHex(r, g, b) {
+ return '#' + [r, g, b].map(v => v.toString(16).padStart(2, '0')).join('').toUpperCase();
+ }
+
+ function hslHex(h, s, l) {
+ return rgbToHex(...hslToRgb(h, s, l));
+ }
+
+ function relLuma(hex) {
+ const r = parseInt(hex.slice(1, 3), 16) / 255;
+ const g = parseInt(hex.slice(3, 5), 16) / 255;
+ const b = parseInt(hex.slice(5, 7), 16) / 255;
+ const f = v => v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
+ return 0.2126 * f(r) + 0.7152 * f(g) + 0.0722 * f(b);
+ }
+
+ function hueLabel(h) {
+ h = ((h % 360) + 360) % 360;
+ let best = HUE_LABELS[0][1];
+ let bestD = 999;
+ for (const [deg, name] of HUE_LABELS) {
+ const d = Math.min(Math.abs(h - deg), 360 - Math.abs(h - deg));
+ if (d < bestD) { bestD = d; best = name; }
+ }
+ return best;
+ }
+
+ function pick(arr, i) {
+ return arr[((i % arr.length) + arr.length) % arr.length];
+ }
+
+ /* ——— Palette generation ——— */
+ function buildPalette(h, m, seed) {
+ let hLight, hSoft, hMid, hDeep, hMetal;
+ const sBase = 28;
+
+ if (m === 'analogous') {
+ hLight = h - 8;
+ hSoft = h + 4;
+ hMid = h + 18;
+ hDeep = h - 22;
+ hMetal = h + 6;
+ } else if (m === 'complementary') {
+ const c = h + 180;
+ hLight = h - 6;
+ hSoft = h + 10;
+ hMid = c;
+ hDeep = c - 14;
+ hMetal = h + 4;
+ } else { // triadic
+ const t1 = h + 120;
+ const t2 = h + 240;
+ hLight = h - 4;
+ hSoft = h + 12;
+ hMid = t1;
+ hDeep = t2;
+ hMetal = h + 8;
+ }
+
+ // Interior-tuned S/L — pale wall, greige trim, mid colorway, deep ink, metallic accent
+ const specs = [
+ { h: hLight, s: Math.max(8, sBase - 14), l: 90, bank: 'light' },
+ { h: hSoft, s: Math.max(6, sBase - 16), l: 72, bank: 'soft' },
+ { h: hMid, s: sBase + 10, l: 48, bank: 'mid' },
+ { h: hDeep, s: Math.min(40, sBase + 6), l: 16, bank: 'deep' },
+ { h: hMetal, s: 42, l: 58, bank: 'metal' }
+ ];
+
+ // Gentle saturation clamp for interiors — avoid neon
+ return specs.map((sp, i) => {
+ const hex = hslHex(sp.h, sp.s, sp.l);
+ const name = pick(NAMES[sp.bank], seed + i * 3 + Math.floor(h / 15));
+ return { hex, name, role: sp.bank, h: sp.h, s: sp.s, l: sp.l };
+ });
+ }
+
+ function titleFor(h, m, seed) {
+ const base = hueLabel(h).split(' ').pop();
+ const frag = pick(TITLE_FRAGMENTS, seed + Math.floor(h / 20));
+ const modeTag = m === 'analogous' ? '' : m === 'complementary' ? ' · Complement' : ' · Triad';
+ return base + ' ' + frag + modeTag;
+ }
+
+ /* ——— Wheel drawing ——— */
+ function drawWheel() {
+ const dpr = 2;
+ const size = 220 * dpr;
+ const cx = size / 2;
+ const cy = size / 2;
+ const outer = size / 2 - 2;
+ const inner = outer * 0.58;
+
+ ctx.clearRect(0, 0, size, size);
+
+ // Conic hue ring
+ for (let a = 0; a < 360; a += 0.4) {
+ const rad = (a - 90) * Math.PI / 180;
+ const rad2 = (a + 0.5 - 90) * Math.PI / 180;
+ ctx.beginPath();
+ ctx.moveTo(cx + Math.cos(rad) * inner, cy + Math.sin(rad) * inner);
+ ctx.lineTo(cx + Math.cos(rad) * outer, cy + Math.sin(rad) * outer);
+ ctx.lineTo(cx + Math.cos(rad2) * outer, cy + Math.sin(rad2) * outer);
+ ctx.lineTo(cx + Math.cos(rad2) * inner, cy + Math.sin(rad2) * inner);
+ ctx.closePath();
+ ctx.fillStyle = 'hsl(' + a + ', 55%, 52%)';
+ ctx.fill();
+ }
+
+ // Inner disc
+ ctx.beginPath();
+ ctx.arc(cx, cy, inner - 2, 0, Math.PI * 2);
+ ctx.fillStyle = '#17171c';
+ ctx.fill();
+
+ // Hairline rings
+ ctx.strokeStyle = 'rgba(245,242,234,0.14)';
+ ctx.lineWidth = 2;
+ ctx.beginPath();
+ ctx.arc(cx, cy, outer, 0, Math.PI * 2);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(cx, cy, inner, 0, Math.PI * 2);
+ ctx.stroke();
+
+ // Center gem
+ const grd = ctx.createRadialGradient(cx, cy, 0, cx, cy, inner * 0.55);
+ const [r, g, b] = hslToRgb(hue, 48, 52);
+ grd.addColorStop(0, 'rgba(' + r + ',' + g + ',' + b + ',0.95)');
+ grd.addColorStop(1, 'rgba(' + r + ',' + g + ',' + b + ',0.15)');
+ ctx.beginPath();
+ ctx.arc(cx, cy, inner * 0.5, 0, Math.PI * 2);
+ ctx.fillStyle = grd;
+ ctx.fill();
+ }
+
+ function placeKnob() {
+ const wrap = 220;
+ const cx = wrap / 2;
+ const cy = wrap / 2;
+ const r = wrap / 2 * 0.79; // mid-ring
+ const rad = (hue - 90) * Math.PI / 180;
+ const x = cx + Math.cos(rad) * r;
+ const y = cy + Math.sin(rad) * r;
+ knob.style.left = x + 'px';
+ knob.style.top = y + 'px';
+ knob.style.background = hslHex(hue, 55, 52);
+ }
+
+ function hueFromEvent(e) {
+ const rect = wheel.getBoundingClientRect();
+ const x = (e.clientX - rect.left) - rect.width / 2;
+ const y = (e.clientY - rect.top) - rect.height / 2;
+ let deg = Math.atan2(y, x) * 180 / Math.PI + 90;
+ if (deg < 0) deg += 360;
+ return deg;
+ }
+
+ /* ——— Render ——— */
+ function render() {
+ palette = buildPalette(hue, mode, nameSeed);
+ drawWheel();
+ placeKnob();
+
+ hueSwatch.style.background = hslHex(hue, 50, 52);
+ hueDeg.textContent = Math.round(hue) + '°';
+ hueMetaLabel.textContent = hueLabel(hue);
+ paletteTitle.textContent = titleFor(hue, mode, nameSeed);
+
+ swatchesEl.innerHTML = '';
+ palette.forEach((sw, i) => {
+ const el = document.createElement('button');
+ el.type = 'button';
+ el.className = 'swatch';
+ el.setAttribute('aria-label', sw.name + ' ' + sw.hex);
+ el.innerHTML =
+ '<div class="swatch-chip" style="background:' + sw.hex + '"></div>' +
+ '<div class="swatch-meta">' +
+ '<div class="swatch-name">' + sw.name + '</div>' +
+ '<div class="swatch-hex">' + sw.hex + '</div>' +
+ '</div>';
+ el.addEventListener('click', () => copyHex(sw.hex, el));
+ swatchesEl.appendChild(el);
+ });
+
+ // Room: wall = light, wainscot = soft, floor = deep, rail/plinth = metal, accent = mid
+ document.getElementById('roomWall').style.background = palette[0].hex;
+ document.getElementById('roomWainscot').style.background = palette[1].hex;
+ document.getElementById('roomFloor').style.backgroundColor = palette[3].hex;
+ document.getElementById('roomRail').style.backgroundColor = palette[4].hex;
+ document.getElementById('roomAccent').style.background = palette[2].hex;
+ document.getElementById('roomPlinth').style.background = palette[4].hex;
+ }
+
+ /* ——— Copy ——— */
+ function copyHex(hex, el) {
+ const done = () => {
+ el.classList.add('copied');
+ showToast('Copied ' + hex);
+ setTimeout(() => el.classList.remove('copied'), 900);
+ };
+ if (navigator.clipboard && navigator.clipboard.writeText) {
+ navigator.clipboard.writeText(hex).then(done).catch(() => fallbackCopy(hex, done));
+ } else {
+ fallbackCopy(hex, done);
+ }
+ }
+
+ function fallbackCopy(text, cb) {
+ const ta = document.createElement('textarea');
+ ta.value = text;
+ ta.style.cssText = 'position:fixed;left:-9999px;top:-9999px';
+ document.body.appendChild(ta);
+ ta.select();
+ try { document.execCommand('copy'); } catch (e) {}
+ document.body.removeChild(ta);
+ cb();
+ }
+
+ let toastTimer;
+ function showToast(msg) {
+ toast.textContent = msg;
+ toast.classList.add('show');
+ clearTimeout(toastTimer);
+ toastTimer = setTimeout(() => toast.classList.remove('show'), 1600);
+ }
+
+ /* ——— Wheel interaction ——— */
+ let dragging = false;
+
+ function onPointer(e) {
+ hue = hueFromEvent(e);
+ render();
+ }
+
+ wheel.addEventListener('pointerdown', (e) => {
+ dragging = true;
+ wheel.setPointerCapture(e.pointerId);
+ onPointer(e);
+ });
+ wheel.addEventListener('pointermove', (e) => {
+ if (dragging) onPointer(e);
+ });
+ wheel.addEventListener('pointerup', () => { dragging = false; });
+ wheel.addEventListener('pointercancel', () => { dragging = false; });
+
+ /* ——— Harmony ——— */
+ document.querySelectorAll('.harmony button').forEach(btn => {
+ btn.addEventListener('click', () => {
+ document.querySelectorAll('.harmony button').forEach(b => {
+ b.classList.remove('active');
+ b.setAttribute('aria-selected', 'false');
+ });
+ btn.classList.add('active');
+ btn.setAttribute('aria-selected', 'true');
+ mode = btn.dataset.mode;
+ render();
+ });
+ });
+
+ document.getElementById('btnShuffle').addEventListener('click', () => {
+ nameSeed = (nameSeed + 1) % 97;
+ render();
+ });
+
+ /* ——— Export 1080 card ——— */
+ function drawExportCard() {
+ const c = exportCanvas;
+ const x = c.getContext('2d');
+ const W = 1080, H = 1080;
+
+ // Ground
+ x.fillStyle = '#0d0d0f';
+ x.fillRect(0, 0, W, H);
+
+ // Fine outer frame
+ x.strokeStyle = 'rgba(201,169,97,0.35)';
+ x.lineWidth = 1;
+ x.strokeRect(48, 48, W - 96, H - 96);
+
+ // Wordmark
+ x.fillStyle = '#f5f2ea';
+ x.font = '400 22px Didot, Bodoni MT, Georgia, serif';
+ x.letterSpacing = '0.18em';
+ x.textAlign = 'left';
+ // letter-spacing polyfill
+ drawTracked(x, 'DESIGNER WALLCOVERINGS', 96, 120, 22, 0.18);
+
+ // Accent rule
+ x.fillStyle = '#c9a961';
+ x.fillRect(96, 148, 64, 2);
+
+ // Title
+ x.fillStyle = '#f5f2ea';
+ x.font = '400 56px Didot, Bodoni MT, Georgia, serif';
+ x.textAlign = 'left';
+ const title = paletteTitle.textContent.replace(/\s·\s.*$/, '');
+ x.fillText(title, 96, 230);
+
+ // Mode caption
+ x.fillStyle = '#8a8578';
+ x.font = '500 16px Avenir Next, Segoe UI, sans-serif';
+ const modeName = mode.charAt(0).toUpperCase() + mode.slice(1) + ' harmony · H ' + Math.round(hue) + '°';
+ x.fillText(modeName.toUpperCase(), 96, 270);
+
+ // Five swatches
+ const swY = 340;
+ const swH = 340;
+ const gap = 16;
+ const side = 96;
+ const totalW = W - side * 2;
+ const swW = (totalW - gap * 4) / 5;
+
+ palette.forEach((sw, i) => {
+ const sx = side + i * (swW + gap);
+ // chip
+ x.fillStyle = sw.hex;
+ x.fillRect(sx, swY, swW, swH);
+ // hairline
+ x.strokeStyle = 'rgba(245,242,234,0.12)';
+ x.lineWidth = 1;
+ x.strokeRect(sx + 0.5, swY + 0.5, swW - 1, swH - 1);
+
+ // name under
+ x.fillStyle = '#f5f2ea';
+ x.font = '400 22px Didot, Bodoni MT, Georgia, serif';
+ x.fillText(sw.name, sx, swY + swH + 40);
+
+ x.fillStyle = '#8a8578';
+ x.font = '500 14px SF Mono, Consolas, monospace';
+ x.fillText(sw.hex, sx, swY + swH + 68);
+ });
+
+ // Room strip
+ const stripY = 860;
+ const stripH = 100;
+ const roles = [0, 1, 2, 3, 4];
+ const widths = [0.34, 0.22, 0.12, 0.18, 0.14];
+ let rx = side;
+ roles.forEach((ri, i) => {
+ const w = totalW * widths[i];
+ x.fillStyle = palette[ri].hex;
+ x.fillRect(rx, stripY, w, stripH);
+ rx += w;
+ });
+ x.strokeStyle = 'rgba(245,242,234,0.12)';
+ x.strokeRect(side + 0.5, stripY + 0.5, totalW - 1, stripH - 1);
+
+ // Footer
+ x.fillStyle = '#8a8578';
+ x.font = '500 13px Avenir Next, Segoe UI, sans-serif';
+ drawTracked(x, 'INTERIOR PALETTE CARD · 1080 × 1080', 96, 1010, 13, 0.14);
+ }
+
+ function drawTracked(ctx, text, x, y, size, trackingEm) {
+ const tracking = size * trackingEm;
+ let cx = x;
+ for (let i = 0; i < text.length; i++) {
+ ctx.fillText(text[i], cx, y);
+ cx += ctx.measureText(text[i]).width + tracking;
+ }
+ }
+
+ document.getElementById('btnExport').addEventListener('click', () => {
+ drawExportCard();
+ exportCanvas.toBlob((blob) => {
+ exportBlob = blob;
+ document.getElementById('ovBody').textContent =
+ '“' + paletteTitle.textContent + '” — five finishes on a 1080×1080 card. Download for social or client decks.';
+ overlay.classList.add('open');
+ overlay.setAttribute('aria-hidden', 'false');
+ }, 'image/png');
+ });
+
+ document.getElementById('ovClose').addEventListener('click', () => {
+ overlay.classList.remove('open');
+ overlay.setAttribute('aria-hidden', 'true');
+ });
+
+ overlay.addEventListener('click', (e) => {
+ if (e.target === overlay) {
+ overlay.classList.remove('open');
+ overlay.setAttribute('aria-hidden', 'true');
+ }
+ });
+
+ document.getElementById('ovDownload').addEventListener('click', () => {
+ if (!exportBlob) return;
+ const url = URL.createObjectURL(exportBlob);
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = 'dw-palette-' + Math.round(hue) + '-' + mode + '.png';
+ document.body.appendChild(a);
+ a.click();
+ document.body.removeChild(a);
+ URL.revokeObjectURL(url);
+ showToast('Download started');
+ });
+
+ // Init
+ render();
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/98e38ea3773f/grok.png b/data/artifacts/98e38ea3773f/grok.png
new file mode 100644
index 0000000..3218f19
Binary files /dev/null and b/data/artifacts/98e38ea3773f/grok.png differ
diff --git a/data/artifacts/98e38ea3773f/hermes3-8b.html b/data/artifacts/98e38ea3773f/hermes3-8b.html
new file mode 100644
index 0000000..95a4b44
--- /dev/null
+++ b/data/artifacts/98e38ea3773f/hermes3-8b.html
@@ -0,0 +1,147 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Designer Wallcoverings</title>
+<style>
+:root {
+ --bg: #f7efe6;
+ --surface: #fff9f1;
+ --text: #3a2c22;
+ --muted: #a08c7a;
+ --accent: #e0a458;
+ --line: rgba(243, 141, 38, 0.15);
+ --shadow: rgba(0, 0, 0, 0.12);
+ --ease: cubic-bezier(0.22, 1, 0.36, 1);
+}
+body {
+ margin: 0;
+ padding: 96px;
+ font-family: -apple-system, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
+ font-size: 16px;
+ line-height: 1.5;
+ background-color: var(--bg);
+ color: var(--text);
+}
+h1 {
+ margin: 0;
+ font-family: 'Didot', 'Bodoni MT', 'Playfair Display', Georgia, serif;
+ font-size: 50px;
+ letter-spacing: 0.18em;
+ color: var(--surface);
+}
+.card {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 24px;
+ margin-bottom: 48px;
+}
+.card:nth-child(3n) {
+ justify-content: space-between;
+}
+.card {
+ padding: 16px;
+ background-color: var(--surface);
+ box-shadow: 0 8px 24px var(--shadow);
+ border-radius: 14px;
+ flex-basis: calc((100% - (var(--gap) * 2)) / 3);
+}
+.card:nth-child(3n+1)::after {
+ content: '';
+ flex-grow: 1;
+}
+.card:hover,
+.overlay {
+ transform: translateY(0);
+ opacity: 1;
+ transition:
+ transform var(--ease),
+ opacity var(--ease)
+ 0.7s;
+ animation: fadeUp 0.7s forwards;
+}
+@keyframes fadeUp {
+ from {
+ opacity: 0;
+ transform: translateY(28px);
+ }
+ to {
+ opacity: 1;
+ transform: none;
+ }
+}
+.overlay,
+button {
+ font-family: 'Segoe UI', Arial, sans-serif;
+ text-transform: uppercase;
+ letter-spacing: 0.15em;
+ color: var(--muted);
+}
+button:hover {
+ filter: drop-shadow(0 4px 8px var(--accent));
+}
+</style>
+<body>
+<div class="card">
+ <h1>Designer Wallcoverings</h1>
+ <div class="overlay">Choose a base hue...</div>
+</div>
+<div class="card">
+ <button>Choose Base Hue</button>
+ <input type="color" value="#f7efe6" hidden>
+</div>
+<div class="card">
+ <h2>Your Palette</h2>
+ <div class="overlay">Tap a swatch for hex...</div>
+</div>
+<div class="card palette">
+ <!-- Palettes will go here -->
+</div>
+<script>
+document.querySelector('.card:nth-child(2) button').addEventListener('click', () => {
+ const input = document.querySelector('input[type=color]');
+ input.click();
+ input.addEventListener('change', () => {
+ const color = input.value;
+ document.documentElement.style.setProperty('--bg', color);
+ document.documentElement.style.setProperty('--surface', lighten(color, 10));
+ document.documentElement.style.setProperty('--text', color);
+ document.documentElement.style.setProperty('--muted', darken(color, 5));
+ document.documentElement.style.setProperty('--accent', complement(color));
+
+ const palette = document.querySelector('.card:nth-child(4) .palette');
+ while (palette.firstChild) {
+ palette.removeChild(palette.lastChild);
+ }
+
+ for (let i = 0; i < 5; i++) {
+ const swatch = document.createElement('div');
+ swatch.style.backgroundColor = generateColor(color, i + 1);
+ swatch.addEventListener('click', () => {
+ alert(`#${swatch.style.backgroundColor.slice(1)}`);
+ });
+ palette.appendChild(swatch);
+ }
+
+ document.querySelector('.card:nth-child(3) .overlay').style.display = 'none';
+});
+
+function lighten(hex, amount) {
+ // Lighten color by percentage
+}
+
+function darken(hex, amount) {
+ // Darken color by percentage
+}
+
+function complement(hex) {
+ // Complementary color
+}
+
+function generateColor(base, index) {
+ // Generate analogous/complementary/triadic colors based on base hue and index
+}
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/98e38ea3773f/hermes3-8b.png b/data/artifacts/98e38ea3773f/hermes3-8b.png
new file mode 100644
index 0000000..d39bebd
Binary files /dev/null and b/data/artifacts/98e38ea3773f/hermes3-8b.png differ
diff --git a/data/artifacts/98e38ea3773f/kimi.html b/data/artifacts/98e38ea3773f/kimi.html
new file mode 100644
index 0000000..768b64a
--- /dev/null
+++ b/data/artifacts/98e38ea3773f/kimi.html
@@ -0,0 +1,835 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Designer Wallcoverings — Curated Palette Studio</title>
+<style>
+:root{
+ --bg:#0d0d0f;
+ --surface:#17171c;
+ --surface-2:#1f1f26;
+ --ink:#f5f2ea;
+ --muted:#8a8578;
+ --accent:#c9a961;
+ --accent-dim:#7d6a45;
+ --line:rgba(245,242,234,.12);
+ --shadow:0 24px 64px rgba(0,0,0,.45);
+ --ease:cubic-bezier(.22,1,.36,1);
+ --font-serif:'Playfair Display','Didot','Bodoni MT',Georgia,serif;
+ --font-sans:-apple-system,BlinkMacSystemFont,'Segoe UI','Helvetica Neue',Arial,sans-serif;
+ --font-mono:'SF Mono',Menlo,Consolas,monospace;
+ --radius:2px;
+ --max-w:1400px;
+}
+
+*{box-sizing:border-box;margin:0;padding:0}
+html{font-size:16px}
+body{
+ background:var(--bg);
+ color:var(--ink);
+ font-family:var(--font-sans);
+ line-height:1.6;
+ -webkit-font-smoothing:antialiased;
+ overflow-x:hidden;
+}
+
+/* Header */
+.header{
+ position:fixed;
+ top:0;left:0;right:0;
+ z-index:100;
+ background:var(--bg);
+ border-bottom:1px solid var(--line);
+ padding:0 48px;
+ height:84px;
+ display:flex;
+ align-items:center;
+ justify-content:space-between;
+}
+
+.wordmark{
+ font-family:var(--font-serif);
+ font-size:18px;
+ font-weight:500;
+ letter-spacing:.18em;
+ text-transform:uppercase;
+ color:var(--ink);
+ line-height:1.3;
+ max-width:280px;
+}
+
+.header-actions{
+ display:flex;
+ gap:16px;
+}
+
+.btn{
+ font-family:var(--font-sans);
+ font-size:11px;
+ letter-spacing:.16em;
+ text-transform:uppercase;
+ padding:12px 24px;
+ background:transparent;
+ color:var(--ink);
+ border:1px solid var(--line);
+ cursor:pointer;
+ transition:all .35s var(--ease);
+ font-weight:500;
+}
+
+.btn:hover{
+ border-color:var(--accent);
+ color:var(--accent);
+}
+
+.btn-primary{
+ background:var(--accent);
+ color:var(--bg);
+ border-color:var(--accent);
+}
+
+.btn-primary:hover{
+ background:transparent;
+ color:var(--accent);
+}
+
+/* Main */
+.main{
+ padding-top:84px;
+ min-height:100vh;
+}
+
+.editorial{
+ max-width:var(--max-w);
+ margin:0 auto;
+ padding:64px 48px;
+}
+
+.hero{
+ text-align:center;
+ margin-bottom:80px;
+ animation:fadeUp 1s var(--ease) both;
+}
+
+.hero h1{
+ font-family:var(--font-serif);
+ font-size:clamp(38px,5vw,67px);
+ font-weight:400;
+ line-height:1.1;
+ margin-bottom:24px;
+ letter-spacing:-0.02em;
+}
+
+.hero p{
+ font-size:18px;
+ color:var(--muted);
+ max-width:560px;
+ margin:0 auto;
+ line-height:1.7;
+}
+
+/* Layout Grid */
+.workspace{
+ display:grid;
+ grid-template-columns:380px 1fr;
+ gap:64px;
+ align-items:start;
+}
+
+@media(max-width:1100px){
+ .workspace{grid-template-columns:1fr;gap:48px}
+}
+
+/* Color Wheel Section */
+.wheel-section{
+ position:sticky;
+ top:120px;
+ animation:fadeUp 1s var(--ease) .15s both;
+}
+
+.wheel-container{
+ position:relative;
+ width:340px;
+ height:340px;
+ margin:0 auto 32px;
+}
+
+#colorWheel{
+ width:100%;
+ height:100%;
+ border-radius:50%;
+ cursor:pointer;
+ box-shadow:var(--shadow);
+}
+
+.wheel-indicator{
+ position:absolute;
+ width:24px;
+ height:24px;
+ border:2px solid var(--ink);
+ border-radius:50%;
+ background:transparent;
+ transform:translate(-50%,-50%);
+ pointer-events:none;
+ box-shadow:0 2px 8px rgba(0,0,0,.4);
+ transition:all .15s var(--ease);
+}
+
+.scheme-toggle{
+ display:flex;
+ gap:8px;
+ justify-content:center;
+ margin-bottom:32px;
+}
+
+.scheme-btn{
+ font-family:var(--font-sans);
+ font-size:10px;
+ letter-spacing:.2em;
+ text-transform:uppercase;
+ padding:10px 20px;
+ background:var(--surface);
+ border:1px solid var(--line);
+ color:var(--muted);
+ cursor:pointer;
+ transition:all .35s var(--ease);
+}
+
+.scheme-btn.active,.scheme-btn:hover{
+ border-color:var(--accent);
+ color:var(--accent);
+ background:var(--surface-2);
+}
+
+/* Palette Section */
+.palette-section{
+ animation:fadeUp 1s var(--ease) .3s both;
+}
+
+.palette-header{
+ display:flex;
+ justify-content:space-between;
+ align-items:center;
+ margin-bottom:40px;
+ padding-bottom:24px;
+ border-bottom:1px solid var(--line);
+}
+
+.palette-title{
+ font-family:var(--font-serif);
+ font-size:28px;
+ font-weight:400;
+ letter-spacing:-0.01em;
+}
+
+.swatches{
+ display:flex;
+ gap:16px;
+ margin-bottom:48px;
+}
+
+.swatch{
+ flex:1;
+ height:280px;
+ border-radius:var(--radius);
+ position:relative;
+ cursor:pointer;
+ transition:transform .4s var(--ease),box-shadow .4s var(--ease);
+ box-shadow:0 4px 20px rgba(0,0,0,.2);
+ overflow:hidden;
+}
+
+.swatch:hover{
+ transform:translateY(-8px);
+ box-shadow:var(--shadow);
+}
+
+.swatch::before{
+ content:'';
+ position:absolute;
+ inset:0;
+ background:linear-gradient(180deg,transparent 60%,rgba(0,0,0,.4));
+ opacity:0;
+ transition:opacity .4s var(--ease);
+}
+
+.swatch:hover::before{opacity:1}
+
+.swatch-info{
+ position:absolute;
+ bottom:0;
+ left:0;
+ right:0;
+ padding:24px;
+ transform:translateY(20px);
+ opacity:0;
+ transition:all .4s var(--ease);
+}
+
+.swatch:hover .swatch-info{
+ transform:translateY(0);
+ opacity:1;
+}
+
+.swatch-name{
+ font-family:var(--font-serif);
+ font-size:21px;
+ margin-bottom:4px;
+ color:#fff;
+ text-shadow:0 2px 8px rgba(0,0,0,.5);
+}
+
+.swatch-hex{
+ font-family:var(--font-mono);
+ font-size:12px;
+ letter-spacing:.08em;
+ color:rgba(255,255,255,.85);
+ text-transform:uppercase;
+}
+
+/* Room Preview */
+.room-section{
+ margin-top:64px;
+ animation:fadeUp 1s var(--ease) .45s both;
+}
+
+.room-header{
+ font-family:var(--font-sans);
+ font-size:11px;
+ letter-spacing:.2em;
+ text-transform:uppercase;
+ color:var(--muted);
+ margin-bottom:24px;
+}
+
+.room-strip{
+ display:grid;
+ grid-template-columns:repeat(5,1fr);
+ gap:12px;
+ height:200px;
+}
+
+.room-panel{
+ border-radius:var(--radius);
+ position:relative;
+ overflow:hidden;
+ box-shadow:0 4px 24px rgba(0,0,0,.3);
+}
+
+.room-panel::after{
+ content:'';
+ position:absolute;
+ inset:0;
+ opacity:.15;
+ background-image:repeating-linear-gradient(45deg,transparent,transparent 10px,rgba(255,255,255,.1) 10px,rgba(255,255,255,.1) 20px);
+}
+
+.room-panel:nth-child(1)::after{
+ background-image:repeating-linear-gradient(90deg,transparent,transparent 2px,rgba(0,0,0,.1) 2px,rgba(0,0,0,.1) 4px);
+}
+
+.room-panel:nth-child(2)::after{
+ background-image:radial-gradient(circle at 30% 30%,rgba(255,255,255,.15) 1px,transparent 1px);
+ background-size:12px 12px;
+}
+
+.room-panel:nth-child(3)::after{
+ background-image:linear-gradient(135deg,rgba(0,0,0,.08) 25%,transparent 25%,transparent 50%,rgba(0,0,0,.08) 50%,rgba(0,0,0,.08) 75%,transparent 75%);
+ background-size:20px 20px;
+}
+
+.room-panel:nth-child(4)::after{
+ background-image:repeating-linear-gradient(0deg,transparent,transparent 8px,rgba(255,255,255,.08) 8px,rgba(255,255,255,.08) 16px);
+}
+
+.room-panel:nth-child(5)::after{
+ background-image:conic-gradient(from 0deg at 50% 50%,transparent 0deg,rgba(0,0,0,.06) 20deg,transparent 40deg,rgba(0,0,0,.06) 60deg,transparent 80deg);
+ background-size:30px 30px;
+}
+
+/* Toast */
+.toast{
+ position:fixed;
+ bottom:48px;
+ left:50%;
+ transform:translateX(-50%) translateY(100px);
+ background:var(--surface-2);
+ border:1px solid var(--line);
+ padding:16px 32px;
+ font-family:var(--font-sans);
+ font-size:12px;
+ letter-spacing:.12em;
+ text-transform:uppercase;
+ color:var(--ink);
+ opacity:0;
+ transition:all .5s var(--ease);
+ z-index:200;
+ box-shadow:var(--shadow);
+}
+
+.toast.show{
+ transform:translateX(-50%) translateY(0);
+ opacity:1;
+}
+
+/* Export Overlay */
+.export-overlay{
+ position:fixed;
+ inset:0;
+ background:rgba(13,13,15,.95);
+ display:flex;
+ align-items:center;
+ justify-content:center;
+ z-index:300;
+ opacity:0;
+ pointer-events:none;
+ transition:opacity .5s var(--ease);
+}
+
+.export-overlay.active{
+ opacity:1;
+ pointer-events:all;
+}
+
+.export-card{
+ width:540px;
+ background:var(--surface);
+ border:1px solid var(--line);
+ padding:48px;
+ position:relative;
+ box-shadow:var(--shadow);
+}
+
+.export-header{
+ font-family:var(--font-serif);
+ font-size:32px;
+ margin-bottom:32px;
+ text-align:center;
+}
+
+.export-preview{
+ width:100%;
+ height:320px;
+ background:var(--bg);
+ margin-bottom:32px;
+ display:flex;
+ gap:8px;
+ padding:24px;
+}
+
+.export-swatch{
+ flex:1;
+ height:100%;
+ border-radius:var(--radius);
+}
+
+.export-actions{
+ display:flex;
+ gap:16px;
+ justify-content:center;
+}
+
+/* Animations */
+@keyframes fadeUp{
+ from{opacity:0;transform:translateY(28px)}
+ to{opacity:1;transform:none}
+}
+
+/* Preview card canvas for actual export */
+#exportCanvas{display:none}
+</style>
+</head>
+<body>
+<header class="header">
+ <div class="wordmark">Designer Wallcoverings</div>
+ <div class="header-actions">
+ <button class="btn" onclick="randomizePalette()">Surprise Me</button>
+ <button class="btn btn-primary" onclick="openExport()">Export Card</button>
+ </div>
+</header>
+
+<main class="main">
+ <div class="editorial">
+ <div class="hero">
+ <h1>Curated Palettes</h1>
+ <p>Select a foundation hue to generate an architecturally-balanced wallcovering collection with designer-grade tints.</p>
+ </div>
+
+ <div class="workspace">
+ <div class="wheel-section">
+ <div class="wheel-container">
+ <canvas id="colorWheel"></canvas>
+ <div class="wheel-indicator" id="wheelIndicator"></div>
+ </div>
+
+ <div class="scheme-toggle">
+ <button class="scheme-btn active" data-scheme="analogous">Analogous</button>
+ <button class="scheme-btn" data-scheme="complementary">Complementary</button>
+ <button class="scheme-btn" data-scheme="triadic">Triadic</button>
+ </div>
+ </div>
+
+ <div class="palette-section">
+ <div class="palette-header">
+ <h2 class="palette-title" id="paletteTitle">The Alabaster Collection</h2>
+ </div>
+
+ <div class="swatches" id="swatches">
+ <!-- Generated by JS -->
+ </div>
+
+ <div class="room-section">
+ <div class="room-header">Room Preview</div>
+ <div class="room-strip" id="roomStrip">
+ <!-- Generated by JS -->
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</main>
+
+<div class="toast" id="toast">Hex copied to clipboard</div>
+
+<div class="export-overlay" id="exportOverlay">
+ <div class="export-card">
+ <h3 class="export-header">Export Preview</h3>
+ <div class="export-preview" id="exportPreview">
+ <!-- Generated -->
+ </div>
+ <div class="export-actions">
+ <button class="btn" onclick="closeExport()">Close</button>
+ <button class="btn btn-primary" onclick="downloadCard()">Download 1080x1080</button>
+ </div>
+ </div>
+</div>
+
+<canvas id="exportCanvas" width="1080" height="1080"></canvas>
+
+<script>
+// Color utilities
+function hsvToRgb(h,s,v){
+ let c=v*s;
+ let x=c*(1-Math.abs((h/60)%2-1));
+ let m=v-c;
+ let r,g,b;
+ if(h<60){r=c;g=x;b=0}
+ else if(h<120){r=x;g=c;b=0}
+ else if(h<180){r=0;g=c;b=x}
+ else if(h<240){r=0;g=x;b=c}
+ else if(h<300){r=x;g=0;b=c}
+ else{r=c;g=0;b=x}
+ return[Math.round((r+m)*255),Math.round((g+m)*255),Math.round((b+m)*255)]
+}
+
+function rgbToHex(r,g,b){
+ return'#'+[r,g,b].map(x=>x.toString(16).padStart(2,'0')).join('')
+}
+
+function rgbToHsl(r,g,b){
+ r/=255;g/=255;b/=255;
+ let max=Math.max(r,g,b),min=Math.min(r,g,b);
+ let h,s,l=(max+min)/2;
+ if(max===min){h=s=0}
+ else{
+ let d=max-min;
+ s=l>.5?d/(2-max-min):d/(max+min);
+ switch(max){
+ case r:h=(g-b)/d+(g<b?6:0);break;
+ case g:h=(b-r)/d+2;break;
+ case b:h=(r-g)/d+4;break;
+ }
+ h/=6;
+ }
+ return[h*360,s,l]
+}
+
+function hslToHex(h,s,l){
+ let c=(1-Math.abs(2*l-1))*s;
+ let x=c*(1-Math.abs((h/60)%2-1));
+ let m=l-c/2;
+ let r,g,b;
+ if(h<60){r=c;g=x;b=0}
+ else if(h<120){r=x;g=c;b=0}
+ else if(h<180){r=0;g=c;b=x}
+ else if(h<240){r=0;g=x;b=c}
+ else if(h<300){r=x;g=0;b=c}
+ else{r=c;g=0;b=x}
+ return rgbToHex(Math.round((r+m)*255),Math.round((g+m)*255),Math.round((b+m)*255))
+}
+
+// Designer names
+const designerNames=['Alabaster','Greige','Celadon','Ink','Brass','Ochre','Sage','Blush','Slate','Mink','Dove','Noir','Parchment','Terracotta','Moss','Indigo','Amber','Pewter','Sepia','Ivory','Charcoal','Champagne','Petal','Storm','Verdigris'];
+
+// State
+let currentHue=30;
+let currentScheme='analogous';
+let currentPalette=[];
+let isDragging=false;
+
+// Canvas setup
+const wheel=document.getElementById('colorWheel');
+const ctx=wheel.getContext('2d');
+const indicator=document.getElementById('wheelIndicator');
+
+function resizeWheel(){
+ const rect=wheel.parentElement.getBoundingClientRect();
+ wheel.width=rect.width*2;
+ wheel.height=rect.height*2;
+ wheel.style.width=rect.width+'px';
+ wheel.style.height=rect.height+'px';
+ ctx.scale(2,2);
+ drawWheel();
+}
+
+function drawWheel(){
+ const centerX=wheel.width/4;
+ const centerY=wheel.height/4;
+ const radius=centerX-4;
+
+ for(let angle=0;angle<360;angle++){
+ const startAngle=(angle-90)*Math.PI/180;
+ const endAngle=(angle-89)*Math.PI/180;
+ ctx.beginPath();
+ ctx.moveTo(centerX,centerY);
+ ctx.arc(centerX,centerY,radius,startAngle,endAngle);
+ ctx.closePath();
+ const rgb=hsvToRgb(angle,1,1);
+ ctx.fillStyle=`rgb(${rgb[0]},${rgb[1]},${rgb[2]})`;
+ ctx.fill();
+ }
+
+ // Inner circle for depth
+ ctx.beginPath();
+ ctx.arc(centerX,centerY,radius*0.85,0,Math.PI*2);
+ ctx.fillStyle='#0d0d0f';
+ ctx.fill();
+
+ updateIndicator();
+}
+
+function updateIndicator(){
+ const rect=wheel.parentElement.getBoundingClientRect();
+ const centerX=rect.width/2;
+ const centerY=rect.height/2;
+ const radius=centerX-20;
+ const angle=(currentHue-90)*Math.PI/180;
+ const x=centerX+radius*Math.cos(angle);
+ const y=centerY+radius*Math.sin(angle);
+ indicator.style.left=x+'px';
+ indicator.style.top=y+'px';
+ indicator.style.background=rgbToHex(...hsvToRgb(currentHue,1,1));
+}
+
+// Palette generation
+function generatePalette(){
+ const baseHue=currentHue;
+ const colors=[];
+
+ if(currentScheme==='analogous'){
+ colors.push({h:(baseHue+330)%360,s:0.15,l:0.94});
+ colors.push({h:(baseHue+350)%360,s:0.12,l:0.82});
+ colors.push({h:baseHue,s:0.25,l:0.72});
+ colors.push({h:(baseHue+20)%360,s:0.35,l:0.45});
+ colors.push({h:(baseHue+180)%360,s:0.55,l:0.25});
+ }else if(currentScheme==='complementary'){
+ colors.push({h:(baseHue+30)%360,s:0.08,l:0.96});
+ colors.push({h:(baseHue+15)%360,s:0.18,l:0.75});
+ colors.push({h:baseHue,s:0.45,l:0.55});
+ colors.push({h:(baseHue+180)%360,s:0.50,l:0.45});
+ colors.push({h:(baseHue+180)%360,s:0.25,l:0.20});
+ }else{ // triadic
+ colors.push({h:(baseHue+40)%360,s:0.10,l:0.93});
+ colors.push({h:(baseHue+120)%360,s:0.22,l:0.78});
+ colors.push({h:baseHue,s:0.40,l:0.60});
+ colors.push({h:(baseHue+180)%360,s:0.35,l:0.40});
+ colors.push({h:(baseHue+240)%360,s:0.45,l:0.28});
+ }
+
+ currentPalette=colors.map((c,i)=>({
+ hex:hslToHex(c.h,c.s,c.l),
+ hsl:c,
+ name:designerNames[Math.floor(Math.random()*designerNames.length)]
+ }));
+
+ renderSwatches();
+ renderRoom();
+}
+
+function renderSwatches(){
+ const container=document.getElementById('swatches');
+ container.innerHTML='';
+
+ currentPalette.forEach((color,i)=>{
+ const swatch=document.createElement('div');
+ swatch.className='swatch';
+ swatch.style.background=color.hex;
+ swatch.style.animationDelay=(i*0.1)+'s';
+ swatch.innerHTML=`
+ <div class="swatch-info">
+ <div class="swatch-name">${color.name}</div>
+ <div class="swatch-hex">${color.hex}</div>
+ </div>
+ `;
+ swatch.onclick=()=>copyHex(color.hex);
+ container.appendChild(swatch);
+ });
+
+ // Update title based on dominant color
+ const baseName=currentPalette[2].name;
+ document.getElementById('paletteTitle').textContent=`The ${baseName} Collection`;
+}
+
+function renderRoom(){
+ const container=document.getElementById('roomStrip');
+ container.innerHTML='';
+
+ currentPalette.forEach((color,i)=>{
+ const panel=document.createElement('div');
+ panel.className='room-panel';
+ panel.style.background=color.hex;
+ container.appendChild(panel);
+ });
+}
+
+function copyHex(hex){
+ navigator.clipboard.writeText(hex).then(()=>{
+ const toast=document.getElementById('toast');
+ toast.classList.add('show');
+ setTimeout(()=>toast.classList.remove('show'),2000);
+ });
+}
+
+// Wheel interaction
+function handleWheelInteraction(e){
+ const rect=wheel.getBoundingClientRect();
+ const centerX=rect.width/2;
+ const centerY=rect.height/2;
+ const x=(e.clientX||e.touches?.[0]?.clientX)-rect.left-centerX;
+ const y=(e.clientY||e.touches?.[0]?.clientY)-rect.top-centerY;
+ let angle=Math.atan2(y,x)*180/Math.PI+90;
+ if(angle<0)angle+=360;
+ currentHue=Math.round(angle);
+ updateIndicator();
+ generatePalette();
+}
+
+wheel.addEventListener('mousedown',e=>{
+ isDragging=true;
+ handleWheelInteraction(e);
+});
+
+wheel.addEventListener('mousemove',e=>{
+ if(isDragging)handleWheelInteraction(e);
+});
+
+wheel.addEventListener('mouseup',()=>isDragging=false);
+wheel.addEventListener('mouseleave',()=>isDragging=false);
+
+wheel.addEventListener('touchstart',e=>{
+ isDragging=true;
+ handleWheelInteraction(e);
+ e.preventDefault();
+},{passive:false});
+
+wheel.addEventListener('touchmove',e=>{
+ if(isDragging)handleWheelInteraction(e);
+ e.preventDefault();
+},{passive:false});
+
+wheel.addEventListener('touchend',()=>isDragging=false);
+
+// Scheme toggle
+document.querySelectorAll('.scheme-btn').forEach(btn=>{
+ btn.addEventListener('click',()=>{
+ document.querySelectorAll('.scheme-btn').forEach(b=>b.classList.remove('active'));
+ btn.classList.add('active');
+ currentScheme=btn.dataset.scheme;
+ generatePalette();
+ });
+});
+
+function randomizePalette(){
+ currentHue=Math.floor(Math.random()*360);
+ updateIndicator();
+ generatePalette();
+}
+
+// Export
+function openExport(){
+ const overlay=document.getElementById('exportOverlay');
+ const preview=document.getElementById('exportPreview');
+ preview.innerHTML='';
+
+ currentPalette.forEach(color=>{
+ const div=document.createElement('div');
+ div.className='export-swatch';
+ div.style.background=color.hex;
+ preview.appendChild(div);
+ });
+
+ overlay.classList.add('active');
+}
+
+function closeExport(){
+ document.getElementById('exportOverlay').classList.remove('active');
+}
+
+function downloadCard(){
+ const canvas=document.getElementById('exportCanvas');
+ const ctx=canvas.getContext('2d');
+
+ // Background
+ ctx.fillStyle='#0d0d0f';
+ ctx.fillRect(0,0,1080,1080);
+
+ // Header
+ ctx.fillStyle='#c9a961';
+ ctx.font='500 24px "Playfair Display", Georgia, serif';
+ ctx.textAlign='center';
+ ctx.letterSpacing='0.18em';
+ ctx.fillText('DESIGNER WALLCOVERINGS',540,120);
+
+ // Palette name
+ ctx.fillStyle='#f5f2ea';
+ ctx.font='400 48px "Playfair Display", Georgia, serif';
+ ctx.fillText(document.getElementById('paletteTitle').textContent,540,200);
+
+ // Swatches
+ const swatchWidth=900/currentPalette.length;
+ const startX=90;
+ const swatchY=320;
+ const swatchHeight=440;
+
+ currentPalette.forEach((color,i)=>{
+ ctx.fillStyle=color.hex;
+ ctx.fillRect(startX+i*swatchWidth,swatchY,swatchWidth-12,swatchHeight);
+
+ // Color name
+ ctx.fillStyle='#f5f2ea';
+ ctx.font='400 28px "Playfair Display", Georgia, serif';
+ ctx.fillText(color.name,startX+i*swatchWidth+(swatchWidth-12)/2,swatchY+swatchHeight+50);
+
+ // Hex
+ ctx.fillStyle='#8a8578';
+ ctx.font='500 18px "SF Mono", monospace';
+ ctx.fillText(color.hex.toUpperCase(),startX+i*swatchWidth+(swatchWidth-12)/2,swatchY+swatchHeight+85);
+ });
+
+ // Download
+ const link=document.createElement('a');
+ link.download='designer-wallcoverings-palette.png';
+ link.href=canvas.toDataURL();
+ link.click();
+}
+
+// Init
+window.addEventListener('resize',resizeWheel);
+window.addEventListener('load',()=>{
+ resizeWheel();
+ generatePalette();
+});
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/98e38ea3773f/kimi.png b/data/artifacts/98e38ea3773f/kimi.png
new file mode 100644
index 0000000..b6e178c
Binary files /dev/null and b/data/artifacts/98e38ea3773f/kimi.png differ
diff --git a/data/artifacts/98e38ea3773f/qwen25-7b.html b/data/artifacts/98e38ea3773f/qwen25-7b.html
new file mode 100644
index 0000000..c97e959
--- /dev/null
+++ b/data/artifacts/98e38ea3773f/qwen25-7b.html
@@ -0,0 +1,137 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>DESIGNER WALLCOVERINGS</title>
+ <style>
+ :root {
+ --bg: #0d0d0f;
+ --surface: #17171c;
+ --text: #f5f2ea;
+ --muted: #8a8578;
+ --accent: #c9a961;
+ --line: 1px solid var(--bg);
+ --shadow: 0 8px 24px rgba(0,0,0,.12), hover 0 16px 48px rgba(0,0,0,.18);
+ --ease: cubic-bezier(.22,1,.36,1) both;
+ }
+ body {
+ background-color: var(--bg);
+ color: var(--text);
+ font-family: 'Didot', 'Bodoni MT', 'Playfair Display', Georgia, serif;
+ margin: 0;
+ padding: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100vh;
+ overflow: hidden;
+ }
+ .header {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ background-color: var(--surface);
+ color: var(--text);
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 24px;
+ }
+ .header h1 {
+ font-size: 38px;
+ letter-spacing: .18em;
+ text-transform: uppercase;
+ }
+ .content {
+ width: 90%;
+ max-width: 600px;
+ background-color: var(--surface);
+ border-radius: 14px;
+ box-shadow: var(--shadow);
+ margin-top: 64px;
+ padding: 32px;
+ display: flex;
+ gap: 24px;
+ }
+ .swatches {
+ width: 50%;
+ display: flex;
+ flex-wrap: wrap;
+ gap: 16px;
+ }
+ .swatch {
+ background-color: var(--accent);
+ border-radius: 14px;
+ padding: 24px;
+ cursor: pointer;
+ transition: transform .7s ease-in-out, box-shadow .3s ease-in-out;
+ }
+ .swatch:hover {
+ transform: scale(1.05);
+ box-shadow: var(--shadow) inset, var(--accent) 0 0 24px 8px;
+ }
+ .preview {
+ width: 50%;
+ background-color: #f7efe6;
+ border-radius: 14px;
+ padding: 32px;
+ }
+ .export-button {
+ margin-top: 32px;
+ text-align: center;
+ }
+ .export-button button {
+ background-color: var(--accent);
+ color: var(--text);
+ border: none;
+ padding: 16px 24px;
+ cursor: pointer;
+ font-size: 18px;
+ letter-spacing: .15em;
+ transition: transform .7s ease-in-out, box-shadow .3s ease-in-out;
+ }
+ .export-button button:hover {
+ transform: scale(1.05);
+ box-shadow: var(--shadow) inset, var(--accent) 0 0 24px 8px;
+ }
+ </style>
+</head>
+<body>
+ <div class="header">
+ <h1>DESIGNER WALLCOVERINGS</h1>
+ <button class="nav-button">×</button>
+ </div>
+ <main class="content">
+ <div class="swatches">
+ <div class="swatch" style="background-color: var(--accent);"></div>
+ <div class="swatch" style="background-color: var(--accent);"></div>
+ <div class="swatch" style="background-color: var(--accent);"></div>
+ <div class="swatch" style="background-color: var(--accent);"></div>
+ <div class="swatch" style="background-color: var(--accent);"></div>
+ </div>
+ <div class="preview">
+ <!-- Room Preview Strip -->
+ </div>
+ </main>
+ <script>
+ document.querySelectorAll('.swatch').forEach(swatch => {
+ swatch.addEventListener('click', () => {
+ navigator.clipboard.writeText(`#${(window.getComputedStyle(swatch).backgroundColor.match(/\d+/g) || []).map(Number).join('')}`);
+ });
+ });
+
+ const exportButton = document.querySelector('.export-button button');
+ exportButton.addEventListener('click', () => {
+ const preview = document.querySelector('.preview');
+ preview.style.backgroundImage = `url('https://via.placeholder.com/1080x1080?text=DESIGNER+ WALLCOVERINGS')`;
+ setTimeout(() => {
+ preview.style.backgroundPosition = 'center';
+ preview.style.backgroundSize = 'cover';
+ preview.style.transition = 'background-image 2s ease-in-out';
+ }, 500);
+ });
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/98e38ea3773f/qwen25-7b.png b/data/artifacts/98e38ea3773f/qwen25-7b.png
new file mode 100644
index 0000000..b67297a
Binary files /dev/null and b/data/artifacts/98e38ea3773f/qwen25-7b.png differ
diff --git a/data/artifacts/98e38ea3773f/qwen3-14b.html b/data/artifacts/98e38ea3773f/qwen3-14b.html
new file mode 100644
index 0000000..99a6a8d
--- /dev/null
+++ b/data/artifacts/98e38ea3773f/qwen3-14b.html
@@ -0,0 +1,468 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title>Designer Wallcoverings</title>
+ <style>
+ :root {
+ --bg: #faf8f4;
+ --surface: #ffffff;
+ --text: #1c1a17;
+ --muted: #9b948a;
+ --accent: #b0472e;
+ --accent2: #2f4c39;
+ --line: #e0e0e0;
+ --shadow: 0 8px 24px rgba(0,0,0,0.12);
+ --shadow-hover: 0 16px 48px rgba(0,0,0,0.18);
+ --shadow-glow: 0 0 24px rgba(176,71,46,0.35);
+ --ease: cubic-bezier(0.22, 1, 0.36, 1);
+ --font-display: 'Playfair Display', Georgia, serif;
+ --font-body: -apple-system, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
+ --spacing-4: 4px;
+ --spacing-8: 8px;
+ --spacing-12: 12px;
+ --spacing-16: 16px;
+ --spacing-24: 24px;
+ --spacing-32: 32px;
+ --spacing-48: 48px;
+ --spacing-64: 64px;
+ --card-radius: 14px;
+ --card-gap: 24px;
+ --card-min: 260px;
+ --card-max: 1fr;
+ --transition: 0.25s ease;
+ }
+
+ * {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ }
+
+ body {
+ background-color: var(--bg);
+ color: var(--text);
+ font-family: var(--font-body);
+ font-size: 16px;
+ line-height: 1.5;
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
+ }
+
+ header {
+ background-color: var(--surface);
+ padding: var(--spacing-32) var(--spacing-48);
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ z-index: 1000;
+ box-shadow: var(--shadow);
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ }
+
+ header h1 {
+ font-family: var(--font-display);
+ font-size: 28px;
+ letter-spacing: 0.18em;
+ color: var(--text);
+ margin: 0;
+ text-transform: uppercase;
+ max-width: 280px;
+ white-space: normal;
+ }
+
+ main {
+ padding-top: var(--spacing-128);
+ padding-bottom: var(--spacing-48);
+ padding-left: var(--spacing-48);
+ padding-right: var(--spacing-48);
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-48);
+ align-items: center;
+ }
+
+ .palette-builder {
+ display: flex;
+ gap: var(--spacing-32);
+ align-items: flex-start;
+ flex-wrap: wrap;
+ }
+
+ .palette-builder .color-wheel {
+ flex: 1 1 300px;
+ min-width: 200px;
+ background-color: var(--surface);
+ padding: var(--spacing-24);
+ border-radius: var(--card-radius);
+ box-shadow: var(--shadow);
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-16);
+ }
+
+ .color-wheel h2 {
+ font-size: 24px;
+ font-family: var(--font-display);
+ text-transform: uppercase;
+ letter-spacing: 0.15em;
+ color: var(--muted);
+ }
+
+ .color-wheel .palette-toggle {
+ display: flex;
+ gap: var(--spacing-8);
+ }
+
+ .color-wheel .palette-toggle button {
+ background-color: var(--surface);
+ border: 1px solid var(--line);
+ border-radius: var(--card-radius);
+ padding: var(--spacing-8) var(--spacing-16);
+ font-size: 12px;
+ text-transform: uppercase;
+ letter-spacing: 0.15em;
+ cursor: pointer;
+ transition: var(--transition);
+ }
+
+ .color-wheel .palette-toggle button:hover {
+ background-color: var(--accent2);
+ color: var(--text);
+ }
+
+ .color-wheel .color-picker {
+ display: flex;
+ gap: var(--spacing-8);
+ align-items: center;
+ }
+
+ .color-wheel .color-picker label {
+ font-size: 12px;
+ text-transform: uppercase;
+ letter-spacing: 0.15em;
+ color: var(--muted);
+ }
+
+ .color-wheel .color-picker input[type="range"] {
+ flex: 1;
+ }
+
+ .palette {
+ flex: 1 1 400px;
+ min-width: 300px;
+ display: flex;
+ flex-direction: column;
+ gap: var(--spacing-24);
+ }
+
+ .palette .swatch-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(var(--card-min), 1fr));
+ gap: var(--spacing-24);
+ }
+
+ .swatch {
+ background-color: var(--surface);
+ border: 1px solid var(--line);
+ padding: var(--spacing-24);
+ box-shadow: var(--shadow);
+ border-radius: var(--card-radius);
+ cursor: pointer;
+ transition: var(--transition);
+ }
+
+ .swatch:hover {
+ box-shadow: var(--shadow-hover);
+ }
+
+ .swatch::before {
+ content: '';
+ display: block;
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ top: 0;
+ left: 0;
+ border-radius: var(--card-radius);
+ box-shadow: var(--shadow-glow);
+ opacity: 0;
+ transition: var(--transition);
+ }
+
+ .swatch:focus-within::before {
+ opacity: 1;
+ }
+
+ .room-preview {
+ background-color: var(--surface);
+ padding: var(--spacing-24);
+ border-radius: var(--card-radius);
+ box-shadow: var(--shadow);
+ width: 100%;
+ max-width: 800px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+ }
+
+ .room-preview::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: linear-gradient(120deg, var(--accent), var(--accent2));
+ opacity: 0.05;
+ z-index: 0;
+ pointer-events: none;
+ }
+
+ .room-preview .preview-container {
+ width: 100%;
+ aspect-ratio: 1 / 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background-color: var(--surface);
+ border-radius: var(--card-radius);
+ box-shadow: var(--shadow);
+ position: relative;
+ z-index: 1;
+ }
+
+ .room-preview .preview-container svg {
+ width: 100%;
+ height: 100%;
+ }
+
+ .export-button {
+ background-color: var(--accent);
+ color: var(--text);
+ padding: var(--spacing-12) var(--spacing-24);
+ border: none;
+ border-radius: var(--card-radius);
+ font-size: 14px;
+ text-transform: uppercase;
+ letter-spacing: 0.1em;
+ cursor: pointer;
+ transition: var(--transition);
+ }
+
+ .export-button:hover {
+ background-color: var(--accent2);
+ }
+
+ @keyframes fadeUp {
+ from { opacity: 0; transform: translateY(28px); }
+ to { opacity: 1; transform: translateY(0); }
+ }
+
+ .fade-up {
+ animation: fadeUp 0.7s var(--ease) both;
+ }
+
+ .swatch::before {
+ animation: fadeUp 0.25s var(--ease) both;
+ }
+
+ @media (prefers-reduced-motion: no-preference) {
+ .fade-up {
+ animation: fadeUp 0.7s var(--ease) both;
+ }
+ }
+ </style>
+</head>
+<body>
+ <header>
+ <h1>DESIGNER WALLCOVERINGS</h1>
+ </header>
+ <main class="fade-up">
+ <div class="palette-builder">
+ <div class="color-wheel">
+ <h2>SELECT HUE</h2>
+ <div class="palette-toggle">
+ <button data-type="analogous">analogous</button>
+ <button data-type="complementary">complementary</button>
+ <button data-type="triadic">triadic</button>
+ </div>
+ <div class="color-picker">
+ <label for="hue">Hue</label>
+ <input type="range" id="hue" min="0" max="360" value="20" />
+ </div>
+ </div>
+ <div class="palette">
+ <div class="swatch-grid" id="swatchGrid">
+ <!-- Swatches will be injected here -->
+ </div>
+ </div>
+ </div>
+ <div class="room-preview">
+ <div class="preview-container" id="roomPreview">
+ <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
+ <rect x="0" y="0" width="100" height="100" fill="#ffffff" />
+ <path d="M0,0 L100,0 L100,50 L0,50 Z" fill="url(#pattern)" />
+ <defs>
+ <pattern id="pattern" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse">
+ <rect x="0" y="0" width="20" height="20" fill="#ffffff" />
+ <rect x="0" y="0" width="5" height="5" fill="#8a8578" />
+ </pattern>
+ </defs>
+ </svg>
+ </div>
+ </div>
+ <button class="export-button" id="exportButton">EXPORT AS 1080x1080 CARD</button>
+ </main>
+ <script>
+ const hueSlider = document.getElementById('hue');
+ const swatchGrid = document.getElementById('swatchGrid');
+ const roomPreview = document.getElementById('roomPreview');
+ const exportButton = document.getElementById('exportButton');
+ const paletteToggleButtons = document.querySelectorAll('.palette-toggle button');
+
+ let currentPaletteType = 'analogous';
+
+ function generatePalette(baseHue, paletteType) {
+ const baseColor = `hsl(${baseHue}, 70%, 50%)`;
+ let palette = [];
+
+ if (paletteType === 'analogous') {
+ palette = [
+ `hsl(${baseHue - 30}, 70%, 50%)`,
+ `hsl(${baseHue - 15}, 70%, 50%)`,
+ baseColor,
+ `hsl(${baseHue + 15}, 70%, 50%)`,
+ `hsl(${baseHue + 30}, 70%, 50%)`,
+ ];
+ } else if (paletteType === 'complementary') {
+ palette = [
+ `hsl(${baseHue}, 70%, 50%)`,
+ `hsl(${baseHue + 60}, 70%, 50%)`,
+ `hsl(${baseHue + 120}, 70%, 50%)`,
+ `hsl(${baseHue + 180}, 70%, 50%)`,
+ `hsl(${baseHue + 240}, 70%, 50%)`,
+ ];
+ } else if (paletteType === 'triadic') {
+ palette = [
+ `hsl(${baseHue}, 70%, 50%)`,
+ `hsl(${baseHue + 120}, 70%, 50%)`,
+ `hsl(${baseHue + 240}, 70%, 50%)`,
+ `hsl(${baseHue - 60}, 70%, 50%)`,
+ `hsl(${baseHue + 60}, 70%, 50%)`,
+ ];
+ }
+
+ return palette;
+ }
+
+ function updateSwatches(palette) {
+ swatchGrid.innerHTML = '';
+ palette.forEach((color, index) => {
+ const swatch = document.createElement('div');
+ swatch.className = 'swatch';
+ swatch.style.backgroundColor = color;
+ swatch.innerHTML = `<div class="swatch-copy" style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; display: flex; align-items: center; justify-content: center; color: #fff; font-size: 14px; text-transform: uppercase; letter-spacing: 0.1em; opacity: 0; transition: opacity 0.2s; pointer-events: none;">${color}</div>`;
+ swatch.addEventListener('click', () => {
+ navigator.clipboard.writeText(color);
+ swatch.querySelector('.swatch-copy').style.opacity = 1;
+ setTimeout(() => {
+ swatch.querySelector('.swatch-copy').style.opacity = 0;
+ }, 1000);
+ });
+ swatchGrid.appendChild(swatch);
+ });
+ }
+
+ function updateRoomPreview(palette) {
+ const pattern = document.getElementById('pattern');
+ if (pattern) {
+ pattern.setAttribute('fill', `url(#pattern${palette.length})`);
+ }
+ let patternSVG = '';
+ for (let i = 0; i < palette.length; i++) {
+ patternSVG += `<rect x="${i * 20}" y="0" width="20" height="20" fill="${palette[i]}" />\n`;
+ }
+ const defs = document.querySelector('defs');
+ if (defs) {
+ defs.innerHTML = `
+ <pattern id="pattern${palette.length}" x="0" y="0" width="100" height="100" patternUnits="userSpaceOnUse">
+ ${patternSVG}
+ </pattern>
+ `;
+ }
+ }
+
+ function updateExportButton(palette) {
+ exportButton.addEventListener('click', () => {
+ const canvas = document.createElement('canvas');
+ canvas.width = 1080;
+ canvas.height = 1080;
+ const ctx = canvas.getContext('2d');
+ const imageData = ctx.createImageData(1080, 1080);
+ for (let i = 0; i < imageData.data.length; i += 4) {
+ imageData.data[i] = 255; // R
+ imageData.data[i + 1] = 255; // G
+ imageData.data[i + 2] = 255; // B
+ imageData.data[i + 3] = 255; // A
+ }
+ ctx.putImageData(imageData, 0, 0);
+
+ const pattern = document.getElementById('pattern');
+ if (pattern) {
+ const patternURL = pattern.getAttribute('fill');
+ if (patternURL.startsWith('url(#')) {
+ const patternId = patternURL.match(/#([^)]+)/)[1];
+ const patternSVG = document.querySelector(`pattern#${patternId}`);
+ if (patternSVG) {
+ const svgNS = "http://www.w3.org/2000/svg";
+ const svg = document.createElementNS(svgNS, 'svg');
+ svg.setAttribute('width', '1080');
+ svg.setAttribute('height', '1080');
+ svg.setAttribute('viewBox', '0 0 1080 1080');
+ svg.innerHTML = patternSVG.outerHTML;
+ canvas.getContext('2d').drawImage(svg, 0, 0, 1080, 1080);
+ }
+ }
+ }
+
+ const link = document.createElement('a');
+ link.download = 'wallcovering-card.png';
+ link.href = canvas.toDataURL('image/png');
+ link.click();
+ });
+ }
+
+ function init() {
+ updateSwatches(generatePalette(hueSlider.value, currentPaletteType));
+ updateRoomPreview(generatePalette(hueSlider.value, currentPaletteType));
+ updateExportButton(generatePalette(hueSlider.value, currentPaletteType));
+ }
+
+ hueSlider.addEventListener('input', () => {
+ const palette = generatePalette(hueSlider.value, currentPaletteType);
+ updateSwatches(palette);
+ updateRoomPreview(palette);
+ });
+
+ paletteToggleButtons.forEach(button => {
+ button.addEventListener('click', (e) => {
+ paletteToggleButtons.forEach(btn => btn.classList.remove('active'));
+ e.currentTarget.classList.add('active');
+ currentPaletteType = e.currentTarget.dataset.type;
+ const palette = generatePalette(hueSlider.value, currentPaletteType);
+ updateSwatches(palette);
+ updateRoomPreview(palette);
+ });
+ });
+
+ init();
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/98e38ea3773f/qwen3-14b.png b/data/artifacts/98e38ea3773f/qwen3-14b.png
new file mode 100644
index 0000000..7b3bacc
Binary files /dev/null and b/data/artifacts/98e38ea3773f/qwen3-14b.png differ
diff --git a/data/artifacts/a17a50ae57ef/qwen25-7b.html b/data/artifacts/a17a50ae57ef/qwen25-7b.html
new file mode 100644
index 0000000..fc75c36
--- /dev/null
+++ b/data/artifacts/a17a50ae57ef/qwen25-7b.html
@@ -0,0 +1,146 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Which Design Era?</title>
+<style>
+:root {
+ --bg: #f7efe6;
+ --surface: #fff9f1;
+ --text: #3a2c22;
+ --muted: #a08c7a;
+ --accent: #c65f38;
+ --line: 1px solid var(--bg);
+ --shadow: 0 8px 24px rgba(0,0,0,.12), hover 0 16px 48px rgba(0,0,0,.18);
+ --ease: cubic-bezier(.22,1,.36,1);
+}
+
+body {
+ background-color: var(--bg);
+ margin: 0;
+ padding: 96px;
+ font-family: 'Didot', 'Bodoni MT', Georgia, serif;
+}
+
+header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 48px;
+}
+
+.wordmark {
+ font-size: 32px;
+ letter-spacing: .15em;
+ text-transform: uppercase;
+ color: var(--text);
+}
+
+.swatch {
+ display: inline-block;
+ width: 100px;
+ height: 100px;
+ background-color: var(--surface);
+ border: var(--line);
+ margin-right: 24px;
+ box-shadow: var(--shadow);
+ cursor: pointer;
+ transition: transform .7s var(--ease) both, box-shadow .5s ease-in-out;
+}
+
+.swatch:hover {
+ transform: scale(1.08);
+ box-shadow: var(--shadow), glow 0 0 24px rgba(var(--accent),35%);
+}
+
+.game-over {
+ display: none;
+ text-align: center;
+ margin-top: 96px;
+}
+
+.game-over span {
+ font-size: 24px;
+ color: var(--text);
+ letter-spacing: .18em;
+}
+
+.scoreboard {
+ font-size: 18px;
+ color: var(--text);
+ letter-spacing: .15em;
+ margin-top: 24px;
+}
+</style>
+</head>
+<body>
+<header>
+<div class="wordmark">DESIGNER WALLCOVERINGS</div>
+<button id="victorian" class="swatch"></button>
+<button id="artdeco" class="swatch"></button>
+<button id="midcentury" class="swatch"></button>
+<button id="grandmillennial" class="swatch"></button>
+<div class="scoreboard">Score: 0 / 8</div>
+</header>
+
+<div id="game-over" class="game-over">
+ <span></span>
+</div>
+
+<script>
+const eras = [
+ { name: 'Victorian', color: '#c65f38' },
+ { name: 'Art Deco', color: '#b0472e' },
+ { name: 'Mid-Century Modern', color: '#7d6a45' },
+ { name: 'Grandmillennial', color: '#2f4c39' }
+];
+
+let score = 0;
+const rounds = 8;
+
+document.querySelectorAll('.swatch').forEach(button => {
+ button.addEventListener('click', () => {
+ const correctEra = eras[Math.floor(Math.random() * eras.length)];
+ if (button.id === correctEra.name) {
+ score++;
+ }
+ updateScore();
+ setTimeout(() => {
+ revealCorrectEra(correctEra);
+ }, 1000);
+ });
+});
+
+function updateScore() {
+ document.querySelector('.scoreboard').textContent = `Score: ${score} / 8`;
+}
+
+function revealCorrectEra(era) {
+ const gameOverText = `The correct era was ${era.name}. Fun fact: ${getFunFact(era.name)}!`;
+ document.getElementById('game-over').style.display = 'block';
+ document.querySelector('#game-over span').textContent = gameOverText;
+}
+
+function getFunFact(name) {
+ if (name === 'Victorian') return "Victorians loved ornate designs and rich colors.";
+ if (name === 'Art Deco') return "Art Deco was all about geometric shapes and metallic accents.";
+ if (name === 'Mid-Century Modern') return "Mid-century modern embraced clean lines and a mix of materials.";
+ if (name === 'Grandmillennial') return "Grandmillennial design combines classic and futuristic elements.";
+ return '';
+}
+
+if (!localStorage.getItem('bestScore')) {
+ localStorage.setItem('bestScore', 0);
+}
+
+const bestScore = parseInt(localStorage.getItem('bestScore'), 10);
+
+document.addEventListener('DOMContentLoaded', () => {
+ if (score > bestScore) {
+ localStorage.setItem('bestScore', score);
+ }
+});
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/a17a50ae57ef/qwen25-7b.png b/data/artifacts/a17a50ae57ef/qwen25-7b.png
new file mode 100644
index 0000000..b31d4dd
Binary files /dev/null and b/data/artifacts/a17a50ae57ef/qwen25-7b.png differ
diff --git a/data/challenges.json b/data/challenges.json
index bd5dbf5..7e77b6d 100644
--- a/data/challenges.json
+++ b/data/challenges.json
@@ -15887,13 +15887,13 @@
"queued_at": "2026-07-25T08:12:12.472Z",
"bytes": 9441,
"thumb": true,
- "aiScore": 7.5,
- "aiReason": "The game fulfills the challenge well and has good visual quality with clear text and simple graphics.",
+ "aiScore": 7,
+ "aiReason": "The game is functional and meets the challenge criteria but lacks polish in visual quality.",
"aiScores": {
- "qwen2.5vl:7b": 9,
- "minicpm-v:latest": 6
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 7
},
- "aiSpread": 3
+ "aiSpread": 0
},
{
"model": "hermes3-8b",
@@ -21118,93 +21118,126 @@
"runs": [
{
"model": "qwen3-14b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T11:00:11.352Z"
+ "seconds": 93,
+ "cost": 0,
+ "started_at": "2026-07-25T11:00:18.883Z",
+ "finished_at": "2026-07-25T11:01:51.963Z",
+ "queued_at": "2026-07-25T11:00:11.352Z",
+ "bytes": 13736,
+ "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-25T11:00:11.360Z"
+ "seconds": 71,
+ "cost": 0,
+ "started_at": "2026-07-25T11:01:51.973Z",
+ "finished_at": "2026-07-25T11:03:02.798Z",
+ "queued_at": "2026-07-25T11:00:11.360Z",
+ "bytes": 10413,
+ "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-25T11:00:11.367Z"
+ "seconds": 15,
+ "cost": 0,
+ "started_at": "2026-07-25T11:03:02.808Z",
+ "finished_at": "2026-07-25T11:03:18.170Z",
+ "queued_at": "2026-07-25T11:00:11.367Z",
+ "bytes": 3597,
+ "thumb": true
},
{
"model": "qwen25-7b",
- "status": "running",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
+ "seconds": 32,
+ "cost": 0,
"started_at": "2026-07-25T11:00:11.397Z",
- "finished_at": null,
- "queued_at": "2026-07-25T11:00:11.374Z"
+ "finished_at": "2026-07-25T11:00:43.583Z",
+ "queued_at": "2026-07-25T11:00:11.374Z",
+ "bytes": 4609,
+ "thumb": true
},
{
"model": "hf-qwen-coder-32b",
- "status": "queued",
+ "status": "running",
"error": null,
"seconds": null,
"cost": null,
- "started_at": null,
+ "started_at": "2026-07-25T11:03:18.182Z",
"finished_at": null,
"queued_at": "2026-07-25T11:00:11.379Z"
},
{
"model": "claude-code",
- "status": "running",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
+ "seconds": 189,
+ "cost": 0,
"started_at": "2026-07-25T11:00:11.400Z",
- "finished_at": null,
- "queued_at": "2026-07-25T11:00:11.382Z"
+ "finished_at": "2026-07-25T11:03:20.530Z",
+ "queued_at": "2026-07-25T11:00:11.382Z",
+ "bytes": 27985,
+ "thumb": true
},
{
"model": "kimi",
- "status": "running",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
+ "seconds": 107,
+ "cost": 0.02,
"started_at": "2026-07-25T11:00:11.405Z",
- "finished_at": null,
- "queued_at": "2026-07-25T11:00:11.386Z"
+ "finished_at": "2026-07-25T11:01:58.600Z",
+ "queued_at": "2026-07-25T11:00:11.386Z",
+ "toolCalls": [
+ "opendesign",
+ "opendesign",
+ "hyperframes",
+ "hyperframes"
+ ],
+ "bytes": 19732,
+ "thumb": true
},
{
"model": "gpt",
- "status": "running",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
+ "seconds": 164,
+ "cost": 0.1791,
"started_at": "2026-07-25T11:00:11.410Z",
- "finished_at": null,
- "queued_at": "2026-07-25T11:00:11.389Z"
+ "finished_at": "2026-07-25T11:02:55.905Z",
+ "queued_at": "2026-07-25T11:00:11.389Z",
+ "toolCalls": [
+ "opendesign",
+ "opendesign",
+ "hyperframes"
+ ],
+ "bytes": 39730,
+ "thumb": true
},
{
"model": "grok",
- "status": "running",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
+ "seconds": 127,
+ "cost": 0.1694,
"started_at": "2026-07-25T11:00:11.414Z",
- "finished_at": null,
- "queued_at": "2026-07-25T11:00:11.392Z"
+ "finished_at": "2026-07-25T11:02:18.265Z",
+ "queued_at": "2026-07-25T11:00:11.392Z",
+ "toolCalls": [
+ "opendesign",
+ "opendesign",
+ "opendesign",
+ "hyperframes"
+ ],
+ "bytes": 30160,
+ "thumb": true
}
]
},
@@ -21249,13 +21282,15 @@
},
{
"model": "qwen25-7b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T11:00:11.459Z"
+ "seconds": 30,
+ "cost": 0,
+ "started_at": "2026-07-25T11:00:43.590Z",
+ "finished_at": "2026-07-25T11:01:13.572Z",
+ "queued_at": "2026-07-25T11:00:11.459Z",
+ "bytes": 3696,
+ "thumb": true
},
{
"model": "hf-qwen-coder-32b",
@@ -21269,41 +21304,41 @@
},
{
"model": "claude-code",
- "status": "queued",
+ "status": "running",
"error": null,
"seconds": null,
"cost": null,
- "started_at": null,
+ "started_at": "2026-07-25T11:03:20.533Z",
"finished_at": null,
"queued_at": "2026-07-25T11:00:11.465Z"
},
{
"model": "kimi",
- "status": "queued",
+ "status": "running",
"error": null,
"seconds": null,
"cost": null,
- "started_at": null,
+ "started_at": "2026-07-25T11:01:58.611Z",
"finished_at": null,
"queued_at": "2026-07-25T11:00:11.469Z"
},
{
"model": "gpt",
- "status": "queued",
+ "status": "running",
"error": null,
"seconds": null,
"cost": null,
- "started_at": null,
+ "started_at": "2026-07-25T11:02:55.914Z",
"finished_at": null,
"queued_at": "2026-07-25T11:00:11.472Z"
},
{
"model": "grok",
- "status": "queued",
+ "status": "running",
"error": null,
"seconds": null,
"cost": null,
- "started_at": null,
+ "started_at": "2026-07-25T11:02:18.286Z",
"finished_at": null,
"queued_at": "2026-07-25T11:00:11.476Z"
}
diff --git a/data/costlog.jsonl b/data/costlog.jsonl
index 37e80e3..6f4c888 100644
--- a/data/costlog.jsonl
+++ b/data/costlog.jsonl
@@ -288,3 +288,6 @@
{"ts":"2026-07-25T10:50:14.949Z","provider":"moonshot","model":"kimi-k2.5","task":"model-arena-tools","input_tokens":5474,"output_tokens":7446,"cost_usd":0.021899}
{"ts":"2026-07-25T10:51:01.288Z","provider":"xai","model":"grok-4.5","task":"model-arena-tools","input_tokens":3553,"output_tokens":6925,"cost_usd":0.114534}
{"ts":"2026-07-25T10:52:03.363Z","provider":"moonshot","model":"kimi-k2.5","task":"model-arena-tools","input_tokens":3086,"output_tokens":6952,"cost_usd":0.019232}
+{"ts":"2026-07-25T11:01:58.596Z","provider":"moonshot","model":"kimi-k2.5","task":"model-arena-tools","input_tokens":5665,"output_tokens":6660,"cost_usd":0.020049}
+{"ts":"2026-07-25T11:02:18.261Z","provider":"xai","model":"grok-4.5","task":"model-arena-tools","input_tokens":3990,"output_tokens":10493,"cost_usd":0.169365}
+{"ts":"2026-07-25T11:02:55.901Z","provider":"openai","model":"gpt-5.1","task":"model-arena-tools","input_tokens":3037,"output_tokens":12414,"cost_usd":0.179111}
← 17212b1 night-loop: cycle 04:00 — judged=987bed245bf6 · fired 2 →; F
·
back to Model Arena
·
night-loop: cycle 04:12 — judged=689983752ba8 · fired 2 →; F c5f0c76 →