← back to Model Arena
auto-save: 2026-07-25T00:32:03 (22 files) — data/challenges.json data/costlog.jsonl data/artifacts/724633a205b0/ data/artifacts/ce24cf987953/ data/artifacts/f2e21f2299c9/
bab74b1241ee4f96d8a4379df5a9d234d19ba5a8 · 2026-07-25 00:32:12 -0700 · Steve Abrams
Files touched
A data/artifacts/724633a205b0/claude-code.htmlA data/artifacts/724633a205b0/gpt.htmlA data/artifacts/724633a205b0/gpt.pngA data/artifacts/724633a205b0/grok.htmlA data/artifacts/724633a205b0/grok.pngA data/artifacts/724633a205b0/qwen25-7b.htmlA data/artifacts/724633a205b0/qwen25-7b.pngA data/artifacts/ce24cf987953/claude-code.htmlA data/artifacts/ce24cf987953/claude-code.pngA data/artifacts/ce24cf987953/gemma3-12b.htmlA data/artifacts/ce24cf987953/gemma3-12b.pngA data/artifacts/ce24cf987953/gpt.htmlA data/artifacts/ce24cf987953/gpt.pngA data/artifacts/ce24cf987953/grok.htmlA data/artifacts/ce24cf987953/grok.pngA data/artifacts/ce24cf987953/hermes3-8b.htmlA data/artifacts/ce24cf987953/hermes3-8b.pngA data/artifacts/ce24cf987953/qwen25-7b.htmlA data/artifacts/ce24cf987953/qwen25-7b.pngA data/artifacts/ce24cf987953/qwen3-14b.htmlA data/artifacts/ce24cf987953/qwen3-14b.pngA data/artifacts/f2e21f2299c9/claude-code.htmlA data/artifacts/f2e21f2299c9/claude-code.pngA data/artifacts/f2e21f2299c9/gpt.htmlA data/artifacts/f2e21f2299c9/gpt.pngA data/artifacts/f2e21f2299c9/grok.htmlA data/artifacts/f2e21f2299c9/grok.pngA data/artifacts/f2e21f2299c9/qwen25-7b.htmlA data/artifacts/f2e21f2299c9/qwen25-7b.pngA data/artifacts/f585b9cfcaea/claude-code.htmlA data/artifacts/f585b9cfcaea/claude-code.pngA data/artifacts/f585b9cfcaea/gemma3-12b.htmlA data/artifacts/f585b9cfcaea/gemma3-12b.pngA data/artifacts/f585b9cfcaea/gpt.htmlA data/artifacts/f585b9cfcaea/gpt.pngA data/artifacts/f585b9cfcaea/grok.htmlA data/artifacts/f585b9cfcaea/grok.pngA data/artifacts/f585b9cfcaea/hermes3-8b.htmlA data/artifacts/f585b9cfcaea/hermes3-8b.pngA data/artifacts/f585b9cfcaea/hf-qwen-coder-32b.htmlA data/artifacts/f585b9cfcaea/hf-qwen-coder-32b.pngA data/artifacts/f585b9cfcaea/kimi.htmlA data/artifacts/f585b9cfcaea/kimi.pngA data/artifacts/f585b9cfcaea/qwen3-14b.htmlA data/artifacts/f585b9cfcaea/qwen3-14b.pngM data/challenges.jsonM data/costlog.jsonlA data/landings/724633a205b0-grok.html
Diff
commit bab74b1241ee4f96d8a4379df5a9d234d19ba5a8
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Sat Jul 25 00:32:12 2026 -0700
auto-save: 2026-07-25T00:32:03 (22 files) — data/challenges.json data/costlog.jsonl data/artifacts/724633a205b0/ data/artifacts/ce24cf987953/ data/artifacts/f2e21f2299c9/
---
data/artifacts/724633a205b0/claude-code.html | 403 ++++++
data/artifacts/724633a205b0/gpt.html | 727 ++++++++++
data/artifacts/724633a205b0/gpt.png | Bin 0 -> 239042 bytes
data/artifacts/724633a205b0/grok.html | 544 +++++++
data/artifacts/724633a205b0/grok.png | Bin 0 -> 496071 bytes
data/artifacts/724633a205b0/qwen25-7b.html | 50 +
data/artifacts/724633a205b0/qwen25-7b.png | Bin 0 -> 2977 bytes
data/artifacts/ce24cf987953/claude-code.html | 362 +++++
data/artifacts/ce24cf987953/claude-code.png | Bin 0 -> 203330 bytes
data/artifacts/ce24cf987953/gemma3-12b.html | 239 ++++
data/artifacts/ce24cf987953/gemma3-12b.png | Bin 0 -> 36384 bytes
data/artifacts/ce24cf987953/gpt.html | 675 +++++++++
data/artifacts/ce24cf987953/gpt.png | Bin 0 -> 218058 bytes
data/artifacts/ce24cf987953/grok.html | 207 +++
data/artifacts/ce24cf987953/grok.png | Bin 0 -> 134319 bytes
data/artifacts/ce24cf987953/hermes3-8b.html | 164 +++
data/artifacts/ce24cf987953/hermes3-8b.png | Bin 0 -> 24191 bytes
data/artifacts/ce24cf987953/qwen25-7b.html | 105 ++
data/artifacts/ce24cf987953/qwen25-7b.png | Bin 0 -> 32621 bytes
data/artifacts/ce24cf987953/qwen3-14b.html | 282 ++++
data/artifacts/ce24cf987953/qwen3-14b.png | Bin 0 -> 12383 bytes
data/artifacts/f2e21f2299c9/claude-code.html | 323 +++++
data/artifacts/f2e21f2299c9/claude-code.png | Bin 0 -> 168587 bytes
data/artifacts/f2e21f2299c9/gpt.html | 1478 ++++++++++++++++++++
data/artifacts/f2e21f2299c9/gpt.png | Bin 0 -> 325923 bytes
data/artifacts/f2e21f2299c9/grok.html | 623 +++++++++
data/artifacts/f2e21f2299c9/grok.png | Bin 0 -> 506771 bytes
data/artifacts/f2e21f2299c9/qwen25-7b.html | 81 ++
data/artifacts/f2e21f2299c9/qwen25-7b.png | Bin 0 -> 13924 bytes
data/artifacts/f585b9cfcaea/claude-code.html | 295 ++++
data/artifacts/f585b9cfcaea/claude-code.png | Bin 0 -> 100827 bytes
data/artifacts/f585b9cfcaea/gemma3-12b.html | 207 +++
data/artifacts/f585b9cfcaea/gemma3-12b.png | Bin 0 -> 21332 bytes
data/artifacts/f585b9cfcaea/gpt.html | 1447 +++++++++++++++++++
data/artifacts/f585b9cfcaea/gpt.png | Bin 0 -> 329784 bytes
data/artifacts/f585b9cfcaea/grok.html | 377 +++++
data/artifacts/f585b9cfcaea/grok.png | Bin 0 -> 83386 bytes
data/artifacts/f585b9cfcaea/hermes3-8b.html | 183 +++
data/artifacts/f585b9cfcaea/hermes3-8b.png | Bin 0 -> 63011 bytes
data/artifacts/f585b9cfcaea/hf-qwen-coder-32b.html | 93 ++
data/artifacts/f585b9cfcaea/hf-qwen-coder-32b.png | Bin 0 -> 19408 bytes
data/artifacts/f585b9cfcaea/kimi.html | 404 ++++++
data/artifacts/f585b9cfcaea/kimi.png | Bin 0 -> 61378 bytes
data/artifacts/f585b9cfcaea/qwen3-14b.html | 167 +++
data/artifacts/f585b9cfcaea/qwen3-14b.png | Bin 0 -> 134916 bytes
data/challenges.json | 320 +++--
data/costlog.jsonl | 9 +
data/landings/724633a205b0-grok.html | 553 ++++++++
48 files changed, 10181 insertions(+), 137 deletions(-)
diff --git a/data/artifacts/724633a205b0/claude-code.html b/data/artifacts/724633a205b0/claude-code.html
new file mode 100644
index 0000000..f167473
--- /dev/null
+++ b/data/artifacts/724633a205b0/claude-code.html
@@ -0,0 +1,403 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Grasscloth Weave Simulator</title>
+<style>
+ :root{
+ --bg:#0e0d0a;
+ --panel:rgba(28,25,20,0.72);
+ --edge:rgba(190,170,130,0.18);
+ --gold:#c9a86a;
+ --gold-2:#e6d4a8;
+ --txt:#e8e1d2;
+ --txt-dim:#9c9482;
+ }
+ *{box-sizing:border-box;margin:0;padding:0}
+ html,body{height:100%}
+ body{
+ background:
+ radial-gradient(1200px 700px at 70% -10%, #1c1810 0%, #0e0d0a 60%),
+ var(--bg);
+ color:var(--txt);
+ font-family:"Georgia","Times New Roman",serif;
+ display:flex;
+ min-height:100vh;
+ overflow:hidden;
+ }
+ .stage{
+ flex:1;
+ position:relative;
+ display:flex;
+ align-items:center;
+ justify-content:center;
+ padding:34px;
+ }
+ .frame{
+ position:relative;
+ width:min(78vh, calc(100vw - 400px));
+ aspect-ratio:1/1;
+ border-radius:4px;
+ box-shadow:
+ 0 40px 90px -30px rgba(0,0,0,0.85),
+ 0 0 0 1px rgba(201,168,106,0.22),
+ 0 0 0 12px rgba(20,17,12,0.55),
+ 0 0 0 13px rgba(201,168,106,0.16);
+ overflow:hidden;
+ }
+ canvas{display:block;width:100%;height:100%}
+ .plate{
+ position:absolute;
+ left:24px;bottom:22px;
+ font-size:12px;
+ letter-spacing:.28em;
+ text-transform:uppercase;
+ color:rgba(233,225,210,0.66);
+ text-shadow:0 1px 3px rgba(0,0,0,.7);
+ pointer-events:none;
+ }
+ .plate small{display:block;font-size:9px;letter-spacing:.2em;color:rgba(233,225,210,0.4);margin-top:3px}
+
+ .panel{
+ width:360px;
+ background:var(--panel);
+ backdrop-filter:blur(14px);
+ border-left:1px solid var(--edge);
+ padding:38px 34px;
+ display:flex;
+ flex-direction:column;
+ gap:8px;
+ overflow-y:auto;
+ }
+ .brand{
+ font-size:11px;letter-spacing:.42em;text-transform:uppercase;
+ color:var(--gold);margin-bottom:2px;
+ }
+ h1{
+ font-size:26px;font-weight:400;line-height:1.15;
+ letter-spacing:.01em;color:var(--gold-2);
+ margin-bottom:6px;
+ }
+ .sub{font-size:12.5px;line-height:1.6;color:var(--txt-dim);margin-bottom:26px;font-style:italic}
+
+ .ctrl{margin-bottom:22px}
+ .ctrl .lab{
+ display:flex;justify-content:space-between;align-items:baseline;
+ font-size:11px;letter-spacing:.2em;text-transform:uppercase;
+ color:var(--txt);margin-bottom:11px;
+ }
+ .ctrl .val{color:var(--gold);font-size:11px;letter-spacing:.12em}
+
+ input[type=range]{
+ -webkit-appearance:none;appearance:none;width:100%;height:2px;
+ background:linear-gradient(to right,var(--gold),rgba(201,168,106,0.15));
+ border-radius:2px;outline:none;cursor:pointer;
+ }
+ input[type=range]::-webkit-slider-thumb{
+ -webkit-appearance:none;appearance:none;width:15px;height:15px;border-radius:50%;
+ background:radial-gradient(circle at 35% 30%,#f4e7c4,#b8934f 70%);
+ border:1px solid rgba(0,0,0,.35);
+ box-shadow:0 2px 6px rgba(0,0,0,.5);cursor:pointer;
+ }
+ input[type=range]::-moz-range-thumb{
+ width:15px;height:15px;border-radius:50%;border:1px solid rgba(0,0,0,.35);
+ background:radial-gradient(circle at 35% 30%,#f4e7c4,#b8934f 70%);
+ box-shadow:0 2px 6px rgba(0,0,0,.5);cursor:pointer;
+ }
+
+ .swatchrow{display:flex;gap:18px;margin-bottom:8px}
+ .swatch{flex:1}
+ .swatch .lab{font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--txt-dim);margin-bottom:9px}
+ .chips{display:flex;flex-wrap:wrap;gap:7px}
+ .chip{
+ width:26px;height:26px;border-radius:50%;cursor:pointer;
+ border:1px solid rgba(255,255,255,0.12);
+ box-shadow:inset 0 1px 2px rgba(255,255,255,0.15),0 1px 3px rgba(0,0,0,.4);
+ transition:transform .15s ease, box-shadow .15s ease;
+ }
+ .chip:hover{transform:scale(1.12)}
+ .chip.sel{
+ box-shadow:0 0 0 2px var(--bg),0 0 0 3px var(--gold);
+ transform:scale(1.1);
+ }
+ .picker{margin-top:11px;display:flex;align-items:center;gap:10px}
+ .picker input[type=color]{
+ -webkit-appearance:none;appearance:none;width:34px;height:22px;border:none;
+ background:none;cursor:pointer;padding:0;
+ }
+ .picker input[type=color]::-webkit-color-swatch-wrapper{padding:0}
+ .picker input[type=color]::-webkit-color-swatch{border:1px solid rgba(255,255,255,.2);border-radius:3px}
+ .picker span{font-size:10px;letter-spacing:.1em;color:var(--txt-dim);text-transform:uppercase}
+
+ .divider{height:1px;background:var(--edge);margin:20px 0 24px}
+ .foot{font-size:10px;letter-spacing:.12em;color:rgba(156,148,130,0.55);line-height:1.7;margin-top:auto;padding-top:20px}
+
+ @media(max-width:820px){
+ body{flex-direction:column;overflow:auto}
+ .frame{width:min(88vw,88vw)}
+ .panel{width:100%;border-left:none;border-top:1px solid var(--edge)}
+ }
+</style>
+</head>
+<body>
+ <div class="stage">
+ <div class="frame">
+ <canvas id="c"></canvas>
+ <div class="plate">Natural Grasscloth<small>Hand-woven simulation</small></div>
+ </div>
+ </div>
+
+ <aside class="panel">
+ <div class="brand">Atelier · Wallcoverings</div>
+ <h1>Grasscloth Weave Studio</h1>
+ <div class="sub">A living study in woven natural fiber — adjust the hand, hue and light of a bespoke wallcovering.</div>
+
+ <div class="ctrl">
+ <div class="lab"><span>Weave Density</span><span class="val" id="vDensity">Medium</span></div>
+ <input type="range" id="density" min="14" max="72" value="34" step="1">
+ </div>
+
+ <div class="ctrl">
+ <div class="lab"><span>Sheen</span><span class="val" id="vSheen">45%</span></div>
+ <input type="range" id="sheen" min="0" max="100" value="45" step="1">
+ </div>
+
+ <div class="ctrl">
+ <div class="lab"><span>Fiber Irregularity</span><span class="val" id="vRough">38%</span></div>
+ <input type="range" id="rough" min="0" max="100" value="38" step="1">
+ </div>
+
+ <div class="divider"></div>
+
+ <div class="swatchrow">
+ <div class="swatch">
+ <div class="lab">Warp Tone</div>
+ <div class="chips" id="chipsA"></div>
+ <div class="picker"><input type="color" id="colA" value="#b8a279"><span id="hexA">#b8a279</span></div>
+ </div>
+ <div class="swatch">
+ <div class="lab">Weft Tone</div>
+ <div class="chips" id="chipsB"></div>
+ <div class="picker"><input type="color" id="colB" value="#7d6a45"><span id="hexB">#7d6a45</span></div>
+ </div>
+ </div>
+
+ <div class="foot">Rendered live on canvas · subtle light sweep active · woven two-tone fiber</div>
+ </aside>
+
+<script>
+(function(){
+ const cvs = document.getElementById('c');
+ const ctx = cvs.getContext('2d', { alpha:false });
+
+ // ---- state ----
+ const state = {
+ density: 34, // fibers across
+ sheen: 0.45,
+ rough: 0.38,
+ colA: '#b8a279', // warp
+ colB: '#7d6a45' // weft
+ };
+
+ const palette = [
+ '#d8c9a6','#c4b48c','#b8a279','#a68a5c','#8f7a52',
+ '#7d6a45','#655137','#4d3f2c','#c9b79a','#9a8f78',
+ '#8a9078','#6f7a63','#b5a58f','#e2d8c2'
+ ];
+
+ // ---- color utils ----
+ function hex2rgb(h){
+ h=h.replace('#','');
+ if(h.length===3)h=h.split('').map(c=>c+c).join('');
+ return [parseInt(h.slice(0,2),16),parseInt(h.slice(2,4),16),parseInt(h.slice(4,6),16)];
+ }
+ function mix(a,b,t){return a+(b-a)*t;}
+ function clamp(v,lo,hi){return v<lo?lo:v>hi?hi:v;}
+ function shade(rgb,f){ // f>1 lighten, <1 darken
+ return [clamp(rgb[0]*f,0,255),clamp(rgb[1]*f,0,255),clamp(rgb[2]*f,0,255)];
+ }
+ function rgbStr(c){return 'rgb('+(c[0]|0)+','+(c[1]|0)+','+(c[2]|0)+')';}
+
+ // ---- deterministic noise per fiber ----
+ function hash(x){
+ x = (x<<13) ^ x;
+ return 1.0 - ((x * (x*x*15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0;
+ }
+
+ // ---- sizing ----
+ let W=0,H=0,DPR=Math.min(window.devicePixelRatio||1,2);
+ function resize(){
+ const r = cvs.getBoundingClientRect();
+ W = Math.max(2, Math.floor(r.width));
+ H = Math.max(2, Math.floor(r.height));
+ cvs.width = Math.floor(W*DPR);
+ cvs.height = Math.floor(H*DPR);
+ ctx.setTransform(DPR,0,0,DPR,0,0);
+ }
+
+ // ---- render ----
+ let t0 = performance.now();
+ function draw(now){
+ const time = (now - t0)/1000;
+
+ const rgbA = hex2rgb(state.colA);
+ const rgbB = hex2rgb(state.colB);
+ // ground / base weave color = darker blend for gaps
+ const ground = shade([mix(rgbA[0],rgbB[0],.5),mix(rgbA[1],rgbB[1],.5),mix(rgbA[2],rgbB[2],.5)],0.42);
+
+ ctx.fillStyle = rgbStr(ground);
+ ctx.fillRect(0,0,W,H);
+
+ const n = state.density|0; // fibers per axis
+ const cell = Math.max(3, W / n); // pixel size of one weave cell
+ const fiberW = cell*0.86; // thread thickness
+ const gap = (cell - fiberW)/2;
+ const sheen = state.sheen;
+ const rough = state.rough;
+
+ // light sweep position (diagonal), slow
+ const sweep = (Math.sin(time*0.35)*0.5+0.5); // 0..1
+ const sweepX = sweep * W * 1.4 - W*0.2;
+ const sweepBand = W*0.55;
+
+ // Precompute how "lit" a point is by the moving highlight
+ function litAt(px,py){
+ // diagonal coordinate
+ const d = (px*0.72 + py*0.28);
+ const dist = Math.abs(d - sweepX - py*0.0);
+ const g = Math.max(0, 1 - dist/sweepBand);
+ return g*g; // 0..1 soft band
+ }
+
+ const cols = Math.ceil(W/cell)+1;
+ const rows = Math.ceil(H/cell)+1;
+
+ // Draw plain-weave: alternate which thread is "on top".
+ // Horizontal (weft) and vertical (warp) threads interlace.
+ for(let ry=0; ry<rows; ry++){
+ const y = ry*cell;
+ for(let rx=0; rx<cols; rx++){
+ const x = rx*cell;
+ const over = ((rx+ry)&1)===0; // checkerboard over/under
+
+ // per-fiber slubby variation (natural irregularity)
+ const hv = hash(rx*92821 + ry*3);
+ const hh = hash(ry*76543 + rx*7);
+ const wobV = 1 + hv*rough*0.5; // warp thickness var
+ const wobH = 1 + hh*rough*0.5; // weft thickness var
+ const toneV = 1 + hash(rx*13+ry*131)*rough*0.28;
+ const toneH = 1 + hash(ry*17+rx*151)*rough*0.28;
+
+ const centerX = x+cell/2, centerY = y+cell/2;
+ const light = litAt(centerX,centerY);
+
+ function paintThread(vertical, colorRGB, tone, wob){
+ // base shaded color
+ let base = shade(colorRGB, tone);
+ // cylindrical shading across the thread + sheen highlight from sweep
+ const tw = fiberW*wob;
+ const half = tw/2;
+ const steps = Math.max(3, Math.min(9, Math.round(cell/3)));
+ for(let s=0;s<steps;s++){
+ const f = s/(steps-1); // 0..1 across thread
+ // cross-section brightness: bright center, dark edges
+ const cross = Math.sin(f*Math.PI); // 0..1..0
+ let b = 0.62 + cross*0.5; // ambient + round shading
+ // sheen: moving highlight lifts glossy center
+ b += light * sheen * cross * 0.85;
+ const col = shade(base, b);
+ ctx.fillStyle = rgbStr(col);
+ if(vertical){
+ const sx = centerX - half + f*tw;
+ ctx.fillRect(sx, y-0.5, tw/steps+0.6, cell+1);
+ }else{
+ const sy = centerY - half + f*tw;
+ ctx.fillRect(x-0.5, sy, cell+1, tw/steps+0.6);
+ }
+ }
+ // subtle end-shadow where thread dips under the crossing one
+ ctx.fillStyle='rgba(20,15,8,0.30)';
+ if(vertical){
+ ctx.fillRect(centerX-half, y-0.5, tw, cell*0.16);
+ ctx.fillRect(centerX-half, y+cell*0.84, tw, cell*0.16);
+ }else{
+ ctx.fillRect(x-0.5, centerY-half, cell*0.16, tw);
+ ctx.fillRect(x+cell*0.84, centerY-half, cell*0.16, tw);
+ }
+ }
+
+ // paint under-thread first, then over-thread
+ if(over){
+ paintThread(false, rgbB, toneH, wobH); // weft under
+ paintThread(true, rgbA, toneV, wobV); // warp over
+ }else{
+ paintThread(true, rgbA, toneV, wobV); // warp under
+ paintThread(false, rgbB, toneH, wobH); // weft over
+ }
+ }
+ }
+
+ // vignette for luxury framing
+ const vg = ctx.createRadialGradient(W/2,H*0.42,W*0.2, W/2,H/2,W*0.75);
+ vg.addColorStop(0,'rgba(0,0,0,0)');
+ vg.addColorStop(1,'rgba(10,8,4,0.42)');
+ ctx.fillStyle=vg;
+ ctx.fillRect(0,0,W,H);
+
+ // faint global sheen glaze that follows the sweep, adds "silk" life
+ const gx = ctx.createLinearGradient(sweepX-sweepBand,0,sweepX+sweepBand,H);
+ gx.addColorStop(0,'rgba(255,246,220,0)');
+ gx.addColorStop(0.5,'rgba(255,246,220,'+(0.05+sheen*0.10)+')');
+ gx.addColorStop(1,'rgba(255,246,220,0)');
+ ctx.fillStyle=gx;
+ ctx.fillRect(0,0,W,H);
+
+ requestAnimationFrame(draw);
+ }
+
+ // ---- UI wiring ----
+ const $ = id=>document.getElementById(id);
+ const densityLabels = v => v<22?'Fine':v<38?'Medium':v<56?'Coarse':'Rustic';
+
+ function buildChips(container, targetInput, hexSpan, which){
+ palette.forEach(col=>{
+ const d=document.createElement('div');
+ d.className='chip';
+ d.style.background=col;
+ d.dataset.col=col;
+ d.addEventListener('click',()=>{
+ targetInput.value=col;
+ hexSpan.textContent=col;
+ state[which]=col;
+ markSel(container,col);
+ });
+ container.appendChild(d);
+ });
+ }
+ function markSel(container,col){
+ [...container.children].forEach(c=>{
+ c.classList.toggle('sel', c.dataset.col.toLowerCase()===col.toLowerCase());
+ });
+ }
+
+ buildChips($('chipsA'),$('colA'),$('hexA'),'colA');
+ buildChips($('chipsB'),$('colB'),$('hexB'),'colB');
+ markSel($('chipsA'),state.colA);
+ markSel($('chipsB'),state.colB);
+
+ $('density').addEventListener('input',e=>{state.density=+e.target.value; $('vDensity').textContent=densityLabels(state.density);});
+ $('sheen').addEventListener('input',e=>{state.sheen=e.target.value/100; $('vSheen').textContent=e.target.value+'%';});
+ $('rough').addEventListener('input',e=>{state.rough=e.target.value/100; $('vRough').textContent=e.target.value+'%';});
+ $('colA').addEventListener('input',e=>{state.colA=e.target.value; $('hexA').textContent=e.target.value; markSel($('chipsA'),e.target.value);});
+ $('colB').addEventListener('input',e=>{state.colB=e.target.value; $('hexB').textContent=e.target.value; markSel($('chipsB'),e.target.value);});
+
+ $('vDensity').textContent=densityLabels(state.density);
+
+ window.addEventListener('resize',resize);
+ resize();
+ requestAnimationFrame(draw);
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/724633a205b0/gpt.html b/data/artifacts/724633a205b0/gpt.html
new file mode 100644
index 0000000..083d500
--- /dev/null
+++ b/data/artifacts/724633a205b0/gpt.html
@@ -0,0 +1,727 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>Grasscloth Weave Simulator</title>
+<style>
+ :root {
+ color-scheme: dark light;
+ --bg: #050608;
+ --panel-bg: rgba(12, 12, 14, 0.96);
+ --accent: #c0a878;
+ --accent-soft: #7b6745;
+ --text-main: #f6f2e9;
+ --text-muted: #b6afa1;
+ --border-subtle: rgba(255,255,255,0.08);
+ --shadow-soft: 0 24px 60px rgba(0,0,0,0.75);
+ --radius-lg: 18px;
+ --radius-md: 10px;
+ }
+ * {
+ box-sizing: border-box;
+ }
+ html, body {
+ margin: 0;
+ padding: 0;
+ height: 100%;
+ width: 100%;
+ overflow: hidden;
+ background: radial-gradient(circle at top, #202024 0%, #050608 45%, #020205 100%);
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "SF Pro Text",
+ "Segoe UI", Roboto, sans-serif;
+ color: var(--text-main);
+ }
+ body {
+ display: flex;
+ align-items: stretch;
+ justify-content: center;
+ }
+ .shell {
+ display: flex;
+ flex-direction: row;
+ width: min(1180px, 100vw);
+ height: min(680px, 100vh);
+ margin: auto;
+ padding: 18px;
+ gap: 18px;
+ }
+ .card {
+ background: radial-gradient(circle at top left, rgba(255,255,255,0.06), transparent 55%),
+ radial-gradient(circle at bottom right, rgba(255,255,255,0.05), transparent 60%),
+ var(--panel-bg);
+ border-radius: var(--radius-lg);
+ border: 1px solid rgba(255,255,255,0.06);
+ box-shadow: var(--shadow-soft);
+ backdrop-filter: blur(20px) saturate(140%);
+ -webkit-backdrop-filter: blur(20px) saturate(140%);
+ overflow: hidden;
+ position: relative;
+ }
+ #viewCard {
+ flex: 1 1 auto;
+ display: flex;
+ align-items: stretch;
+ justify-content: center;
+ }
+ #controlsCard {
+ width: 310px;
+ min-width: 270px;
+ display: flex;
+ flex-direction: column;
+ padding: 16px 16px 18px;
+ gap: 10px;
+ }
+ .view-inner {
+ position: relative;
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ }
+ #weaveCanvas {
+ flex: 1;
+ width: 100%;
+ height: 100%;
+ display: block;
+ border-radius: calc(var(--radius-lg) - 2px);
+ background: #151515;
+ }
+ .view-header {
+ position: absolute;
+ z-index: 2;
+ top: 12px;
+ left: 16px;
+ padding: 8px 12px;
+ border-radius: 999px;
+ background: radial-gradient(circle at top, rgba(0,0,0,0.3), rgba(0,0,0,0.75));
+ border: 1px solid rgba(255,255,255,0.12);
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 8px;
+ pointer-events: none;
+ }
+ .view-title {
+ font-size: 13px;
+ letter-spacing: 0.12em;
+ text-transform: uppercase;
+ color: var(--text-muted);
+ }
+ .view-pill {
+ font-size: 11px;
+ text-transform: uppercase;
+ letter-spacing: 0.16em;
+ color: rgba(248,244,233,0.88);
+ padding: 3px 9px;
+ border-radius: 999px;
+ border: 1px solid rgba(235,220,188,0.45);
+ background: linear-gradient(120deg,
+ rgba(242,228,200,0.24),
+ rgba(176,148,103,0.22),
+ rgba(32,26,18,0.8));
+ box-shadow: 0 0 18px rgba(230,214,186,0.4);
+ }
+ .view-footer {
+ position: absolute;
+ bottom: 12px;
+ left: 16px;
+ right: 16px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ font-size: 11px;
+ color: rgba(245,240,229,0.78);
+ pointer-events: none;
+ }
+ .view-footer span {
+ border-radius: 999px;
+ padding: 4px 9px;
+ background: radial-gradient(circle at top, rgba(0,0,0,0.65), rgba(0,0,0,0.95));
+ border: 1px solid rgba(255,255,255,0.14);
+ backdrop-filter: blur(8px);
+ }
+ /* Controls */
+ .header-row {
+ display: flex;
+ align-items: baseline;
+ justify-content: space-between;
+ gap: 6px;
+ margin-bottom: 4px;
+ }
+ h1 {
+ margin: 0;
+ font-size: 17px;
+ letter-spacing: 0.1em;
+ text-transform: uppercase;
+ color: var(--text-main);
+ }
+ .sub {
+ font-size: 11px;
+ text-transform: uppercase;
+ letter-spacing: 0.18em;
+ color: var(--text-muted);
+ }
+ .divider {
+ height: 1px;
+ background: linear-gradient(90deg,
+ transparent,
+ rgba(255,255,255,0.32),
+ transparent);
+ opacity: 0.6;
+ margin: 2px 0 6px;
+ }
+ .group {
+ margin-top: 6px;
+ padding: 8px 10px;
+ border-radius: var(--radius-md);
+ background: radial-gradient(circle at top left, rgba(255,255,255,0.04), transparent 55%),
+ radial-gradient(circle at bottom right, rgba(0,0,0,0.75), rgba(0,0,0,0.95));
+ border: 1px solid rgba(255,255,255,0.07);
+ }
+ .group-label {
+ font-size: 11px;
+ text-transform: uppercase;
+ letter-spacing: 0.2em;
+ color: rgba(224,214,190,0.84);
+ margin-bottom: 6px;
+ display: flex;
+ justify-content: space-between;
+ }
+ .group-label span.meta {
+ color: rgba(198,188,166,0.8);
+ }
+ .slider-row {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ margin: 4px 0;
+ }
+ .slider-label {
+ width: 70px;
+ font-size: 10px;
+ text-transform: uppercase;
+ letter-spacing: 0.16em;
+ color: var(--text-muted);
+ }
+ .slider-wrap {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ }
+ input[type="range"] {
+ -webkit-appearance: none;
+ appearance: none;
+ width: 100%;
+ background: transparent;
+ }
+ input[type="range"]:focus {
+ outline: none;
+ }
+ input[type="range"]::-webkit-slider-runnable-track {
+ height: 4px;
+ cursor: pointer;
+ background: linear-gradient(90deg,
+ rgba(130,110,78,0.4),
+ rgba(217,194,146,0.9));
+ border-radius: 999px;
+ }
+ input[type="range"]::-moz-range-track {
+ height: 4px;
+ cursor: pointer;
+ background: linear-gradient(90deg,
+ rgba(130,110,78,0.4),
+ rgba(217,194,146,0.9));
+ border-radius: 999px;
+ }
+ input[type="range"]::-webkit-slider-thumb {
+ -webkit-appearance: none;
+ appearance: none;
+ margin-top: -4px;
+ width: 14px;
+ height: 14px;
+ border-radius: 50%;
+ background: radial-gradient(circle at 30% 30%, #fff7e1, #c4a469 55%, #56442b 100%);
+ border: 0;
+ box-shadow: 0 0 0 4px rgba(238,221,188,0.3);
+ }
+ input[type="range"]::-moz-range-thumb {
+ width: 14px;
+ height: 14px;
+ border-radius: 50%;
+ background: radial-gradient(circle at 30% 30%, #fff7e1, #c4a469 55%, #56442b 100%);
+ border: 0;
+ box-shadow: 0 0 0 4px rgba(238,221,188,0.3);
+ }
+ .value-pill {
+ min-width: 42px;
+ padding: 2px 6px;
+ border-radius: 999px;
+ font-size: 10px;
+ text-align: right;
+ color: rgba(244,236,220,0.9);
+ background: radial-gradient(circle at top, rgba(255,255,255,0.16), rgba(0,0,0,0.92));
+ border: 1px solid rgba(255,255,255,0.18);
+ }
+ /* Color swatches */
+ .swatch-row {
+ display: flex;
+ gap: 6px;
+ margin-top: 6px;
+ }
+ .swatch {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ padding: 6px 7px;
+ border-radius: 999px;
+ background: radial-gradient(circle at top left, rgba(255,255,255,0.12), rgba(0,0,0,0.85));
+ border: 1px solid rgba(255,255,255,0.14);
+ }
+ .swatch-label {
+ font-size: 10px;
+ text-transform: uppercase;
+ letter-spacing: 0.12em;
+ color: var(--text-muted);
+ }
+ .swatch-chip {
+ width: 18px;
+ height: 18px;
+ border-radius: 999px;
+ border: 1px solid rgba(255,255,255,0.65);
+ box-shadow: 0 0 0 1px rgba(0,0,0,0.65), 0 0 18px rgba(0,0,0,0.85);
+ }
+ .footer-note {
+ margin-top: auto;
+ font-size: 10px;
+ letter-spacing: 0.16em;
+ text-transform: uppercase;
+ color: rgba(187,174,152,0.9);
+ display: flex;
+ justify-content: space-between;
+ gap: 8px;
+ opacity: 0.9;
+ }
+ .footer-note span {
+ white-space: nowrap;
+ }
+ @media (max-width: 900px) {
+ .shell {
+ flex-direction: column-reverse;
+ height: 100vh;
+ width: 100vw;
+ padding: 8px;
+ }
+ #controlsCard {
+ width: 100%;
+ max-height: 40%;
+ min-height: 220px;
+ }
+ }
+</style>
+</head>
+<body>
+<div class="shell">
+ <div id="viewCard" class="card">
+ <div class="view-inner">
+ <canvas id="weaveCanvas"></canvas>
+ <div class="view-header">
+ <div class="view-title">Grasscloth Weave Study</div>
+ <div class="view-pill">Natural Fibre / Brushed Light</div>
+ </div>
+ <div class="view-footer">
+ <span id="footerDensity">Density • 0.52</span>
+ <span>Realtime Weave Shader</span>
+ </div>
+ </div>
+ </div>
+ <div id="controlsCard" class="card">
+ <div class="header-row">
+ <h1>Texture Simulator</h1>
+ <div class="sub">Canvas • 60 FPS</div>
+ </div>
+ <div class="divider"></div>
+
+ <div class="group">
+ <div class="group-label">
+ <span>Weave Density</span>
+ <span class="meta">Warp / Weft Scale</span>
+ </div>
+ <div class="slider-row">
+ <div class="slider-label">Threads</div>
+ <div class="slider-wrap">
+ <input id="densitySlider" type="range" min="0.25" max="0.85" step="0.01" value="0.52">
+ <div id="densityValue" class="value-pill">0.52</div>
+ </div>
+ </div>
+ <div class="slider-row">
+ <div class="slider-label">Irregular</div>
+ <div class="slider-wrap">
+ <input id="slubSlider" type="range" min="0" max="1" step="0.02" value="0.45">
+ <div id="slubValue" class="value-pill">0.45</div>
+ </div>
+ </div>
+ </div>
+
+ <div class="group">
+ <div class="group-label">
+ <span>Fibre Palette</span>
+ <span class="meta">Two‑Tone Neutral</span>
+ </div>
+ <div class="slider-row">
+ <div class="slider-label">Hue Mix</div>
+ <div class="slider-wrap">
+ <input id="hueSlider" type="range" min="-0.12" max="0.18" step="0.01" value="0.04">
+ <div id="hueValue" class="value-pill">Warm</div>
+ </div>
+ </div>
+ <div class="slider-row">
+ <div class="slider-label">Contrast</div>
+ <div class="slider-wrap">
+ <input id="contrastSlider" type="range" min="0" max="1" step="0.02" value="0.55">
+ <div id="contrastValue" class="value-pill">0.55</div>
+ </div>
+ </div>
+ <div class="swatch-row">
+ <div class="swatch">
+ <div class="swatch-label">Warp</div>
+ <div id="warpChip" class="swatch-chip"></div>
+ </div>
+ <div class="swatch">
+ <div class="swatch-label">Weft</div>
+ <div id="weftChip" class="swatch-chip"></div>
+ </div>
+ </div>
+ </div>
+
+ <div class="group">
+ <div class="group-label">
+ <span>Sheen & Light</span>
+ <span class="meta">Brushed Highlight</span>
+ </div>
+ <div class="slider-row">
+ <div class="slider-label">Sheen</div>
+ <div class="slider-wrap">
+ <input id="sheenSlider" type="range" min="0" max="1" step="0.02" value="0.52">
+ <div id="sheenValue" class="value-pill">0.52</div>
+ </div>
+ </div>
+ <div class="slider-row">
+ <div class="slider-label">Depth</div>
+ <div class="slider-wrap">
+ <input id="depthSlider" type="range" min="0" max="1" step="0.02" value="0.6">
+ <div id="depthValue" class="value-pill">0.60</div>
+ </div>
+ </div>
+ <div class="slider-row">
+ <div class="slider-label">Sweep</div>
+ <div class="slider-wrap">
+ <input id="speedSlider" type="range" min="0.3" max="2.0" step="0.05" value="0.9">
+ <div id="speedValue" class="value-pill">0.90×</div>
+ </div>
+ </div>
+ </div>
+
+ <div class="footer-note">
+ <span>Hand‑loomed simulation</span>
+ <span>Subtle noise · No tiling</span>
+ </div>
+ </div>
+</div>
+
+<script>
+(function(){
+ const canvas = document.getElementById('weaveCanvas');
+ const ctx = canvas.getContext('2d', { alpha:false });
+
+ const densitySlider = document.getElementById('densitySlider');
+ const slubSlider = document.getElementById('slubSlider');
+ const hueSlider = document.getElementById('hueSlider');
+ const contrastSlider = document.getElementById('contrastSlider');
+ const sheenSlider = document.getElementById('sheenSlider');
+ const depthSlider = document.getElementById('depthSlider');
+ const speedSlider = document.getElementById('speedSlider');
+
+ const densityValue = document.getElementById('densityValue');
+ const slubValue = document.getElementById('slubValue');
+ const hueValue = document.getElementById('hueValue');
+ const contrastValue = document.getElementById('contrastValue');
+ const sheenValue = document.getElementById('sheenValue');
+ const depthValue = document.getElementById('depthValue');
+ const speedValue = document.getElementById('speedValue');
+ const footerDensity = document.getElementById('footerDensity');
+
+ const warpChip = document.getElementById('warpChip');
+ const weftChip = document.getElementById('weftChip');
+
+ let width = 0, height = 0, pixelRatio = 1;
+
+ function resize() {
+ const rect = canvas.getBoundingClientRect();
+ pixelRatio = window.devicePixelRatio || 1;
+ width = Math.max(2, rect.width * pixelRatio);
+ height = Math.max(2, rect.height * pixelRatio);
+ if (canvas.width !== width || canvas.height !== height) {
+ canvas.width = width;
+ canvas.height = height;
+ }
+ }
+ window.addEventListener('resize', resize);
+ resize();
+
+ function clamp(v,min,max){return v<min?min:v>max?max:v;}
+
+ function hslToRgb(h,s,l){
+ let r,g,b;
+ if (s === 0){
+ r=g=b=l;
+ } else {
+ const hue2rgb = (p,q,t)=>{
+ if(t<0) t+=1;
+ if(t>1) t-=1;
+ if(t<1/6) return p+(q-p)*6*t;
+ if(t<1/2) return q;
+ if(t<2/3) return p+(q-p)*(2/3-t)*6;
+ return p;
+ };
+ const q = l < 0.5 ? l*(1+s) : l + s - l*s;
+ const p = 2*l - q;
+ r = hue2rgb(p,q,h+1/3);
+ g = hue2rgb(p,q,h);
+ b = hue2rgb(p,q,h-1/3);
+ }
+ return [Math.round(r*255),Math.round(g*255),Math.round(b*255)];
+ }
+
+ function updateUI() {
+ const density = parseFloat(densitySlider.value);
+ const slub = parseFloat(slubSlider.value);
+ const hueShift = parseFloat(hueSlider.value);
+ const contrast = parseFloat(contrastSlider.value);
+ const sheen = parseFloat(sheenSlider.value);
+ const depth = parseFloat(depthSlider.value);
+ const speed = parseFloat(speedSlider.value);
+
+ densityValue.textContent = density.toFixed(2);
+ slubValue.textContent = slub.toFixed(2);
+ contrastValue.textContent = contrast.toFixed(2);
+ sheenValue.textContent = sheen.toFixed(2);
+ depthValue.textContent = depth.toFixed(2);
+ speedValue.textContent = speed.toFixed(2) + '×';
+ footerDensity.textContent = 'Density • ' + density.toFixed(2);
+
+ let tone;
+ if (hueShift < -0.04) tone="Olive";
+ else if (hueShift < 0.02) tone="Neutral";
+ else if (hueShift < 0.09) tone="Warm";
+ else tone="Sand";
+ hueValue.textContent = tone;
+
+ const baseHue = 0.10 + hueShift; // around warm neutral
+ const warpHue = (baseHue + 1) % 1;
+ const weftHue = (baseHue + 0.03) % 1;
+
+ const baseLight = 0.76;
+ const diff = 0.22 * contrast;
+ const warpLight = clamp(baseLight + diff*0.6, 0, 1);
+ const weftLight = clamp(baseLight - diff, 0, 1);
+
+ const baseSat = 0.32;
+ const warpSat = clamp(baseSat + 0.10*contrast, 0, 1);
+ const weftSat = clamp(baseSat + 0.05*contrast, 0, 1);
+
+ const warpRgb = hslToRgb(warpHue, warpSat, warpLight);
+ const weftRgb = hslToRgb(weftHue, weftSat, weftLight);
+
+ const warpStr = 'rgb('+warpRgb[0]+','+warpRgb[1]+','+warpRgb[2]+')';
+ const weftStr = 'rgb('+weftRgb[0]+','+weftRgb[1]+','+weftRgb[2]+')';
+
+ warpChip.style.background = warpStr;
+ weftChip.style.background = weftStr;
+
+ state.colors.warp = warpRgb;
+ state.colors.weft = weftRgb;
+ state.params = { density, slub, contrast, sheen, depth, speed };
+ }
+
+ const state = {
+ time: 0,
+ params: {
+ density: parseFloat(densitySlider.value),
+ slub: parseFloat(slubSlider.value),
+ contrast: parseFloat(contrastSlider.value),
+ sheen: parseFloat(sheenSlider.value),
+ depth: parseFloat(depthSlider.value),
+ speed: parseFloat(speedSlider.value),
+ },
+ colors: {
+ warp: [212,188,146],
+ weft: [172,148,118]
+ }
+ };
+ updateUI();
+
+ const sliders = [densitySlider, slubSlider, hueSlider, contrastSlider, sheenSlider, depthSlider, speedSlider];
+ sliders.forEach(el=>{
+ el.addEventListener('input', updateUI);
+ });
+
+ function hash(x,y){
+ const s = Math.sin(x*127.1 + y*311.7) * 43758.5453;
+ return s - Math.floor(s);
+ }
+ function noise2d(x,y){
+ const iX = Math.floor(x);
+ const iY = Math.floor(y);
+ const fX = x - iX;
+ const fY = y - iY;
+ const uX = fX*fX*(3-2*fX);
+ const uY = fY*fY*(3-2*fY);
+ const n00 = hash(iX, iY);
+ const n10 = hash(iX+1, iY);
+ const n01 = hash(iX, iY+1);
+ const n11 = hash(iX+1, iY+1);
+ const nx0 = n00*(1-uX) + n10*uX;
+ const nx1 = n01*(1-uX) + n11*uX;
+ return nx0*(1-uY) + nx1*uY;
+ }
+
+ function fbm(x,y,octaves){
+ let sum = 0;
+ let amp = 0.5;
+ let freq = 1;
+ for(let i=0;i<octaves;i++){
+ sum += noise2d(x*freq, y*freq) * amp;
+ freq *= 2.3;
+ amp *= 0.55;
+ }
+ return sum;
+ }
+
+ function renderFrame(dt){
+ if (!width || !height) return;
+
+ const { density, slub, contrast, sheen, depth, speed } = state.params;
+ state.time += dt * 0.001 * speed;
+
+ const img = ctx.getImageData(0,0,width,height);
+ const data = img.data;
+
+ const scale = 0.25 + density * 0.85; // threads per px
+ const warpFreq = scale * 1.18;
+ const weftFreq = scale * 0.92;
+
+ const slubIntensity = 0.15 + slub * 0.45;
+ const threadSoftness = 0.4;
+ const baseDepth = 0.45 + depth * 0.4;
+ const sheenAmt = sheen;
+ const microContrast = 0.35 + contrast * 0.4;
+
+ const warpColor = state.colors.warp;
+ const weftColor = state.colors.weft;
+
+ const lightAngle = -0.6;
+ const lightDirX = Math.cos(lightAngle);
+ const lightDirY = Math.sin(lightAngle);
+
+ const sweepPhase = state.time * 0.14;
+ const sweepWidth = 0.65;
+ const invW = 1/width;
+ const invH = 1/height;
+
+ for(let y=0, idx=0; y<height; y++){
+ const v = y * invH;
+ const sweepCenter = 0.5 + 0.5*Math.sin(sweepPhase + v*2.1);
+ for(let x=0; x<width; x++, idx+=4){
+ const u = x * invW;
+
+ const wx = x * warpFreq * invW * 2.2;
+ const wy = y * 0.7 * invH * 2.0;
+ const vx = x * 0.65 * invW * 2.0;
+ const vy = y * weftFreq * invH * 2.4;
+
+ const warpBase = 0.5 + 0.5*Math.cos(wx*Math.PI*2);
+ const weftBase = 0.5 + 0.5*Math.cos(vy*Math.PI*2);
+
+ const warpProfile = Math.pow(1 - Math.abs(warpBase-0.5)*2, 1.9);
+ const weftProfile = Math.pow(1 - Math.abs(weftBase-0.5)*2, 1.8);
+
+ const slubWarp = fbm(wx*0.35, wy*1.8, 3);
+ const slubWeft = fbm(vx*1.4, vy*0.28, 3);
+ const warpSlubMod = 1 + (slubWarp-0.5)*slubIntensity*2.4;
+ const weftSlubMod = 1 + (slubWeft-0.5)*slubIntensity*2.1;
+
+ const warpThread = clamp(warpProfile * warpSlubMod, 0, 1);
+ const weftThread = clamp(weftProfile * weftSlubMod, 0, 1);
+
+ const warpMicro = noise2d(wx*4.1, wy*4.3);
+ const weftMicro = noise2d(vx*4.0, vy*4.2);
+
+ const warp = clamp(warpThread * (0.75 + warpMicro*0.35), 0, 1);
+ const weft = clamp(weftThread * (0.75 + weftMicro*0.35), 0, 1);
+
+ const weaveMask = warp + weft - warp*weft*threadSoftness;
+ const cross = warp*weft;
+
+ const baseMixWarp = clamp(warp + cross*0.6, 0, 1);
+ const baseMixWeft = clamp(weft + cross*0.6, 0, 1);
+ const mixTotal = baseMixWarp + baseMixWeft + 1e-4;
+ const wWarp = baseMixWarp / mixTotal;
+ const wWeft = baseMixWeft / mixTotal;
+
+ const baseR = warpColor[0]*wWarp + weftColor[0]*wWeft;
+ const baseG = warpColor[1]*wWarp + weftColor[1]*wWeft;
+ const baseB = warpColor[2]*wWarp + weftColor[2]*wWeft;
+
+ const normalX = (weft - warp)*0.6;
+ const normalY = (warp - weft)*0.6;
+ const normalZ = Math.sqrt(1 - Math.min(1, normalX*normalX + normalY*normalY));
+ const ndotl = clamp(normalX*lightDirX + normalY*lightDirY + normalZ*0.9, 0, 1);
+
+ const highlight = Math.pow(ndotl, 9) * sheenAmt;
+ const sweepPos = u;
+ const sweepCurve = Math.exp(-Math.pow((sweepPos - sweepCenter)/(sweepWidth*0.5), 2));
+ const sweep = highlight * (0.3 + 0.7*sweepCurve);
+
+ const occlusion = clamp(baseDepth - weaveMask*0.45 - cross*0.25, 0.12, 1);
+ const grain = fbm(x*0.0018, y*0.0018, 4);
+ const grainBand = 0.5 + (grain-0.5)*0.7;
+
+ const shade = occlusion * (0.7 + grainBand*0.5);
+ const lit = 0.6 + ndotl*0.55;
+ let l = shade*lit + sweep;
+
+ let r = baseR * l;
+ let g = baseG * l;
+ let b = baseB * l;
+
+ const avg = (r+g+b)/3;
+ r = avg + (r-avg)*(1+microContrast*0.4);
+ g = avg + (g-avg)*(1+microContrast*0.4);
+ b = avg + (b-avg)*(1+microContrast*0.4);
+
+ r = clamp(r, 6, 245);
+ g = clamp(g, 5, 240);
+ b = clamp(b, 3, 230);
+
+ data[idx] = r;
+ data[idx+1] = g;
+ data[idx+2] = b;
+ data[idx+3] = 255;
+ }
+ }
+ ctx.putImageData(img,0,0);
+ }
+
+ let lastTime = performance.now();
+ function loop(now){
+ const dt = now - lastTime;
+ lastTime = now;
+ renderFrame(Math.min(dt, 32));
+ requestAnimationFrame(loop);
+ }
+ requestAnimationFrame(loop);
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/724633a205b0/gpt.png b/data/artifacts/724633a205b0/gpt.png
new file mode 100644
index 0000000..2b1325b
Binary files /dev/null and b/data/artifacts/724633a205b0/gpt.png differ
diff --git a/data/artifacts/724633a205b0/grok.html b/data/artifacts/724633a205b0/grok.html
new file mode 100644
index 0000000..b32c5ac
--- /dev/null
+++ b/data/artifacts/724633a205b0/grok.html
@@ -0,0 +1,544 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Grasscloth Weave Simulator</title>
+<style>
+ @import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@400;500&family=DM+Sans:wght@400;500&display=swap');
+ * { margin: 0; padding: 0; box-sizing: border-box; }
+ html, body {
+ width: 100%; height: 100%;
+ overflow: hidden;
+ background: #1a1814;
+ font-family: 'DM Sans', system-ui, sans-serif;
+ color: #e8e0d4;
+ }
+ .app {
+ display: grid;
+ grid-template-columns: 1fr 280px;
+ height: 100vh;
+ gap: 0;
+ }
+ .stage {
+ position: relative;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: radial-gradient(ellipse at 40% 35%, #2a2620 0%, #141210 70%);
+ overflow: hidden;
+ }
+ canvas {
+ display: block;
+ border-radius: 2px;
+ box-shadow:
+ 0 0 0 1px rgba(255,245,230,0.06),
+ 0 24px 80px rgba(0,0,0,0.55),
+ 0 4px 16px rgba(0,0,0,0.35);
+ max-width: calc(100% - 64px);
+ max-height: calc(100% - 64px);
+ }
+ .panel {
+ background: linear-gradient(180deg, #221f1a 0%, #1a1714 100%);
+ border-left: 1px solid rgba(232,224,212,0.08);
+ padding: 36px 28px;
+ display: flex;
+ flex-direction: column;
+ gap: 28px;
+ overflow-y: auto;
+ }
+ .brand {
+ margin-bottom: 8px;
+ }
+ .brand h1 {
+ font-family: 'Cormorant Garamond', Georgia, serif;
+ font-weight: 500;
+ font-size: 1.55rem;
+ letter-spacing: 0.04em;
+ color: #f0e8dc;
+ line-height: 1.2;
+ }
+ .brand p {
+ font-size: 0.7rem;
+ letter-spacing: 0.18em;
+ text-transform: uppercase;
+ color: #8a8070;
+ margin-top: 6px;
+ }
+ .control {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ }
+ .control label {
+ display: flex;
+ justify-content: space-between;
+ align-items: baseline;
+ font-size: 0.72rem;
+ letter-spacing: 0.12em;
+ text-transform: uppercase;
+ color: #a09888;
+ }
+ .control label span.val {
+ font-variant-numeric: tabular-nums;
+ color: #d4c8b4;
+ letter-spacing: 0.04em;
+ }
+ input[type="range"] {
+ -webkit-appearance: none;
+ appearance: none;
+ width: 100%;
+ height: 3px;
+ background: #3a342c;
+ border-radius: 2px;
+ outline: none;
+ cursor: pointer;
+ }
+ input[type="range"]::-webkit-slider-thumb {
+ -webkit-appearance: none;
+ appearance: none;
+ width: 14px;
+ height: 14px;
+ border-radius: 50%;
+ background: linear-gradient(145deg, #e8dcc8, #c4b49a);
+ box-shadow: 0 1px 4px rgba(0,0,0,0.4);
+ cursor: grab;
+ border: none;
+ }
+ input[type="range"]::-moz-range-thumb {
+ width: 14px;
+ height: 14px;
+ border-radius: 50%;
+ background: linear-gradient(145deg, #e8dcc8, #c4b49a);
+ box-shadow: 0 1px 4px rgba(0,0,0,0.4);
+ cursor: grab;
+ border: none;
+ }
+ .swatch-row {
+ display: flex;
+ gap: 10px;
+ align-items: center;
+ }
+ .swatch {
+ width: 28px;
+ height: 28px;
+ border-radius: 4px;
+ border: 1px solid rgba(255,255,255,0.12);
+ box-shadow: inset 0 1px 2px rgba(0,0,0,0.25);
+ flex-shrink: 0;
+ }
+ input[type="color"] {
+ -webkit-appearance: none;
+ appearance: none;
+ width: 100%;
+ height: 32px;
+ border: 1px solid rgba(232,224,212,0.12);
+ border-radius: 4px;
+ background: transparent;
+ cursor: pointer;
+ padding: 2px;
+ }
+ input[type="color"]::-webkit-color-swatch-wrapper { padding: 2px; }
+ input[type="color"]::-webkit-color-swatch {
+ border: none;
+ border-radius: 2px;
+ }
+ .divider {
+ height: 1px;
+ background: linear-gradient(90deg, transparent, rgba(232,224,212,0.1), transparent);
+ }
+ .hint {
+ font-size: 0.68rem;
+ color: #6a6258;
+ line-height: 1.55;
+ letter-spacing: 0.02em;
+ margin-top: auto;
+ }
+ @media (max-width: 720px) {
+ .app { grid-template-columns: 1fr; grid-template-rows: 1fr auto; }
+ .panel {
+ border-left: none;
+ border-top: 1px solid rgba(232,224,212,0.08);
+ padding: 20px 20px 28px;
+ max-height: 42vh;
+ }
+ }
+</style>
+</head>
+<body>
+<div class="app">
+ <div class="stage">
+ <canvas id="c" width="640" height="640"></canvas>
+ </div>
+ <aside class="panel">
+ <div class="brand">
+ <h1>Grasscloth</h1>
+ <p>Weave Texture Studio</p>
+ </div>
+ <div class="divider"></div>
+ <div class="control">
+ <label>Weave Density <span class="val" id="vDensity">48</span></label>
+ <input type="range" id="density" min="16" max="96" value="48" step="1">
+ </div>
+ <div class="control">
+ <label>Warp Fiber</label>
+ <div class="swatch-row">
+ <div class="swatch" id="sw1"></div>
+ <input type="color" id="color1" value="#c4a882">
+ </div>
+ </div>
+ <div class="control">
+ <label>Weft Fiber</label>
+ <div class="swatch-row">
+ <div class="swatch" id="sw2"></div>
+ <input type="color" id="color2" value="#8a7a62">
+ </div>
+ </div>
+ <div class="control">
+ <label>Sheen <span class="val" id="vSheen">35</span></label>
+ <input type="range" id="sheen" min="0" max="100" value="35" step="1">
+ </div>
+ <div class="control">
+ <label>Fiber Variation <span class="val" id="vVar">55</span></label>
+ <input type="range" id="variation" min="0" max="100" value="55" step="1">
+ </div>
+ <div class="divider"></div>
+ <p class="hint">Natural grasscloth wallcovering — handwoven fiber simulation with live specular sweep. Luxury earth palette.</p>
+ </aside>
+</div>
+<script>
+(function () {
+ const canvas = document.getElementById('c');
+ const ctx = canvas.getContext('2d', { alpha: false });
+ const W = canvas.width;
+ const H = canvas.height;
+
+ const densityEl = document.getElementById('density');
+ const color1El = document.getElementById('color1');
+ const color2El = document.getElementById('color2');
+ const sheenEl = document.getElementById('sheen');
+ const variationEl = document.getElementById('variation');
+ const vDensity = document.getElementById('vDensity');
+ const vSheen = document.getElementById('vSheen');
+ const vVar = document.getElementById('vVar');
+ const sw1 = document.getElementById('sw1');
+ const sw2 = document.getElementById('sw2');
+
+ let density = +densityEl.value;
+ let c1 = hexToRgb(color1El.value);
+ let c2 = hexToRgb(color2El.value);
+ let sheen = +sheenEl.value / 100;
+ let variation = +variationEl.value / 100;
+ let dirty = true;
+ let lightPhase = 0;
+
+ // Precomputed noise tables for fiber irregularity
+ const NOISE_N = 2048;
+ const fiberNoise = new Float32Array(NOISE_N);
+ const shadeNoise = new Float32Array(NOISE_N);
+ const twistNoise = new Float32Array(NOISE_N);
+ for (let i = 0; i < NOISE_N; i++) {
+ fiberNoise[i] = Math.random() * 2 - 1;
+ shadeNoise[i] = Math.random() * 2 - 1;
+ twistNoise[i] = Math.random();
+ }
+
+ // Offscreen buffer for base weave (rebuilt on param change)
+ const baseCanvas = document.createElement('canvas');
+ baseCanvas.width = W;
+ baseCanvas.height = H;
+ const baseCtx = baseCanvas.getContext('2d', { alpha: false });
+ const baseImg = baseCtx.createImageData(W, H);
+ const baseData = baseImg.data;
+
+ function hexToRgb(hex) {
+ const h = hex.replace('#', '');
+ return [
+ parseInt(h.slice(0, 2), 16),
+ parseInt(h.slice(2, 4), 16),
+ parseInt(h.slice(4, 6), 16)
+ ];
+ }
+
+ function lerp(a, b, t) { return a + (b - a) * t; }
+ function clamp(v, a, b) { return v < a ? a : v > b ? b : v; }
+ function smoothstep(e0, e1, x) {
+ const t = clamp((x - e0) / (e1 - e0), 0, 1);
+ return t * t * (3 - 2 * t);
+ }
+ function n1(i) { return fiberNoise[((i % NOISE_N) + NOISE_N) % NOISE_N]; }
+ function n2(i) { return shadeNoise[((i % NOISE_N) + NOISE_N) % NOISE_N]; }
+ function n3(i) { return twistNoise[((i % NOISE_N) + NOISE_N) % NOISE_N]; }
+
+ // Hash-ish for stable per-fiber seed
+ function fiberSeed(row, col) {
+ return ((row * 73856093) ^ (col * 19349663)) >>> 0;
+ }
+
+ function rebuildBase() {
+ const cell = Math.max(4, Math.floor(W / density));
+ const half = cell * 0.5;
+ const cols = Math.ceil(W / cell) + 2;
+ const rows = Math.ceil(H / cell) + 2;
+ const varAmt = variation;
+
+ // Clear to mid tone
+ const midR = (c1[0] + c2[0]) * 0.5;
+ const midG = (c1[1] + c2[1]) * 0.5;
+ const midB = (c1[2] + c2[2]) * 0.5;
+
+ for (let i = 0, len = W * H; i < len; i++) {
+ const pi = i * 4;
+ baseData[pi] = midR;
+ baseData[pi + 1] = midG;
+ baseData[pi + 2] = midB;
+ baseData[pi + 3] = 255;
+ }
+
+ // Draw interlaced plain weave: warp (vertical) and weft (horizontal)
+ // For each cell, alternate which yarn is on top
+ for (let ry = -1; ry < rows; ry++) {
+ for (let cx = -1; cx < cols; cx++) {
+ const x0 = cx * cell;
+ const y0 = ry * cell;
+ const overWarp = ((cx + ry) & 1) === 0;
+ const seedW = fiberSeed(ry, cx);
+ const seedF = fiberSeed(cx, ry + 17);
+
+ // Yarn thickness with natural variation
+ const warpThick = half * (0.72 + 0.28 * n3(seedW));
+ const weftThick = half * (0.70 + 0.30 * n3(seedF + 3));
+
+ // Color variation per fiber strand
+ const wVar = 1 + varAmt * 0.35 * n1(seedW);
+ const fVar = 1 + varAmt * 0.35 * n1(seedF);
+ const wShade = varAmt * 0.22 * n2(seedW + 5);
+ const fShade = varAmt * 0.22 * n2(seedF + 7);
+
+ const warpCol = [
+ clamp(c1[0] * wVar + wShade * 40, 0, 255),
+ clamp(c1[1] * wVar + wShade * 35, 0, 255),
+ clamp(c1[2] * wVar + wShade * 28, 0, 255)
+ ];
+ const weftCol = [
+ clamp(c2[0] * fVar + fShade * 40, 0, 255),
+ clamp(c2[1] * fVar + fShade * 35, 0, 255),
+ clamp(c2[2] * fVar + fShade * 28, 0, 255)
+ ];
+
+ // Micro-twist offset along fiber
+ const twistW = n3(seedW + 11) * 1.8;
+ const twistF = n3(seedF + 13) * 1.8;
+
+ // Draw both yarns; top yarn last for occlusion
+ if (overWarp) {
+ drawWeftSegment(x0, y0, cell, weftThick, weftCol, twistF, seedF, varAmt);
+ drawWarpSegment(x0, y0, cell, warpThick, warpCol, twistW, seedW, varAmt);
+ } else {
+ drawWarpSegment(x0, y0, cell, warpThick, warpCol, twistW, seedW, varAmt);
+ drawWeftSegment(x0, y0, cell, weftThick, weftCol, twistF, seedF, varAmt);
+ }
+ }
+ }
+
+ // Subtle paper/backing grain in gaps
+ for (let y = 0; y < H; y++) {
+ for (let x = 0; x < W; x++) {
+ const pi = (y * W + x) * 4;
+ const g = 0.92 + 0.08 * n1(x * 3 + y * 7);
+ // Soften only very dark interstitial pixels slightly
+ // Add fine vertical/horizontal striations of natural fiber hair
+ const hair = n2(x + y * 19) * varAmt * 6;
+ baseData[pi] = clamp(baseData[pi] * g + hair, 0, 255);
+ baseData[pi + 1] = clamp(baseData[pi + 1] * g + hair * 0.9, 0, 255);
+ baseData[pi + 2] = clamp(baseData[pi + 2] * g + hair * 0.75, 0, 255);
+ }
+ }
+
+ baseCtx.putImageData(baseImg, 0, 0);
+ dirty = false;
+ }
+
+ function drawWarpSegment(x0, y0, cell, thick, col, twist, seed, varAmt) {
+ // Vertical yarn through cell, cylindrical shading
+ const cx = x0 + cell * 0.5;
+ const yStart = Math.max(0, Math.floor(y0));
+ const yEnd = Math.min(H, Math.ceil(y0 + cell + 1));
+ const r = thick * 0.5;
+
+ for (let y = yStart; y < yEnd; y++) {
+ const ly = (y - y0) / cell;
+ // slight S-curve / natural bend
+ const bend = Math.sin(ly * Math.PI) * twist + n1(seed + y) * varAmt * 0.9;
+ const centerX = cx + bend;
+ const xStart = Math.max(0, Math.floor(centerX - r - 1));
+ const xEnd = Math.min(W, Math.ceil(centerX + r + 1));
+
+ for (let x = xStart; x < xEnd; x++) {
+ const dx = x - centerX;
+ const dist = Math.abs(dx);
+ if (dist > r) continue;
+
+ const u = dist / r; // 0 center → 1 edge
+ // Cylindrical lambert-ish profile
+ const profile = Math.sqrt(Math.max(0, 1 - u * u));
+ // Edge darkening + core highlight bias
+ const shade = 0.55 + 0.55 * profile;
+ // Longitudinal fiber striations
+ const stria = 1 + varAmt * 0.12 * n1((seed + Math.floor(y * 2.3) + Math.floor(dx * 3)) | 0);
+ // Soft edge falloff for anti-alias / fiber fringe
+ const edge = smoothstep(1.0, 0.82, u);
+ const a = edge;
+
+ const pi = (y * W + x) * 4;
+ const nr = col[0] * shade * stria;
+ const ng = col[1] * shade * stria;
+ const nb = col[2] * shade * stria;
+
+ baseData[pi] = clamp(lerp(baseData[pi], nr, a), 0, 255);
+ baseData[pi + 1] = clamp(lerp(baseData[pi + 1], ng, a), 0, 255);
+ baseData[pi + 2] = clamp(lerp(baseData[pi + 2], nb, a), 0, 255);
+ }
+ }
+ }
+
+ function drawWeftSegment(x0, y0, cell, thick, col, twist, seed, varAmt) {
+ // Horizontal yarn
+ const cy = y0 + cell * 0.5;
+ const xStart = Math.max(0, Math.floor(x0));
+ const xEnd = Math.min(W, Math.ceil(x0 + cell + 1));
+ const r = thick * 0.5;
+
+ for (let x = xStart; x < xEnd; x++) {
+ const lx = (x - x0) / cell;
+ const bend = Math.sin(lx * Math.PI) * twist + n1(seed + x + 40) * varAmt * 0.9;
+ const centerY = cy + bend;
+ const yStart = Math.max(0, Math.floor(centerY - r - 1));
+ const yEnd = Math.min(H, Math.ceil(centerY + r + 1));
+
+ for (let y = yStart; y < yEnd; y++) {
+ const dy = y - centerY;
+ const dist = Math.abs(dy);
+ if (dist > r) continue;
+
+ const u = dist / r;
+ const profile = Math.sqrt(Math.max(0, 1 - u * u));
+ const shade = 0.52 + 0.58 * profile;
+ const stria = 1 + varAmt * 0.12 * n1((seed + Math.floor(x * 2.1) + Math.floor(dy * 3) + 90) | 0);
+ const edge = smoothstep(1.0, 0.82, u);
+ const a = edge;
+
+ const pi = (y * W + x) * 4;
+ const nr = col[0] * shade * stria;
+ const ng = col[1] * shade * stria;
+ const nb = col[2] * shade * stria;
+
+ baseData[pi] = clamp(lerp(baseData[pi], nr, a), 0, 255);
+ baseData[pi + 1] = clamp(lerp(baseData[pi + 1], ng, a), 0, 255);
+ baseData[pi + 2] = clamp(lerp(baseData[pi + 2], nb, a), 0, 255);
+ }
+ }
+ }
+
+ // Composite frame: base + animated light sweep + sheen
+ const frameImg = ctx.createImageData(W, H);
+ const frameData = frameImg.data;
+
+ function render(time) {
+ if (dirty) rebuildBase();
+
+ lightPhase = (time * 0.00015) % 1;
+ // Sweep center moves slowly diagonally
+ const lx = (0.15 + 0.7 * (0.5 + 0.5 * Math.sin(lightPhase * Math.PI * 2))) * W;
+ const ly = (0.2 + 0.6 * (0.5 + 0.5 * Math.cos(lightPhase * Math.PI * 2 * 0.7 + 0.4))) * H;
+ const sheenStr = sheen;
+ const sweepRadius = W * 0.55;
+
+ // Copy base and apply lighting in one pass
+ const src = baseData;
+ const dst = frameData;
+
+ for (let y = 0; y < H; y++) {
+ for (let x = 0; x < W; x++) {
+ const i = (y * W + x) * 4;
+ let r = src[i];
+ let g = src[i + 1];
+ let b = src[i + 2];
+
+ // Distance to light center
+ const dx = x - lx;
+ const dy = y - ly;
+ const dist = Math.sqrt(dx * dx + dy * dy);
+ const fall = Math.exp(-(dist * dist) / (2 * sweepRadius * sweepRadius));
+
+ // Ambient occlusion-ish from local luminance (darker fibers recede)
+ const lum = (r * 0.3 + g * 0.59 + b * 0.11) / 255;
+ // Specular response stronger on lighter fiber ridges
+ const spec = sheenStr * fall * (0.35 + 0.65 * smoothstep(0.25, 0.75, lum));
+ // Warm luxury light tint
+ const warmR = 1.08;
+ const warmG = 1.02;
+ const warmB = 0.94;
+
+ // Soft directional fill
+ const fill = 0.88 + 0.14 * fall;
+ // Specular bloom (additive, warm ivory)
+ const bloom = spec * 55;
+
+ r = clamp(r * fill * warmR + bloom * 1.15, 0, 255);
+ g = clamp(g * fill * warmG + bloom * 1.05, 0, 255);
+ b = clamp(b * fill * warmB + bloom * 0.88, 0, 255);
+
+ // Very subtle vignette for depth
+ const vx = (x / W - 0.5) * 2;
+ const vy = (y / H - 0.5) * 2;
+ const vig = 1 - 0.12 * (vx * vx + vy * vy);
+ r *= vig; g *= vig; b *= vig;
+
+ dst[i] = r;
+ dst[i + 1] = g;
+ dst[i + 2] = b;
+ dst[i + 3] = 255;
+ }
+ }
+
+ ctx.putImageData(frameImg, 0, 0);
+
+ // Soft overlay gradient for gallery lighting feel
+ const grd = ctx.createRadialGradient(lx, ly, 0, lx, ly, sweepRadius * 1.2);
+ grd.addColorStop(0, 'rgba(255,248,235,' + (0.04 + sheenStr * 0.06) + ')');
+ grd.addColorStop(0.5, 'rgba(255,240,220,0.015)');
+ grd.addColorStop(1, 'rgba(0,0,0,0)');
+ ctx.fillStyle = grd;
+ ctx.fillRect(0, 0, W, H);
+
+ requestAnimationFrame(render);
+ }
+
+ function syncUI() {
+ density = +densityEl.value;
+ c1 = hexToRgb(color1El.value);
+ c2 = hexToRgb(color2El.value);
+ sheen = +sheenEl.value / 100;
+ variation = +variationEl.value / 100;
+ vDensity.textContent = densityEl.value;
+ vSheen.textContent = sheenEl.value;
+ vVar.textContent = variationEl.value;
+ sw1.style.background = color1El.value;
+ sw2.style.background = color2El.value;
+ dirty = true;
+ }
+
+ densityEl.addEventListener('input', syncUI);
+ color1El.addEventListener('input', syncUI);
+ color2El.addEventListener('input', syncUI);
+ sheenEl.addEventListener('input', syncUI);
+ variationEl.addEventListener('input', syncUI);
+
+ syncUI();
+ rebuildBase();
+ requestAnimationFrame(render);
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/724633a205b0/grok.png b/data/artifacts/724633a205b0/grok.png
new file mode 100644
index 0000000..9d55838
Binary files /dev/null and b/data/artifacts/724633a205b0/grok.png differ
diff --git a/data/artifacts/724633a205b0/qwen25-7b.html b/data/artifacts/724633a205b0/qwen25-7b.html
new file mode 100644
index 0000000..35639a6
--- /dev/null
+++ b/data/artifacts/724633a205b0/qwen25-7b.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Grasscloth Weave Simulator</title>
+ <style>
+ body { margin: 0; overflow: hidden; background-color: #f5deb3; }
+ canvas { display: block; width: 100%; height: 100vh; }
+ </style>
+</head>
+<body>
+<canvas id="weaveCanvas"></canvas>
+<script>
+const canvas = document.getElementById('weaveCanvas');
+const ctx = canvas.getContext('2d');
+
+let density = 5;
+let colorA = '#8b4513';
+let colorB = '#dda08e';
+let sheen = 0.3;
+
+function drawWeave() {
+ const width = canvas.width;
+ const height = canvas.height;
+ ctx.fillStyle = 'white';
+ ctx.fillRect(0, 0, width, height);
+
+ for (let i = 0; i < width; i += 1) {
+ if ((i % density + sheen * Math.sin(i / 10)) % 2 > 1) {
+ ctx.fillStyle = colorA;
+ } else {
+ ctx.fillStyle = colorB;
+ }
+ for (let j = 0; j < height; j += 1) {
+ ctx.fillRect(i, j, 1, 1);
+ }
+ }
+}
+
+function animate() {
+ drawWeave();
+ requestAnimationFrame(animate);
+}
+
+animate();
+
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/724633a205b0/qwen25-7b.png b/data/artifacts/724633a205b0/qwen25-7b.png
new file mode 100644
index 0000000..02d878e
Binary files /dev/null and b/data/artifacts/724633a205b0/qwen25-7b.png differ
diff --git a/data/artifacts/ce24cf987953/claude-code.html b/data/artifacts/ce24cf987953/claude-code.html
new file mode 100644
index 0000000..3f9e828
--- /dev/null
+++ b/data/artifacts/ce24cf987953/claude-code.html
@@ -0,0 +1,362 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Atelier Memory — Wallcovering Swatch Match</title>
+<style>
+ :root{
+ --bg:#e9e4da;
+ --panel:#f4f0e8;
+ --ink:#3a352d;
+ --muted:#8a8072;
+ --line:#d6cec0;
+ --gold:#a9915f;
+ --shadow:rgba(58,53,45,.18);
+ --radius:14px;
+ }
+ *{box-sizing:border-box;margin:0;padding:0}
+ html,body{height:100%}
+ body{
+ font-family:"Georgia","Times New Roman",serif;
+ background:
+ radial-gradient(1200px 700px at 50% -10%, #f3eee4, transparent 60%),
+ linear-gradient(160deg,#eae4d9,#ded6c7);
+ color:var(--ink);
+ min-height:100%;
+ display:flex;align-items:center;justify-content:center;
+ padding:24px;
+ }
+ .wrap{
+ width:100%;max-width:560px;
+ background:var(--panel);
+ border:1px solid var(--line);
+ border-radius:22px;
+ padding:26px 26px 30px;
+ box-shadow:0 30px 60px -30px var(--shadow), inset 0 1px 0 #fffdf8;
+ }
+ header{text-align:center;margin-bottom:20px}
+ .eyebrow{
+ font-family:"Helvetica Neue",Arial,sans-serif;
+ text-transform:uppercase;letter-spacing:.42em;
+ font-size:10px;color:var(--gold);font-weight:600;
+ margin-bottom:10px;padding-left:.42em;
+ }
+ h1{
+ font-weight:400;font-size:29px;letter-spacing:.02em;line-height:1.1;
+ }
+ h1 em{font-style:italic;color:var(--muted)}
+ .stats{
+ display:flex;justify-content:center;gap:14px;
+ margin:18px 0 22px;
+ font-family:"Helvetica Neue",Arial,sans-serif;
+ }
+ .stat{
+ flex:1;max-width:150px;
+ background:linear-gradient(180deg,#fffdf8,#f1ece2);
+ border:1px solid var(--line);border-radius:var(--radius);
+ padding:12px 10px;text-align:center;
+ box-shadow:inset 0 1px 0 #fff;
+ }
+ .stat .label{
+ font-size:9px;text-transform:uppercase;letter-spacing:.22em;
+ color:var(--muted);margin-bottom:5px;
+ }
+ .stat .value{
+ font-size:24px;font-variant-numeric:tabular-nums;letter-spacing:.02em;
+ color:var(--ink);font-weight:500;
+ }
+ .board{
+ position:relative;
+ display:grid;grid-template-columns:repeat(4,1fr);gap:12px;
+ }
+ .card{
+ position:relative;aspect-ratio:1/1;
+ perspective:900px;
+ cursor:pointer;
+ background:transparent;border:0;padding:0;
+ }
+ .inner{
+ position:absolute;inset:0;
+ transform-style:preserve-3d;
+ transition:transform .55s cubic-bezier(.5,.05,.2,1);
+ border-radius:var(--radius);
+ }
+ .card.flipped .inner,.card.matched .inner{transform:rotateY(180deg)}
+ .face{
+ position:absolute;inset:0;
+ backface-visibility:hidden;
+ border-radius:var(--radius);
+ overflow:hidden;
+ box-shadow:0 10px 22px -12px var(--shadow), inset 0 0 0 1px rgba(0,0,0,.04);
+ }
+ /* back (shown when face-down) */
+ .back{
+ background:
+ radial-gradient(circle at 30% 25%, rgba(255,255,255,.25), transparent 45%),
+ linear-gradient(135deg,#5f5749,#463f34);
+ display:flex;align-items:center;justify-content:center;
+ }
+ .back::before{
+ content:"";position:absolute;inset:9px;
+ border:1px solid rgba(201,178,124,.45);border-radius:9px;
+ }
+ .monogram{
+ font-size:22px;color:rgba(201,178,124,.85);
+ font-style:italic;letter-spacing:.02em;
+ text-shadow:0 1px 1px rgba(0,0,0,.35);
+ }
+ /* front (the swatch) */
+ .front{transform:rotateY(180deg);background:#efeae0}
+ .swatch{position:absolute;inset:0}
+ .swatch::after{
+ content:"";position:absolute;inset:0;
+ box-shadow:inset 0 0 0 5px rgba(255,255,255,.35), inset 0 0 22px rgba(0,0,0,.08);
+ pointer-events:none;
+ }
+ .card.matched .inner{box-shadow:0 0 0 2px var(--gold), 0 12px 24px -12px var(--shadow)}
+ .card.matched{animation:pop .45s ease}
+ @keyframes pop{0%{transform:scale(1)}40%{transform:scale(1.06)}100%{transform:scale(1)}}
+
+ /* ── Luxury wallcovering swatch patterns (all CSS) ── */
+ .p-damask{
+ background:
+ radial-gradient(circle at 50% 22%, #b7a184 0 6%, transparent 8%),
+ radial-gradient(circle at 50% 78%, #b7a184 0 6%, transparent 8%),
+ radial-gradient(ellipse 30% 22% at 50% 50%, #a99270 0 40%, transparent 42%),
+ linear-gradient(#4d5b53,#3f4c45);
+ background-size:50% 50%,50% 50%,60% 60%,100% 100%;
+ background-position:center;
+ }
+ .p-herringbone{
+ background:
+ repeating-linear-gradient(45deg,#8d7a5e 0 6px,#7a6a51 6px 12px),
+ repeating-linear-gradient(-45deg,rgba(255,255,255,.06) 0 6px,transparent 6px 12px);
+ }
+ .p-grasscloth{
+ background:
+ repeating-linear-gradient(90deg,#c9b891 0 3px,#bfad83 3px 6px),
+ repeating-linear-gradient(0deg,rgba(120,100,70,.14) 0 2px,transparent 2px 5px);
+ }
+ .p-trellis{
+ background:
+ repeating-linear-gradient(45deg,transparent 0 16px,#9a8a63 16px 18px),
+ repeating-linear-gradient(-45deg,transparent 0 16px,#9a8a63 16px 18px),
+ #f0ead9;
+ }
+ .p-toile{
+ background:
+ radial-gradient(circle at 25% 25%, #6d7f9a 0 3px, transparent 4px),
+ radial-gradient(circle at 75% 75%, #6d7f9a 0 3px, transparent 4px),
+ radial-gradient(circle at 75% 25%, #8b9bb2 0 2px, transparent 3px),
+ radial-gradient(circle at 25% 75%, #8b9bb2 0 2px, transparent 3px),
+ #eef1f5;
+ background-size:50% 50%;
+ }
+ .p-moire{
+ background:
+ repeating-radial-gradient(circle at 50% 50%,#7d5c5c 0 4px,#6a4d4d 4px 8px);
+ }
+ .p-fleur{
+ background:
+ radial-gradient(circle at 50% 50%, #cdb47e 0 5%, transparent 7%),
+ conic-gradient(from 0deg at 50% 50%, #b89c6a 0 12%, transparent 12% 25%,
+ #b89c6a 25% 37%, transparent 37% 50%, #b89c6a 50% 62%, transparent 62% 75%,
+ #b89c6a 75% 87%, transparent 87%),
+ #4a4a40;
+ background-size:50% 50%,50% 50%,100% 100%;
+ background-position:center;
+ }
+ .p-stripe{
+ background:
+ repeating-linear-gradient(90deg,#c7b7a0 0 12px,#b6a488 12px 14px,#a8caba 14px 26px,#b6a488 26px 28px);
+ }
+
+ .win{
+ position:absolute;inset:-2px;
+ background:linear-gradient(180deg,rgba(244,240,232,.9),rgba(238,232,220,.97));
+ backdrop-filter:blur(3px);
+ border-radius:18px;
+ display:none;flex-direction:column;align-items:center;justify-content:center;
+ text-align:center;padding:26px;
+ animation:fade .5s ease;
+ }
+ .win.show{display:flex}
+ @keyframes fade{from{opacity:0;transform:scale(.97)}to{opacity:1;transform:scale(1)}}
+ .win .seal{
+ width:64px;height:64px;border-radius:50%;
+ background:radial-gradient(circle at 35% 30%, #c9b27c, #a9915f);
+ display:flex;align-items:center;justify-content:center;
+ color:#3a352d;font-size:28px;font-style:italic;
+ box-shadow:0 8px 18px -8px var(--shadow), inset 0 0 0 4px rgba(255,255,255,.25);
+ margin-bottom:16px;
+ }
+ .win h2{font-weight:400;font-size:26px;margin-bottom:6px}
+ .win p{
+ font-family:"Helvetica Neue",Arial,sans-serif;font-size:13px;
+ color:var(--muted);margin-bottom:20px;letter-spacing:.03em;line-height:1.6;
+ }
+ .win p b{color:var(--ink);font-weight:600}
+ .btn{
+ font-family:"Helvetica Neue",Arial,sans-serif;
+ font-size:11px;text-transform:uppercase;letter-spacing:.24em;font-weight:600;
+ color:#f4f0e8;background:linear-gradient(180deg,#5b5344,#453f34);
+ border:0;border-radius:30px;padding:13px 30px;cursor:pointer;
+ box-shadow:0 10px 22px -12px var(--shadow);
+ transition:transform .15s ease,box-shadow .15s ease;
+ }
+ .btn:hover{transform:translateY(-1px);box-shadow:0 14px 26px -12px var(--shadow)}
+ .btn:active{transform:translateY(0)}
+ .toolbar{display:flex;justify-content:center;margin-top:22px}
+ .btn.ghost{
+ color:var(--muted);background:transparent;
+ border:1px solid var(--line);box-shadow:none;
+ }
+ .btn.ghost:hover{color:var(--ink);border-color:var(--gold)}
+ @media(max-width:420px){
+ .board{gap:9px}.wrap{padding:20px}h1{font-size:24px}
+ }
+</style>
+</head>
+<body>
+ <div class="wrap">
+ <header>
+ <div class="eyebrow">Atelier Collection</div>
+ <h1>Swatch <em>Memory</em></h1>
+ </header>
+
+ <div class="stats">
+ <div class="stat"><div class="label">Moves</div><div class="value" id="moves">0</div></div>
+ <div class="stat"><div class="label">Time</div><div class="value" id="time">0:00</div></div>
+ </div>
+
+ <div class="board" id="board">
+ <div class="win" id="win">
+ <div class="seal">✦</div>
+ <h2>Perfectly Paired</h2>
+ <p>You matched every swatch in <b id="fMoves">0</b> moves<br>and <b id="fTime">0:00</b>.</p>
+ <button class="btn" id="again">Play Again</button>
+ </div>
+ </div>
+
+ <div class="toolbar">
+ <button class="btn ghost" id="restart">Restart</button>
+ </div>
+ </div>
+
+<script>
+(function(){
+ const patterns = [
+ {c:'p-damask', m:'D'},
+ {c:'p-herringbone', m:'H'},
+ {c:'p-grasscloth', m:'G'},
+ {c:'p-trellis', m:'T'},
+ {c:'p-toile', m:'T'},
+ {c:'p-moire', m:'M'},
+ {c:'p-fleur', m:'F'},
+ {c:'p-stripe', m:'S'}
+ ];
+
+ const board = document.getElementById('board');
+ const winEl = document.getElementById('win');
+ const movesEl = document.getElementById('moves');
+ const timeEl = document.getElementById('time');
+ const fMoves = document.getElementById('fMoves');
+ const fTime = document.getElementById('fTime');
+
+ let deck=[], first=null, second=null, lock=false;
+ let moves=0, matched=0, started=false, timer=null, seconds=0;
+
+ function shuffle(a){
+ 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 fmt(s){
+ const m=Math.floor(s/60), r=s%60;
+ return m+':'+(r<10?'0':'')+r;
+ }
+
+ function startTimer(){
+ if(started) return;
+ started=true;
+ timer=setInterval(()=>{ seconds++; timeEl.textContent=fmt(seconds); },1000);
+ }
+
+ function build(){
+ // clear cards but keep win overlay
+ [...board.querySelectorAll('.card')].forEach(c=>c.remove());
+ deck = shuffle(patterns.concat(patterns.map(p=>({...p}))));
+ deck.forEach((p,i)=>{
+ const card=document.createElement('button');
+ card.className='card';
+ card.setAttribute('aria-label','swatch card');
+ card.dataset.key=p.c;
+ card.innerHTML=
+ '<div class="inner">'+
+ '<div class="face back"><span class="monogram">'+p.m+'</span></div>'+
+ '<div class="face front"><div class="swatch '+p.c+'"></div></div>'+
+ '</div>';
+ card.addEventListener('click',()=>flip(card));
+ board.appendChild(card);
+ });
+ }
+
+ function flip(card){
+ if(lock) return;
+ if(card.classList.contains('flipped')||card.classList.contains('matched')) return;
+ startTimer();
+ card.classList.add('flipped');
+
+ if(!first){ first=card; return; }
+ second=card;
+ moves++; movesEl.textContent=moves;
+ lock=true;
+
+ if(first.dataset.key===second.dataset.key){
+ setTimeout(()=>{
+ first.classList.add('matched');
+ second.classList.add('matched');
+ reset();
+ matched++;
+ if(matched===patterns.length) endGame();
+ },420);
+ } else {
+ setTimeout(()=>{
+ first.classList.remove('flipped');
+ second.classList.remove('flipped');
+ reset();
+ },850);
+ }
+ }
+
+ function reset(){ first=null; second=null; lock=false; }
+
+ function endGame(){
+ clearInterval(timer);
+ fMoves.textContent=moves;
+ fTime.textContent=fmt(seconds);
+ setTimeout(()=>winEl.classList.add('show'),350);
+ }
+
+ function newGame(){
+ clearInterval(timer);
+ moves=0; matched=0; seconds=0; started=false;
+ reset();
+ movesEl.textContent='0';
+ timeEl.textContent='0:00';
+ winEl.classList.remove('show');
+ build();
+ }
+
+ document.getElementById('restart').addEventListener('click',newGame);
+ document.getElementById('again').addEventListener('click',newGame);
+
+ newGame();
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/ce24cf987953/claude-code.png b/data/artifacts/ce24cf987953/claude-code.png
new file mode 100644
index 0000000..1cf4fa4
Binary files /dev/null and b/data/artifacts/ce24cf987953/claude-code.png differ
diff --git a/data/artifacts/ce24cf987953/gemma3-12b.html b/data/artifacts/ce24cf987953/gemma3-12b.html
new file mode 100644
index 0000000..114bbc7
--- /dev/null
+++ b/data/artifacts/ce24cf987953/gemma3-12b.html
@@ -0,0 +1,239 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Luxury Swatch Memory Game</title>
+ <style>
+ body {
+ font-family: sans-serif;
+ margin: 0;
+ padding: 0;
+ background-color: #f8f8ff; /* Light Lavender */
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100vh;
+ }
+
+ .game-container {
+ width: 400px;
+ /* Adjust width as needed */
+ perspective: 1000px; /* For the 3D flip effect */
+ }
+
+ .card-grid {
+ display: grid;
+ grid-template-columns: repeat(4, 80px); /* Adjust column size as needed */
+ grid-gap: 10px;
+ width: calc(4 * 80px + 3 * 10px);
+ }
+
+ .card {
+ position: relative;
+ width: 80px;
+ height: 80px;
+ transform-style: preserve-3d;
+ transition: transform 0.5s ease-in-out;
+ cursor: pointer;
+ box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.1);
+ }
+
+ .card.flipped {
+ transform: rotateY(180deg);
+ }
+
+ .card-front {
+ background-color: #ddd; /* Light Gray */
+ border: 1px solid #ccc; /* Medium Gray */
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-size: 24px;
+ color: #666; /* Dark Gray */
+ }
+
+ .card-back {
+ background: linear-gradient(to bottom, #e0f2f1, #a7d4c8); /* Teal Gradient */
+ transform: rotateY(180deg);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-size: 24px;
+ color: #666;
+ }
+
+ .game-info {
+ margin-top: 20px;
+ text-align: center;
+ }
+
+ .win-screen {
+ display: none;
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: rgba(255, 255, 255, 0.8);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+ z-index: 1000;
+ }
+
+ .win-screen h2 {
+ font-size: 36px;
+ color: #444; /* Darker Gray */
+ }
+
+ .restart-button {
+ padding: 10px 20px;
+ background-color: #98c1d9; /* Light Blue/Gray */
+ border: none;
+ cursor: pointer;
+ font-size: 16px;
+ color: white;
+ margin-top: 20px;
+ }
+
+ </style>
+</head>
+<body>
+
+ <div class="game-container">
+ <div class="card-grid" id="cardGrid">
+ <!-- Card elements will be dynamically added here -->
+ </div>
+
+ <div class="game-info">
+ <span id="moves">Moves: 0</span> | <span id="timer">Time: 0.00</span>
+ </div>
+
+ <div class="win-screen" id="winScreen">
+ <h2>Congratulations! You Win!</h2>
+ <button class="restart-button" onclick="restartGame()">Restart</button>
+ </div>
+ </div>
+
+ <script>
+ const cardGrid = document.getElementById('cardGrid');
+ const movesSpan = document.getElementById('moves');
+ const timerSpan = document.getElementById('timer');
+ const winScreen = document.getElementById('winScreen');
+ let cards = [];
+ let flippedCards = [];
+ let moves = 0;
+ let startTime;
+ let timerInterval;
+
+ const swatches = [
+ '#a7d4c8', '#e0f2f1', '#ffb366', '#ff8a65',
+ '#98c1d9', '#6dbcb3', '#ffd966', '#ffa07a'
+ ];
+
+ function shuffleArray(array) {
+ for (let i = array.length - 1; i > 0; i--) {
+ const j = Math.floor(Math.random() * (i + 1));
+ [array[i], array[j]] = [array[j], array[i]];
+ }
+ }
+
+ function createCard(index) {
+ const card = document.createElement('div');
+ card.classList.add('card');
+ card.dataset.index = index;
+ card.innerHTML = `
+ <div class="card-front">?</div>
+ <div class="card-back">${swatches[index]}</div>
+ `;
+ card.addEventListener('click', flipCard);
+ return card;
+ }
+
+ function flipCard(event) {
+ const card = event.target.closest('.card');
+ const index = parseInt(card.dataset.index);
+
+ if (flippedCards.length === 2) return; // Limit to two flipped cards
+
+ card.classList.toggle('flipped');
+
+ if (!flippedCards.includes(index)) {
+ flippedCards.push(index);
+ }
+
+ if (flippedCards.length === 2) {
+ setTimeout(() => {
+ if (cards[flippedCards[0]].dataset.value === cards[flippedCards[1]].dataset.value) {
+ // Match found, disable the cards
+ card.classList.add('matched');
+ cards[flippedCards[0]].classList.add('matched');
+
+ } else {
+ // No match, flip back
+ card.classList.remove('flipped');
+ cards[flippedCards[0]].classList.remove('flipped');
+ }
+ flippedCards = [];
+ }, 500);
+ }
+ moves++;
+ movesSpan.textContent = `Moves: ${moves}`;
+
+ }
+
+
+ function startGame() {
+ cards = []; // Reset cards array
+ moves = 0;
+ movesSpan.textContent = `Moves: ${moves}`;
+ timerSpan.textContent = "Time: 0.00";
+ winScreen.style.display = 'none';
+
+ const cardValues = Array.from({ length: 4 }, () => Math.floor(Math.random() * swatches.length));
+ shuffleArray(cardValues);
+
+ for (let i = 0; i < 16; i++) {
+ const card = createCard(i);
+ card.dataset.value = cardValues[i]; // Assign value to the card
+ cards.push(card);
+ cardGrid.appendChild(card);
+ }
+ }
+
+ function restartGame() {
+ startGame();
+ }
+
+
+ function startTimer() {
+ startTime = new Date().getTime();
+ timerInterval = setInterval(() => {
+ const elapsedTime = (new Date().getTime() - startTime) / 1000;
+ timerSpan.textContent = `Time: ${elapsedTime.toFixed(2)}`;
+ }, 10);
+ }
+
+ function checkWin(){
+ let allMatched = true;
+ for (const card of cards){
+ if(!card.classList.contains('matched')){
+ allMatched=false;
+ break;
+ }
+ }
+ if(allMatched){
+ clearInterval(timerInterval);
+ winScreen.style.display = 'flex';
+ }
+ }
+
+
+ startGame();
+ startTimer();
+
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/ce24cf987953/gemma3-12b.png b/data/artifacts/ce24cf987953/gemma3-12b.png
new file mode 100644
index 0000000..51d91c5
Binary files /dev/null and b/data/artifacts/ce24cf987953/gemma3-12b.png differ
diff --git a/data/artifacts/ce24cf987953/gpt.html b/data/artifacts/ce24cf987953/gpt.html
new file mode 100644
index 0000000..f5498e7
--- /dev/null
+++ b/data/artifacts/ce24cf987953/gpt.html
@@ -0,0 +1,675 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<title>Luxury Wallcovering Memory</title>
+<style>
+ * { box-sizing: border-box; margin: 0; padding: 0; }
+ html, body {
+ height: 100%;
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
+ background: radial-gradient(circle at top, #f6f4f2 0, #d5d1cc 40%, #b5b0a8 100%);
+ color: #3e3a36;
+ }
+ body {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+ .game-wrapper {
+ background: rgba(245, 242, 238, 0.96);
+ border-radius: 24px;
+ box-shadow:
+ 0 24px 60px rgba(33, 25, 20, 0.38),
+ 0 0 0 1px rgba(255,255,255,0.7),
+ inset 0 0 0 1px rgba(255,255,255,0.35);
+ width: 720px;
+ max-width: 92vw;
+ padding: 26px 28px 28px;
+ backdrop-filter: blur(18px);
+ position: relative;
+ overflow: hidden;
+ }
+ .header {
+ display: flex;
+ justify-content: space-between;
+ align-items: baseline;
+ margin-bottom: 18px;
+ }
+ .title-group {
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+ }
+ h1 {
+ font-size: 20px;
+ letter-spacing: 0.14em;
+ text-transform: uppercase;
+ font-weight: 500;
+ }
+ .subtitle {
+ font-size: 11px;
+ letter-spacing: 0.25em;
+ text-transform: uppercase;
+ color: #8a847d;
+ }
+ .stats {
+ display: flex;
+ gap: 18px;
+ align-items: center;
+ font-size: 13px;
+ }
+ .stat-label {
+ font-size: 10px;
+ text-transform: uppercase;
+ letter-spacing: 0.15em;
+ color: #a19990;
+ }
+ .stat-value {
+ font-variant-numeric: tabular-nums;
+ font-weight: 500;
+ }
+ .stat-block {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
+ gap: 2px;
+ }
+ .restart-btn {
+ border-radius: 999px;
+ border: none;
+ padding: 7px 16px;
+ font-size: 11px;
+ letter-spacing: 0.16em;
+ text-transform: uppercase;
+ background: linear-gradient(145deg, #ccc5be, #b5ada4);
+ color: #272320;
+ cursor: pointer;
+ box-shadow:
+ 0 2px 4px rgba(0,0,0,0.12),
+ inset 0 0 0 1px rgba(255,255,255,0.65);
+ transition: transform 0.15s ease-out, box-shadow 0.15s ease-out, background 0.2s ease-out;
+ }
+ .restart-btn:hover {
+ background: linear-gradient(145deg, #d5cec6, #beb6ac);
+ box-shadow:
+ 0 5px 16px rgba(0,0,0,0.16),
+ inset 0 0 0 1px rgba(255,255,255,0.9);
+ transform: translateY(-1px);
+ }
+ .restart-btn:active {
+ transform: translateY(0);
+ box-shadow:
+ 0 1px 4px rgba(0,0,0,0.18),
+ inset 0 0 0 1px rgba(255,255,255,0.7);
+ }
+
+ .board {
+ width: 100%;
+ margin-top: 6px;
+ padding: 14px 12px 10px;
+ border-radius: 18px;
+ background: radial-gradient(circle at top left, #f5f2ee 0, #d7d1ca 45%, #b4aea7 100%);
+ box-shadow:
+ inset 0 0 0 1px rgba(255,255,255,0.9),
+ inset 0 16px 26px rgba(255,255,255,0.8),
+ inset 0 -16px 30px rgba(0,0,0,0.09);
+ display: grid;
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ gap: 13px;
+ justify-items: center;
+ }
+
+ .card {
+ width: 100%;
+ padding-top: 100%;
+ position: relative;
+ perspective: 900px;
+ cursor: pointer;
+ border-radius: 16px;
+ }
+ .card-inner {
+ position: absolute;
+ inset: 0;
+ border-radius: 16px;
+ transform-style: preserve-3d;
+ transition: transform 0.45s cubic-bezier(.23,.79,.34,1.12);
+ }
+ .card.flipped .card-inner {
+ transform: rotateY(180deg);
+ }
+ .card.matched {
+ pointer-events: none;
+ }
+
+ .card-face {
+ position: absolute;
+ inset: 0;
+ backface-visibility: hidden;
+ border-radius: 16px;
+ overflow: hidden;
+ }
+ .card-front {
+ background: linear-gradient(135deg, #b9b1a7, #a29a90);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-shadow:
+ 0 10px 22px rgba(36,24,16,0.45),
+ 0 0 0 1px rgba(255,255,255,0.6);
+ }
+ .card-front::before {
+ content: "";
+ position: absolute;
+ inset: 10%;
+ border-radius: 12px;
+ border: 1px solid rgba(255,255,255,0.8);
+ box-shadow:
+ inset 0 0 0 1px rgba(120,104,88,0.5),
+ 0 0 0 1px rgba(255,255,255,0.45);
+ background:
+ radial-gradient(circle at 30% 20%, rgba(255,255,255,0.42), transparent 55%),
+ radial-gradient(circle at 70% 80%, rgba(0,0,0,0.18), transparent 60%);
+ opacity: 0.98;
+ }
+ .card-back {
+ transform: rotateY(180deg);
+ box-shadow:
+ 0 10px 22px rgba(36,24,16,0.45),
+ 0 0 0 1px rgba(255,255,255,0.7);
+ background: #d8d2c9;
+ }
+
+ /* Swatch base */
+ .swatch {
+ position: absolute;
+ inset: 0;
+ }
+
+ /* 1. Herringbone Linen */
+ .pattern-herringbone {
+ background:
+ linear-gradient(135deg, rgba(214,204,192,0.75) 25%, transparent 25%) -8px 0,
+ linear-gradient(225deg, rgba(214,204,192,0.75) 25%, transparent 25%) -8px 0,
+ linear-gradient(315deg, rgba(214,204,192,0.75) 25%, transparent 25%),
+ linear-gradient(45deg, rgba(214,204,192,0.75) 25%, transparent 25%);
+ background-size: 16px 16px;
+ background-color: #e9e2d6;
+ }
+ .pattern-herringbone::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ background: linear-gradient(to bottom, rgba(255,255,255,0.35), rgba(166,151,135,0.4));
+ mix-blend-mode: soft-light;
+ }
+
+ /* 2. Damask */
+ .pattern-damask {
+ background-color: #e2d6ce;
+ background-image:
+ radial-gradient(circle at 50% 0, rgba(164,144,130,0.8) 0 7%, transparent 8%),
+ radial-gradient(circle at 0 50%, rgba(164,144,130,0.8) 0 7%, transparent 8%),
+ radial-gradient(circle at 100% 50%, rgba(164,144,130,0.8) 0 7%, transparent 8%),
+ radial-gradient(circle at 50% 100%, rgba(164,144,130,0.8) 0 7%, transparent 8%);
+ background-size: 40px 40px;
+ background-position: center;
+ }
+ .pattern-damask::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ background-image:
+ radial-gradient(circle at 20% 30%, rgba(255,255,255,0.6) 0, transparent 55%),
+ radial-gradient(circle at 80% 70%, rgba(112,95,82,0.35) 0, transparent 60%);
+ mix-blend-mode: screen;
+ }
+
+ /* 3. Vertical Silk Stripes */
+ .pattern-silk {
+ background-image:
+ linear-gradient(90deg,
+ rgba(181,170,161,0.76) 0 2px,
+ rgba(229,222,214,0.95) 2px 18px,
+ rgba(181,170,161,0.76) 18px 20px);
+ background-size: 20px 100%;
+ background-color: #e9e3d9;
+ }
+ .pattern-silk::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ background-image:
+ linear-gradient(180deg, rgba(255,255,255,0.6), rgba(167,149,134,0.25));
+ mix-blend-mode: soft-light;
+ opacity: 0.9;
+ }
+
+ /* 4. Geometric Lattice */
+ .pattern-lattice {
+ background-color: #d8d0c4;
+ background-image:
+ linear-gradient(45deg, transparent 46%, rgba(152,137,121,0.9) 47%, rgba(152,137,121,0.9) 53%, transparent 54%),
+ linear-gradient(-45deg, transparent 46%, rgba(152,137,121,0.9) 47%, rgba(152,137,121,0.9) 53%, transparent 54%);
+ background-size: 22px 22px;
+ }
+ .pattern-lattice::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ background:
+ radial-gradient(circle at 30% 20%, rgba(255,255,255,0.5), transparent 55%),
+ radial-gradient(circle at 70% 80%, rgba(94,80,67,0.4), transparent 60%);
+ mix-blend-mode: soft-light;
+ }
+
+ /* 5. Grasscloth */
+ .pattern-grasscloth {
+ background-color: #d9d0c1;
+ background-image:
+ linear-gradient(90deg, rgba(158,143,127,0.5) 1px, transparent 1px),
+ linear-gradient(180deg, rgba(134,117,99,0.45) 0.5px, transparent 0.5px),
+ linear-gradient(180deg, rgba(221,211,199,0.8) 0 3px, transparent 3px);
+ background-size: 4px 100%, 100% 3px, 100% 6px;
+ }
+ .pattern-grasscloth::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ background: linear-gradient(145deg, rgba(255,255,255,0.5), rgba(166,151,133,0.45));
+ mix-blend-mode: soft-light;
+ }
+
+ /* 6. Chevron Ombre */
+ .pattern-chevron {
+ background:
+ linear-gradient(135deg, #e6ded3 0, #c8bfb2 50%, #a99e8e 100%);
+ mask-image:
+ linear-gradient(135deg, transparent 23%, #000 23% 27%, transparent 27% 73%, #000 73% 77%, transparent 77%),
+ linear-gradient(225deg, transparent 23%, #000 23% 27%, transparent 27% 73%, #000 73% 77%, transparent 77%);
+ mask-size: 28px 28px;
+ mask-position: 0 0, 14px 14px;
+ }
+ .pattern-chevron::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ background:
+ radial-gradient(circle at 25% 20%, rgba(255,255,255,0.5), transparent 50%),
+ radial-gradient(circle at 75% 80%, rgba(70,58,48,0.4), transparent 55%);
+ mix-blend-mode: soft-light;
+ }
+
+ /* 7. Art Deco Fan */
+ .pattern-fan {
+ background-color: #ddd4c8;
+ background-image:
+ radial-gradient(circle at 50% 100%, rgba(151,134,120,0.9) 20%, transparent 21%),
+ radial-gradient(circle at 0 100%, rgba(151,134,120,0.9) 20%, transparent 21%),
+ radial-gradient(circle at 100% 100%, rgba(151,134,120,0.9) 20%, transparent 21%);
+ background-size: 40px 20px;
+ background-position: 0 0, -20px 10px, 20px 10px;
+ }
+ .pattern-fan::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ background-image:
+ linear-gradient(0deg, rgba(255,255,255,0.7), rgba(132,113,97,0.25));
+ mix-blend-mode: soft-light;
+ }
+
+ /* 8. Crosshatch Weave */
+ .pattern-weave {
+ background-color: #e3dbcf;
+ background-image:
+ linear-gradient(90deg, rgba(171,156,139,0.65) 1px, transparent 1px),
+ linear-gradient(180deg, rgba(171,156,139,0.65) 1px, transparent 1px),
+ linear-gradient(90deg, rgba(255,255,255,0.7) 1px, transparent 1px),
+ linear-gradient(180deg, rgba(255,255,255,0.7) 1px, transparent 1px);
+ background-size: 6px 6px, 6px 6px, 24px 24px, 24px 24px;
+ background-position: 0 0, 0 0, 0 0, 0 0;
+ }
+ .pattern-weave::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ background:
+ radial-gradient(circle at 20% 25%, rgba(255,255,255,0.5), transparent 55%),
+ radial-gradient(circle at 80% 75%, rgba(118,102,86,0.35), transparent 60%);
+ mix-blend-mode: soft-light;
+ }
+
+ /* Win overlay */
+ .overlay {
+ position: absolute;
+ inset: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ pointer-events: none;
+ }
+ .overlay.visible {
+ pointer-events: auto;
+ }
+ .overlay-backdrop {
+ position: absolute;
+ inset: 0;
+ background: radial-gradient(circle at top, rgba(255,255,255,0.9) 0, rgba(0,0,0,0.5) 100%);
+ opacity: 0;
+ transition: opacity 0.35s ease-out;
+ }
+ .overlay.visible .overlay-backdrop {
+ opacity: 1;
+ }
+ .overlay-panel {
+ position: relative;
+ background: linear-gradient(145deg, #f8f5f1, #ddd5cb);
+ border-radius: 22px;
+ padding: 24px 28px 22px;
+ box-shadow:
+ 0 24px 60px rgba(0,0,0,0.45),
+ 0 0 0 1px rgba(255,255,255,0.9),
+ inset 0 0 0 1px rgba(255,255,255,0.9);
+ max-width: 360px;
+ text-align: center;
+ transform: translateY(20px) scale(0.96);
+ opacity: 0;
+ transition: transform 0.35s cubic-bezier(.19,.74,.32,1.25), opacity 0.35s ease-out;
+ }
+ .overlay.visible .overlay-panel {
+ transform: translateY(0) scale(1);
+ opacity: 1;
+ }
+ .overlay-title {
+ text-transform: uppercase;
+ font-size: 12px;
+ letter-spacing: 0.3em;
+ color: #94887b;
+ margin-bottom: 10px;
+ }
+ .overlay-main {
+ font-size: 22px;
+ letter-spacing: 0.12em;
+ text-transform: uppercase;
+ margin-bottom: 12px;
+ }
+ .overlay-metrics {
+ display: flex;
+ justify-content: center;
+ gap: 28px;
+ font-size: 13px;
+ margin-bottom: 16px;
+ }
+ .overlay-label {
+ font-size: 10px;
+ letter-spacing: 0.16em;
+ text-transform: uppercase;
+ color: #a79a8b;
+ margin-bottom: 3px;
+ }
+ .overlay-value {
+ font-variant-numeric: tabular-nums;
+ font-weight: 500;
+ }
+ .overlay-actions {
+ display: flex;
+ justify-content: center;
+ }
+ .overlay button {
+ border-radius: 999px;
+ border: none;
+ padding: 8px 20px;
+ font-size: 11px;
+ letter-spacing: 0.18em;
+ text-transform: uppercase;
+ background: linear-gradient(145deg, #c9c0b4, #b1a598);
+ color: #272320;
+ cursor: pointer;
+ box-shadow:
+ 0 3px 8px rgba(0,0,0,0.2),
+ inset 0 0 0 1px rgba(255,255,255,0.8);
+ transition: transform 0.15s ease-out, box-shadow 0.15s ease-out, background 0.2s ease-out;
+ }
+ .overlay button:hover {
+ background: linear-gradient(145deg, #d3c9bd, #b9aea1);
+ box-shadow:
+ 0 6px 18px rgba(0,0,0,0.28),
+ inset 0 0 0 1px rgba(255,255,255,0.9);
+ transform: translateY(-1px);
+ }
+ .overlay button:active {
+ transform: translateY(0);
+ box-shadow:
+ 0 2px 6px rgba(0,0,0,0.24),
+ inset 0 0 0 1px rgba(255,255,255,0.82);
+ }
+
+ @media (max-width: 640px) {
+ .game-wrapper {
+ padding: 18px 16px 18px;
+ border-radius: 20px;
+ }
+ h1 { font-size: 17px; }
+ .subtitle { font-size: 9px; letter-spacing: 0.22em; }
+ .stats { gap: 12px; font-size: 12px; }
+ .board {
+ padding: 10px 8px 8px;
+ gap: 9px;
+ }
+ .overlay-panel {
+ padding: 18px 18px 16px;
+ max-width: 92vw;
+ }
+ .overlay-main { font-size: 18px; }
+ }
+</style>
+</head>
+<body>
+<div class="game-wrapper">
+ <div class="header">
+ <div class="title-group">
+ <h1>Atelier Memory</h1>
+ <div class="subtitle">Curated Wallcovering Swatches</div>
+ </div>
+ <div class="stats">
+ <div class="stat-block">
+ <div class="stat-label">Moves</div>
+ <div class="stat-value" id="moves">0</div>
+ </div>
+ <div class="stat-block">
+ <div class="stat-label">Time</div>
+ <div class="stat-value" id="time">00:00</div>
+ </div>
+ <button class="restart-btn" id="restartTop">Restart</button>
+ </div>
+ </div>
+
+ <div class="board" id="board"></div>
+
+ <div class="overlay" id="overlay">
+ <div class="overlay-backdrop"></div>
+ <div class="overlay-panel">
+ <div class="overlay-title">Collection Completed</div>
+ <div class="overlay-main">All Swatches Found</div>
+ <div class="overlay-metrics">
+ <div>
+ <div class="overlay-label">Total Moves</div>
+ <div class="overlay-value" id="finalMoves">0</div>
+ </div>
+ <div>
+ <div class="overlay-label">Elapsed Time</div>
+ <div class="overlay-value" id="finalTime">00:00</div>
+ </div>
+ </div>
+ <div class="overlay-actions">
+ <button id="restartWin">Play Again</button>
+ </div>
+ </div>
+ </div>
+</div>
+
+<script>
+(function() {
+ const patterns = [
+ "pattern-herringbone",
+ "pattern-damask",
+ "pattern-silk",
+ "pattern-lattice",
+ "pattern-grasscloth",
+ "pattern-chevron",
+ "pattern-fan",
+ "pattern-weave"
+ ];
+
+ const boardEl = document.getElementById('board');
+ const movesEl = document.getElementById('moves');
+ const timeEl = document.getElementById('time');
+ const overlayEl = document.getElementById('overlay');
+ const finalMovesEl = document.getElementById('finalMoves');
+ const finalTimeEl = document.getElementById('finalTime');
+ const restartTop = document.getElementById('restartTop');
+ const restartWin = document.getElementById('restartWin');
+
+ let cards = [];
+ let flipped = [];
+ let lockBoard = false;
+ let moves = 0;
+ let matches = 0;
+ let startTime = null;
+ let timerId = null;
+
+ function shuffle(array) {
+ for (let i = array.length - 1; i > 0; i--) {
+ const j = (Math.random() * (i + 1)) | 0;
+ [array[i], array[j]] = [array[j], array[i]];
+ }
+ return array;
+ }
+
+ function formatTime(seconds) {
+ const m = Math.floor(seconds / 60);
+ const s = seconds % 60;
+ return (m < 10 ? "0" + m : "" + m) + ":" + (s < 10 ? "0" + s : "" + s);
+ }
+
+ function startTimer() {
+ if (timerId) return;
+ startTime = Date.now();
+ timerId = setInterval(() => {
+ const elapsed = Math.floor((Date.now() - startTime) / 1000);
+ timeEl.textContent = formatTime(elapsed);
+ }, 250);
+ }
+
+ function stopTimer() {
+ if (timerId) {
+ clearInterval(timerId);
+ timerId = null;
+ }
+ }
+
+ function resetStats() {
+ moves = 0;
+ matches = 0;
+ movesEl.textContent = "0";
+ timeEl.textContent = "00:00";
+ stopTimer();
+ startTime = null;
+ }
+
+ function createCard(patternClass, id) {
+ const card = document.createElement('div');
+ card.className = 'card';
+ card.dataset.pattern = patternClass;
+ card.dataset.id = id;
+
+ const inner = document.createElement('div');
+ inner.className = 'card-inner';
+
+ const front = document.createElement('div');
+ front.className = 'card-face card-front';
+
+ const back = document.createElement('div');
+ back.className = 'card-face card-back';
+ const swatch = document.createElement('div');
+ swatch.className = 'swatch ' + patternClass;
+ back.appendChild(swatch);
+
+ inner.appendChild(front);
+ inner.appendChild(back);
+ card.appendChild(inner);
+
+ card.addEventListener('click', () => handleCardClick(card));
+ return card;
+ }
+
+ function handleCardClick(card) {
+ if (lockBoard) return;
+ if (card.classList.contains('flipped')) return;
+
+ if (!startTime) startTimer();
+
+ card.classList.add('flipped');
+ flipped.push(card);
+
+ if (flipped.length === 2) {
+ lockBoard = true;
+ moves++;
+ movesEl.textContent = moves;
+ const [a, b] = flipped;
+ if (a.dataset.pattern === b.dataset.pattern) {
+ a.classList.add('matched');
+ b.classList.add('matched');
+ flipped = [];
+ lockBoard = false;
+ matches++;
+ if (matches === patterns.length) {
+ onWin();
+ }
+ } else {
+ setTimeout(() => {
+ a.classList.remove('flipped');
+ b.classList.remove('flipped');
+ flipped = [];
+ lockBoard = false;
+ }, 650);
+ }
+ }
+ }
+
+ function onWin() {
+ stopTimer();
+ const elapsed = startTime ? Math.floor((Date.now() - startTime) / 1000) : 0;
+ finalMovesEl.textContent = moves;
+ finalTimeEl.textContent = formatTime(elapsed);
+ requestAnimationFrame(() => {
+ overlayEl.classList.add('visible');
+ });
+ }
+
+ function hideOverlay() {
+ overlayEl.classList.remove('visible');
+ }
+
+ function initBoard() {
+ boardEl.innerHTML = '';
+ const deck = shuffle([...patterns, ...patterns]);
+ cards = deck.map((pattern, idx) => createCard(pattern, idx));
+ cards.forEach(card => boardEl.appendChild(card));
+ }
+
+ function restartGame() {
+ hideOverlay();
+ resetStats();
+ initBoard();
+ }
+
+ restartTop.addEventListener('click', restartGame);
+ restartWin.addEventListener('click', restartGame);
+
+ initBoard();
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/ce24cf987953/gpt.png b/data/artifacts/ce24cf987953/gpt.png
new file mode 100644
index 0000000..4cfe80f
Binary files /dev/null and b/data/artifacts/ce24cf987953/gpt.png differ
diff --git a/data/artifacts/ce24cf987953/grok.html b/data/artifacts/ce24cf987953/grok.html
new file mode 100644
index 0000000..745672b
--- /dev/null
+++ b/data/artifacts/ce24cf987953/grok.html
@@ -0,0 +1,207 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Swatch Memory</title>
+<style>
+*{margin:0;padding:0;box-sizing:border-box}
+:root{
+--bg:#2c2a28;--surface:#3a3734;--card-back:#4a4540;--text:#e8e2d9;--muted:#a89f94;
+--accent:#8b7355;--gold:#c4a574;--success:#6b8f71;--border:#5c564e;
+}
+body{
+font-family:Georgia,"Times New Roman",serif;
+background:var(--bg);
+color:var(--text);
+min-height:100vh;
+display:flex;
+flex-direction:column;
+align-items:center;
+justify-content:center;
+padding:20px;
+background-image:
+radial-gradient(ellipse at 20% 50%,rgba(139,115,85,.08) 0%,transparent 50%),
+radial-gradient(ellipse at 80% 20%,rgba(196,165,116,.06) 0%,transparent 40%);
+}
+h1{
+font-weight:400;
+letter-spacing:.18em;
+font-size:1.35rem;
+text-transform:uppercase;
+color:var(--gold);
+margin-bottom:6px;
+}
+.subtitle{font-size:.75rem;color:var(--muted);letter-spacing:.12em;margin-bottom:22px;font-style:italic}
+.hud{
+display:flex;gap:28px;margin-bottom:20px;align-items:center;
+font-size:.85rem;letter-spacing:.06em;color:var(--muted);
+}
+.hud span{color:var(--text);font-variant-numeric:tabular-nums}
+.hud b{font-weight:400;color:var(--gold);margin-right:4px}
+button{
+background:transparent;border:1px solid var(--border);color:var(--text);
+padding:8px 20px;font-family:inherit;font-size:.75rem;letter-spacing:.14em;
+text-transform:uppercase;cursor:pointer;transition:all .3s;border-radius:2px;
+}
+button:hover{border-color:var(--gold);color:var(--gold)}
+.board{
+display:grid;grid-template-columns:repeat(4,1fr);gap:12px;
+width:min(440px,92vw);perspective:1000px;
+}
+.card{
+aspect-ratio:1;cursor:pointer;position:relative;
+transform-style:preserve-3d;transition:transform .55s cubic-bezier(.4,.1,.2,1);
+border-radius:4px;
+}
+.card.flipped,.card.matched{transform:rotateY(180deg);cursor:default}
+.card.matched{pointer-events:none}
+.face{
+position:absolute;inset:0;backface-visibility:hidden;border-radius:4px;
+overflow:hidden;border:1px solid var(--border);
+}
+.back{
+background:var(--card-back);
+display:flex;align-items:center;justify-content:center;
+background-image:
+repeating-linear-gradient(45deg,transparent,transparent 6px,rgba(0,0,0,.06) 6px,rgba(0,0,0,.06) 7px),
+repeating-linear-gradient(-45deg,transparent,transparent 6px,rgba(0,0,0,.06) 6px,rgba(0,0,0,.06) 7px),
+linear-gradient(145deg,#524d47,#3d3935);
+}
+.back::after{
+content:"";width:28%;height:28%;border:1.5px solid var(--accent);
+border-radius:50%;opacity:.45;
+}
+.front{transform:rotateY(180deg);background:#d4cfc6}
+/* —— Wallcovering patterns —— */
+.p0{background:#c9b8a8;
+background-image:radial-gradient(ellipse 40% 30% at 50% 50%,#a89078 0%,transparent 70%),
+repeating-linear-gradient(0deg,transparent,transparent 14px,rgba(120,90,60,.12) 14px,rgba(120,90,60,.12) 15px),
+repeating-linear-gradient(90deg,transparent,transparent 14px,rgba(120,90,60,.12) 14px,rgba(120,90,60,.12) 15px)}
+.p1{background:#b7c4b0;
+background-image:repeating-linear-gradient(60deg,transparent,transparent 8px,rgba(80,100,70,.18) 8px,rgba(80,100,70,.18) 10px),
+repeating-linear-gradient(-60deg,transparent,transparent 8px,rgba(80,100,70,.12) 8px,rgba(80,100,70,.12) 10px)}
+.p2{background:#c4b5a5;
+background-image:radial-gradient(circle at 25% 25%,#9a8570 2px,transparent 2.5px),
+radial-gradient(circle at 75% 75%,#9a8570 2px,transparent 2.5px),
+radial-gradient(circle at 25% 75%,#a8927c 1.5px,transparent 2px),
+radial-gradient(circle at 75% 25%,#a8927c 1.5px,transparent 2px);
+background-size:20px 20px}
+.p3{background:#a8b0b8;
+background-image:repeating-linear-gradient(90deg,#8a929a 0px,#8a929a 3px,transparent 3px,transparent 12px),
+linear-gradient(180deg,rgba(255,255,255,.08),transparent)}
+.p4{background:#cfc3b0;
+background-image:repeating-linear-gradient(0deg,transparent,transparent 5px,rgba(140,120,90,.15) 5px,rgba(140,120,90,.15) 6px),
+repeating-linear-gradient(90deg,transparent,transparent 18px,rgba(140,120,90,.2) 18px,rgba(140,120,90,.2) 20px)}
+.p5{background:#b5a8b0;
+background-image:radial-gradient(ellipse 60% 40% at 50% 0%,rgba(120,90,110,.25),transparent),
+radial-gradient(ellipse 60% 40% at 50% 100%,rgba(120,90,110,.25),transparent),
+radial-gradient(circle at 50% 50%,transparent 30%,rgba(100,80,95,.15) 31%,transparent 32%);
+background-size:100% 100%,100% 100%,24px 24px}
+.p6{background:#b8b0a0;
+background-image:conic-gradient(from 45deg at 50% 50%,#a09080 0deg 90deg,#c0b8a8 90deg 180deg,#a09080 180deg 270deg,#c0b8a8 270deg 360deg);
+background-size:16px 16px}
+.p7{background:#c0b8a8;
+background-image:linear-gradient(135deg,rgba(150,130,100,.2) 25%,transparent 25%),
+linear-gradient(225deg,rgba(150,130,100,.2) 25%,transparent 25%),
+linear-gradient(45deg,rgba(150,130,100,.2) 25%,transparent 25%),
+linear-gradient(315deg,rgba(150,130,100,.2) 25%,transparent 25%);
+background-size:18px 18px;background-position:0 0,9px 0,9px -9px,0 9px}
+/* Win overlay */
+.overlay{
+position:fixed;inset:0;background:rgba(30,28,26,.88);
+display:flex;flex-direction:column;align-items:center;justify-content:center;
+opacity:0;pointer-events:none;transition:opacity .5s;z-index:10;
+}
+.overlay.show{opacity:1;pointer-events:auto}
+.overlay h2{
+font-weight:400;font-size:1.6rem;letter-spacing:.2em;text-transform:uppercase;
+color:var(--gold);margin-bottom:12px;
+}
+.overlay p{color:var(--muted);font-size:.9rem;letter-spacing:.06em;margin-bottom:28px;line-height:1.7;text-align:center}
+.overlay .stats{color:var(--text);margin-bottom:8px}
+</style>
+</head>
+<body>
+<h1>Swatch & Recall</h1>
+<p class="subtitle">A study in pattern recognition</p>
+<div class="hud">
+<div><b>Moves</b> <span id="moves">0</span></div>
+<div><b>Time</b> <span id="timer">0:00</span></div>
+<button id="restart" type="button">Restart</button>
+</div>
+<div class="board" id="board"></div>
+<div class="overlay" id="overlay">
+<h2>Well Matched</h2>
+<p class="stats" id="winStats"></p>
+<p>Every pattern found its pair.</p>
+<button id="playAgain" type="button">Play Again</button>
+</div>
+<script>
+(function(){
+const PATTERNS=8;
+const board=document.getElementById('board');
+const movesEl=document.getElementById('moves');
+const timerEl=document.getElementById('timer');
+const overlay=document.getElementById('overlay');
+const winStats=document.getElementById('winStats');
+let cards=[],flipped=[],moves=0,matched=0,lock=false,timerId=null,seconds=0,started=false;
+
+function shuffle(a){
+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 fmt(s){const m=Math.floor(s/60);const ss=s%60;return m+':'+(ss<10?'0':'')+ss}
+function startTimer(){
+if(started)return;started=true;
+timerId=setInterval(()=>{seconds++;timerEl.textContent=fmt(seconds)},1000);
+}
+function stopTimer(){if(timerId){clearInterval(timerId);timerId=null}}
+function build(){
+stopTimer();started=false;seconds=0;moves=0;matched=0;flipped=[];lock=false;
+movesEl.textContent='0';timerEl.textContent='0:00';overlay.classList.remove('show');
+board.innerHTML='';
+const ids=shuffle([...Array(PATTERNS).keys(),...Array(PATTERNS).keys()]);
+cards=ids.map((pid,i)=>{
+const el=document.createElement('div');
+el.className='card';
+el.dataset.pattern=pid;
+el.innerHTML='<div class="face back"></div><div class="face front p'+pid+'"></div>';
+el.addEventListener('click',()=>onFlip(el));
+board.appendChild(el);
+return el;
+});
+}
+function onFlip(el){
+if(lock||el.classList.contains('flipped')||el.classList.contains('matched'))return;
+startTimer();
+el.classList.add('flipped');
+flipped.push(el);
+if(flipped.length<2)return;
+moves++;movesEl.textContent=moves;
+const[a,b]=flipped;
+if(a.dataset.pattern===b.dataset.pattern){
+a.classList.add('matched');b.classList.add('matched');
+flipped=[];matched++;
+if(matched===PATTERNS){
+stopTimer();
+setTimeout(()=>{
+winStats.textContent=moves+' moves · '+fmt(seconds);
+overlay.classList.add('show');
+},600);
+}
+}else{
+lock=true;
+setTimeout(()=>{
+a.classList.remove('flipped');b.classList.remove('flipped');
+flipped=[];lock=false;
+},700);
+}
+}
+document.getElementById('restart').addEventListener('click',build);
+document.getElementById('playAgain').addEventListener('click',build);
+build();
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/ce24cf987953/grok.png b/data/artifacts/ce24cf987953/grok.png
new file mode 100644
index 0000000..83ede0b
Binary files /dev/null and b/data/artifacts/ce24cf987953/grok.png differ
diff --git a/data/artifacts/ce24cf987953/hermes3-8b.html b/data/artifacts/ce24cf987953/hermes3-8b.html
new file mode 100644
index 0000000..899f709
--- /dev/null
+++ b/data/artifacts/ce24cf987953/hermes3-8b.html
@@ -0,0 +1,164 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Memory Card Game</title>
+ <style>
+ body {
+ font-family: Arial, sans-serif;
+ background-color: #f0f0f0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100vh;
+ margin: 0;
+ }
+
+ .container {
+ width: 400px;
+ }
+
+ h1 {
+ text-align: center;
+ color: #333;
+ }
+
+ .grid {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ grid-gap: 10px;
+ }
+
+ .card {
+ background-color: #fff;
+ border-radius: 8px;
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+ cursor: pointer;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-size: 24px;
+ height: 120px;
+ margin-bottom: 10px;
+ transition: transform 0.3s ease-in-out;
+ }
+
+ .card.flipped {
+ transform: rotateY(180deg);
+ }
+
+ .card.front,
+ .card.back {
+ backface-visibility: hidden;
+ border: none;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-size: 24px;
+ height: 120px;
+ margin-bottom: 10px;
+ }
+
+ .card.front {
+ z-index: 2;
+ }
+
+ .card.back {
+ transform: rotateY(180deg);
+ }
+
+ .timer {
+ color: #333;
+ font-size: 24px;
+ margin-top: 20px;
+ }
+ </style>
+</head>
+<body>
+ <div class="container">
+ <h1>Memory Card Game</h1>
+ <div class="grid" id="grid"></div>
+ <div class="timer" id="timer">Time: 00.0s</div>
+ </div>
+
+ <script>
+ const cards = [
+ { front: 'wallpaper1', back: '✓' },
+ { front: 'wallpaper2', back: '✓' },
+ { front: 'wallpaper3', back: '✓' },
+ { front: 'wallpaper4', back: '✓' },
+ { front: 'wallpaper5', back: '✓' },
+ { front: 'wallpaper6', back: '✓' },
+ { front: 'wallpaper7', back: '✓' },
+ { front: 'wallpaper8', back: '✓' }
+ ];
+
+ const gridSize = 4;
+ let moves = 0;
+ let timeStarted = null;
+ let timerInterval = null;
+
+ function startTimer() {
+ if (timeStarted === null) {
+ timeStarted = Date.now();
+ timerInterval = setInterval(() => {
+ document.getElementById('timer').textContent = `Time: ${(Date.now() - timeStarted) / 1000}.s`;
+ }, 10);
+ }
+ }
+
+ function cardClicked(cardElement, card) {
+ if (!cardElement.classList.contains('flipped')) {
+ cardElement.querySelector('.card.front').style.transform = 'rotateY(180deg)';
+ cardElement.classList.add('flipped');
+ moves++;
+
+ if (card.front === card.back) {
+ cardElement.style.pointerEvents = 'none';
+ document.getElementById('grid').style.pointerEvents = 'none';
+
+ setTimeout(() => {
+ cardElement.querySelector('.card.flipped').innerText = '';
+ document.getElementById('grid').style.pointerEvents = 'none';
+ }, 1000);
+ }
+ }
+ }
+
+ function createCard(card) {
+ const cardElement = document.createElement('div');
+ cardElement.className = 'card';
+ cardElement.innerHTML = `
+ <div class="card front">${card.front}</div>
+ <div class="card back" onclick="cardClicked(this, ${JSON.stringify(card)})">${card.back}</div>
+ `;
+ return cardElement;
+ }
+
+ function shuffleArray(array) {
+ for (let i = array.length - 1; i > 0; i--) {
+ const j = Math.floor(Math.random() * (i + 1));
+ [array[i], array[j]] = [array[j], array[i]];
+ }
+ }
+
+ function startGame() {
+ shuffleArray(cards);
+ document.getElementById('grid').innerHTML = '';
+
+ for (let i = 0; i < gridSize * gridSize; i++) {
+ const card = cards[i];
+ document.getElementById('grid').appendChild(createCard(card));
+ }
+
+ document.getElementById('grid').style.pointerEvents = 'auto';
+ startTimer();
+ }
+
+ document.addEventListener('DOMContentLoaded', () => {
+ startGame();
+ });
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/ce24cf987953/hermes3-8b.png b/data/artifacts/ce24cf987953/hermes3-8b.png
new file mode 100644
index 0000000..eeefbf9
Binary files /dev/null and b/data/artifacts/ce24cf987953/hermes3-8b.png differ
diff --git a/data/artifacts/ce24cf987953/qwen25-7b.html b/data/artifacts/ce24cf987953/qwen25-7b.html
new file mode 100644
index 0000000..9c45a5d
--- /dev/null
+++ b/data/artifacts/ce24cf987953/qwen25-7b.html
@@ -0,0 +1,105 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Wallcovering Memory Game</title>
+ <style>
+ body {
+ background: #f0e9d5;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100vh;
+ margin: 0;
+ font-family: 'Arial', sans-serif;
+ }
+ .grid-container {
+ perspective: 1000px;
+ width: 320px;
+ height: 640px;
+ position: relative;
+ display: grid;
+ grid-template-columns: repeat(4, 80px);
+ gap: 10px;
+ }
+ .card {
+ width: 70px;
+ height: 140px;
+ background: linear-gradient(to bottom, #d6b99c, #a38b5f);
+ position: relative;
+ transform-style: preserve-3d;
+ transition: transform 0.5s;
+ }
+ .card.flipped {
+ transform: rotateY(180deg);
+ }
+ .card img {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ backface-visibility: hidden;
+ }
+ #timer {
+ position: absolute;
+ top: 20px;
+ left: 50%;
+ transform: translateX(-50%);
+ font-size: 24px;
+ color: #6a583d;
+ }
+ </style>
+</head>
+<body>
+ <div class="grid-container" id="grid">
+ <!-- Card placeholders -->
+ </div>
+ <div id="timer">Time: 0s</div>
+ <script>
+ const cards = Array.from({ length: 8 }, (_, i) => `Swatch${i+1}`).concat(Array(8).fill(''));
+ let shuffleCards = [...cards, ...cards].sort(() => Math.random() - 0.5);
+ const grid = document.getElementById('grid');
+ let moves = 0;
+ let timerId;
+
+ function createCard(card) {
+ return `
+ <div class="card" onclick="flip(this)">
+ <img src="" alt="${card}" />
+ </div>
+ `;
+ }
+
+ shuffleCards.forEach((card, index) => {
+ const cardElement = createCard(card);
+ grid.innerHTML += cardElement;
+ });
+
+ function flip(card) {
+ if (card.classList.contains('flipped')) return;
+ card.classList.add('flipped');
+ moves++;
+ document.getElementById('timer').textContent = `Time: ${moves}s`;
+ setTimeout(() => {
+ card.classList.remove('flipped');
+ if (grid.querySelectorAll('.flipped').length === 8) {
+ alert(`Congratulations! You won in ${moves} moves!`);
+ location.reload();
+ }
+ }, 500);
+ }
+
+ function startTimer() {
+ const timer = document.getElementById('timer');
+ let time = 0;
+ clearInterval(timerId);
+ timerId = setInterval(() => {
+ time++;
+ timer.textContent = `Time: ${time}s`;
+ }, 1000);
+ }
+
+ window.onload = startTimer;
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/ce24cf987953/qwen25-7b.png b/data/artifacts/ce24cf987953/qwen25-7b.png
new file mode 100644
index 0000000..f623f17
Binary files /dev/null and b/data/artifacts/ce24cf987953/qwen25-7b.png differ
diff --git a/data/artifacts/ce24cf987953/qwen3-14b.html b/data/artifacts/ce24cf987953/qwen3-14b.html
new file mode 100644
index 0000000..b2a2c14
--- /dev/null
+++ b/data/artifacts/ce24cf987953/qwen3-14b.html
@@ -0,0 +1,282 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title>Luxury Wallcovering Memory Game</title>
+ <style>
+ * {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ }
+ body {
+ font-family: 'Georgia', serif;
+ background: #1a1a1a;
+ color: #f0f0f0;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ min-height: 100vh;
+ padding: 20px;
+ }
+ h1 {
+ margin-bottom: 20px;
+ }
+ #game {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ gap: 10px;
+ width: 400px;
+ }
+ .card {
+ width: 100px;
+ height: 100px;
+ perspective: 1000px;
+ cursor: pointer;
+ background: #2a2a2a;
+ border: 2px solid #3a3a3a;
+ position: relative;
+ transition: transform 0.6s;
+ transform-style: preserve-3d;
+ }
+ .card.flipped {
+ transform: rotateY(180deg);
+ }
+ .card-inner {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ backface-visibility: hidden;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 40px;
+ font-weight: bold;
+ color: #fff;
+ text-shadow: 0 2px 4px rgba(0,0,0,0.5);
+ background: #2a2a2a;
+ }
+ .card-inner.back {
+ transform: rotateY(180deg);
+ }
+ .card-inner.front {
+ background: linear-gradient(135deg, #4f4f4f, #5a5a5a);
+ box-shadow: 0 8px 16px rgba(0,0,0,0.4);
+ border-radius: 8px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 32px;
+ color: #1a1a1a;
+ text-shadow: 0 2px 4px rgba(255,255,255,0.2);
+ }
+ .card-inner.front.pattern1 {
+ background: repeating-linear-gradient(
+ 45deg,
+ #8a7f7f,
+ #8a7f7f 10px,
+ #968f8f 10px,
+ #968f8f 20px
+ );
+ }
+ .card-inner.front.pattern2 {
+ background: repeating-linear-gradient(
+ 45deg,
+ #a59d9d,
+ #a59d9d 10px,
+ #b0a8a8 10px,
+ #b0a8a8 20px
+ );
+ }
+ .card-inner.front.pattern3 {
+ background: repeating-linear-gradient(
+ 45deg,
+ #c2b8b8,
+ #c2b8b8 10px,
+ #c8c2c2 10px,
+ #c8c2c2 20px
+ );
+ }
+ .card-inner.front.pattern4 {
+ background: repeating-linear-gradient(
+ 45deg,
+ #e0d6d6,
+ #e0d6d6 10px,
+ #e6ddd6 10px,
+ #e6ddd6 20px
+ );
+ }
+ #info {
+ margin: 20px 0;
+ font-size: 18px;
+ }
+ #timer, #moves {
+ margin: 5px 0;
+ }
+ #win-screen {
+ display: none;
+ text-align: center;
+ margin-top: 20px;
+ font-size: 24px;
+ color: #4caf50;
+ }
+ #restart {
+ margin-top: 15px;
+ padding: 10px 20px;
+ font-size: 16px;
+ background: #4caf50;
+ color: #fff;
+ border: none;
+ border-radius: 5px;
+ cursor: pointer;
+ }
+ #restart:hover {
+ background: #388e3c;
+ }
+ </style>
+</head>
+<body>
+ <h1>Luxury Wallcovering Memory Game</h1>
+ <div id="game"></div>
+ <div id="info">
+ <div id="timer">Time: 0s</div>
+ <div id="moves">Moves: 0</div>
+ </div>
+ <div id="win-screen">🎉 You matched all swatches! Refresh to play again.</div>
+ <button id="restart">Restart Game</button>
+
+ <script>
+ const game = document.getElementById('game');
+ const winScreen = document.getElementById('win-screen');
+ const timerDisplay = document.getElementById('timer');
+ const movesDisplay = document.getElementById('moves');
+ const restartBtn = document.getElementById('restart');
+
+ let cards = [];
+ let firstCard = null;
+ let secondCard = null;
+ let lockBoard = false;
+ let moves = 0;
+ let time = 0;
+ let timerInterval;
+
+ const patterns = ['pattern1', 'pattern2', 'pattern3', 'pattern4'];
+ const cardData = [];
+
+ // Generate 8 pairs of cards
+ for (let i = 0; i < 8; i++) {
+ patterns.forEach(p => {
+ cardData.push(p);
+ });
+ }
+
+ // Shuffle the card data
+ cardData.sort(() => Math.random() - 0.5);
+
+ // Create the cards
+ cardData.forEach((pattern, index) => {
+ const card = document.createElement('div');
+ card.classList.add('card');
+ card.dataset.index = index;
+ card.dataset.pattern = pattern;
+
+ const inner = document.createElement('div');
+ inner.classList.add('card-inner');
+
+ const back = document.createElement('div');
+ back.classList.add('back');
+ back.textContent = ' ';
+
+ const front = document.createElement('div');
+ front.classList.add('front');
+ front.classList.add(pattern);
+
+ inner.appendChild(back);
+ inner.appendChild(front);
+ card.appendChild(inner);
+
+ card.addEventListener('click', flipCard);
+ game.appendChild(card);
+ cards.push(card);
+ });
+
+ function flipCard() {
+ if (lockBoard || this.classList.contains('flipped')) return;
+
+ this.classList.add('flipped');
+
+ if (!firstCard) {
+ firstCard = this;
+ return;
+ }
+
+ secondCard = this;
+ lockBoard = true;
+ moves++;
+ movesDisplay.textContent = 'Moves: ' + moves;
+
+ checkForMatch();
+ }
+
+ function checkForMatch() {
+ const isMatch = firstCard.dataset.pattern === secondCard.dataset.pattern;
+
+ if (isMatch) {
+ setTimeout(() => {
+ firstCard.removeEventListener('click', flipCard);
+ secondCard.removeEventListener('click', flipCard);
+ firstCard = null;
+ secondCard = null;
+ lockBoard = false;
+ checkWin();
+ }, 500);
+ } else {
+ setTimeout(() => {
+ firstCard.classList.remove('flipped');
+ secondCard.classList.remove('flipped');
+ firstCard = null;
+ secondCard = null;
+ lockBoard = false;
+ }, 1000);
+ }
+ }
+
+ function checkWin() {
+ const allFlipped = cards.every(card => card.classList.contains('flipped'));
+ if (allFlipped) {
+ clearInterval(timerInterval);
+ winScreen.style.display = 'block';
+ restartBtn.style.display = 'block';
+ }
+ }
+
+ function startTimer() {
+ time = 0;
+ timerDisplay.textContent = 'Time: 0s';
+ timerInterval = setInterval(() => {
+ time++;
+ timerDisplay.textContent = 'Time: ' + time + 's';
+ }, 1000);
+ }
+
+ restartBtn.addEventListener('click', () => {
+ winScreen.style.display = 'none';
+ restartBtn.style.display = 'none';
+ cards.forEach(card => {
+ card.classList.remove('flipped');
+ card.addEventListener('click', flipCard);
+ });
+ firstCard = null;
+ secondCard = null;
+ lockBoard = false;
+ moves = 0;
+ movesDisplay.textContent = 'Moves: 0';
+ startTimer();
+ });
+
+ startTimer();
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/ce24cf987953/qwen3-14b.png b/data/artifacts/ce24cf987953/qwen3-14b.png
new file mode 100644
index 0000000..de3df65
Binary files /dev/null and b/data/artifacts/ce24cf987953/qwen3-14b.png differ
diff --git a/data/artifacts/f2e21f2299c9/claude-code.html b/data/artifacts/f2e21f2299c9/claude-code.html
new file mode 100644
index 0000000..8ac0595
--- /dev/null
+++ b/data/artifacts/f2e21f2299c9/claude-code.html
@@ -0,0 +1,323 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Fleet Value Delivered</title>
+<style>
+ :root{
+ --bg:#07090f;
+ --panel:rgba(255,255,255,0.03);
+ --panel-brd:rgba(255,255,255,0.08);
+ --accent:#4ade80;
+ --accent2:#38bdf8;
+ --gold:#fbbf24;
+ --ink:#e8edf5;
+ --muted:#8a93a6;
+ --glow:0 0 40px rgba(74,222,128,0.15);
+ }
+ *{box-sizing:border-box;margin:0;padding:0}
+ html,body{height:100%}
+ body{
+ background:
+ radial-gradient(1200px 700px at 15% -10%, rgba(56,189,248,0.10), transparent 60%),
+ radial-gradient(1000px 600px at 100% 0%, rgba(74,222,128,0.08), transparent 55%),
+ radial-gradient(900px 900px at 50% 120%, rgba(124,58,237,0.10), transparent 60%),
+ var(--bg);
+ color:var(--ink);
+ font-family:"SF Pro Display",-apple-system,BlinkMacSystemFont,"Segoe UI",Inter,system-ui,sans-serif;
+ min-height:100vh;
+ overflow-x:hidden;
+ -webkit-font-smoothing:antialiased;
+ }
+ .grid-overlay{
+ position:fixed;inset:0;pointer-events:none;z-index:0;
+ background-image:
+ linear-gradient(rgba(255,255,255,0.018) 1px,transparent 1px),
+ linear-gradient(90deg,rgba(255,255,255,0.018) 1px,transparent 1px);
+ background-size:48px 48px;
+ mask-image:radial-gradient(circle at 50% 30%,#000 40%,transparent 85%);
+ }
+ .wrap{position:relative;z-index:1;max-width:1280px;margin:0 auto;padding:34px 26px 60px}
+
+ header{display:flex;align-items:center;justify-content:space-between;gap:20px;flex-wrap:wrap;margin-bottom:30px}
+ .brand{display:flex;align-items:center;gap:14px}
+ .logo{
+ width:44px;height:44px;border-radius:12px;position:relative;
+ background:linear-gradient(135deg,var(--accent),var(--accent2));
+ box-shadow:var(--glow);
+ display:grid;place-items:center;
+ }
+ .logo::before{content:"";width:18px;height:18px;border-radius:5px;background:#07090f;transform:rotate(45deg)}
+ .logo::after{content:"";position:absolute;width:7px;height:7px;border-radius:50%;background:var(--accent)}
+ .brand h1{font-size:19px;font-weight:700;letter-spacing:.3px}
+ .brand p{font-size:12px;color:var(--muted);letter-spacing:.6px;text-transform:uppercase;margin-top:2px}
+ .status{display:flex;align-items:center;gap:9px;font-size:12.5px;color:var(--muted);
+ background:var(--panel);border:1px solid var(--panel-brd);padding:9px 15px;border-radius:100px}
+ .dot{width:8px;height:8px;border-radius:50%;background:var(--accent);box-shadow:0 0 12px var(--accent);animation:pulse 2s infinite}
+ @keyframes pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.45;transform:scale(.8)}}
+
+ .hero{
+ display:grid;grid-template-columns:1fr 1fr;gap:22px;margin-bottom:26px;
+ }
+ .odo{
+ position:relative;overflow:hidden;
+ background:var(--panel);border:1px solid var(--panel-brd);border-radius:22px;
+ padding:34px 34px 30px;
+ backdrop-filter:blur(8px);
+ }
+ .odo::after{content:"";position:absolute;inset:0;border-radius:22px;pointer-events:none;
+ background:linear-gradient(160deg,rgba(255,255,255,0.05),transparent 45%)}
+ .odo .cap{display:flex;align-items:center;gap:10px;font-size:12.5px;letter-spacing:1px;text-transform:uppercase;color:var(--muted);margin-bottom:16px}
+ .odo .cap .ic{width:26px;height:26px;border-radius:8px;display:grid;place-items:center;font-size:14px}
+ .odo.money .ic{background:rgba(74,222,128,0.12);color:var(--accent)}
+ .odo.hours .ic{background:rgba(56,189,248,0.12);color:var(--accent2)}
+ .num{font-variant-numeric:tabular-nums;font-weight:800;line-height:1;letter-spacing:-2px;
+ font-size:clamp(46px,7vw,78px);display:flex;align-items:baseline}
+ .odo.money .num{background:linear-gradient(180deg,#eafff2,var(--accent));-webkit-background-clip:text;background-clip:text;color:transparent}
+ .odo.hours .num{background:linear-gradient(180deg,#eaf7ff,var(--accent2));-webkit-background-clip:text;background-clip:text;color:transparent}
+ .num .pre{font-size:.55em;margin-right:4px;font-weight:700;opacity:.85;-webkit-text-fill-color:currentColor}
+ .num .suf{font-size:.34em;margin-left:10px;font-weight:600;color:var(--muted);-webkit-text-fill-color:var(--muted);letter-spacing:0}
+ .sub{margin-top:16px;display:flex;align-items:center;gap:8px;font-size:13px;color:var(--muted)}
+ .chip{color:var(--accent);font-weight:600;background:rgba(74,222,128,0.1);padding:3px 9px;border-radius:6px;font-size:12px}
+ .odo.hours .chip{color:var(--accent2);background:rgba(56,189,248,0.1)}
+ .spark{position:absolute;right:22px;bottom:20px;display:flex;gap:4px;align-items:flex-end;height:44px;opacity:.55}
+ .spark span{width:5px;border-radius:3px;background:currentColor;animation:bar 1.6s ease-in-out infinite}
+ .odo.money .spark{color:var(--accent)} .odo.hours .spark{color:var(--accent2)}
+ @keyframes bar{0%,100%{transform:scaleY(.4)}50%{transform:scaleY(1)}}
+
+ .lower{display:grid;grid-template-columns:1.35fr 1fr;gap:22px}
+ .card{background:var(--panel);border:1px solid var(--panel-brd);border-radius:22px;padding:24px;backdrop-filter:blur(8px)}
+ .card h2{font-size:14px;font-weight:700;letter-spacing:.4px;display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}
+ .card h2 .t{display:flex;align-items:center;gap:9px}
+ .card h2 small{font-weight:500;color:var(--muted);font-size:11px;letter-spacing:.8px;text-transform:uppercase}
+
+ /* feed */
+ .feed-viewport{position:relative;height:340px;overflow:hidden;margin-top:8px;
+ mask-image:linear-gradient(180deg,transparent,#000 9%,#000 88%,transparent)}
+ .feed-track{display:flex;flex-direction:column;gap:10px;animation:scrollup 26s linear infinite}
+ .feed-viewport:hover .feed-track{animation-play-state:paused}
+ @keyframes scrollup{0%{transform:translateY(0)}100%{transform:translateY(-50%)}}
+ .win{display:flex;align-items:center;gap:13px;padding:12px 13px;border-radius:13px;
+ background:rgba(255,255,255,0.025);border:1px solid rgba(255,255,255,0.05)}
+ .win .av{width:34px;height:34px;border-radius:9px;flex:none;display:grid;place-items:center;font-size:15px;
+ background:rgba(255,255,255,0.05)}
+ .win .body{flex:1;min-width:0}
+ .win .ttl{font-size:13.5px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
+ .win .meta{font-size:11.5px;color:var(--muted);margin-top:2px;display:flex;gap:8px;align-items:center}
+ .win .agent{color:var(--accent2)}
+ .win .amt{font-variant-numeric:tabular-nums;font-weight:700;font-size:14px;color:var(--accent);flex:none;white-space:nowrap}
+ .win .amt.hrs{color:var(--accent2)}
+
+ /* chart */
+ .chart{margin-top:18px;display:flex;flex-direction:column;gap:15px}
+ .row{display:grid;grid-template-columns:96px 1fr auto;align-items:center;gap:12px}
+ .row .lbl{font-size:12.5px;color:var(--muted)}
+ .track{height:12px;border-radius:8px;background:rgba(255,255,255,0.05);overflow:hidden}
+ .fill{height:100%;width:0;border-radius:8px;transition:width 1.6s cubic-bezier(.16,1,.3,1)}
+ .row .val{font-size:12.5px;font-weight:700;font-variant-numeric:tabular-nums;min-width:52px;text-align:right}
+ .legend{margin-top:20px;padding-top:16px;border-top:1px solid var(--panel-brd);
+ display:flex;justify-content:space-between;font-size:12px;color:var(--muted)}
+ .legend b{color:var(--ink);font-size:16px;font-weight:800;display:block;font-variant-numeric:tabular-nums}
+
+ footer{margin-top:30px;text-align:center;font-size:11.5px;color:var(--muted);letter-spacing:.5px}
+
+ @media(max-width:880px){.hero{grid-template-columns:1fr}.lower{grid-template-columns:1fr}}
+</style>
+</head>
+<body>
+<div class="grid-overlay"></div>
+<div class="wrap">
+ <header>
+ <div class="brand">
+ <div class="logo"></div>
+ <div>
+ <h1>ATLAS · Agent Fleet</h1>
+ <p>Value Delivered · Live</p>
+ </div>
+ </div>
+ <div class="status"><span class="dot"></span> 24 agents active · streaming realtime</div>
+ </header>
+
+ <section class="hero">
+ <div class="odo money">
+ <div class="cap"><span class="ic">$</span> Total Dollars Saved</div>
+ <div class="num" id="money"><span class="pre">$</span><span class="digits">0</span></div>
+ <div class="sub"><span class="chip" id="moneyRate">+$0/hr</span> compounding across the fleet</div>
+ <div class="spark" id="sparkM"></div>
+ </div>
+ <div class="odo hours">
+ <div class="cap"><span class="ic">⏱</span> Engineering Hours Saved</div>
+ <div class="num" id="hours"><span class="digits">0</span><span class="suf">hrs</span></div>
+ <div class="sub"><span class="chip" id="hoursRate">+0/hr</span> ≈ <span id="fte">0</span> full-time engineers</div>
+ <div class="spark" id="sparkH"></div>
+ </div>
+ </section>
+
+ <section class="lower">
+ <div class="card">
+ <h2><span class="t">🏆 Recent Wins</span><small>auto-scrolling · hover to pause</small></h2>
+ <div class="feed-viewport">
+ <div class="feed-track" id="feed"></div>
+ </div>
+ </div>
+
+ <div class="card">
+ <h2><span class="t">📊 Savings by Category</span><small>this quarter</small></h2>
+ <div class="chart" id="chart"></div>
+ <div class="legend">
+ <div><b id="legTop">—</b><span>Top category</span></div>
+ <div style="text-align:right"><b id="legTotal">$0</b><span>Categorized total</span></div>
+ </div>
+ </div>
+ </section>
+
+ <footer>ATLAS Fleet Intelligence · figures update as agents close tasks · demo dashboard</footer>
+</div>
+
+<script>
+(function(){
+ "use strict";
+
+ // ---------- config ----------
+ var MONEY_TARGET = 4820750; // $ saved
+ var HOURS_TARGET = 38640; // eng-hours saved
+ var MONEY_RATE = 1240; // $/hr headline
+ var HOURS_RATE = 62; // hrs/hr headline
+
+ var wins = [
+ {a:"Sentinel", ic:"🛡️", t:"Auto-patched 14 CVEs before exploit window", v:82400, unit:"$"},
+ {a:"Ledger", ic:"📒", t:"Reconciled Q3 invoices, caught duplicate billing", v:31900, unit:"$"},
+ {a:"Cartographer",ic:"🗺️",t:"Migrated legacy ETL to streaming pipeline", v:640, unit:"h"},
+ {a:"Scribe", ic:"✍️", t:"Generated 1,200 API docs from source", v:210, unit:"h"},
+ {a:"Forge", ic:"⚙️", t:"Refactored monolith → 9 services, cut cloud spend", v:118600, unit:"$"},
+ {a:"Watchtower",ic:"📡", t:"Predicted outage, rerouted traffic pre-failure", v:54300, unit:"$"},
+ {a:"Quill", ic:"🪶", t:"Drafted & filed 38 support macros overnight", v:96, unit:"h"},
+ {a:"Prospector", ic:"⛏️", t:"Enriched 40k leads, deduped CRM", v:27750, unit:"$"},
+ {a:"Loom", ic:"🧵", t:"Wove 22 dashboards from raw telemetry", v:154, unit:"h"},
+ {a:"Beacon", ic:"🔦", t:"Localized product into 11 languages", v:44200, unit:"$"},
+ {a:"Anvil", ic:"🔨", t:"Hardened CI/CD, eliminated flaky test suite", v:308, unit:"h"},
+ {a:"Compass", ic:"🧭", t:"Optimized routing, trimmed delivery miles", v:61500, unit:"$"},
+ {a:"Cipher", ic:"🔐", t:"Rotated 900 secrets, closed audit gaps", v:73, unit:"h"},
+ {a:"Harvest", ic:"🌾", t:"Batch-processed 2.1M records for finance", v:38900, unit:"$"}
+ ];
+
+ var categories = [
+ {name:"Infra & Cloud", v:1486000, c:"#4ade80"},
+ {name:"Support Ops", v:1092000, c:"#38bdf8"},
+ {name:"Engineering", v:948000, c:"#a78bfa"},
+ {name:"Security", v:712000, c:"#fbbf24"},
+ {name:"Data & ML", v:582750, c:"#f472b6"}
+ ];
+
+ // ---------- helpers ----------
+ function fmt(n){
+ n = Math.round(n);
+ return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g,",");
+ }
+ function easeOutExpo(t){ return t===1?1:1-Math.pow(2,-10*t); }
+
+ function countUp(el, target, dur, prefix, suffix){
+ var start=null, from=0;
+ function step(ts){
+ if(!start) start=ts;
+ var p=Math.min((ts-start)/dur,1);
+ var val=from+(target-from)*easeOutExpo(p);
+ el.textContent=(prefix||"")+fmt(val)+(suffix||"");
+ if(p<1) requestAnimationFrame(step);
+ else el.textContent=(prefix||"")+fmt(target)+(suffix||"");
+ }
+ requestAnimationFrame(step);
+ }
+
+ // ---------- odometers ----------
+ var moneyDigits = document.querySelector("#money .digits");
+ var hoursDigits = document.querySelector("#hours .digits");
+ countUp(moneyDigits, MONEY_TARGET, 2600, "", "");
+ countUp(hoursDigits, HOURS_TARGET, 2600, "", "");
+
+ document.getElementById("moneyRate").textContent = "+$"+fmt(MONEY_RATE)+"/hr";
+ document.getElementById("hoursRate").textContent = "+"+HOURS_RATE+"/hr";
+ document.getElementById("fte").textContent = (HOURS_TARGET/2000).toFixed(1);
+
+ // live ticking after the count-up settles
+ var mLive = MONEY_TARGET, hLive = HOURS_TARGET;
+ setTimeout(function(){
+ setInterval(function(){
+ mLive += MONEY_RATE/3600 * 1.2 + Math.random()*6;
+ hLive += HOURS_RATE/3600 * 1.2 + Math.random()*0.4;
+ moneyDigits.textContent = fmt(mLive);
+ hoursDigits.textContent = fmt(hLive);
+ },1200);
+ }, 2800);
+
+ // sparklines
+ function spark(id){
+ var host=document.getElementById(id), h="";
+ for(var i=0;i<16;i++){
+ var ht=8+Math.random()*36, d=(Math.random()*1.6).toFixed(2);
+ h+='<span style="height:'+ht+'px;animation-delay:'+d+'s"></span>';
+ }
+ host.innerHTML=h;
+ }
+ spark("sparkM"); spark("sparkH");
+
+ // ---------- wins feed (duplicated for seamless loop) ----------
+ var feed=document.getElementById("feed");
+ function winNode(w){
+ var el=document.createElement("div");
+ el.className="win";
+ var amt = w.unit==="$" ? "$"+fmt(w.v) : fmt(w.v)+"h";
+ var cls = w.unit==="$" ? "amt" : "amt hrs";
+ el.innerHTML =
+ '<div class="av">'+w.ic+'</div>'+
+ '<div class="body">'+
+ '<div class="ttl">'+w.t+'</div>'+
+ '<div class="meta"><span class="agent">'+w.a+'</span> · closed just now</div>'+
+ '</div>'+
+ '<div class="'+cls+'">'+amt+'</div>';
+ return el;
+ }
+ function buildFeed(){
+ feed.innerHTML="";
+ wins.concat(wins).forEach(function(w){ feed.appendChild(winNode(w)); });
+ }
+ buildFeed();
+
+ // occasionally surface a fresh win at the top
+ var freshTemplates=[
+ {a:"Nomad", ic:"🚀", t:"Autoscaled cluster, absorbed traffic spike", v:19800, unit:"$"},
+ {a:"Tally", ic:"🧮", t:"Closed the books 3 days early", v:52, unit:"h"},
+ {a:"Relay", ic:"📨", t:"Triaged 5k tickets, deflected 61%", v:14600, unit:"$"},
+ {a:"Prism", ic:"🔺", t:"A/B tuned checkout, lifted conversion", v:33400, unit:"$"}
+ ];
+ setInterval(function(){
+ var w=freshTemplates[Math.floor(Math.random()*freshTemplates.length)];
+ wins.unshift(w); if(wins.length>18) wins.pop();
+ buildFeed();
+ }, 7000);
+
+ // ---------- category chart ----------
+ var chart=document.getElementById("chart");
+ var max=Math.max.apply(null,categories.map(function(c){return c.v;}));
+ var total=categories.reduce(function(s,c){return s+c.v;},0);
+ categories.forEach(function(c,i){
+ var row=document.createElement("div");
+ row.className="row";
+ row.innerHTML=
+ '<div class="lbl">'+c.name+'</div>'+
+ '<div class="track"><div class="fill" style="background:linear-gradient(90deg,'+c.c+'88,'+c.c+')"></div></div>'+
+ '<div class="val" style="color:'+c.c+'">$0</div>';
+ chart.appendChild(row);
+ var fill=row.querySelector(".fill");
+ var valEl=row.querySelector(".val");
+ setTimeout(function(){ fill.style.width=(c.v/max*100)+"%"; }, 300+i*120);
+ countUp(valEl, c.v, 2200, "$", "");
+ });
+ document.getElementById("legTop").textContent=categories[0].name;
+ countUp(document.getElementById("legTotal"), total, 2400, "$", "");
+
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/f2e21f2299c9/claude-code.png b/data/artifacts/f2e21f2299c9/claude-code.png
new file mode 100644
index 0000000..d435c15
Binary files /dev/null and b/data/artifacts/f2e21f2299c9/claude-code.png differ
diff --git a/data/artifacts/f2e21f2299c9/gpt.html b/data/artifacts/f2e21f2299c9/gpt.html
new file mode 100644
index 0000000..e1ea387
--- /dev/null
+++ b/data/artifacts/f2e21f2299c9/gpt.html
@@ -0,0 +1,1478 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>AI Agent Fleet – Value Delivered</title>
+<style>
+ :root {
+ --bg: #050711;
+ --bg-alt: #090b1a;
+ --bg-elevated: #0f1224;
+ --accent: #4da3ff;
+ --accent-soft: rgba(77,163,255,0.35);
+ --accent-strong: #7cf0ff;
+ --accent-gold: #ffcf5a;
+ --accent-danger: #ff5a88;
+ --text-main: #f5f7ff;
+ --text-sub: #a3b1d9;
+ --border-subtle: rgba(255,255,255,0.06);
+ --glass: rgba(10,16,40,0.92);
+ }
+
+ * {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ }
+
+ html, body {
+ width: 100%;
+ height: 100%;
+ background: radial-gradient(circle at top, #171b42 0, #050711 40%, #020308 100%);
+ color: var(--text-main);
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "SF Pro Text",
+ "Segoe UI", sans-serif;
+ overflow: hidden;
+ }
+
+ body {
+ display: flex;
+ align-items: stretch;
+ justify-content: center;
+ }
+
+ .root {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ padding: 18px min(32px,4vw);
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+ z-index: 1;
+ }
+
+ /* Cinematic background flourishes */
+ .bg-orbit {
+ pointer-events: none;
+ position: fixed;
+ inset: 0;
+ overflow: hidden;
+ z-index: 0;
+ }
+
+ .bg-orbit::before,
+ .bg-orbit::after {
+ content: "";
+ position: absolute;
+ border-radius: 999px;
+ filter: blur(36px);
+ opacity: 0.18;
+ mix-blend-mode: screen;
+ }
+
+ .bg-orbit::before {
+ width: 580px;
+ height: 580px;
+ border: 1px solid rgba(124,240,255,0.7);
+ top: -260px;
+ left: -120px;
+ box-shadow:
+ 0 0 60px rgba(124,240,255,0.55),
+ 0 0 160px rgba(124,240,255,0.35);
+ }
+
+ .bg-orbit::after {
+ width: 640px;
+ height: 640px;
+ border: 1px solid rgba(255,207,90,0.5);
+ bottom: -320px;
+ right: -180px;
+ box-shadow:
+ 0 0 50px rgba(255,207,90,0.45),
+ 0 0 160px rgba(255,207,90,0.3);
+ }
+
+ .bg-stars {
+ pointer-events: none;
+ position: fixed;
+ inset: 0;
+ background-image:
+ radial-gradient(circle at 20% 20%, rgba(255,255,255,0.20) 0, transparent 40%),
+ radial-gradient(circle at 80% 70%, rgba(124,240,255,0.18) 0, transparent 45%);
+ opacity: 0.05;
+ mix-blend-mode: screen;
+ z-index: 0;
+ }
+
+ /* Header */
+ .header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 12px;
+ z-index: 2;
+ }
+
+ .brand {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ }
+
+ .brand-mark {
+ width: 26px;
+ height: 26px;
+ border-radius: 9px;
+ background: radial-gradient(circle at 20% 20%, #7cf0ff 0, #4da3ff 40%, #141a3d 80%);
+ box-shadow:
+ 0 0 18px rgba(124,240,255,0.8),
+ 0 0 40px rgba(77,163,255,0.9);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+ overflow: visible;
+ }
+
+ .brand-mark::after {
+ content: "";
+ position: absolute;
+ inset: 4px;
+ border-radius: 7px;
+ border: 1px solid rgba(5,7,17,0.9);
+ box-shadow: inset 0 0 10px rgba(0,0,0,0.8);
+ }
+
+ .brand-mark-core {
+ width: 9px;
+ height: 9px;
+ border-radius: 50%;
+ background: radial-gradient(circle, #ffffff 0, #ffe7a5 40%, #ffcf5a 100%);
+ box-shadow:
+ 0 0 10px rgba(255,255,255,0.9),
+ 0 0 22px rgba(255,207,90,0.9);
+ animation: corePulse 2.4s ease-in-out infinite;
+ position: relative;
+ z-index: 1;
+ }
+
+ @keyframes corePulse {
+ 0%, 100% { transform: scale(1); opacity: 0.9; }
+ 40% { transform: scale(1.18); opacity: 1; }
+ 70% { transform: scale(0.95); opacity: 0.75; }
+ }
+
+ .brand-title {
+ font-weight: 600;
+ letter-spacing: 0.06em;
+ text-transform: uppercase;
+ font-size: 11px;
+ color: var(--text-sub);
+ }
+
+ .brand-title span {
+ color: var(--accent-strong);
+ }
+
+ .header-right {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ font-size: 11px;
+ color: var(--text-sub);
+ }
+
+ .chip {
+ border-radius: 999px;
+ padding: 4px 10px;
+ border: 1px solid var(--border-subtle);
+ background: radial-gradient(circle at top left, rgba(124,240,255,0.14), transparent 60%),
+ rgba(6,10,30,0.9);
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ backdrop-filter: blur(10px);
+ }
+
+ .chip-dot {
+ width: 7px;
+ height: 7px;
+ border-radius: 999px;
+ background: radial-gradient(circle, #2bff88 0, #008f4a 70%);
+ box-shadow: 0 0 8px rgba(43,255,136,0.9);
+ }
+
+ .chip-label {
+ text-transform: uppercase;
+ font-size: 10px;
+ letter-spacing: 0.08em;
+ color: var(--text-sub);
+ }
+
+ .chip-value {
+ color: var(--accent-strong);
+ font-weight: 500;
+ }
+
+ /* Layout main */
+ .main {
+ flex: 1;
+ display: grid;
+ grid-template-columns: minmax(0, 1.45fr) minmax(0, 1.1fr);
+ grid-auto-rows: 1fr;
+ gap: 16px;
+ min-height: 0;
+ z-index: 2;
+ }
+
+ @media (max-width: 900px) {
+ body {
+ overflow: auto;
+ }
+ .root {
+ padding: 14px 14px 18px;
+ }
+ .main {
+ grid-template-columns: minmax(0, 1fr);
+ grid-auto-rows: auto;
+ overflow: visible;
+ }
+ }
+
+ /* Glass panel */
+ .panel {
+ border-radius: 20px;
+ background:
+ radial-gradient(circle at top left, rgba(124,240,255,0.12), transparent 55%),
+ radial-gradient(circle at bottom right, rgba(255,207,90,0.08), transparent 55%),
+ var(--glass);
+ border: 1px solid rgba(255,255,255,0.08);
+ box-shadow:
+ 0 18px 40px rgba(0,0,0,0.7),
+ 0 0 0 1px rgba(255,255,255,0.02);
+ padding: 18px 18px 16px;
+ position: relative;
+ overflow: hidden;
+ }
+
+ .panel::before {
+ content: "";
+ position: absolute;
+ inset: -1px;
+ border-radius: inherit;
+ border: 1px solid rgba(255,255,255,0.04);
+ pointer-events: none;
+ }
+
+ .panel-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 12px;
+ margin-bottom: 12px;
+ }
+
+ .panel-title {
+ text-transform: uppercase;
+ font-size: 11px;
+ letter-spacing: 0.12em;
+ color: var(--text-sub);
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ }
+
+ .panel-title-dot {
+ width: 5px;
+ height: 18px;
+ border-radius: 999px;
+ background: linear-gradient(to bottom, var(--accent-strong), transparent);
+ box-shadow: 0 0 14px rgba(124,240,255,0.9);
+ }
+
+ .panel-subtitle {
+ font-size: 11px;
+ color: var(--text-sub);
+ opacity: 0.85;
+ }
+
+ /* Odometer area */
+ .odometer-grid {
+ display: grid;
+ grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
+ gap: 16px;
+ align-items: stretch;
+ min-height: 0;
+ }
+
+ @media (max-width: 720px) {
+ .odometer-grid {
+ grid-template-columns: minmax(0, 1fr);
+ }
+ }
+
+ .odometer-card {
+ position: relative;
+ border-radius: 16px;
+ background: radial-gradient(circle at 20% 0, rgba(124,240,255,0.18), transparent 55%),
+ linear-gradient(135deg, rgba(11,16,46,0.98), rgba(6,8,22,0.98));
+ border: 1px solid rgba(124,240,255,0.25);
+ padding: 16px 16px 14px;
+ box-shadow:
+ 0 14px 40px rgba(0,0,0,0.9),
+ 0 0 0 1px rgba(10,200,255,0.18);
+ overflow: hidden;
+ }
+
+ .odometer-card::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ background:
+ radial-gradient(circle at 20% -20%, rgba(255,255,255,0.16) 0, transparent 45%),
+ radial-gradient(circle at 110% 110%, rgba(255,207,90,0.08) 0, transparent 45%);
+ mix-blend-mode: screen;
+ opacity: 0.5;
+ pointer-events: none;
+ }
+
+ .odometer-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 8px;
+ position: relative;
+ z-index: 1;
+ }
+
+ .odometer-label {
+ text-transform: uppercase;
+ font-size: 11px;
+ letter-spacing: 0.14em;
+ color: rgba(188,204,255,0.9);
+ }
+
+ .odometer-tagline {
+ font-size: 11px;
+ color: rgba(178,197,255,0.85);
+ }
+
+ .odometer-main-row {
+ position: relative;
+ z-index: 1;
+ margin-top: 6px;
+ display: flex;
+ align-items: flex-end;
+ gap: 10px;
+ }
+
+ .odometer-prefix {
+ font-size: 20px;
+ color: var(--accent-gold);
+ text-shadow: 0 0 12px rgba(255,229,160,0.9);
+ margin-bottom: 6px;
+ }
+
+ .odometer-number {
+ display: flex;
+ align-items: flex-end;
+ gap: 2px;
+ font-variant-numeric: tabular-nums;
+ }
+
+ .odometer-digit-group {
+ display: flex;
+ align-items: flex-end;
+ gap: 1px;
+ }
+
+ .odometer-digit {
+ position: relative;
+ width: 18px;
+ height: 32px;
+ border-radius: 6px;
+ background: radial-gradient(circle at 50% 10%, rgba(255,255,255,0.22), transparent 55%),
+ linear-gradient(to bottom, rgba(3,6,18,0.9), rgba(5,9,30,0.98));
+ overflow: hidden;
+ box-shadow:
+ 0 2px 8px rgba(0,0,0,0.85),
+ 0 0 0 1px rgba(255,255,255,0.06);
+ }
+
+ .odometer-digit::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ background: linear-gradient(to bottom,
+ rgba(124,240,255,0.1),
+ rgba(255,255,255,0.04),
+ rgba(0,0,0,0.2));
+ mix-blend-mode: screen;
+ opacity: 0.9;
+ pointer-events: none;
+ }
+
+ .odometer-digit-strip {
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 0;
+ transition: transform 0.7s cubic-bezier(0.17, 0.84, 0.44, 1.1);
+ }
+
+ .odometer-digit-num {
+ height: 32px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: #f9fbff;
+ font-weight: 600;
+ font-size: 19px;
+ text-shadow: 0 0 9px rgba(124,240,255,0.9);
+ }
+
+ .odometer-comma {
+ font-size: 24px;
+ opacity: 0.6;
+ margin: 0 2px 3px;
+ }
+
+ .odometer-decimal {
+ font-size: 22px;
+ opacity: 0.8;
+ margin: 0 1px 3px;
+ }
+
+ .odometer-suffix {
+ font-size: 13px;
+ text-transform: uppercase;
+ letter-spacing: 0.18em;
+ color: rgba(178,197,255,0.85);
+ margin-bottom: 4px;
+ }
+
+ .odometer-meta-row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-top: 8px;
+ position: relative;
+ z-index: 1;
+ font-size: 11px;
+ color: rgba(180,196,255,0.85);
+ }
+
+ .odometer-meta-row .delta {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+ padding: 3px 8px;
+ border-radius: 999px;
+ background: radial-gradient(circle at 0 0, rgba(43,255,136,0.18), transparent 60%),
+ rgba(10,21,28,0.95);
+ border: 1px solid rgba(40,215,128,0.45);
+ color: #e2ffe8;
+ }
+
+ .delta-arrow {
+ font-size: 10px;
+ }
+
+ .delta-label {
+ text-transform: uppercase;
+ letter-spacing: 0.09em;
+ }
+
+ .odometer-submeta {
+ opacity: 0.8;
+ }
+
+ .sparkline {
+ position: absolute;
+ right: -18px;
+ bottom: -40px;
+ width: 160px;
+ height: 160px;
+ border-radius: 50%;
+ background:
+ conic-gradient(from 200deg,
+ rgba(124,240,255,0.8) 0deg,
+ rgba(124,240,255,0.1) 110deg,
+ transparent 180deg,
+ transparent 360deg);
+ opacity: 0.35;
+ filter: blur(4px);
+ mix-blend-mode: screen;
+ z-index: 0;
+ }
+
+ .sparkline-ring {
+ position: absolute;
+ inset: 32px;
+ border-radius: 50%;
+ border: 1px dashed rgba(255,255,255,0.25);
+ opacity: 0.35;
+ }
+
+ .sparkline-glow {
+ position: absolute;
+ inset: 46px;
+ border-radius: 50%;
+ box-shadow: 0 0 26px rgba(124,240,255,1);
+ opacity: 0.26;
+ }
+
+ /* Secondary odometer */
+ .hours-card {
+ position: relative;
+ border-radius: 16px;
+ background:
+ radial-gradient(circle at 0 0, rgba(124,240,255,0.12), transparent 55%),
+ linear-gradient(135deg, rgba(11,15,40,0.96), rgba(5,7,19,0.98));
+ border: 1px solid rgba(103,177,255,0.3);
+ padding: 14px 14px 12px;
+ box-shadow:
+ 0 14px 34px rgba(0,0,0,0.9),
+ 0 0 0 1px rgba(64,155,255,0.18);
+ overflow: hidden;
+ }
+
+ .hours-label {
+ text-transform: uppercase;
+ font-size: 10px;
+ letter-spacing: 0.16em;
+ color: rgba(178,197,255,0.9);
+ }
+
+ .hours-number-row {
+ margin-top: 6px;
+ display: flex;
+ align-items: baseline;
+ gap: 6px;
+ }
+
+ .hours-main {
+ font-variant-numeric: tabular-nums;
+ font-size: 26px;
+ font-weight: 600;
+ letter-spacing: 0.02em;
+ color: #f7fbff;
+ text-shadow: 0 0 16px rgba(124,240,255,0.9);
+ }
+
+ .hours-main span {
+ opacity: 0.55;
+ }
+
+ .hours-unit {
+ font-size: 11px;
+ text-transform: uppercase;
+ letter-spacing: 0.16em;
+ color: rgba(178,197,255,0.9);
+ }
+
+ .hours-meter {
+ position: relative;
+ margin-top: 10px;
+ height: 6px;
+ border-radius: 999px;
+ background: radial-gradient(circle at 0 0, rgba(124,240,255,0.28), transparent 60%),
+ rgba(5,8,24,0.95);
+ overflow: hidden;
+ box-shadow: inset 0 0 6px rgba(0,0,0,0.9);
+ }
+
+ .hours-meter-fill {
+ position: absolute;
+ inset: 0;
+ width: 40%;
+ background: linear-gradient(90deg, #35ffb2, #7cf0ff, #ffcf5a);
+ box-shadow:
+ 0 0 14px rgba(124,240,255,0.9),
+ 0 0 30px rgba(53,255,178,0.9);
+ transform-origin: left center;
+ transform: scaleX(0.75);
+ transition: transform 1.6s cubic-bezier(0.17, 0.84, 0.44, 1.1);
+ }
+
+ .hours-meta-row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-top: 8px;
+ font-size: 11px;
+ color: rgba(178,197,255,0.9);
+ }
+
+ .hours-pill {
+ padding: 3px 7px;
+ border-radius: 999px;
+ background: rgba(10,20,35,0.95);
+ border: 1px solid rgba(75,132,255,0.6);
+ }
+
+ /* Right panel: feed + bar chart */
+ .side-panel {
+ display: grid;
+ grid-template-rows: minmax(0, 1.1fr) minmax(0, 0.95fr);
+ gap: 12px;
+ min-height: 0;
+ }
+
+ @media (max-width: 900px) {
+ .side-panel {
+ grid-template-rows: minmax(0, 260px) minmax(0, 220px);
+ }
+ }
+
+ /* Win feed */
+ .feed-list {
+ margin-top: 6px;
+ position: relative;
+ border-radius: 12px;
+ background: radial-gradient(circle at top, rgba(124,240,255,0.12), transparent 55%),
+ linear-gradient(135deg, rgba(7,10,30,0.96), rgba(4,6,18,0.98));
+ border: 1px solid rgba(106,152,255,0.35);
+ padding: 6px 0 4px;
+ overflow: hidden;
+ min-height: 0;
+ }
+
+ .feed-fade-top,
+ .feed-fade-bot {
+ position: absolute;
+ left: 0;
+ right: 0;
+ height: 20px;
+ pointer-events: none;
+ z-index: 2;
+ }
+
+ .feed-fade-top {
+ top: 0;
+ background: linear-gradient(to bottom,
+ rgba(6,9,26,1), rgba(6,9,26,0));
+ }
+
+ .feed-fade-bot {
+ bottom: 0;
+ background: linear-gradient(to top,
+ rgba(6,9,26,1), rgba(6,9,26,0));
+ }
+
+ .feed-scroll {
+ max-height: 100%;
+ overflow: hidden;
+ position: relative;
+ }
+
+ .feed-items {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+ padding: 2px 3px 10px;
+ animation: feedScroll 22s linear infinite;
+ }
+
+ .feed-item {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 6px;
+ padding: 7px 9px;
+ border-radius: 9px;
+ background:
+ radial-gradient(circle at 0 0, rgba(124,240,255,0.16), transparent 60%),
+ rgba(9,13,36,0.96);
+ border: 1px solid rgba(73,120,255,0.25);
+ box-shadow: 0 10px 20px rgba(0,0,0,0.75);
+ }
+
+ .feed-item:nth-child(2n) {
+ background:
+ radial-gradient(circle at 100% 0, rgba(255,207,90,0.12), transparent 55%),
+ rgba(7,10,28,0.98);
+ border-color: rgba(255,207,90,0.22);
+ }
+
+ .feed-main {
+ display: flex;
+ align-items: center;
+ gap: 7px;
+ min-width: 0;
+ }
+
+ .feed-dot {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background: radial-gradient(circle, #7cf0ff 0, #4da3ff 60%, #181e4f 100%);
+ box-shadow: 0 0 8px rgba(124,240,255,0.9);
+ }
+
+ .feed-text {
+ min-width: 0;
+ }
+
+ .feed-title {
+ font-size: 11px;
+ font-weight: 500;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ color: #f7f9ff;
+ }
+
+ .feed-sub {
+ margin-top: 1px;
+ font-size: 10px;
+ color: var(--text-sub);
+ }
+
+ .feed-amount {
+ font-size: 11px;
+ font-variant-numeric: tabular-nums;
+ white-space: nowrap;
+ color: var(--accent-gold);
+ text-shadow: 0 0 8px rgba(255,207,90,0.9);
+ }
+
+ .feed-amount span {
+ color: #96ffd1;
+ }
+
+ @keyframes feedScroll {
+ 0% { transform: translateY(0); }
+ 100% { transform: translateY(-50%); }
+ }
+
+ /* Duplicate list for seamless scroll */
+ .feed-items-inner {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+ }
+
+ /* Bar chart */
+ .chart {
+ position: relative;
+ border-radius: 14px;
+ background:
+ radial-gradient(circle at 20% 0, rgba(124,240,255,0.18), transparent 55%),
+ linear-gradient(135deg, rgba(7,9,28,0.98), rgba(3,4,14,0.99));
+ border: 1px solid rgba(104,149,255,0.4);
+ padding: 12px 12px 10px;
+ box-shadow:
+ 0 14px 30px rgba(0,0,0,0.9),
+ 0 0 0 1px rgba(124,240,255,0.14);
+ overflow: hidden;
+ }
+
+ .chart-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 8px;
+ font-size: 11px;
+ color: var(--text-sub);
+ margin-bottom: 6px;
+ }
+
+ .chart-tag {
+ padding: 2px 7px;
+ border-radius: 999px;
+ background: rgba(13,21,49,0.96);
+ border: 1px solid rgba(99,147,255,0.7);
+ font-size: 10px;
+ text-transform: uppercase;
+ letter-spacing: 0.12em;
+ }
+
+ .chart-body {
+ position: relative;
+ margin-top: 4px;
+ height: 100%;
+ min-height: 140px;
+ display: flex;
+ flex-direction: column;
+ }
+
+ .chart-grid {
+ position: absolute;
+ inset: 4px 4px 20px 4px;
+ pointer-events: none;
+ }
+
+ .chart-grid-line {
+ position: absolute;
+ left: 0;
+ right: 0;
+ height: 1px;
+ background: linear-gradient(90deg,
+ rgba(255,255,255,0.06),
+ rgba(255,255,255,0.1),
+ rgba(255,255,255,0.06));
+ }
+
+ .chart-grid-line:nth-child(1) { top: 0; }
+ .chart-grid-line:nth-child(2) { top: 33%; }
+ .chart-grid-line:nth-child(3) { top: 66%; }
+
+ .chart-grid-line:nth-child(4) {
+ bottom: 0;
+ opacity: 0.9;
+ background: linear-gradient(90deg,
+ rgba(255,255,255,0.3),
+ rgba(124,240,255,0.6),
+ rgba(255,255,255,0.3));
+ }
+
+ .chart-bars {
+ position: relative;
+ display: flex;
+ align-items: flex-end;
+ justify-content: space-between;
+ gap: 9px;
+ flex: 1;
+ padding: 8px 3px 16px 3px;
+ }
+
+ .chart-bar {
+ flex: 1;
+ min-width: 0;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 5px;
+ }
+
+ .chart-bar-outer {
+ position: relative;
+ width: 100%;
+ border-radius: 999px;
+ background: linear-gradient(180deg, rgba(10,13,35,0.5), rgba(2,3,9,0.95));
+ box-shadow:
+ inset 0 0 6px rgba(0,0,0,0.9),
+ 0 0 0 1px rgba(255,255,255,0.03);
+ overflow: hidden;
+ }
+
+ .chart-bar-inner {
+ position: relative;
+ width: 100%;
+ border-radius: inherit;
+ background: linear-gradient(180deg, #7cf0ff, #4da3ff);
+ box-shadow:
+ 0 0 12px rgba(124,240,255,0.9),
+ 0 0 26px rgba(77,163,255,0.9);
+ transform-origin: bottom center;
+ transform: scaleY(0);
+ transition: transform 1.4s cubic-bezier(0.17, 0.84, 0.44, 1.08);
+ }
+
+ .chart-bar-inner[data-color="green"] {
+ background: linear-gradient(180deg, #5dffbb, #00b686);
+ box-shadow:
+ 0 0 12px rgba(93,255,187,1),
+ 0 0 26px rgba(0,182,134,1);
+ }
+
+ .chart-bar-inner[data-color="gold"] {
+ background: linear-gradient(180deg, #ffef8a, #ffcf5a);
+ box-shadow:
+ 0 0 12px rgba(255,239,138,1),
+ 0 0 26px rgba(255,207,90,1);
+ }
+
+ .chart-bar-inner[data-color="pink"] {
+ background: linear-gradient(180deg, #ff9dce, #ff5a88);
+ box-shadow:
+ 0 0 12px rgba(255,157,206,1),
+ 0 0 26px rgba(255,90,136,1);
+ }
+
+ .chart-bar-label {
+ font-size: 10px;
+ text-align: center;
+ text-transform: uppercase;
+ letter-spacing: 0.12em;
+ color: var(--text-sub);
+ }
+
+ .chart-bar-value {
+ font-size: 10px;
+ color: #f9fbff;
+ font-variant-numeric: tabular-nums;
+ }
+
+ .chart-footer {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ font-size: 10px;
+ color: var(--text-sub);
+ padding-top: 3px;
+ border-top: 1px solid rgba(255,255,255,0.05);
+ margin-top: auto;
+ }
+
+ .chart-foot-metric {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ }
+
+ .chart-foot-dot {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background: conic-gradient(
+ from 180deg,
+ #7cf0ff, #4da3ff, #ffcf5a, #ff5a88, #7cf0ff
+ );
+ box-shadow: 0 0 12px rgba(124,240,255,1);
+ }
+
+ /* Timeline / bottom meta */
+ .bottom-row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 10px;
+ padding: 0 2px 2px;
+ z-index: 2;
+ font-size: 10px;
+ color: var(--text-sub);
+ }
+
+ .bottom-left {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ }
+
+ .timeline {
+ position: relative;
+ display: flex;
+ align-items: center;
+ gap: 2px;
+ }
+
+ .timeline-line {
+ width: 110px;
+ height: 2px;
+ border-radius: 999px;
+ background: linear-gradient(90deg,
+ rgba(255,255,255,0.2),
+ rgba(124,240,255,0.9),
+ rgba(255,207,90,0.7),
+ rgba(255,255,255,0.2));
+ position: relative;
+ overflow: hidden;
+ }
+
+ .timeline-pulse {
+ position: absolute;
+ inset: 0;
+ background: linear-gradient(90deg,
+ transparent,
+ rgba(255,255,255,0.8),
+ transparent);
+ transform: translateX(-100%);
+ animation: timelineSweep 3s linear infinite;
+ }
+
+ @keyframes timelineSweep {
+ 0% { transform: translateX(-100%); }
+ 60%,100% { transform: translateX(100%); }
+ }
+
+ .bottom-right {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ }
+
+ .bottom-metric {
+ padding: 3px 8px;
+ border-radius: 999px;
+ border: 1px solid var(--border-subtle);
+ background: rgba(8,10,28,0.95);
+ }
+
+ .bottom-metric span {
+ color: var(--accent-strong);
+ }
+
+ /* Entry animation */
+ .fade-in-up {
+ opacity: 0;
+ transform: translateY(6px);
+ animation: fadeInUp 0.7s ease-out forwards;
+ }
+
+ .fade-in-up.delay-1 { animation-delay: 0.08s; }
+ .fade-in-up.delay-2 { animation-delay: 0.16s; }
+ .fade-in-up.delay-3 { animation-delay: 0.25s; }
+
+ @keyframes fadeInUp {
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ }
+</style>
+</head>
+<body>
+<div class="bg-orbit"></div>
+<div class="bg-stars"></div>
+
+<div class="root">
+ <header class="header fade-in-up">
+ <div class="brand">
+ <div class="brand-mark">
+ <div class="brand-mark-core"></div>
+ </div>
+ <div class="brand-title">
+ Agent Fleet <span>Value Stream</span>
+ </div>
+ </div>
+ <div class="header-right">
+ <div class="chip">
+ <div class="chip-dot"></div>
+ <div class="chip-label">Agents Live</div>
+ <div class="chip-value" id="agent-count">128</div>
+ </div>
+ <div class="chip">
+ <div class="chip-label">Window</div>
+ <div class="chip-value">Last 90 days</div>
+ </div>
+ </div>
+ </header>
+
+ <main class="main">
+ <!-- Left: odometers -->
+ <section class="panel fade-in-up delay-1">
+ <div class="panel-header">
+ <div class="panel-title">
+ <div class="panel-title-dot"></div>
+ Value Delivered – Real Time
+ </div>
+ <div class="panel-subtitle">
+ Aggregated impact across the autonomous agent fleet.
+ </div>
+ </div>
+
+ <div class="odometer-grid">
+ <div class="odometer-card">
+ <div class="odometer-header">
+ <div>
+ <div class="odometer-label">Total Value Generated</div>
+ <div class="odometer-tagline">Cumulative cost savings from automated execution.</div>
+ </div>
+ </div>
+ <div class="odometer-main-row">
+ <div class="odometer-prefix">$</div>
+ <div class="odometer-number" id="cash-odometer">
+ <!-- JS will inject digits -->
+ </div>
+ <div class="odometer-suffix">Savings</div>
+ </div>
+ <div class="odometer-meta-row">
+ <div class="delta">
+ <span class="delta-arrow">▲</span>
+ <span class="delta-label">+24.6% vs. last week</span>
+ </div>
+ <div class="odometer-submeta">
+ Streaming from 47 production workloads
+ </div>
+ </div>
+
+ <div class="sparkline">
+ <div class="sparkline-ring"></div>
+ <div class="sparkline-glow"></div>
+ </div>
+ </div>
+
+ <div class="hours-card">
+ <div class="hours-label">Human Hours Unlocked</div>
+ <div class="hours-number-row">
+ <div class="hours-main" id="hours-counter">
+ 0<span>h</span>
+ </div>
+ <div class="hours-unit">Engineering Hours</div>
+ </div>
+ <div class="hours-meter">
+ <div class="hours-meter-fill" id="hours-meter-fill"></div>
+ </div>
+ <div class="hours-meta-row">
+ <div class="hours-pill">
+ 71% of savings from fully autonomous runs
+ </div>
+ <div>Baseline: blended fully-loaded eng cost</div>
+ </div>
+ </div>
+ </div>
+ </section>
+
+ <!-- Right: feed + chart -->
+ <section class="panel fade-in-up delay-2">
+ <div class="side-panel">
+ <!-- Win feed -->
+ <div>
+ <div class="panel-header">
+ <div class="panel-title">
+ <div class="panel-title-dot"></div>
+ Latest Wins
+ </div>
+ <div class="panel-subtitle">
+ Streaming, ordered by realized impact.
+ </div>
+ </div>
+ <div class="feed-list">
+ <div class="feed-fade-top"></div>
+ <div class="feed-fade-bot"></div>
+ <div class="feed-scroll">
+ <div class="feed-items" id="feed-items">
+ <div class="feed-items-inner" id="feed-template">
+ <div class="feed-item">
+ <div class="feed-main">
+ <div class="feed-dot"></div>
+ <div class="feed-text">
+ <div class="feed-title">Agent Orion: Auto‑triaged 1.2k support tickets</div>
+ <div class="feed-sub">Eliminated L1 queue for an entire shift.</div>
+ </div>
+ </div>
+ <div class="feed-amount">
+ +$184,300
+ </div>
+ </div>
+
+ <div class="feed-item">
+ <div class="feed-main">
+ <div class="feed-dot"></div>
+ <div class="feed-text">
+ <div class="feed-title">Agent Nova: CI failure auto‑remediation</div>
+ <div class="feed-sub">Reduced mean time to green by 63%.</div>
+ </div>
+ </div>
+ <div class="feed-amount">
+ +$96,800
+ </div>
+ </div>
+
+ <div class="feed-item">
+ <div class="feed-main">
+ <div class="feed-dot"></div>
+ <div class="feed-text">
+ <div class="feed-title">Agent Atlas: infra right‑sizing sweep</div>
+ <div class="feed-sub">Decommissioned idle fleets across 3 regions.</div>
+ </div>
+ </div>
+ <div class="feed-amount">
+ +$312,450
+ </div>
+ </div>
+
+ <div class="feed-item">
+ <div class="feed-main">
+ <div class="feed-dot"></div>
+ <div class="feed-text">
+ <div class="feed-title">Agent Echo: incident runbook automation</div>
+ <div class="feed-sub">Remediated 84% of P2 alerts without human touch.</div>
+ </div>
+ </div>
+ <div class="feed-amount">
+ +$138,900
+ </div>
+ </div>
+
+ <div class="feed-item">
+ <div class="feed-main">
+ <div class="feed-dot"></div>
+ <div class="feed-text">
+ <div class="feed-title">Agent Helios: build cache optimization</div>
+ <div class="feed-sub">Cut average build times from 14m to 6m.</div>
+ </div>
+ </div>
+ <div class="feed-amount">
+ +$72,640
+ </div>
+ </div>
+
+ <div class="feed-item">
+ <div class="feed-main">
+ <div class="feed-dot"></div>
+ <div class="feed-text">
+ <div class="feed-title">Agent Vega: contract anomaly sweeps</div>
+ <div class="feed-sub">Flagged under‑billed usage in 3 major accounts.</div>
+ </div>
+ </div>
+ <div class="feed-amount">
+ +$221,100
+ </div>
+ </div>
+
+ <div class="feed-item">
+ <div class="feed-main">
+ <div class="feed-dot"></div>
+ <div class="feed-text">
+ <div class="feed-title">Agent Lyra: knowledge base auto‑curation</div>
+ <div class="feed-sub">Boosted self‑serve deflection by 18 pts.</div>
+ </div>
+ </div>
+ <div class="feed-amount">
+ +$64,250
+ </div>
+ </div>
+
+ <div class="feed-item">
+ <div class="feed-main">
+ <div class="feed-dot"></div>
+ <div class="feed-text">
+ <div class="feed-title">Agent Titan: nightly data pipeline repairs</div>
+ <div class="feed-sub">Removed on‑call rotations for ETL failures.</div>
+ </div>
+ </div>
+ <div class="feed-amount">
+ +$147,320
+ </div>
+ </div>
+
+ <div class="feed-item">
+ <div class="feed-main">
+ <div class="feed-dot"></div>
+ <div class="feed-text">
+ <div class="feed-title">Agent Quasar: churn‑risk retention offers</div>
+ <div class="feed-sub">Protected $9.3M in ARR in Q2 cohort.</div>
+ </div>
+ </div>
+ <div class="feed-amount">
+ +$408,600
+ </div>
+ </div>
+
+ <div class="feed-item">
+ <div class="feed-main">
+ <div class="feed-dot"></div>
+ <div class="feed-text">
+ <div class="feed-title">Agent Halo: sandbox environment cleanup</div>
+ <div class="feed-sub">Expired 3,800 stale environments in 48h.</div>
+ </div>
+ </div>
+ <div class="feed-amount">
+ +$55,910
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <!-- Bar chart -->
+ <div>
+ <div class="panel-header">
+ <div class="panel-title">
+ <div class="panel-title-dot"></div>
+ Savings by Category
+ </div>
+ <div class="panel-subtitle">
+ Cumulative realized value, USD.
+ </div>
+ </div>
+
+ <div class="chart">
+ <div class="chart-header">
+ <div class="chart-tag">Distribution</div>
+ <div>Normalized for the selected time window.</div>
+ </div>
+ <div class="chart-body">
+ <div class="chart-grid">
+ <div class="chart-grid-line"></div>
+ <div class="chart-grid-line"></div>
+ <div class="chart-grid-line"></div>
+ <div class="chart-grid-line"></div>
+ </div>
+
+ <div class="chart-bars">
+ <div class="chart-bar">
+ <div class="chart-bar-outer">
+ <div class="chart-bar-inner" data-h="0.96" data-color="green"></div>
+ </div>
+ <div class="chart-bar-value">$4.8M</div>
+ <div class="chart-bar-label">Infra</div>
+ </div>
+ <div class="chart-bar">
+ <div class="chart-bar-outer">
+ <div class="chart-bar-inner" data-h="0.83" data-color="gold"></div>
+ </div>
+ <div class="chart-bar-value">$3.9M</div>
+ <div class="chart-bar-label">Ops & SRE</div>
+ </div>
+ <div class="chart-bar">
+ <div class="chart-bar-outer">
+ <div class="chart-bar-inner" data-h="0.72" data-color="pink"></div>
+ </div>
+ <div class="chart-bar-value">$3.2M</div>
+ <div class="chart-bar-label">Support</div>
+ </div>
+ <div class="chart-bar">
+ <div class="chart-bar-outer">
+ <div class="chart-bar-inner" data-h="0.64" data-color="green"></div>
+ </div>
+ <div class="chart-bar-value">$2.8M</div>
+ <div class="chart-bar-label">RevOps</div>
+ </div>
+ <div class="chart-bar">
+ <div class="chart-bar-outer">
+ <div class="chart-bar-inner" data-h="0.51" data-color="gold"></div>
+ </div>
+ <div class="chart-bar-value">$2.1M</div>
+ <div class="chart-bar-label">Security</div>
+ </div>
+ </div>
+
+ <div class="chart-footer">
+ <div class="chart-foot-metric">
+ <div class="chart-foot-dot"></div>
+ <span>Blended payback period: < 5 weeks</span>
+ </div>
+ <div>Real‑time stream from production telemetry.</div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ </div>
+ </section>
+ </main>
+
+ <footer class="bottom-row fade-in-up delay-3">
+ <div class="bottom-left">
+ <div class="timeline">
+ <div class="timeline-line">
+ <div class="timeline-pulse"></div>
+ </div>
+ </div>
+ <div>Now streaming: fleet‑wide agent impact in production.</div>
+ </div>
+ <div class="bottom-right">
+ <div class="bottom-metric">Current run‑rate: <span>$38.6M / yr</span></div>
+ <div class="bottom-metric">Avg. task TTL: <span>19s</span></div>
+ </div>
+ </footer>
+</div>
+
+<script>
+(function() {
+ // ---------- ODOMETER ----------
+ const targetCash = 12843032; // dollars
+ const cashOdometerEl = document.getElementById('cash-odometer');
+
+ function buildOdometerDigits(value) {
+ cashOdometerEl.innerHTML = '';
+ const formatted = value.toLocaleString('en-US', {maximumFractionDigits: 0});
+ for (let ch of formatted) {
+ if (ch === ',') {
+ const comma = document.createElement('div');
+ comma.className = 'odometer-comma';
+ comma.textContent = ',';
+ cashOdometerEl.appendChild(comma);
+ continue;
+ }
+ const digit = document.createElement('div');
+ digit.className = 'odometer-digit';
+ const strip = document.createElement('div');
+ strip.className = 'odometer-digit-strip';
+ for (let i = 0; i <= 9; i++) {
+ const n = document.createElement('div');
+ n.className = 'odometer-digit-num';
+ n.textContent = i;
+ strip.appendChild(n);
+ }
+ digit.appendChild(strip);
+ cashOdometerEl.appendChild(digit);
+ }
+ }
+
+ buildOdometerDigits(targetCash);
+
+ function animateOdometer(value, duration) {
+ const digits = Array.from(
+ cashOdometerEl.querySelectorAll('.odometer-digit .odometer-digit-strip')
+ );
+ const chars = value.toLocaleString('en-US', {maximumFractionDigits: 0});
+ const numericChars = chars.replace(/,/g, '');
+ const delayBase = 80;
+
+ digits.forEach((strip, index) => {
+ const ch = numericChars[index] || '0';
+ const digit = parseInt(ch, 10);
+ const offset = digit * 32; // 32px per cell
+ const extraSpins = 3 + Math.floor(Math.random() * 2); // 3-4 full spins
+ const total = offset + 32 * 10 * extraSpins;
+ const delay = index * delayBase;
+ strip.style.transition = `transform ${duration}ms cubic-bezier(0.17, 0.84, 0.44, 1.1) ${delay}ms`;
+ strip.style.transform = `translateY(-${total}px)`;
+ });
+ }
+
+ // ---------- HOURS COUNTER ----------
+ const hoursTarget = 342_810;
+ const hoursCounterEl = document.getElementById('hours-counter');
+ const hoursMeterFill = document.getElementById('hours-meter-fill');
+
+ function formatHours(h) {
+ if (h < 1000) return `${Math.round(h).toLocaleString()}<span>h</span>`;
+ const k = h / 1000;
+ if (k < 10) return `${k.toFixed(1)}k<span>h</span>`;
+ return `${Math.round(k).toLocaleString()}k<span>h</span>`;
+ }
+
+ function animateHours(duration) {
+ const start = performance.now();
+ function step(now) {
+ const t = Math.min(1, (now - start) / duration);
+ const eased = 1 - Math.pow(1 - t, 3);
+ const val = hoursTarget * eased;
+ hoursCounterEl.innerHTML = formatHours(val);
+ hoursMeterFill.style.transform = `scaleX(${0.35 + eased * 0.55})`;
+ if (t < 1) requestAnimationFrame(step);
+ }
+ requestAnimationFrame(step);
+ }
+
+ // ---------- BAR CHART ----------
+ function animateBars() {
+ const bars = document.querySelectorAll('.chart-bar-inner');
+ bars.forEach((bar, i) => {
+ const h = parseFloat(bar.getAttribute('data-h') || '0.5');
+ const delay = 200 + i * 90;
+ bar.style.transitionDelay = `${delay}ms`;
+ bar.style.transform = `scaleY(${h})`;
+ });
+ }
+
+ // ---------- FEED SCROLL DUPLICATION ----------
+ (function setupFeedLoop() {
+ const template = document.getElementById('feed-template');
+ const items = template.cloneNode(true);
+ const container = document.getElementById('feed-items');
+ container.appendChild(items);
+ })();
+
+ // ---------- INIT ----------
+ window.addEventListener('load', function() {
+ // Slight delay for cinematic stagger.
+ setTimeout(function() {
+ animateOdometer(targetCash, 1800);
+ animateHours(1800);
+ animateBars();
+ }, 220);
+ });
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/f2e21f2299c9/gpt.png b/data/artifacts/f2e21f2299c9/gpt.png
new file mode 100644
index 0000000..8f22ef5
Binary files /dev/null and b/data/artifacts/f2e21f2299c9/gpt.png differ
diff --git a/data/artifacts/f2e21f2299c9/grok.html b/data/artifacts/f2e21f2299c9/grok.html
new file mode 100644
index 0000000..471ba3f
--- /dev/null
+++ b/data/artifacts/f2e21f2299c9/grok.html
@@ -0,0 +1,623 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Value Delivered — AI Agent Fleet</title>
+<style>
+ :root {
+ --bg: #07090f;
+ --bg2: #0c1019;
+ --panel: #111722;
+ --panel-border: rgba(255,255,255,0.06);
+ --gold: #f0c14b;
+ --gold-dim: #b8922e;
+ --cyan: #3de0c8;
+ --cyan-dim: #1a8f7f;
+ --violet: #8b7cf6;
+ --text: #e8ecf4;
+ --muted: #7a8499;
+ --win: #2dd4a8;
+ --bar-glow: rgba(61,224,200,0.35);
+ }
+ * { box-sizing: border-box; margin: 0; padding: 0; }
+ html, body {
+ height: 100%;
+ background: var(--bg);
+ color: var(--text);
+ font-family: "Segoe UI", system-ui, -apple-system, sans-serif;
+ overflow: hidden;
+ }
+ body {
+ display: flex;
+ flex-direction: column;
+ min-height: 100vh;
+ background:
+ radial-gradient(ellipse 80% 50% at 50% -20%, rgba(61,224,200,0.08), transparent),
+ radial-gradient(ellipse 60% 40% at 100% 100%, rgba(139,124,246,0.06), transparent),
+ var(--bg);
+ }
+ .grain {
+ pointer-events: none;
+ position: fixed;
+ inset: 0;
+ opacity: 0.035;
+ z-index: 100;
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
+ }
+ header {
+ padding: 1.25rem 2rem 0.75rem;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ border-bottom: 1px solid var(--panel-border);
+ background: linear-gradient(180deg, rgba(17,23,34,0.9), transparent);
+ }
+ .brand {
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+ }
+ .brand-mark {
+ width: 36px;
+ height: 36px;
+ border-radius: 10px;
+ background: linear-gradient(135deg, var(--cyan), var(--violet));
+ display: grid;
+ place-items: center;
+ box-shadow: 0 0 24px rgba(61,224,200,0.35);
+ font-weight: 700;
+ font-size: 14px;
+ letter-spacing: -0.5px;
+ }
+ .brand h1 {
+ font-size: 0.95rem;
+ font-weight: 600;
+ letter-spacing: 0.04em;
+ text-transform: uppercase;
+ color: var(--text);
+ }
+ .brand span {
+ display: block;
+ font-size: 0.7rem;
+ color: var(--muted);
+ font-weight: 400;
+ letter-spacing: 0.12em;
+ margin-top: 2px;
+ }
+ .live {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ font-size: 0.7rem;
+ letter-spacing: 0.14em;
+ text-transform: uppercase;
+ color: var(--win);
+ font-weight: 600;
+ }
+ .live-dot {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background: var(--win);
+ box-shadow: 0 0 10px var(--win);
+ animation: pulse 1.6s ease-in-out infinite;
+ }
+ @keyframes pulse {
+ 0%, 100% { opacity: 1; transform: scale(1); }
+ 50% { opacity: 0.45; transform: scale(0.85); }
+ }
+ main {
+ flex: 1;
+ display: grid;
+ grid-template-rows: auto 1fr;
+ gap: 1.25rem;
+ padding: 1.25rem 2rem 1.5rem;
+ min-height: 0;
+ }
+ .hero {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 1.25rem;
+ }
+ .odometer-card {
+ position: relative;
+ background: linear-gradient(165deg, rgba(20,28,42,0.95), rgba(12,16,25,0.98));
+ border: 1px solid var(--panel-border);
+ border-radius: 16px;
+ padding: 1.5rem 1.75rem 1.35rem;
+ overflow: hidden;
+ }
+ .odometer-card::before {
+ content: "";
+ position: absolute;
+ top: 0; left: 0; right: 0;
+ height: 1px;
+ background: linear-gradient(90deg, transparent, rgba(61,224,200,0.45), transparent);
+ }
+ .odometer-card.gold::before {
+ background: linear-gradient(90deg, transparent, rgba(240,193,75,0.5), transparent);
+ }
+ .odometer-card .label {
+ font-size: 0.68rem;
+ letter-spacing: 0.18em;
+ text-transform: uppercase;
+ color: var(--muted);
+ margin-bottom: 0.85rem;
+ font-weight: 600;
+ }
+ .odometer {
+ display: flex;
+ align-items: baseline;
+ gap: 0.15rem;
+ font-variant-numeric: tabular-nums;
+ font-feature-settings: "tnum";
+ }
+ .odo-prefix, .odo-suffix {
+ font-size: 1.75rem;
+ font-weight: 300;
+ color: var(--muted);
+ align-self: flex-start;
+ margin-top: 0.35rem;
+ }
+ .odo-card.gold .odo-prefix { color: var(--gold-dim); }
+ .digits {
+ display: flex;
+ gap: 3px;
+ }
+ .digit-slot {
+ position: relative;
+ width: 1.15em;
+ height: 1.35em;
+ overflow: hidden;
+ background: linear-gradient(180deg, #0a0e16, #151c2a);
+ border-radius: 6px;
+ border: 1px solid rgba(255,255,255,0.05);
+ box-shadow: inset 0 2px 8px rgba(0,0,0,0.45);
+ font-size: 2.75rem;
+ font-weight: 600;
+ line-height: 1.35em;
+ text-align: center;
+ }
+ .odometer-card.gold .digit-slot {
+ color: var(--gold);
+ text-shadow: 0 0 28px rgba(240,193,75,0.35);
+ }
+ .odometer-card.cyan .digit-slot {
+ color: var(--cyan);
+ text-shadow: 0 0 28px rgba(61,224,200,0.35);
+ }
+ .digit-strip {
+ display: flex;
+ flex-direction: column;
+ transition: transform 1.4s cubic-bezier(0.16, 1, 0.3, 1);
+ }
+ .digit-strip span {
+ display: block;
+ height: 1.35em;
+ line-height: 1.35em;
+ }
+ .comma-slot {
+ font-size: 2.4rem;
+ font-weight: 500;
+ color: var(--muted);
+ align-self: flex-end;
+ padding-bottom: 0.15em;
+ width: 0.4em;
+ }
+ .sub {
+ margin-top: 0.85rem;
+ font-size: 0.78rem;
+ color: var(--muted);
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ }
+ .sub .delta {
+ color: var(--win);
+ font-weight: 600;
+ }
+ .lower {
+ display: grid;
+ grid-template-columns: 1.1fr 1fr;
+ gap: 1.25rem;
+ min-height: 0;
+ }
+ .panel {
+ background: linear-gradient(165deg, rgba(17,23,34,0.9), rgba(10,14,22,0.95));
+ border: 1px solid var(--panel-border);
+ border-radius: 16px;
+ display: flex;
+ flex-direction: column;
+ min-height: 0;
+ overflow: hidden;
+ }
+ .panel-head {
+ padding: 1rem 1.25rem 0.75rem;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ border-bottom: 1px solid var(--panel-border);
+ }
+ .panel-head h2 {
+ font-size: 0.72rem;
+ letter-spacing: 0.16em;
+ text-transform: uppercase;
+ color: var(--muted);
+ font-weight: 600;
+ }
+ .panel-head .badge {
+ font-size: 0.65rem;
+ padding: 0.2rem 0.55rem;
+ border-radius: 999px;
+ background: rgba(61,224,200,0.1);
+ color: var(--cyan);
+ border: 1px solid rgba(61,224,200,0.2);
+ letter-spacing: 0.06em;
+ }
+ .feed-wrap {
+ flex: 1;
+ overflow: hidden;
+ position: relative;
+ mask-image: linear-gradient(180deg, transparent, #000 8%, #000 88%, transparent);
+ }
+ .feed {
+ display: flex;
+ flex-direction: column;
+ gap: 0;
+ animation: scrollFeed 48s linear infinite;
+ padding: 0.5rem 0;
+ }
+ .feed:hover { animation-play-state: paused; }
+ @keyframes scrollFeed {
+ 0% { transform: translateY(0); }
+ 100% { transform: translateY(-50%); }
+ }
+ .win {
+ display: grid;
+ grid-template-columns: 1fr auto;
+ gap: 0.75rem;
+ align-items: center;
+ padding: 0.85rem 1.25rem;
+ border-bottom: 1px solid rgba(255,255,255,0.03);
+ transition: background 0.2s;
+ }
+ .win:hover { background: rgba(255,255,255,0.02); }
+ .win-title {
+ font-size: 0.88rem;
+ font-weight: 500;
+ color: var(--text);
+ line-height: 1.35;
+ }
+ .win-meta {
+ font-size: 0.68rem;
+ color: var(--muted);
+ margin-top: 0.25rem;
+ letter-spacing: 0.04em;
+ }
+ .win-impact {
+ font-variant-numeric: tabular-nums;
+ font-weight: 600;
+ font-size: 0.9rem;
+ color: var(--gold);
+ white-space: nowrap;
+ text-align: right;
+ }
+ .win-impact small {
+ display: block;
+ font-size: 0.62rem;
+ color: var(--muted);
+ font-weight: 500;
+ margin-top: 2px;
+ }
+ .chart-body {
+ flex: 1;
+ padding: 1.25rem 1.5rem 1.5rem;
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-end;
+ gap: 0.65rem;
+ min-height: 0;
+ }
+ .bar-row {
+ display: grid;
+ grid-template-columns: 110px 1fr 72px;
+ align-items: center;
+ gap: 0.75rem;
+ }
+ .bar-label {
+ font-size: 0.72rem;
+ color: var(--muted);
+ text-align: right;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+ .bar-track {
+ height: 22px;
+ background: rgba(255,255,255,0.03);
+ border-radius: 6px;
+ overflow: hidden;
+ position: relative;
+ }
+ .bar-fill {
+ height: 100%;
+ width: 0%;
+ border-radius: 6px;
+ background: linear-gradient(90deg, var(--cyan-dim), var(--cyan));
+ box-shadow: 0 0 16px var(--bar-glow);
+ transition: width 1.8s cubic-bezier(0.16, 1, 0.3, 1);
+ position: relative;
+ }
+ .bar-fill::after {
+ content: "";
+ position: absolute;
+ top: 0; right: 0; bottom: 0;
+ width: 40%;
+ background: linear-gradient(90deg, transparent, rgba(255,255,255,0.25));
+ }
+ .bar-row:nth-child(2) .bar-fill { background: linear-gradient(90deg, #6b5fd4, var(--violet)); box-shadow: 0 0 16px rgba(139,124,246,0.35); }
+ .bar-row:nth-child(3) .bar-fill { background: linear-gradient(90deg, var(--gold-dim), var(--gold)); box-shadow: 0 0 16px rgba(240,193,75,0.3); }
+ .bar-row:nth-child(4) .bar-fill { background: linear-gradient(90deg, #1a7a6a, #2dd4a8); box-shadow: 0 0 16px rgba(45,212,168,0.3); }
+ .bar-row:nth-child(5) .bar-fill { background: linear-gradient(90deg, #8a4b2a, #e07a3d); box-shadow: 0 0 16px rgba(224,122,61,0.3); }
+ .bar-row:nth-child(6) .bar-fill { background: linear-gradient(90deg, #3d5a80, #6ea8d9); box-shadow: 0 0 16px rgba(110,168,217,0.3); }
+ .bar-val {
+ font-size: 0.75rem;
+ font-variant-numeric: tabular-nums;
+ font-weight: 600;
+ color: var(--text);
+ text-align: right;
+ }
+ footer {
+ padding: 0.5rem 2rem 0.75rem;
+ font-size: 0.65rem;
+ color: var(--muted);
+ letter-spacing: 0.08em;
+ display: flex;
+ justify-content: space-between;
+ opacity: 0.7;
+ }
+ @media (max-width: 900px) {
+ .hero, .lower { grid-template-columns: 1fr; }
+ .digit-slot { font-size: 2rem; }
+ body { overflow: auto; }
+ main { overflow: auto; }
+ }
+</style>
+</head>
+<body>
+<div class="grain"></div>
+<header>
+ <div class="brand">
+ <div class="brand-mark">AF</div>
+ <h1>Agent Fleet<span>Value Delivered Command Center</span></h1>
+ </div>
+ <div class="live"><span class="live-dot"></span> Live telemetry</div>
+</header>
+<main>
+ <section class="hero">
+ <div class="odometer-card gold">
+ <div class="label">Total dollars saved</div>
+ <div class="odometer" id="odo-dollars"></div>
+ <div class="sub"><span class="delta">▲ $128.4K</span> this week · fleet-wide</div>
+ </div>
+ <div class="odometer-card cyan">
+ <div class="label">Engineering hours saved</div>
+ <div class="odometer" id="odo-hours"></div>
+ <div class="sub"><span class="delta">▲ 412 hrs</span> this week · 47 active agents</div>
+ </div>
+ </section>
+ <section class="lower">
+ <div class="panel">
+ <div class="panel-head">
+ <h2>Recent wins</h2>
+ <span class="badge">STREAMING</span>
+ </div>
+ <div class="feed-wrap">
+ <div class="feed" id="feed"></div>
+ </div>
+ </div>
+ <div class="panel">
+ <div class="panel-head">
+ <h2>Savings by category</h2>
+ <span class="badge">YTD</span>
+ </div>
+ <div class="chart-body" id="chart"></div>
+ </div>
+ </section>
+</main>
+<footer>
+ <span>AI AGENT FLEET · VALUE OPS</span>
+ <span id="clock"></span>
+</footer>
+<script>
+(function () {
+ const DOLLAR_TARGET = 4827650;
+ const HOURS_TARGET = 18340;
+
+ const wins = [
+ { t: "Incident triage auto-resolved P2 cluster", m: "SRE · Agent Orion", d: 42000, h: 28 },
+ { t: "Legacy ETL migration scripts generated", m: "Data · Agent Nova", d: 67500, h: 96 },
+ { t: "Customer churn model feature pipeline", m: "ML · Agent Helix", d: 31000, h: 40 },
+ { t: "SOC2 evidence pack assembled", m: "Sec · Agent Cipher", d: 18500, h: 62 },
+ { t: "API contract tests for payments v3", m: "Platform · Agent Forge", d: 9200, h: 18 },
+ { t: "On-call runbook synthesis from tickets", m: "SRE · Agent Orion", d: 24000, h: 35 },
+ { t: "Query optimization across 14 warehouses", m: "Data · Agent Nova", d: 88000, h: 52 },
+ { t: "Design-system token migration", m: "Frontend · Agent Prism", d: 15600, h: 44 },
+ { t: "Vendor invoice anomaly batch closed", m: "Finance · Agent Ledger", d: 53000, h: 22 },
+ { t: "K8s cost rightsizing recommendations", m: "Infra · Agent Atlas", d: 71000, h: 30 },
+ { t: "Support macro library from 9k threads", m: "CX · Agent Echo", d: 12800, h: 55 },
+ { t: "Threat intel digest → SIEM rules", m: "Sec · Agent Cipher", d: 26500, h: 38 },
+ ];
+
+ const categories = [
+ { name: "Infrastructure", value: 1240000 },
+ { name: "Data & ML", value: 980000 },
+ { name: "Security", value: 720000 },
+ { name: "Engineering", value: 890000 },
+ { name: "Support / CX", value: 410000 },
+ { name: "Finance Ops", value: 587650 },
+ ];
+
+ function easeOutExpo(t) {
+ return t === 1 ? 1 : 1 - Math.pow(2, -10 * t);
+ }
+
+ function formatDollars(n) {
+ return Math.round(n).toLocaleString("en-US");
+ }
+
+ function buildOdometer(el, value, prefix, suffix) {
+ const str = Math.round(value).toString();
+ const parts = [];
+ el.innerHTML = "";
+ if (prefix) {
+ const p = document.createElement("span");
+ p.className = "odo-prefix";
+ p.textContent = prefix;
+ el.appendChild(p);
+ }
+ const digitsWrap = document.createElement("div");
+ digitsWrap.className = "digits";
+ const chars = str.split("");
+ const totalDigits = chars.length;
+ chars.forEach((ch, i) => {
+ if (i > 0 && (totalDigits - i) % 3 === 0) {
+ const c = document.createElement("span");
+ c.className = "comma-slot";
+ c.textContent = ",";
+ digitsWrap.appendChild(c);
+ }
+ const slot = document.createElement("div");
+ slot.className = "digit-slot";
+ const strip = document.createElement("div");
+ strip.className = "digit-strip";
+ for (let d = 0; d <= 9; d++) {
+ const s = document.createElement("span");
+ s.textContent = d;
+ strip.appendChild(s);
+ }
+ slot.appendChild(strip);
+ digitsWrap.appendChild(slot);
+ parts.push({ strip, digit: parseInt(ch, 10), index: i });
+ });
+ el.appendChild(digitsWrap);
+ if (suffix) {
+ const s = document.createElement("span");
+ s.className = "odo-suffix";
+ s.textContent = suffix;
+ el.appendChild(s);
+ }
+ return parts;
+ }
+
+ function animateOdometer(parts, duration) {
+ const start = performance.now();
+ function frame(now) {
+ const t = Math.min(1, (now - start) / duration);
+ const e = easeOutExpo(t);
+ parts.forEach((p, idx) => {
+ const delay = idx * 0.04;
+ const local = Math.max(0, Math.min(1, (e - delay) / (1 - delay * 0.5)));
+ const le = easeOutExpo(local);
+ const spins = 2 + (parts.length - idx) * 0.35;
+ const offset = (spins * 10 + p.digit) * le;
+ const em = offset % 10;
+ p.strip.style.transform = "translateY(-" + em * 1.35 + "em)";
+ });
+ if (t < 1) requestAnimationFrame(frame);
+ else {
+ parts.forEach((p) => {
+ p.strip.style.transition = "transform 0.35s cubic-bezier(0.16,1,0.3,1)";
+ p.strip.style.transform = "translateY(-" + p.digit * 1.35 + "em)";
+ });
+ }
+ }
+ requestAnimationFrame(frame);
+ }
+
+ function countUpDisplay(parts, target, duration, isMoney) {
+ /* Snap strips to final after cinematic roll */
+ animateOdometer(parts, duration);
+ }
+
+ const dollarEl = document.getElementById("odo-dollars");
+ const hoursEl = document.getElementById("odo-hours");
+ const dollarParts = buildOdometer(dollarEl, DOLLAR_TARGET, "$", "");
+ const hoursParts = buildOdometer(hoursEl, HOURS_TARGET, "", "");
+
+ setTimeout(() => countUpDisplay(dollarParts, DOLLAR_TARGET, 2800, true), 200);
+ setTimeout(() => countUpDisplay(hoursParts, HOURS_TARGET, 2800, false), 350);
+
+ /* Continuous slow tick on dollars */
+ let liveDollars = DOLLAR_TARGET;
+ let liveHours = HOURS_TARGET;
+ setInterval(() => {
+ liveDollars += Math.floor(Math.random() * 40) + 5;
+ liveHours += Math.random() < 0.3 ? 1 : 0;
+ updateOdoFinal(dollarEl, liveDollars, "$", "");
+ updateOdoFinal(hoursEl, liveHours, "", "");
+ }, 3200);
+
+ function updateOdoFinal(el, value, prefix, suffix) {
+ const str = Math.round(value).toString();
+ const strips = el.querySelectorAll(".digit-strip");
+ const slotsNeeded = str.length;
+ if (strips.length !== slotsNeeded) {
+ const parts = buildOdometer(el, value, prefix, suffix);
+ parts.forEach((p) => {
+ p.strip.style.transition = "none";
+ p.strip.style.transform = "translateY(-" + p.digit * 1.35 + "em)";
+ });
+ return;
+ }
+ str.split("").forEach((ch, i) => {
+ const d = parseInt(ch, 10);
+ strips[i].style.transition = "transform 0.7s cubic-bezier(0.16,1,0.3,1)";
+ strips[i].style.transform = "translateY(-" + d * 1.35 + "em)";
+ });
+ }
+
+ /* Feed */
+ const feed = document.getElementById("feed");
+ function fmtMoney(n) {
+ if (n >= 1000) return "$" + (n / 1000).toFixed(n % 1000 === 0 ? 0 : 1) + "K";
+ return "$" + n;
+ }
+ function winHTML(w) {
+ return '<div class="win"><div><div class="win-title">' + w.t + '</div><div class="win-meta">' + w.m + '</div></div><div class="win-impact">' + fmtMoney(w.d) + '<small>' + w.h + ' eng-hrs</small></div></div>';
+ }
+ const doubled = wins.concat(wins);
+ feed.innerHTML = doubled.map(winHTML).join("");
+
+ /* Chart */
+ const chart = document.getElementById("chart");
+ const maxV = Math.max.apply(null, categories.map(function (c) { return c.value; }));
+ categories.forEach(function (c) {
+ const row = document.createElement("div");
+ row.className = "bar-row";
+ row.innerHTML =
+ '<div class="bar-label">' + c.name + '</div>' +
+ '<div class="bar-track"><div class="bar-fill" data-w="' + (c.value / maxV * 100) + '"></div></div>' +
+ '<div class="bar-val">' + fmtMoney(c.value) + '</div>';
+ chart.appendChild(row);
+ });
+ requestAnimationFrame(function () {
+ setTimeout(function () {
+ chart.querySelectorAll(".bar-fill").forEach(function (b) {
+ b.style.width = b.getAttribute("data-w") + "%";
+ });
+ }, 400);
+ });
+
+ function tickClock() {
+ const n = new Date();
+ document.getElementById("clock").textContent =
+ n.toISOString().replace("T", " ").slice(0, 19) + " UTC";
+ }
+ tickClock();
+ setInterval(tickClock, 1000);
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/f2e21f2299c9/grok.png b/data/artifacts/f2e21f2299c9/grok.png
new file mode 100644
index 0000000..fb55637
Binary files /dev/null and b/data/artifacts/f2e21f2299c9/grok.png differ
diff --git a/data/artifacts/f2e21f2299c9/qwen25-7b.html b/data/artifacts/f2e21f2299c9/qwen25-7b.html
new file mode 100644
index 0000000..9aa1b88
--- /dev/null
+++ b/data/artifacts/f2e21f2299c9/qwen25-7b.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>AI Agent Fleet Value Delivered Dashboard</title>
+ <style>
+ body {
+ background: #222;
+ color: white;
+ font-family: Arial, sans-serif;
+ display: flex;
+ justify-content: space-between;
+ padding: 20px;
+ }
+ .odometer {
+ width: 150px;
+ height: 80px;
+ margin-right: 20px;
+ }
+ .scrolling-feed {
+ overflow-x: auto;
+ white-space: nowrap;
+ max-width: calc(96vw - 340px);
+ }
+ .bar-chart {
+ display: flex;
+ gap: 15px;
+ width: 80%;
+ }
+ .bar {
+ background: #f0d35c;
+ height: 20px;
+ margin-right: 10px;
+ transition: transform 0.4s ease-in-out;
+ }
+ .bar-label {
+ font-size: 12px;
+ }
+ </style>
+</head>
+<body>
+ <div class="odometer">
+ <span id="totalSavings">$00,000,000</span><br>
+ <span>Total Savings</span>
+ </div>
+ <div class="scrolling-feed" id="recentWinsFeed">
+ <div class="win">Win 1: $5,000,000</div>
+ <div class="win">Win 2: $3,500,000</div>
+ <div class="win">Win 3: $4,200,000</div>
+ </div>
+ <div class="bar-chart">
+ <div class="bar" style="width: 60%;"><span class="bar-label">Category A</span></div>
+ <div class="bar" style="width: 45%;"><span class="bar-label">Category B</span></div>
+ <div class="bar" style="width: 72%;"><span class="bar-label">Category C</span></div>
+ </div>
+
+ <script>
+ const odometer = document.getElementById('totalSavings');
+ let count = 0;
+ function updateOdometer() {
+ if (count >= 10000000) return;
+ requestAnimationFrame(updateOdometer);
+ count += 5000;
+ odometer.textContent = `$${(count / 1000).toLocaleString()}k`;
+ }
+ updateOdometer();
+
+ function scrollFeed() {
+ const feed = document.getElementById('recentWinsFeed');
+ if (feed.scrollWidth > feed.clientWidth) {
+ requestAnimationFrame(scrollFeed);
+ const scrollPos = (feed.scrollLeft + 50) % feed.scrollWidth;
+ feed.scrollTo({left: scrollPos, behavior: 'smooth'});
+ }
+ }
+ setInterval(scrollFeed, 200);
+
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/f2e21f2299c9/qwen25-7b.png b/data/artifacts/f2e21f2299c9/qwen25-7b.png
new file mode 100644
index 0000000..d1b3528
Binary files /dev/null and b/data/artifacts/f2e21f2299c9/qwen25-7b.png differ
diff --git a/data/artifacts/f585b9cfcaea/claude-code.html b/data/artifacts/f585b9cfcaea/claude-code.html
new file mode 100644
index 0000000..fba3f1a
--- /dev/null
+++ b/data/artifacts/f585b9cfcaea/claude-code.html
@@ -0,0 +1,295 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Agent Reflex</title>
+<style>
+ :root{
+ --bg:#050810;
+ --grid:#0d2030;
+ --cyan:#00f0ff;
+ --magenta:#ff2bd6;
+ --lime:#5cff8f;
+ --amber:#ffb020;
+ --text:#bfe9ff;
+ --panel:rgba(6,18,32,.72);
+ }
+ *{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}
+ html,body{height:100%;overflow:hidden}
+ body{
+ font-family:"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
+ background:
+ radial-gradient(ellipse at 50% -10%,rgba(0,240,255,.14),transparent 55%),
+ radial-gradient(ellipse at 50% 120%,rgba(255,43,214,.10),transparent 55%),
+ var(--bg);
+ color:var(--text);
+ display:flex;align-items:center;justify-content:center;
+ user-select:none;
+ }
+ #wrap{
+ position:relative;
+ width:min(96vw,860px);
+ height:min(94vh,620px);
+ border:1px solid rgba(0,240,255,.28);
+ border-radius:14px;
+ background:
+ linear-gradient(var(--grid) 1px,transparent 1px) 0 0/40px 40px,
+ linear-gradient(90deg,var(--grid) 1px,transparent 1px) 0 0/40px 40px,
+ var(--panel);
+ box-shadow:0 0 60px rgba(0,240,255,.10),inset 0 0 90px rgba(0,60,90,.35);
+ overflow:hidden;
+ }
+ #wrap::before{
+ content:"";position:absolute;inset:0;pointer-events:none;
+ background:repeating-linear-gradient(0deg,rgba(0,0,0,0) 0 2px,rgba(0,240,255,.035) 2px 4px);
+ mix-blend-mode:screen;
+ }
+ /* HUD */
+ #hud{
+ position:absolute;top:0;left:0;right:0;height:64px;
+ display:flex;align-items:center;justify-content:space-between;
+ padding:0 18px;gap:10px;z-index:5;
+ background:linear-gradient(180deg,rgba(4,12,22,.9),rgba(4,12,22,0));
+ pointer-events:none;
+ }
+ .stat{text-align:center;line-height:1.1}
+ .stat .k{font-size:9px;letter-spacing:2px;color:rgba(0,240,255,.6);text-transform:uppercase}
+ .stat .v{font-size:22px;font-weight:800;color:#eafcff;text-shadow:0 0 10px rgba(0,240,255,.55);font-variant-numeric:tabular-nums}
+ #combo .v{color:var(--amber);text-shadow:0 0 12px rgba(255,176,32,.7)}
+ #title{position:absolute;top:8px;left:50%;transform:translateX(-50%);font-size:11px;letter-spacing:5px;color:rgba(0,240,255,.55);text-transform:uppercase;z-index:6}
+ /* timer bar */
+ #timebar{position:absolute;bottom:0;left:0;height:5px;width:100%;background:linear-gradient(90deg,var(--cyan),var(--magenta));box-shadow:0 0 14px var(--cyan);transform-origin:left;z-index:5;transition:transform .1s linear}
+ /* targets */
+ .node{
+ position:absolute;width:62px;height:62px;border-radius:50%;
+ display:flex;align-items:center;justify-content:center;
+ cursor:pointer;z-index:3;
+ background:radial-gradient(circle at 35% 30%,#eaffff,var(--cyan) 45%,rgba(0,120,150,.15) 72%);
+ box-shadow:0 0 22px var(--cyan),0 0 46px rgba(0,240,255,.5),inset 0 0 14px rgba(255,255,255,.6);
+ animation:pop .16s ease-out;
+ will-change:transform,opacity;
+ }
+ .node::after{content:"";position:absolute;inset:12px;border-radius:50%;border:2px solid rgba(255,255,255,.85);opacity:.7}
+ .node .ring{position:absolute;inset:-6px;border-radius:50%;border:2px solid rgba(0,240,255,.9);animation:shrink linear forwards}
+ @keyframes shrink{from{transform:scale(1.35);opacity:.9}to{transform:scale(.55);opacity:.25}}
+ @keyframes pop{from{transform:scale(.2)}to{transform:scale(1)}}
+ .node.hit{animation:burst .28s ease-out forwards;pointer-events:none}
+ @keyframes burst{to{transform:scale(1.9);opacity:0}}
+ .float{position:absolute;z-index:6;font-weight:800;font-size:16px;pointer-events:none;animation:rise .7s ease-out forwards;text-shadow:0 0 8px currentColor}
+ @keyframes rise{from{transform:translateY(0);opacity:1}to{transform:translateY(-38px);opacity:0}}
+ /* overlays */
+ #overlay{position:absolute;inset:0;z-index:20;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:16px;background:rgba(3,8,16,.86);backdrop-filter:blur(2px);padding:24px}
+ #overlay.hidden{display:none}
+ h1{font-size:clamp(30px,7vw,58px);letter-spacing:6px;font-weight:900;color:#eafcff;text-shadow:0 0 18px var(--cyan),0 0 40px rgba(0,240,255,.5);text-transform:uppercase}
+ h1 span{color:var(--magenta);text-shadow:0 0 18px var(--magenta)}
+ .sub{font-size:13px;letter-spacing:2px;color:var(--text);max-width:440px;line-height:1.7;opacity:.85}
+ .best{font-size:13px;letter-spacing:3px;color:var(--amber);text-shadow:0 0 10px rgba(255,176,32,.6)}
+ .finalscore{font-size:56px;font-weight:900;color:var(--lime);text-shadow:0 0 20px rgba(92,255,143,.6);font-variant-numeric:tabular-nums}
+ .grid2{display:flex;gap:26px;flex-wrap:wrap;justify-content:center;margin-top:4px}
+ .grid2 .stat .v{font-size:26px}
+ button{
+ margin-top:8px;font-family:inherit;font-weight:800;letter-spacing:3px;text-transform:uppercase;
+ font-size:15px;color:#02121a;background:linear-gradient(180deg,#7ff7ff,var(--cyan));
+ border:none;padding:15px 40px;border-radius:10px;cursor:pointer;
+ box-shadow:0 0 22px rgba(0,240,255,.55),0 6px 0 rgba(0,120,150,.5);
+ transition:transform .08s,box-shadow .2s;
+ }
+ button:hover{box-shadow:0 0 34px rgba(0,240,255,.85),0 6px 0 rgba(0,120,150,.5)}
+ button:active{transform:translateY(3px);box-shadow:0 0 22px rgba(0,240,255,.55),0 2px 0 rgba(0,120,150,.5)}
+ .badge{font-size:10px;letter-spacing:3px;color:rgba(0,240,255,.55);text-transform:uppercase}
+</style>
+</head>
+<body>
+<div id="wrap">
+ <div id="title">◆ Agent Reflex · Command Center ◆</div>
+ <div id="hud">
+ <div class="stat" id="score"><div class="k">Score</div><div class="v">0</div></div>
+ <div class="stat" id="combo"><div class="k">Combo</div><div class="v">x1</div></div>
+ <div class="stat" id="hits"><div class="k">Hits</div><div class="v">0</div></div>
+ <div class="stat" id="miss"><div class="k">Miss</div><div class="v">0</div></div>
+ <div class="stat" id="time"><div class="k">Time</div><div class="v">30</div></div>
+ </div>
+ <div id="timebar"></div>
+
+ <div id="overlay">
+ <div class="badge">Reflex Protocol</div>
+ <h1>Agent <span>Reflex</span></h1>
+ <p class="sub">Glowing target nodes spawn across the grid. Neutralize each one <b>before it fades</b>. Chain hits without missing to build your combo multiplier. You have <b>30 seconds</b>.</p>
+ <div class="best" id="bestLine">Best: 0</div>
+ <button id="startBtn">Initialize</button>
+ </div>
+</div>
+
+<script>
+(function(){
+ const wrap=document.getElementById('wrap');
+ const overlay=document.getElementById('overlay');
+ const startBtn=document.getElementById('startBtn');
+ const bestLine=document.getElementById('bestLine');
+ const timebar=document.getElementById('timebar');
+ const el={
+ score:document.querySelector('#score .v'),
+ combo:document.querySelector('#combo .v'),
+ hits:document.querySelector('#hits .v'),
+ miss:document.querySelector('#miss .v'),
+ time:document.querySelector('#time .v'),
+ };
+ const COLORS=['#00f0ff','#ff2bd6','#5cff8f','#ffb020','#8a7bff'];
+ const ROUND=30; // seconds
+
+ let state={running:false,score:0,combo:1,hits:0,miss:0,timeLeft:ROUND};
+ let best=+(localStorage.getItem('agentReflexBest')||0);
+ let nodes=new Set();
+ let lastSpawn=0, spawnGap=900, endTime=0, raf=0;
+
+ bestLine.textContent='Best: '+best;
+
+ function fmt(){
+ el.score.textContent=state.score;
+ el.combo.textContent='x'+state.combo;
+ el.hits.textContent=state.hits;
+ el.miss.textContent=state.miss;
+ el.time.textContent=Math.ceil(Math.max(0,state.timeLeft));
+ }
+
+ function rand(a,b){return a+Math.random()*(b-a);}
+
+ function spawn(now){
+ const rect=wrap.getBoundingClientRect();
+ const size=rand(46,66);
+ const margin=14;
+ const topPad=72, botPad=20;
+ const x=rand(margin,rect.width-size-margin);
+ const y=rand(topPad,rect.height-size-botPad);
+ const color=COLORS[(Math.random()*COLORS.length)|0];
+ // life shrinks as time runs out -> faster/harder
+ const prog=1-(state.timeLeft/ROUND);
+ const life=rand(1500,2100)-prog*900; // ms visible before fade
+
+ const n=document.createElement('div');
+ n.className='node';
+ n.style.width=n.style.height=size+'px';
+ n.style.left=x+'px';n.style.top=y+'px';
+ n.style.background='radial-gradient(circle at 35% 30%,#ffffff,'+color+' 45%,rgba(0,0,0,.05) 72%)';
+ n.style.boxShadow='0 0 22px '+color+',0 0 48px '+color+'88,inset 0 0 14px rgba(255,255,255,.6)';
+ const ring=document.createElement('div');
+ ring.className='ring';
+ ring.style.borderColor=color;
+ ring.style.animationDuration=life+'ms';
+ n.appendChild(ring);
+
+ const item={node:n,color:color,expire:now+life,dead:false};
+ n.addEventListener('pointerdown',ev=>{ev.preventDefault();hit(item,ev);});
+ nodes.add(item);
+ wrap.appendChild(n);
+ }
+
+ function floatText(x,y,txt,color){
+ const f=document.createElement('div');
+ f.className='float';f.textContent=txt;f.style.color=color;
+ f.style.left=x+'px';f.style.top=y+'px';
+ wrap.appendChild(f);
+ setTimeout(()=>f.remove(),720);
+ }
+
+ function hit(item,ev){
+ if(item.dead||!state.running)return;
+ item.dead=true;
+ nodes.delete(item);
+ const base=100;
+ const gained=base*state.combo;
+ state.score+=gained;
+ state.hits++;
+ state.combo=Math.min(state.combo+1,20);
+ const r=wrap.getBoundingClientRect();
+ floatText(ev.clientX-r.left-12,ev.clientY-r.top-20,'+'+gained,item.color);
+ item.node.classList.add('hit');
+ setTimeout(()=>item.node.remove(),280);
+ fmt();
+ }
+
+ function expire(item){
+ item.dead=true;
+ nodes.delete(item);
+ state.miss++;
+ state.combo=1;
+ const x=parseFloat(item.node.style.left)+10;
+ const y=parseFloat(item.node.style.top)+10;
+ floatText(x,y,'MISS','#ff5470');
+ item.node.style.transition='opacity .18s,transform .18s';
+ item.node.style.opacity='0';
+ item.node.style.transform='scale(.4)';
+ setTimeout(()=>item.node.remove(),180);
+ fmt();
+ }
+
+ function loop(now){
+ if(!state.running)return;
+ state.timeLeft=(endTime-now)/1000;
+ if(state.timeLeft<=0){state.timeLeft=0;fmt();return endGame();}
+
+ // difficulty ramp
+ const prog=1-(state.timeLeft/ROUND);
+ spawnGap=900-prog*520; // faster spawns near end
+
+ if(now-lastSpawn>spawnGap){
+ spawn(now);
+ lastSpawn=now;
+ }
+ // expire
+ for(const item of nodes){
+ if(now>=item.expire) expire(item);
+ }
+ timebar.style.transform='scaleX('+(state.timeLeft/ROUND)+')';
+ el.time.textContent=Math.ceil(state.timeLeft);
+ raf=requestAnimationFrame(loop);
+ }
+
+ function clearNodes(){
+ for(const item of nodes){item.node.remove();}
+ nodes.clear();
+ }
+
+ function startGame(){
+ clearNodes();
+ state={running:true,score:0,combo:1,hits:0,miss:0,timeLeft:ROUND};
+ fmt();
+ overlay.classList.add('hidden');
+ timebar.style.transform='scaleX(1)';
+ const now=performance.now();
+ endTime=now+ROUND*1000;
+ lastSpawn=now-1000;
+ raf=requestAnimationFrame(loop);
+ }
+
+ function endGame(){
+ state.running=false;
+ cancelAnimationFrame(raf);
+ clearNodes();
+ const acc=state.hits+state.miss>0?Math.round(state.hits/(state.hits+state.miss)*100):0;
+ let record=false;
+ if(state.score>best){best=state.score;localStorage.setItem('agentReflexBest',best);record=true;}
+ bestLine.textContent='Best: '+best;
+
+ overlay.innerHTML=
+ '<div class="badge">Mission Report</div>'+
+ '<h1>'+(record?'<span>New Record</span>':'Complete')+'</h1>'+
+ '<div class="finalscore">'+state.score+'</div>'+
+ '<div class="grid2">'+
+ '<div class="stat"><div class="k">Hits</div><div class="v">'+state.hits+'</div></div>'+
+ '<div class="stat"><div class="k">Miss</div><div class="v">'+state.miss+'</div></div>'+
+ '<div class="stat"><div class="k">Accuracy</div><div class="v">'+acc+'%</div></div>'+
+ '</div>'+
+ '<div class="best">Best: '+best+'</div>'+
+ '<button id="startBtn">Redeploy</button>';
+ overlay.classList.remove('hidden');
+ document.getElementById('startBtn').addEventListener('click',startGame);
+ }
+
+ startBtn.addEventListener('click',startGame);
+ window.addEventListener('keydown',e=>{if((e.key==='Enter'||e.key===' ')&&!state.running)startGame();});
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/f585b9cfcaea/claude-code.png b/data/artifacts/f585b9cfcaea/claude-code.png
new file mode 100644
index 0000000..92febde
Binary files /dev/null and b/data/artifacts/f585b9cfcaea/claude-code.png differ
diff --git a/data/artifacts/f585b9cfcaea/gemma3-12b.html b/data/artifacts/f585b9cfcaea/gemma3-12b.html
new file mode 100644
index 0000000..afd74eb
--- /dev/null
+++ b/data/artifacts/f585b9cfcaea/gemma3-12b.html
@@ -0,0 +1,207 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Agent Reflex</title>
+ <style>
+ body {
+ background: linear-gradient(to bottom, #3498db, #2980b9); /* Neon Blue Gradient */
+ overflow: hidden;
+ margin: 0;
+ font-family: sans-serif;
+ color: #fff;
+ }
+
+ #gameContainer {
+ position: relative;
+ width: 100%;
+ height: 100vh;
+ }
+
+ .target {
+ position: absolute;
+ width: 30px;
+ height: 30px;
+ border-radius: 50%;
+ background: #ffeb3b; /* Neon Yellow */
+ box-shadow: 0 0 10px #ffeb3b, inset 0 0 5px #ffeb3b;
+ cursor: pointer;
+ animation: fadeOut 2s forwards; /* Initial Fade Out Animation - can be overridden */
+ }
+
+ @keyframes fadeOut {
+ to {
+ opacity: 0;
+ }
+ }
+
+
+ #scoreContainer {
+ position: absolute;
+ top: 10px;
+ left: 10px;
+ font-size: 20px;
+ font-weight: bold;
+ text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
+ }
+
+ #timerContainer {
+ position: absolute;
+ bottom: 10px;
+ right: 10px;
+ font-size: 20px;
+ font-weight: bold;
+ text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
+ }
+
+ #restartButton {
+ position: absolute;
+ bottom: 10px;
+ left: 50%;
+ transform: translateX(-50%);
+ padding: 10px 20px;
+ background-color: #e74c3c; /* Neon Red */
+ color: white;
+ border: none;
+ border-radius: 5px;
+ cursor: pointer;
+ font-size: 16px;
+ text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
+ }
+
+ #bestScoreContainer {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ font-size: 18px;
+ display: none; /* Hidden initially */
+ text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
+ }
+ </style>
+</head>
+<body>
+
+ <div id="gameContainer">
+ <div id="scoreContainer">Score: 0</div>
+ <div id="timerContainer">Time: 30s</div>
+ <button id="restartButton">Restart</button>
+ <div id="bestScoreContainer">Best Score: <span id="bestScoreValue"></span></div>
+ </div>
+
+ <script>
+ const gameContainer = document.getElementById('gameContainer');
+ const scoreContainer = document.getElementById('scoreContainer');
+ const timerContainer = document.getElementById('timerContainer');
+ const restartButton = document.getElementById('restartButton');
+ const bestScoreContainer = document.getElementById('bestScoreContainer');
+ const bestScoreValueSpan = document.getElementById('bestScoreValue');
+
+ let score = 0;
+ let timeLeft = 30;
+ let combo = 1;
+ let lastClickTime = null;
+ let targetNodes = [];
+ let gameRunning = false;
+
+
+ const getRandomPosition = () => {
+ const width = gameContainer.offsetWidth;
+ const height = gameContainer.offsetHeight;
+ return {
+ x: Math.random() * (width - 30),
+ y: Math.random() * (height - 30)
+ };
+ };
+
+ const createTarget = () => {
+ const target = document.createElement('div');
+ target.classList.add('target');
+ const position = getRandomPosition();
+ target.style.left = `${position.x}px`;
+ target.style.top = `${position.y}px`;
+
+ target.addEventListener('click', () => {
+ if (gameRunning) {
+ score += combo;
+ scoreContainer.textContent = `Score: ${score}`;
+ lastClickTime = Date.now();
+ combo = 1; // Reset combo on click
+ target.remove();
+ createTarget();
+ updateCombo();
+
+ }
+ });
+
+ gameContainer.appendChild(target);
+ targetNodes.push(target);
+
+
+ // Make sure the fadeout animation is reset when target is created.
+ target.style.animation = 'fadeOut 2s forwards';
+ };
+
+
+
+ const updateCombo = () => {
+ if (lastClickTime !== null) {
+ setTimeout(() => {
+ combo++;
+ }, 500);
+ }
+
+ };
+
+
+ const startGame = () => {
+ score = 0;
+ timeLeft = 30;
+ combo = 1;
+ lastClickTime = null;
+ targetNodes.forEach(node => node.remove()); // Clear existing targets
+ targetNodes = [];
+ timerContainer.textContent = `Time: ${timeLeft}s`;
+ scoreContainer.textContent = 'Score: 0';
+
+ gameRunning = true;
+ createTarget(); // Initial target creation
+ setInterval(() => {
+ if (timeLeft > 0) {
+ timeLeft--;
+ timerContainer.textContent = `Time: ${timeLeft}s`;
+ createTarget();
+ } else {
+ endGame();
+ }
+ }, 1000);
+
+ };
+
+ const endGame = () => {
+ gameRunning = false;
+ bestScoreValueSpan.textContent = localStorage.getItem('bestScore') || '0';
+ bestScoreContainer.style.display = 'block';
+ restartButton.style.display = 'block';
+
+ };
+
+
+ restartButton.addEventListener('click', startGame);
+
+ // Load best score from localStorage
+ const storedBestScore = localStorage.getItem('bestScore');
+ if (storedBestScore) {
+ bestScoreValueSpan.textContent = storedBestScore;
+ }
+
+
+
+
+ startGame(); // Start the game automatically on load
+
+
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/f585b9cfcaea/gemma3-12b.png b/data/artifacts/f585b9cfcaea/gemma3-12b.png
new file mode 100644
index 0000000..9a3d66c
Binary files /dev/null and b/data/artifacts/f585b9cfcaea/gemma3-12b.png differ
diff --git a/data/artifacts/f585b9cfcaea/gpt.html b/data/artifacts/f585b9cfcaea/gpt.html
new file mode 100644
index 0000000..5abd73e
--- /dev/null
+++ b/data/artifacts/f585b9cfcaea/gpt.html
@@ -0,0 +1,1447 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>Agent Reflex</title>
+<style>
+ :root {
+ --bg: #02030a;
+ --panel: #050814;
+ --accent: #26f6ff;
+ --accent-soft: rgba(38, 246, 255, 0.2);
+ --accent-strong: rgba(38, 246, 255, 0.6);
+ --accent-secondary: #ff2ea6;
+ --danger: #ff3b63;
+ --success: #5dff7a;
+ --text: #e9f5ff;
+ --muted: #7f9dbd;
+ --grid: rgba(90, 190, 255, 0.06);
+ }
+
+ * {
+ box-sizing: border-box;
+ padding: 0;
+ margin: 0;
+ }
+
+ html, body {
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+ background: radial-gradient(circle at 20% 0%, #06101f 0%, #02030a 55%, #000000 100%);
+ color: var(--text);
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
+ }
+
+ body {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .frame {
+ position: relative;
+ width: 100%;
+ max-width: 960px;
+ height: 100vh;
+ max-height: 620px;
+ margin: 0 auto;
+ padding: 16px;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ color: var(--text);
+ }
+
+ .chrome {
+ position: relative;
+ border-radius: 14px;
+ background:
+ radial-gradient(circle at 0 0, rgba(38, 246, 255, 0.18), transparent 55%),
+ radial-gradient(circle at 100% 0, rgba(255, 46, 166, 0.18), transparent 55%),
+ linear-gradient(145deg, #060917, #020109);
+ box-shadow:
+ 0 0 0 1px rgba(120, 200, 255, 0.25),
+ 0 0 40px rgba(0, 0, 0, 0.9),
+ 0 0 80px rgba(38, 246, 255, 0.15);
+ padding: 12px 16px;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ height: 100%;
+ }
+
+ .chrome::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ pointer-events: none;
+ border-radius: inherit;
+ border: 1px solid rgba(255, 255, 255, 0.05);
+ mix-blend-mode: screen;
+ }
+
+ .top-bar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 12px;
+ font-size: 13px;
+ letter-spacing: 0.15em;
+ text-transform: uppercase;
+ color: var(--muted);
+ }
+
+ .top-left, .top-right {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ }
+
+ .brand {
+ font-weight: 700;
+ color: var(--accent);
+ text-shadow: 0 0 6px rgba(38, 246, 255, 0.6);
+ }
+
+ .lights {
+ display: flex;
+ gap: 5px;
+ align-items: center;
+ }
+
+ .light {
+ width: 7px;
+ height: 7px;
+ border-radius: 50%;
+ background: radial-gradient(circle, #ff4444, #630d0d);
+ box-shadow: 0 0 4px rgba(255, 80, 80, 0.9);
+ opacity: 0.4;
+ }
+
+ .light.on {
+ opacity: 1;
+ }
+
+ .divider {
+ width: 1px;
+ height: 16px;
+ background: linear-gradient(to bottom, transparent, rgba(140, 200, 255, 0.7), transparent);
+ opacity: 0.6;
+ }
+
+ .mode-pill {
+ border-radius: 999px;
+ border: 1px solid rgba(120, 200, 255, 0.5);
+ padding: 3px 10px;
+ font-size: 11px;
+ letter-spacing: 0.18em;
+ text-transform: uppercase;
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ color: var(--accent);
+ background: radial-gradient(circle at 0 0, rgba(38, 246, 255, 0.22), rgba(3, 8, 18, 0.95));
+ box-shadow: 0 0 10px rgba(38, 246, 255, 0.3);
+ }
+
+ .mode-dot {
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
+ background: radial-gradient(circle, #26f6ff, transparent);
+ box-shadow: 0 0 6px rgba(38, 246, 255, 0.9);
+ }
+
+ .content {
+ flex: 1;
+ display: grid;
+ grid-template-columns: minmax(0, 2.5fr) minmax(260px, 1.2fr);
+ gap: 12px;
+ min-height: 0;
+ }
+
+ @media (max-width: 780px) {
+ .content {
+ grid-template-columns: minmax(0, 1fr);
+ grid-template-rows: 2fr auto;
+ }
+ }
+
+ .arena-shell {
+ position: relative;
+ border-radius: 12px;
+ background: radial-gradient(circle at 50% 0, rgba(84, 189, 255, 0.16), transparent 55%), #02030a;
+ overflow: hidden;
+ box-shadow:
+ inset 0 0 0 1px rgba(120, 200, 255, 0.25),
+ 0 0 45px rgba(0, 0, 0, 0.95);
+ }
+
+ .arena-inner {
+ position: absolute;
+ inset: 0;
+ padding: 8px;
+ display: flex;
+ flex-direction: column;
+ }
+
+ .grid {
+ position: absolute;
+ inset: 0;
+ background-image:
+ linear-gradient(var(--grid) 1px, transparent 1px),
+ linear-gradient(90deg, var(--grid) 1px, transparent 1px);
+ background-size: 32px 32px;
+ opacity: 0.9;
+ mix-blend-mode: screen;
+ pointer-events: none;
+ transform-origin: center;
+ animation: gridScroll 18s linear infinite;
+ }
+
+ @keyframes gridScroll {
+ 0% { transform: translate3d(0, 0, 0) skewX(-4deg); }
+ 100% { transform: translate3d(-32px, -32px, 0) skewX(-4deg); }
+ }
+
+ .scanline {
+ position: absolute;
+ inset: 0;
+ background-image: linear-gradient(
+ to bottom,
+ rgba(0, 0, 0, 0.4) 50%,
+ rgba(0, 0, 0, 0.75) 50%
+ );
+ background-size: 100% 2px;
+ opacity: 0.4;
+ mix-blend-mode: soft-light;
+ pointer-events: none;
+ }
+
+ #arenaCanvas {
+ position: relative;
+ flex: 1;
+ border-radius: 10px;
+ background: radial-gradient(circle at 50% 120%, #011425 0, #000308 65%);
+ box-shadow:
+ inset 0 0 0 1px rgba(120, 200, 255, 0.2),
+ inset 0 0 25px rgba(9, 162, 255, 0.5);
+ }
+
+ .hud-overlay {
+ position: absolute;
+ inset: 8px;
+ pointer-events: none;
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ font-size: 11px;
+ text-transform: uppercase;
+ letter-spacing: 0.18em;
+ color: var(--muted);
+ }
+
+ .hud-block {
+ background: linear-gradient(135deg, rgba(3, 10, 22, 0.95), rgba(5, 26, 53, 0.85));
+ border-radius: 8px;
+ padding: 6px 8px;
+ border: 1px solid rgba(120, 200, 255, 0.45);
+ box-shadow: 0 0 15px rgba(8, 140, 255, 0.4);
+ min-width: 130px;
+ }
+
+ .hud-label {
+ color: var(--muted);
+ font-size: 10px;
+ margin-bottom: 3px;
+ }
+
+ .hud-value {
+ display: flex;
+ align-items: baseline;
+ justify-content: space-between;
+ gap: 8px;
+ }
+
+ .hud-main-number {
+ font-size: 20px;
+ font-weight: 700;
+ color: var(--accent);
+ text-shadow: 0 0 8px rgba(38, 246, 255, 0.8);
+ }
+
+ .hud-sub {
+ font-size: 10px;
+ color: var(--accent-secondary);
+ }
+
+ .hud-right {
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+ align-items: flex-end;
+ }
+
+ .meta-line {
+ font-size: 10px;
+ color: var(--muted);
+ text-align: right;
+ }
+
+ .meta-line span {
+ color: var(--accent);
+ }
+
+ .status-bar {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ margin-top: 4px;
+ font-size: 10px;
+ text-transform: uppercase;
+ letter-spacing: 0.18em;
+ color: var(--muted);
+ }
+
+ .status-pip {
+ width: 6px;
+ height: 6px;
+ border-radius: 2px;
+ background: radial-gradient(circle, #26f6ff, transparent);
+ box-shadow: 0 0 6px rgba(38, 246, 255, 0.9);
+ animation: pulse 1.3s ease-in-out infinite;
+ }
+
+ @keyframes pulse {
+ 0%, 100% { transform: scale(1); opacity: 0.45; }
+ 50% { transform: scale(1.6); opacity: 1; }
+ }
+
+ .control-panel {
+ border-radius: 12px;
+ background: radial-gradient(circle at 100% 0, rgba(255, 46, 166, 0.13), transparent 55%), #050814;
+ padding: 10px 10px 12px;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ box-shadow:
+ inset 0 0 0 1px rgba(120, 200, 255, 0.25),
+ 0 0 35px rgba(0, 0, 0, 0.9);
+ }
+
+ .panel-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 10px;
+ font-size: 12px;
+ text-transform: uppercase;
+ letter-spacing: 0.18em;
+ color: var(--muted);
+ }
+
+ .panel-title {
+ font-weight: 600;
+ color: var(--accent);
+ }
+
+ .panel-sub {
+ font-size: 10px;
+ letter-spacing: 0.12em;
+ color: var(--muted);
+ }
+
+ .score-grid {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 6px;
+ margin-top: 4px;
+ }
+
+ .score-card {
+ border-radius: 8px;
+ padding: 6px 8px;
+ background: linear-gradient(145deg, rgba(3, 11, 26, 0.95), rgba(7, 20, 41, 0.9));
+ border: 1px solid rgba(120, 200, 255, 0.4);
+ box-shadow: 0 0 16px rgba(19, 122, 244, 0.35);
+ font-size: 11px;
+ }
+
+ .score-label {
+ font-size: 10px;
+ text-transform: uppercase;
+ letter-spacing: 0.18em;
+ color: var(--muted);
+ margin-bottom: 3px;
+ }
+
+ .score-value {
+ display: flex;
+ align-items: baseline;
+ justify-content: space-between;
+ gap: 6px;
+ }
+
+ .score-main {
+ font-size: 16px;
+ font-weight: 700;
+ color: var(--text);
+ }
+
+ .score-tag {
+ font-size: 10px;
+ color: var(--accent);
+ }
+
+ .score-alt {
+ font-size: 11px;
+ color: var(--accent-secondary);
+ }
+
+ .meter-row {
+ margin-top: 4px;
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+ }
+
+ .meter-label-row {
+ display: flex;
+ justify-content: space-between;
+ font-size: 10px;
+ text-transform: uppercase;
+ letter-spacing: 0.16em;
+ color: var(--muted);
+ }
+
+ .meter-bar {
+ position: relative;
+ height: 8px;
+ border-radius: 999px;
+ background: radial-gradient(circle at 0 50%, rgba(15, 34, 65, 0.9), rgba(2, 6, 14, 0.9));
+ overflow: hidden;
+ box-shadow: inset 0 0 0 1px rgba(120, 200, 255, 0.35);
+ }
+
+ .meter-fill {
+ position: absolute;
+ inset: 1px;
+ width: 0%;
+ border-radius: 999px;
+ background: linear-gradient(90deg, #18c2ff, #26f6ff, #5dff7a);
+ box-shadow: 0 0 10px rgba(38, 246, 255, 0.7);
+ transition: width 0.12s linear;
+ }
+
+ .meter-ticks {
+ position: absolute;
+ inset: 0;
+ background-image: linear-gradient(90deg, rgba(3, 24, 54, 0.8) 1px, transparent 1px);
+ background-size: 10% 100%;
+ mix-blend-mode: soft-light;
+ pointer-events: none;
+ opacity: 0.65;
+ }
+
+ .hint-row {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 8px;
+ margin-top: 4px;
+ font-size: 10px;
+ color: var(--muted);
+ }
+
+ .hint-text {
+ text-transform: uppercase;
+ letter-spacing: 0.12em;
+ flex: 1;
+ }
+
+ .keycaps {
+ display: inline-flex;
+ gap: 4px;
+ align-items: center;
+ }
+
+ .keycap {
+ border-radius: 4px;
+ padding: 1px 5px;
+ border: 1px solid rgba(120, 200, 255, 0.7);
+ background: radial-gradient(circle at 0 0, rgba(38, 246, 255, 0.22), rgba(2, 10, 24, 0.95));
+ font-size: 9px;
+ text-transform: uppercase;
+ letter-spacing: 0.16em;
+ color: var(--accent);
+ box-shadow: 0 0 6px rgba(38, 246, 255, 0.6);
+ }
+
+ .btn-row {
+ display: flex;
+ margin-top: 4px;
+ gap: 6px;
+ }
+
+ .btn {
+ flex: 1;
+ border-radius: 999px;
+ padding: 7px 0;
+ border: 1px solid rgba(120, 200, 255, 0.8);
+ background: radial-gradient(circle at 0 0, rgba(38, 246, 255, 0.35), rgba(3, 12, 28, 0.98));
+ color: var(--text);
+ font-size: 11px;
+ text-transform: uppercase;
+ letter-spacing: 0.16em;
+ cursor: pointer;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: 6px;
+ transition: transform 0.08s ease, box-shadow 0.08s ease, background 0.08s ease, border-color 0.1s ease;
+ box-shadow:
+ 0 0 12px rgba(38, 246, 255, 0.6),
+ inset 0 0 0 1px rgba(0, 0, 0, 0.7);
+ position: relative;
+ overflow: hidden;
+ }
+
+ .btn::after {
+ content: "";
+ position: absolute;
+ inset: -40%;
+ background: radial-gradient(circle at 0 0, rgba(255, 255, 255, 0.5), transparent 55%);
+ opacity: 0;
+ transform: translate3d(-60%, -60%, 0);
+ transition: opacity 0.2s ease, transform 0.2s ease;
+ pointer-events: none;
+ }
+
+ .btn:hover::after {
+ opacity: 0.35;
+ transform: translate3d(-45%, -45%, 0);
+ }
+
+ .btn:active {
+ transform: translateY(1px) scale(0.985);
+ box-shadow:
+ 0 0 6px rgba(38, 246, 255, 0.4),
+ inset 0 0 0 1px rgba(0, 0, 0, 0.8);
+ }
+
+ .btn-secondary {
+ border-color: rgba(255, 46, 166, 0.7);
+ background: radial-gradient(circle at 100% 0, rgba(255, 46, 166, 0.45), rgba(7, 6, 16, 0.98));
+ box-shadow:
+ 0 0 10px rgba(255, 46, 166, 0.6),
+ inset 0 0 0 1px rgba(0, 0, 0, 0.8);
+ color: #ffeafd;
+ }
+
+ .btn-label-primary {
+ color: var(--accent);
+ }
+
+ .btn-label-secondary {
+ color: var(--accent-secondary);
+ }
+
+ .btn-shortcut {
+ font-size: 9px;
+ color: var(--muted);
+ }
+
+ .log {
+ margin-top: 4px;
+ border-radius: 8px;
+ border: 1px solid rgba(120, 200, 255, 0.4);
+ padding: 4px 6px;
+ font-size: 10px;
+ max-height: 120px;
+ overflow: hidden;
+ background: radial-gradient(circle at 0 0, rgba(38, 246, 255, 0.08), rgba(2, 8, 20, 0.95));
+ }
+
+ .log-line {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ color: var(--muted);
+ }
+
+ .log-line strong {
+ color: var(--accent);
+ }
+
+ .log-line span {
+ color: var(--accent-secondary);
+ }
+
+ .overlay {
+ position: absolute;
+ inset: 8px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ pointer-events: none;
+ z-index: 4;
+ }
+
+ .overlay-inner {
+ pointer-events: auto;
+ text-align: center;
+ padding: 14px 18px;
+ border-radius: 12px;
+ background: radial-gradient(circle at 0 0, rgba(38, 246, 255, 0.25), transparent 55%),
+ radial-gradient(circle at 100% 0, rgba(255, 46, 166, 0.25), transparent 55%),
+ rgba(3, 8, 20, 0.97);
+ box-shadow:
+ 0 0 26px rgba(0, 0, 0, 0.9),
+ 0 0 30px rgba(38, 246, 255, 0.35);
+ border: 1px solid rgba(120, 200, 255, 0.8);
+ min-width: 260px;
+ max-width: 360px;
+ }
+
+ .overlay-title {
+ font-size: 18px;
+ letter-spacing: 0.25em;
+ text-transform: uppercase;
+ margin-bottom: 4px;
+ color: var(--accent);
+ text-shadow: 0 0 12px rgba(38, 246, 255, 0.8);
+ }
+
+ .overlay-subtitle {
+ font-size: 11px;
+ letter-spacing: 0.16em;
+ text-transform: uppercase;
+ color: var(--muted);
+ margin-bottom: 10px;
+ }
+
+ .overlay-main-score {
+ font-size: 28px;
+ font-weight: 700;
+ color: var(--success);
+ text-shadow: 0 0 18px rgba(93, 255, 122, 0.9);
+ margin-bottom: 4px;
+ }
+
+ .overlay-row {
+ display: flex;
+ justify-content: center;
+ gap: 12px;
+ font-size: 11px;
+ margin-bottom: 6px;
+ }
+
+ .overlay-stat {
+ text-align: left;
+ color: var(--muted);
+ }
+
+ .overlay-stat span {
+ display: block;
+ color: var(--text);
+ }
+
+ .overlay-footer {
+ font-size: 10px;
+ color: var(--muted);
+ margin-top: 6px;
+ }
+
+ .overlay-footer strong {
+ color: var(--accent);
+ }
+
+ .hidden {
+ display: none;
+ }
+</style>
+</head>
+<body>
+<div class="frame">
+ <div class="chrome">
+ <div class="top-bar">
+ <div class="top-left">
+ <span class="brand">AGENT REFLEX</span>
+ <div class="divider"></div>
+ <div class="mode-pill">
+ <div class="mode-dot"></div>
+ TRAINING MODE
+ </div>
+ <div class="lights">
+ <div class="light on"></div>
+ <div class="light"></div>
+ <div class="light"></div>
+ </div>
+ </div>
+ <div class="top-right">
+ <span>CMD CTR / NEURO-RESPONSE</span>
+ <div class="divider"></div>
+ <span id="sessionTag">SESSION 01</span>
+ </div>
+ </div>
+
+ <div class="content">
+ <div class="arena-shell">
+ <div class="grid"></div>
+ <div class="scanline"></div>
+ <div class="arena-inner">
+ <canvas id="arenaCanvas"></canvas>
+ <div class="hud-overlay">
+ <div class="hud-block">
+ <div class="hud-label">Time Window</div>
+ <div class="hud-value">
+ <span class="hud-main-number" id="timeDisplay">30.0</span>
+ <span class="hud-sub" id="comboDisplay">x1 COMBO</span>
+ </div>
+ <div class="status-bar">
+ <div class="status-pip"></div>
+ <span id="statusText">STAND BY</span>
+ </div>
+ </div>
+ <div class="hud-right">
+ <div class="hud-block">
+ <div class="hud-label">Score Channel</div>
+ <div class="hud-value">
+ <span class="hud-main-number" id="scoreDisplay">000000</span>
+ <span class="hud-sub" id="accuracyDisplay">100% ACC</span>
+ </div>
+ </div>
+ <div class="meta-line">PB: <span id="bestScoreHud">000000</span> / NODE <span id="nodeRateHud">0.0</span>/s</div>
+ </div>
+ </div>
+
+ <div class="overlay" id="startOverlay">
+ <div class="overlay-inner">
+ <div class="overlay-title">AGENT REFLEX</div>
+ <div class="overlay-subtitle">Neural Acquisition Calibration • 30 Second Window</div>
+ <p style="font-size:11px; color:var(--muted); margin-bottom:10px;">
+ Glowing nodes will materialize across the grid. Acquire each before it phases out to
+ stabilize your signal. Chain uninterrupted hits to raise your <span style="color:var(--accent-secondary);">combo multiplier</span>.
+ </p>
+ <div class="overlay-row" style="margin-bottom:8px;">
+ <div class="overlay-stat">
+ INPUT MAP
+ <span>
+ • MOUSE / TAP: Acquire node<br>
+ • SPACE / ENTER: Start / Restart
+ </span>
+ </div>
+ </div>
+ <button class="btn" id="startButton">
+ <span class="btn-label-primary">Launch Sequence</span>
+ <span class="btn-shortcut">[SPACE]</span>
+ </button>
+ <div class="overlay-footer">
+ Window duration: <strong>30.0s</strong> • Node lifetime: <strong>600–900ms</strong> • Engine: <strong>60Hz</strong>
+ </div>
+ </div>
+ </div>
+
+ <div class="overlay hidden" id="endOverlay">
+ <div class="overlay-inner">
+ <div class="overlay-title">Window Closed</div>
+ <div class="overlay-subtitle">Acquisition Summary</div>
+ <div class="overlay-main-score" id="finalScoreDisplay">000000</div>
+ <div class="overlay-row">
+ <div class="overlay-stat">
+ HITS
+ <span id="finalHits">0</span>
+ </div>
+ <div class="overlay-stat">
+ MISSES
+ <span id="finalMisses">0</span>
+ </div>
+ <div class="overlay-stat">
+ ACCURACY
+ <span id="finalAccuracy">0%</span>
+ </div>
+ </div>
+ <div class="overlay-row">
+ <div class="overlay-stat">
+ PEAK COMBO
+ <span id="finalPeakCombo">x1</span>
+ </div>
+ <div class="overlay-stat">
+ NODES / S
+ <span id="finalNodesPerSec">0.0</span>
+ </div>
+ <div class="overlay-stat">
+ PERSONAL BEST
+ <span id="finalBestFlag">UNCHANGED</span>
+ </div>
+ </div>
+ <button class="btn btn-secondary" id="restartButton">
+ <span class="btn-label-secondary">Re-Arm Grid</span>
+ <span class="btn-shortcut">[SPACE]</span>
+ </button>
+ <div class="overlay-footer">
+ Hold your cursor near the <strong>center of mass</strong> of the grid; track with minimal travel
+ to optimize latency.
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <aside class="control-panel">
+ <div class="panel-header">
+ <div>
+ <div class="panel-title">Command Console</div>
+ <div class="panel-sub">Session Telemetry</div>
+ </div>
+ <div class="mode-pill" style="font-size:10px; padding-inline:8px;">
+ LIVE FEED
+ </div>
+ </div>
+
+ <div class="score-grid">
+ <div class="score-card">
+ <div class="score-label">Current Round</div>
+ <div class="score-value">
+ <span class="score-main" id="sideScore">000000</span>
+ <span class="score-tag" id="sideCombo">x1</span>
+ </div>
+ </div>
+ <div class="score-card">
+ <div class="score-label">Best Calibration</div>
+ <div class="score-value">
+ <span class="score-main" id="bestScoreDisplay">000000</span>
+ <span class="score-alt">PB</span>
+ </div>
+ </div>
+ </div>
+
+ <div class="meter-row">
+ <div class="meter-label-row">
+ <span>Signal Stability</span>
+ <span id="accuracySide">100% ACC</span>
+ </div>
+ <div class="meter-bar">
+ <div class="meter-fill" id="accuracyMeter"></div>
+ <div class="meter-ticks"></div>
+ </div>
+
+ <div class="meter-label-row">
+ <span>Combo Uplink</span>
+ <span id="comboSide">x1</span>
+ </div>
+ <div class="meter-bar">
+ <div class="meter-fill" id="comboMeter"></div>
+ <div class="meter-ticks"></div>
+ </div>
+ </div>
+
+ <div class="hint-row">
+ <div class="hint-text">
+ Acquire every target node before phase-out to maintain uplink integrity.
+ </div>
+ <div class="keycaps">
+ <div class="keycap">SPACE</div>
+ <div class="keycap">ENTER</div>
+ </div>
+ </div>
+
+ <div class="btn-row">
+ <button class="btn" id="controlStart">
+ <span class="btn-label-primary" id="controlStartLabel">Arm Grid</span>
+ <span class="btn-shortcut">[SPACE]</span>
+ </button>
+ <button class="btn btn-secondary" id="controlResetBest">
+ <span class="btn-label-secondary">Wipe PB</span>
+ </button>
+ </div>
+
+ <div class="log" id="logBox">
+ <div class="log-line">System boot: <strong>Agent Reflex</strong> neural lattice online.</div>
+ </div>
+ </aside>
+ </div>
+ </div>
+</div>
+
+<script>
+(function () {
+ 'use strict';
+
+ const ROUND_DURATION = 30.0;
+ const MIN_NODE_LIFETIME = 0.6;
+ const MAX_NODE_LIFETIME = 0.9;
+ const SPAWN_INTERVAL_MIN = 0.18;
+ const SPAWN_INTERVAL_MAX = 0.42;
+ const BASE_SCORE_PER_HIT = 100;
+ const COMBO_DECAY_ON_MISS = 0.5;
+ const MAX_COMBO_LEVEL = 10;
+
+ const canvas = document.getElementById('arenaCanvas');
+ const ctx = canvas.getContext('2d');
+
+ const timeDisplay = document.getElementById('timeDisplay');
+ const comboDisplay = document.getElementById('comboDisplay');
+ const scoreDisplay = document.getElementById('scoreDisplay');
+ const accuracyDisplay = document.getElementById('accuracyDisplay');
+ const statusText = document.getElementById('statusText');
+ const bestScoreHud = document.getElementById('bestScoreHud');
+ const nodeRateHud = document.getElementById('nodeRateHud');
+
+ const sideScore = document.getElementById('sideScore');
+ const sideCombo = document.getElementById('sideCombo');
+ const bestScoreDisplay = document.getElementById('bestScoreDisplay');
+
+ const accuracySide = document.getElementById('accuracySide');
+ const accuracyMeter = document.getElementById('accuracyMeter');
+ const comboSide = document.getElementById('comboSide');
+ const comboMeter = document.getElementById('comboMeter');
+
+ const logBox = document.getElementById('logBox');
+
+ const startOverlay = document.getElementById('startOverlay');
+ const endOverlay = document.getElementById('endOverlay');
+ const startButton = document.getElementById('startButton');
+ const restartButton = document.getElementById('restartButton');
+
+ const controlStart = document.getElementById('controlStart');
+ const controlStartLabel = document.getElementById('controlStartLabel');
+ const controlResetBest = document.getElementById('controlResetBest');
+
+ const finalScoreDisplay = document.getElementById('finalScoreDisplay');
+ const finalHits = document.getElementById('finalHits');
+ const finalMisses = document.getElementById('finalMisses');
+ const finalAccuracy = document.getElementById('finalAccuracy');
+ const finalPeakCombo = document.getElementById('finalPeakCombo');
+ const finalNodesPerSec = document.getElementById('finalNodesPerSec');
+ const finalBestFlag = document.getElementById('finalBestFlag');
+
+ const sessionTag = document.getElementById('sessionTag');
+
+ let bestScore = 0;
+
+ function loadBestScore() {
+ try {
+ const v = localStorage.getItem('agent_reflex_best_score');
+ if (v != null) bestScore = parseInt(v, 10) || 0;
+ } catch (e) {}
+ bestScoreDisplay.textContent = formatScore(bestScore);
+ bestScoreHud.textContent = formatScore(bestScore);
+ }
+
+ function saveBestScore() {
+ try {
+ localStorage.setItem('agent_reflex_best_score', String(bestScore));
+ } catch (e) {}
+ }
+
+ function wipeBestScore() {
+ bestScore = 0;
+ saveBestScore();
+ bestScoreDisplay.textContent = formatScore(bestScore);
+ bestScoreHud.textContent = formatScore(bestScore);
+ appendLog('PB registry cleared. Fresh calibration required.');
+ }
+
+ function formatScore(v) {
+ const s = Math.max(0, Math.floor(v)).toString();
+ return s.padStart(6, '0');
+ }
+
+ function formatTime(t) {
+ return t.toFixed(1);
+ }
+
+ function formatPercent(p) {
+ return `${Math.round(p)}%`;
+ }
+
+ function clamp(v, min, max) {
+ return v < min ? min : v > max ? max : v;
+ }
+
+ let playing = false;
+ let roundEnded = false;
+ let timeRemaining = ROUND_DURATION;
+ let score = 0;
+ let hits = 0;
+ let misses = 0;
+ let totalNodesSpawned = 0;
+
+ let combo = 1;
+ let comboLevel = 1;
+ let peakCombo = 1;
+
+ let nodes = [];
+ let spawnTimer = 0;
+ let nextSpawnIn = 0.3;
+
+ let lastTimestamp = 0;
+
+ let lastClickWasHit = false;
+ let clickFlash = 0;
+
+ function resetState() {
+ playing = false;
+ roundEnded = false;
+ timeRemaining = ROUND_DURATION;
+ score = 0;
+ hits = 0;
+ misses = 0;
+ totalNodesSpawned = 0;
+ combo = 1;
+ comboLevel = 1;
+ peakCombo = 1;
+ nodes = [];
+ spawnTimer = 0;
+ nextSpawnIn = 0.3;
+ lastTimestamp = 0;
+ lastClickWasHit = false;
+ clickFlash = 0;
+
+ updateHUDInstant();
+
+ statusText.textContent = 'ARMED - WAITING FOR TRIGGER';
+ controlStartLabel.textContent = 'Arm Grid';
+ endOverlay.classList.add('hidden');
+ startOverlay.classList.remove('hidden');
+
+ const sessionId = String(Math.floor(Date.now() / 1000) % 1000).padStart(3, '0');
+ sessionTag.textContent = `SESSION ${sessionId}`;
+ }
+
+ function startRound() {
+ if (playing) return;
+ playing = true;
+ roundEnded = false;
+ timeRemaining = ROUND_DURATION;
+ score = 0;
+ hits = 0;
+ misses = 0;
+ totalNodesSpawned = 0;
+ combo = 1;
+ comboLevel = 1;
+ peakCombo = 1;
+ nodes = [];
+ spawnTimer = 0;
+ nextSpawnIn = randRange(SPAWN_INTERVAL_MIN, SPAWN_INTERVAL_MAX);
+ lastTimestamp = performance.now();
+ statusText.textContent = 'LIVE - ACQUIRE TARGETS';
+ controlStartLabel.textContent = 'Abort';
+ startOverlay.classList.add('hidden');
+ endOverlay.classList.add('hidden');
+ appendLog('Round started. Window active for 30 seconds.');
+ requestAnimationFrame(loop);
+ }
+
+ function endRound() {
+ if (roundEnded) return;
+ playing = false;
+ roundEnded = true;
+ statusText.textContent = 'WINDOW CLOSED';
+ controlStartLabel.textContent = 'Re-Arm';
+ nodes = [];
+
+ const accuracy = hits + misses > 0 ? (hits / (hits + misses)) * 100 : 0;
+ const nodesPerSec = totalNodesSpawned / ROUND_DURATION;
+ const scoreInt = Math.round(score);
+
+ const isNewBest = scoreInt > bestScore;
+ if (isNewBest) {
+ bestScore = scoreInt;
+ saveBestScore();
+ bestScoreDisplay.textContent = formatScore(bestScore);
+ bestScoreHud.textContent = formatScore(bestScore);
+ }
+
+ finalScoreDisplay.textContent = formatScore(scoreInt);
+ finalHits.textContent = String(hits);
+ finalMisses.textContent = String(misses);
+ finalAccuracy.textContent = formatPercent(accuracy);
+ finalPeakCombo.textContent = `x${Math.max(1, Math.floor(peakCombo))}`;
+ finalNodesPerSec.textContent = nodesPerSec.toFixed(2);
+ finalBestFlag.textContent = isNewBest ? 'NEW RECORD' : 'UNCHANGED';
+ finalBestFlag.style.color = isNewBest ? 'var(--accent)' : 'var(--muted)';
+
+ appendLog(
+ `Window closed: score <strong>${formatScore(scoreInt)}</strong> / ` +
+ `hits <span>${hits}</span> / misses <span>${misses}</span> / ` +
+ `peak combo <span>x${Math.max(1, Math.floor(peakCombo))}</span>.`
+ );
+
+ setTimeout(() => {
+ endOverlay.classList.remove('hidden');
+ }, 250);
+ }
+
+ function updateHUDInstant() {
+ const accuracy = hits + misses > 0 ? (hits / (hits + misses)) * 100 : 100;
+ timeDisplay.textContent = formatTime(timeRemaining);
+ scoreDisplay.textContent = formatScore(score);
+ sideScore.textContent = formatScore(score);
+ comboDisplay.textContent = `x${Math.max(1, Math.floor(combo))} COMBO`;
+ sideCombo.textContent = `x${Math.max(1, Math.floor(combo))}`;
+ comboSide.textContent = `x${Math.max(1, Math.floor(combo))}`;
+ const accText = hits + misses === 0 ? '100% ACC' : `${formatPercent(accuracy)} ACC`;
+ accuracyDisplay.textContent = accText;
+ accuracySide.textContent = accText;
+
+ const accNorm = accuracy / 100;
+ accuracyMeter.style.width = `${clamp(accNorm, 0, 1) * 100}%`;
+
+ const comboNorm = clamp((combo - 1) / (MAX_COMBO_LEVEL - 1), 0, 1);
+ comboMeter.style.width = `${comboNorm * 100}%`;
+
+ const nodesPerSec = totalNodesSpawned / (ROUND_DURATION - timeRemaining || ROUND_DURATION);
+ nodeRateHud.textContent = isFinite(nodesPerSec) ? nodesPerSec.toFixed(2) : '0.00';
+ }
+
+ function updateHUD(dt) {
+ updateHUDInstant();
+ }
+
+ function appendLog(html) {
+ const div = document.createElement('div');
+ div.className = 'log-line';
+ div.innerHTML = html;
+ logBox.appendChild(div);
+ while (logBox.children.length > 5) {
+ logBox.removeChild(logBox.firstChild);
+ }
+ logBox.scrollTop = logBox.scrollHeight;
+ }
+
+ function randRange(min, max) {
+ return Math.random() * (max - min) + min;
+ }
+
+ function spawnNode() {
+ const margin = 24;
+ const w = canvas.width;
+ const h = canvas.height;
+ const x = randRange(margin, w - margin);
+ const y = randRange(margin, h - margin);
+ const lifetime = randRange(MIN_NODE_LIFETIME, MAX_NODE_LIFETIME);
+ const now = performance.now() / 1000;
+ nodes.push({
+ x,
+ y,
+ radius: 22,
+ spawnTime: now,
+ lifetime,
+ hit: false
+ });
+ totalNodesSpawned++;
+ }
+
+ function handleClick(ev) {
+ const rect = canvas.getBoundingClientRect();
+ const scaleX = canvas.width / rect.width;
+ const scaleY = canvas.height / rect.height;
+ const x = (ev.clientX - rect.left) * scaleX;
+ const y = (ev.clientY - rect.top) * scaleY;
+
+ if (!playing) return;
+
+ let hitSomething = false;
+ let hitIndex = -1;
+ let hitDistSq = Infinity;
+
+ for (let i = 0; i < nodes.length; i++) {
+ const n = nodes[i];
+ if (n.hit) continue;
+ const dx = x - n.x;
+ const dy = y - n.y;
+ const distSq = dx * dx + dy * dy;
+ const r = n.radius * 0.9;
+ if (distSq <= r * r && distSq < hitDistSq) {
+ hitDistSq = distSq;
+ hitIndex = i;
+ }
+ }
+
+ if (hitIndex >= 0) {
+ const n = nodes[hitIndex];
+ n.hit = true;
+ const reward = BASE_SCORE_PER_HIT * combo;
+ score += reward;
+ hits++;
+ combo = Math.min(combo + 0.15, MAX_COMBO_LEVEL);
+ comboLevel = Math.max(comboLevel, combo);
+ peakCombo = Math.max(peakCombo, combo);
+ lastClickWasHit = true;
+ clickFlash = 1.0;
+
+ const acc = hits + misses > 0 ? (hits / (hits + misses)) * 100 : 100;
+ statusText.textContent = `HIT • +${Math.round(reward)} / COMBO x${Math.max(1, Math.floor(combo))}`;
+ if (Math.abs(combo - Math.round(combo)) < 0.05 && combo > 1) {
+ appendLog(
+ `Combo stabilized at <span>x${Math.round(combo)}</span> • ` +
+ `accuracy <strong>${formatPercent(acc)}</strong>.`
+ );
+ }
+ } else {
+ misses++;
+ combo = Math.max(1, combo * COMBO_DECAY_ON_MISS);
+ lastClickWasHit = false;
+ clickFlash = 1.0;
+ statusText.textContent = 'MISS • UPLINK DEGRADED';
+ }
+
+ updateHUDInstant();
+ }
+
+ canvas.addEventListener('mousedown', handleClick);
+ canvas.addEventListener('touchstart', function (e) {
+ if (e.touches && e.touches.length > 0) {
+ handleClick(e.touches[0]);
+ e.preventDefault();
+ }
+ }, { passive: false });
+
+ function resizeCanvas() {
+ const rect = canvas.parentElement.getBoundingClientRect();
+ const dpr = window.devicePixelRatio || 1;
+ const width = rect.width;
+ const height = rect.height;
+ canvas.width = width * dpr;
+ canvas.height = height * dpr;
+ canvas.style.width = width + 'px';
+ canvas.style.height = height + 'px';
+ ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
+ }
+
+ window.addEventListener('resize', resizeCanvas);
+
+ function loop(timestamp) {
+ if (!playing) {
+ render(0);
+ return;
+ }
+
+ if (!lastTimestamp) lastTimestamp = timestamp;
+ let dt = (timestamp - lastTimestamp) / 1000;
+ if (dt > 0.05) dt = 0.05;
+ lastTimestamp = timestamp;
+
+ step(dt);
+ render(dt);
+
+ if (playing) {
+ requestAnimationFrame(loop);
+ }
+ }
+
+ function step(dt) {
+ timeRemaining -= dt;
+ if (timeRemaining <= 0) {
+ timeRemaining = 0;
+ updateHUD(dt);
+ endRound();
+ return;
+ }
+
+ spawnTimer += dt;
+ if (spawnTimer >= nextSpawnIn) {
+ spawnTimer = 0;
+ nextSpawnIn = randRange(SPAWN_INTERVAL_MIN, SPAWN_INTERVAL_MAX);
+ spawnNode();
+ }
+
+ const now = performance.now() / 1000;
+ let expiredMisses = 0;
+ for (let i = nodes.length - 1; i >= 0; i--) {
+ const n = nodes[i];
+ const age = now - n.spawnTime;
+ if (age >= n.lifetime) {
+ if (!n.hit) {
+ expiredMisses++;
+ }
+ nodes.splice(i, 1);
+ }
+ }
+ if (expiredMisses > 0) {
+ misses += expiredMisses;
+ combo = Math.max(1, combo * Math.pow(COMBO_DECAY_ON_MISS, expiredMisses));
+ statusText.textContent = 'NODE LOST • SIGNAL DIP';
+ }
+
+ if (clickFlash > 0) {
+ clickFlash -= dt * 3;
+ if (clickFlash < 0) clickFlash = 0;
+ }
+
+ updateHUD(dt);
+ }
+
+ function render(dt) {
+ const w = canvas.width / (window.devicePixelRatio || 1);
+ const h = canvas.height / (window.devicePixelRatio || 1);
+
+ ctx.clearRect(0, 0, w, h);
+
+ const now = performance.now() / 1000;
+ const baseHueOuter = 185;
+ const baseHueInner = 185;
+
+ for (let i = 0; i < nodes.length; i++) {
+ const n = nodes[i];
+ const age = now - n.spawnTime;
+ const t = clamp(age / n.lifetime, 0, 1);
+ const appear = t < 0.2 ? t / 0.2 : 1;
+ const fade = t > 0.7 ? 1 - (t - 0.7) / 0.3 : 1;
+ const alpha = clamp(appear * fade, 0, 1);
+
+ const cx = n.x;
+ const cy = n.y;
+ const radius = n.radius;
+
+ const hueShift = n.hit ? 140 : baseHueOuter;
+ const glowAlpha = alpha * 0.8;
+
+ ctx.save();
+
+ const gradientOuter = ctx.createRadialGradient(
+ cx, cy, radius * 0.1,
+ cx, cy, radius * 1.7
+ );
+ gradientOuter.addColorStop(0, `rgba(38, 246, 255, ${0.12 * glowAlpha})`);
+ gradientOuter.addColorStop(0.6, `rgba(38, 246, 255, ${0.08 * glowAlpha})`);
+ gradientOuter.addColorStop(1, 'rgba(0,0,0,0)');
+ ctx.fillStyle = gradientOuter;
+ ctx.beginPath();
+ ctx.arc(cx, cy, radius * 1.7, 0, Math.PI * 2);
+ ctx.fill();
+
+ const gradientCore = ctx.createRadialGradient(
+ cx, cy, 0,
+ cx, cy, radius
+ );
+ const hueInner = n.hit ? 140 : baseHueInner;
+ gradientCore.addColorStop(0, `hsla(${hueInner}, 100%, 70%, ${0.95 * alpha})`);
+ gradientCore.addColorStop(0.6, `hsla(${hueInner}, 100%, 55%, ${0.85 * alpha})`);
+ gradientCore.addColorStop(1, `hsla(${hueInner}, 100%, 45%, ${0.0})`);
+ ctx.fillStyle = gradientCore;
+ ctx.beginPath();
+ ctx.arc(cx, cy, radius, 0, Math.PI * 2);
+ ctx.fill();
+
+ ctx.strokeStyle = `rgba(255,255,255,${0.55 * alpha})`;
+ ctx.lineWidth = 1.2;
+ ctx.beginPath();
+ ctx.arc(cx, cy, radius * 0.7, 0, Math.PI * 2);
+ ctx.stroke();
+
+ ctx.strokeStyle = `rgba(0, 10, 20, ${0.85 * alpha})`;
+ ctx.lineWidth = 1.3;
+ ctx.beginPath();
+ ctx.arc(cx, cy, radius * 0.25, 0, Math.PI * 2);
+ ctx.stroke();
+
+ ctx.globalAlpha = 0.6 * alpha;
+ ctx.strokeStyle = `rgba(5, 250, 255, 0.8)`;
+ ctx.lineWidth = 1;
+ ctx.setLineDash([4, 4]);
+ ctx.beginPath();
+ ctx.arc(cx, cy, radius * (1.1 + Math.sin(now * 4 + i) * 0.08), 0, Math.PI * 2);
+ ctx.stroke();
+ ctx.setLineDash([]);
+
+ ctx.restore();
+ }
+
+ if (clickFlash > 0) {
+ const intensity = clickFlash;
+ const color = lastClickWasHit ? '0, 255, 160' : '255, 60, 120';
+ ctx.save();
+ ctx.fillStyle = `rgba(${color}, ${0.16 * intensity})`;
+ ctx.fillRect(0, 0, w, h);
+ ctx.restore();
+ }
+
+ const borderAlpha = 0.35 + 0.12 * Math.sin(performance.now() / 700);
+ ctx.save();
+ ctx.strokeStyle = `rgba(38, 246, 255, ${borderAlpha})`;
+ ctx.lineWidth = 1;
+ ctx.strokeRect(4.5, 4.5, w - 9, h - 9);
+ ctx.strokeStyle = `rgba(255, 46, 166, ${borderAlpha * 0.6})`;
+ ctx.strokeRect(10.5, 10.5, w - 21, h - 21);
+ ctx.restore();
+
+ const nodeCount = nodes.length;
+ const bars = Math.min(6, nodeCount);
+ if (bars > 0) {
+ const barWidth = 3;
+ const margin = 4;
+ const startX = w - margin - barWidth;
+ const baseY = h - margin;
+ const maxHeight = 18;
+
+ ctx.save();
+ for (let i = 0; i < bars; i++) {
+ const heightNorm = (i + 1) / bars;
+ const barHeight = maxHeight * heightNorm;
+ const x = startX - i * (barWidth + 2);
+ ctx.fillStyle = `rgba(38, 246, 255, ${0.18 + 0.1 * heightNorm})`;
+ ctx.fillRect(x, baseY - barHeight, barWidth, barHeight);
+ ctx.fillStyle = `rgba(255, 46, 166, ${0.12 + 0.08 * heightNorm})`;
+ ctx.fillRect(x, baseY - barHeight, barWidth, 1);
+ }
+ ctx.restore();
+ }
+ }
+
+ function handleKeyDown(ev) {
+ if (ev.code === 'Space' || ev.code === 'Enter') {
+ ev.preventDefault();
+ if (!playing && !roundEnded) {
+ startRound();
+ } else if (playing) {
+ playing = false;
+ roundEnded = true;
+ statusText.textContent = 'ABORTED';
+ controlStartLabel.textContent = 'Re-Arm';
+ nodes = [];
+ appendLog('Run aborted by operator. No score registered.');
+ } else if (!playing && roundEnded) {
+ resetState();
+ startRound();
+ }
+ }
+ }
+
+ startButton.addEventListener('click', startRound);
+ restartButton.addEventListener('click', function () {
+ resetState();
+ startRound();
+ });
+ controlStart.addEventListener('click', function () {
+ if (!playing && !roundEnded) {
+ startRound();
+ } else if (playing) {
+ playing = false;
+ roundEnded = true;
+ statusText.textContent = 'ABORTED';
+ controlStartLabel.textContent = 'Re-Arm';
+ nodes = [];
+ appendLog('Run aborted by operator. No score registered.');
+ } else if (!playing && roundEnded) {
+ resetState();
+ startRound();
+ }
+ });
+ controlResetBest.addEventListener('click', function () {
+ wipeBestScore();
+ });
+
+ window.addEventListener('keydown', handleKeyDown);
+
+ resizeCanvas();
+ loadBestScore();
+ resetState();
+ render(0);
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/f585b9cfcaea/gpt.png b/data/artifacts/f585b9cfcaea/gpt.png
new file mode 100644
index 0000000..2ba7188
Binary files /dev/null and b/data/artifacts/f585b9cfcaea/gpt.png differ
diff --git a/data/artifacts/f585b9cfcaea/grok.html b/data/artifacts/f585b9cfcaea/grok.html
new file mode 100644
index 0000000..0110675
--- /dev/null
+++ b/data/artifacts/f585b9cfcaea/grok.html
@@ -0,0 +1,377 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Agent Reflex</title>
+<style>
+*{margin:0;padding:0;box-sizing:border-box}
+html,body{width:100%;height:100%;overflow:hidden;background:#050510;font-family:'Segoe UI',system-ui,sans-serif;color:#0ff;cursor:crosshair;user-select:none}
+canvas{display:block;position:absolute;inset:0;width:100%;height:100%}
+#ui{position:absolute;inset:0;pointer-events:none;z-index:10}
+.hud{position:absolute;top:0;left:0;right:0;padding:16px 24px;display:flex;justify-content:space-between;align-items:flex-start;background:linear-gradient(180deg,rgba(0,20,40,.85) 0%,transparent 100%)}
+.stat{text-align:center;min-width:90px}
+.stat .label{font-size:10px;letter-spacing:3px;text-transform:uppercase;color:#0af8;opacity:.8;margin-bottom:2px}
+.stat .val{font-size:28px;font-weight:700;text-shadow:0 0 12px #0ff,0 0 24px #0ff4;font-variant-numeric:tabular-nums}
+.stat.combo .val{color:#f0f;text-shadow:0 0 12px #f0f,0 0 24px #f0f4}
+.stat.miss .val{color:#f44;text-shadow:0 0 12px #f44}
+.stat.best .val{color:#ff0;text-shadow:0 0 12px #ff0,0 0 24px #ff04;font-size:22px}
+#timer-bar{position:absolute;top:0;left:0;height:3px;background:linear-gradient(90deg,#0ff,#f0f);box-shadow:0 0 10px #0ff,0 0 20px #f0f;transition:width .1s linear;width:100%}
+#overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:rgba(2,5,15,.92);z-index:20;pointer-events:auto;transition:opacity .3s}
+#overlay.hidden{opacity:0;pointer-events:none}
+.title{font-size:48px;font-weight:800;letter-spacing:8px;text-transform:uppercase;background:linear-gradient(135deg,#0ff,#f0f,#0ff);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;filter:drop-shadow(0 0 20px #0ff8);margin-bottom:8px}
+.subtitle{font-size:14px;letter-spacing:6px;color:#0af;opacity:.7;margin-bottom:32px;text-transform:uppercase}
+.score-big{font-size:72px;font-weight:800;color:#0ff;text-shadow:0 0 30px #0ff,0 0 60px #0ff6;margin:16px 0;font-variant-numeric:tabular-nums}
+.score-label{font-size:12px;letter-spacing:4px;color:#0af8;text-transform:uppercase}
+.btn{margin-top:28px;padding:14px 48px;font-size:16px;font-weight:700;letter-spacing:4px;text-transform:uppercase;color:#050510;background:linear-gradient(135deg,#0ff,#0cf);border:none;border-radius:4px;cursor:pointer;box-shadow:0 0 20px #0ff8,0 0 40px #0ff4;transition:transform .15s,box-shadow .15s;pointer-events:auto}
+.btn:hover{transform:scale(1.05);box-shadow:0 0 30px #0ff,0 0 60px #0ff6}
+.btn:active{transform:scale(.98)}
+.final-stats{display:flex;gap:40px;margin-top:20px}
+.final-stats .fs{text-align:center}
+.final-stats .fs .fl{font-size:10px;letter-spacing:2px;color:#0af6;text-transform:uppercase}
+.final-stats .fs .fv{font-size:24px;font-weight:700;color:#0ff;text-shadow:0 0 10px #0ff}
+#combo-flash{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);font-size:64px;font-weight:900;color:#f0f;text-shadow:0 0 30px #f0f,0 0 60px #f0f;opacity:0;pointer-events:none;z-index:15;letter-spacing:4px}
+.scanlines{position:absolute;inset:0;background:repeating-linear-gradient(0deg,transparent,transparent 2px,rgba(0,0,0,.03) 2px,rgba(0,0,0,.03) 4px);pointer-events:none;z-index:5}
+.vignette{position:absolute;inset:0;background:radial-gradient(ellipse at center,transparent 50%,rgba(0,0,0,.5) 100%);pointer-events:none;z-index:4}
+#grid-bg{position:absolute;inset:0;z-index:0}
+</style>
+</head>
+<body>
+<canvas id="grid-bg"></canvas>
+<canvas id="game"></canvas>
+<div class="scanlines"></div>
+<div class="vignette"></div>
+<div id="ui">
+ <div id="timer-bar"></div>
+ <div class="hud">
+ <div class="stat"><div class="label">Score</div><div class="val" id="score">0</div></div>
+ <div class="stat combo"><div class="label">Combo</div><div class="val" id="combo">x1</div></div>
+ <div class="stat"><div class="label">Hits</div><div class="val" id="hits">0</div></div>
+ <div class="stat miss"><div class="label">Miss</div><div class="val" id="misses">0</div></div>
+ <div class="stat best"><div class="label">Best</div><div class="val" id="best">0</div></div>
+ <div class="stat"><div class="label">Time</div><div class="val" id="time">30</div></div>
+ </div>
+</div>
+<div id="combo-flash"></div>
+<div id="overlay">
+ <div class="title">Agent Reflex</div>
+ <div class="subtitle">Neon Command Center // Target Acquisition</div>
+ <div class="score-label" id="overlay-label">Engage when ready</div>
+ <div class="score-big" id="overlay-score" style="display:none">0</div>
+ <div class="final-stats" id="final-stats" style="display:none">
+ <div class="fs"><div class="fl">Hits</div><div class="fv" id="fs-hits">0</div></div>
+ <div class="fs"><div class="fl">Misses</div><div class="fv" id="fs-miss">0</div></div>
+ <div class="fs"><div class="fl">Max Combo</div><div class="fv" id="fs-combo">0</div></div>
+ <div class="fs"><div class="fl">Best</div><div class="fv" id="fs-best">0</div></div>
+ </div>
+ <button class="btn" id="start-btn">Initialize</button>
+</div>
+<script>
+(function(){
+const canvas=document.getElementById('game');
+const ctx=canvas.getContext('2d');
+const bgCanvas=document.getElementById('grid-bg');
+const bgCtx=bgCanvas.getContext('2d');
+const overlay=document.getElementById('overlay');
+const startBtn=document.getElementById('start-btn');
+const timerBar=document.getElementById('timer-bar');
+const comboFlash=document.getElementById('combo-flash');
+const el={score:document.getElementById('score'),combo:document.getElementById('combo'),hits:document.getElementById('hits'),misses:document.getElementById('misses'),best:document.getElementById('best'),time:document.getElementById('time')};
+
+let W,H,dpr;
+let running=false;
+let score=0,hits=0,misses=0,combo=0,maxCombo=0,multiplier=1;
+let best=parseInt(localStorage.getItem('agentReflexBest')||'0',10);
+el.best.textContent=best;
+let timeLeft=30;
+const ROUND=30;
+let targets=[];
+let particles=[];
+let ripples=[];
+let lastSpawn=0;
+let spawnInterval=900;
+let animId;
+let startTime=0;
+let lastFrame=0;
+let gridOffset=0;
+
+const COLORS=['#00ffff','#ff00ff','#00ff88','#ffaa00','#4488ff','#ff4466'];
+
+function resize(){
+ dpr=window.devicePixelRatio||1;
+ W=window.innerWidth;H=window.innerHeight;
+ canvas.width=W*dpr;canvas.height=H*dpr;
+ canvas.style.width=W+'px';canvas.style.height=H+'px';
+ ctx.setTransform(dpr,0,0,dpr,0,0);
+ bgCanvas.width=W*dpr;bgCanvas.height=H*dpr;
+ bgCanvas.style.width=W+'px';bgCanvas.style.height=H+'px';
+ bgCtx.setTransform(dpr,0,0,dpr,0,0);
+ drawGrid();
+}
+window.addEventListener('resize',resize);
+resize();
+
+function drawGrid(){
+ bgCtx.clearRect(0,0,W,H);
+ const g=bgCtx.createRadialGradient(W/2,H/2,0,W/2,H/2,Math.max(W,H)*.7);
+ g.addColorStop(0,'#0a1525');g.addColorStop(1,'#050510');
+ bgCtx.fillStyle=g;bgCtx.fillRect(0,0,W,H);
+ bgCtx.strokeStyle='rgba(0,100,150,0.08)';bgCtx.lineWidth=1;
+ const sp=40;
+ for(let x=0;x<W;x+=sp){bgCtx.beginPath();bgCtx.moveTo(x,0);bgCtx.lineTo(x,H);bgCtx.stroke()}
+ for(let y=0;y<H;y+=sp){bgCtx.beginPath();bgCtx.moveTo(0,y);bgCtx.lineTo(W,y);bgCtx.stroke()}
+ bgCtx.strokeStyle='rgba(0,200,255,0.04)';
+ bgCtx.beginPath();bgCtx.arc(W/2,H/2,Math.min(W,H)*.3,0,Math.PI*2);bgCtx.stroke();
+ bgCtx.beginPath();bgCtx.arc(W/2,H/2,Math.min(W,H)*.45,0,Math.PI*2);bgCtx.stroke();
+}
+
+function spawnTarget(){
+ const margin=60;
+ const r=18+Math.random()*14;
+ const life=900+Math.random()*700-(Math.min(hits,50)*8);
+ const t={
+ x:margin+Math.random()*(W-margin*2),
+ y:margin+80+Math.random()*(H-margin*2-80),
+ r,maxR:r,
+ life:Math.max(450,life),
+ maxLife:Math.max(450,life),
+ color:COLORS[Math.floor(Math.random()*COLORS.length)],
+ born:performance.now(),
+ hit:false,dead:false,
+ pulse:Math.random()*Math.PI*2,
+ rot:Math.random()*Math.PI*2
+ };
+ targets.push(t);
+}
+
+function spawnParticles(x,y,color,n){
+ for(let i=0;i<n;i++){
+ const a=Math.random()*Math.PI*2;
+ const sp=1+Math.random()*5;
+ particles.push({
+ x,y,vx:Math.cos(a)*sp,vy:Math.sin(a)*sp,
+ life:1,decay:.015+Math.random()*.025,
+ r:1.5+Math.random()*3,color
+ });
+ }
+}
+
+function spawnRipple(x,y,color){
+ ripples.push({x,y,r:5,maxR:60+Math.random()*40,life:1,color});
+}
+
+function flashCombo(text){
+ comboFlash.textContent=text;
+ comboFlash.style.opacity='1';
+ comboFlash.style.transition='none';
+ comboFlash.style.transform='translate(-50%,-50%) scale(1.2)';
+ requestAnimationFrame(()=>{
+ comboFlash.style.transition='opacity .5s, transform .5s';
+ comboFlash.style.opacity='0';
+ comboFlash.style.transform='translate(-50%,-50%) scale(1.8)';
+ });
+}
+
+function updateHUD(){
+ el.score.textContent=score;
+ el.combo.textContent='x'+multiplier;
+ el.hits.textContent=hits;
+ el.misses.textContent=misses;
+ el.time.textContent=Math.ceil(timeLeft);
+ el.best.textContent=best;
+ timerBar.style.width=(timeLeft/ROUND*100)+'%';
+ if(timeLeft<5)timerBar.style.background='linear-gradient(90deg,#f44,#f0f)';
+ else timerBar.style.background='linear-gradient(90deg,#0ff,#f0f)';
+}
+
+function onClick(e){
+ if(!running)return;
+ const x=e.clientX,y=e.clientY;
+ let hitAny=false;
+ for(let i=targets.length-1;i>=0;i--){
+ const t=targets[i];
+ if(t.dead||t.hit)continue;
+ const dx=x-t.x,dy=y-t.y;
+ const dist=Math.sqrt(dx*dx+dy*dy);
+ const hitR=t.r+12;
+ if(dist<=hitR){
+ t.hit=true;t.dead=true;
+ hitAny=true;
+ hits++;
+ combo++;
+ if(combo>maxCombo)maxCombo=combo;
+ multiplier=1+Math.floor(combo/3);
+ if(multiplier>8)multiplier=8;
+ const lifeBonus=Math.ceil((t.life/t.maxLife)*10);
+ const pts=(10+lifeBonus)*multiplier;
+ score+=pts;
+ spawnParticles(t.x,t.y,t.color,18);
+ spawnRipple(t.x,t.y,t.color);
+ if(combo>0&&combo%5===0)flashCombo(combo+' COMBO');
+ break;
+ }
+ }
+ if(!hitAny){
+ misses++;
+ combo=0;
+ multiplier=1;
+ spawnParticles(x,y,'#f44',6);
+ }
+ updateHUD();
+}
+
+canvas.addEventListener('mousedown',onClick);
+canvas.addEventListener('touchstart',function(e){
+ e.preventDefault();
+ const t=e.touches[0];
+ onClick({clientX:t.clientX,clientY:t.clientY});
+},{passive:false});
+
+function drawTarget(t,now){
+ const age=now-t.born;
+ t.life=t.maxLife-age;
+ if(t.life<=0){t.dead=true;return}
+ const progress=t.life/t.maxLife;
+ const appear=Math.min(1,age/150);
+ t.pulse+=.08;
+ t.rot+=.02;
+ const breathe=1+Math.sin(t.pulse)*.08;
+ const r=t.maxR*appear*breathe*(.6+.4*progress);
+ t.r=r;
+ const alpha=progress*appear;
+
+ ctx.save();
+ ctx.globalAlpha=alpha*.3;
+ ctx.beginPath();
+ ctx.arc(t.x,t.y,r*2.2,0,Math.PI*2);
+ const glow=ctx.createRadialGradient(t.x,t.y,0,t.x,t.y,r*2.2);
+ glow.addColorStop(0,t.color);glow.addColorStop(1,'transparent');
+ ctx.fillStyle=glow;ctx.fill();
+
+ ctx.globalAlpha=alpha*.6;
+ ctx.beginPath();
+ ctx.arc(t.x,t.y,r*1.4,0,Math.PI*2);
+ ctx.strokeStyle=t.color;ctx.lineWidth=1.5;ctx.stroke();
+
+ ctx.globalAlpha=alpha;
+ ctx.beginPath();
+ ctx.arc(t.x,t.y,r,0,Math.PI*2);
+ const core=ctx.createRadialGradient(t.x,t.y,0,t.x,t.y,r);
+ core.addColorStop(0,'#fff');core.addColorStop(.3,t.color);core.addColorStop(1,t.color+'00');
+ ctx.fillStyle=core;ctx.fill();
+ ctx.strokeStyle=t.color;ctx.lineWidth=2;ctx.stroke();
+
+ ctx.globalAlpha=alpha*.8;
+ ctx.translate(t.x,t.y);ctx.rotate(t.rot);
+ const tick=r+6;
+ ctx.strokeStyle=t.color;ctx.lineWidth=1.5;
+ for(let i=0;i<4;i++){
+ ctx.rotate(Math.PI/2);
+ ctx.beginPath();ctx.moveTo(0,-r-2);ctx.lineTo(0,-tick);ctx.stroke();
+ }
+ ctx.restore();
+
+ ctx.save();
+ ctx.globalAlpha=alpha*.5;
+ ctx.beginPath();
+ ctx.arc(t.x,t.y,r*(.3+.7*(1-progress)),0,Math.PI*2*progress);
+ ctx.strokeStyle='#fff';ctx.lineWidth=2;ctx.stroke();
+ ctx.restore();
+}
+
+function drawParticles(){
+ for(let i=particles.length-1;i>=0;i--){
+ const p=particles[i];
+ p.x+=p.vx;p.y+=p.vy;p.vy+=.04;p.life-=p.decay;
+ if(p.life<=0){particles.splice(i,1);continue}
+ ctx.globalAlpha=p.life;
+ ctx.beginPath();
+ ctx.arc(p.x,p.y,p.r*p.life,0,Math.PI*2);
+ ctx.fillStyle=p.color;ctx.fill();
+ }
+ ctx.globalAlpha=1;
+}
+
+function drawRipples(){
+ for(let i=ripples.length-1;i>=0;i--){
+ const r=ripples[i];
+ r.r+=(r.maxR-r.r)*.08;
+ r.life-=.03;
+ if(r.life<=0){ripples.splice(i,1);continue}
+ ctx.globalAlpha=r.life*.6;
+ ctx.beginPath();
+ ctx.arc(r.x,r.y,r.r,0,Math.PI*2);
+ ctx.strokeStyle=r.color;ctx.lineWidth=2*r.life;ctx.stroke();
+ }
+ ctx.globalAlpha=1;
+}
+
+function loop(now){
+ if(!running)return;
+ const dt=now-lastFrame;
+ lastFrame=now;
+
+ timeLeft=Math.max(0,ROUND-(now-startTime)/1000);
+ if(timeLeft<=0){endGame();return}
+
+ ctx.clearRect(0,0,W,H);
+
+ if(now-lastSpawn>spawnInterval){
+ spawnTarget();
+ if(Math.random()<.3&&hits>5)spawnTarget();
+ lastSpawn=now;
+ spawnInterval=Math.max(350,900-hits*12-Math.random()*100);
+ }
+
+ for(let i=targets.length-1;i>=0;i--){
+ const t=targets[i];
+ if(t.dead){
+ if(!t.hit){misses++;combo=0;multiplier=1;spawnParticles(t.x,t.y,'#666',8)}
+ targets.splice(i,1);
+ continue;
+ }
+ drawTarget(t,now);
+ }
+
+ drawRipples();
+ drawParticles();
+ updateHUD();
+
+ animId=requestAnimationFrame(loop);
+}
+
+function startGame(){
+ score=0;hits=0;misses=0;combo=0;maxCombo=0;multiplier=1;
+ timeLeft=ROUND;targets=[];particles=[];ripples=[];
+ spawnInterval=900;lastSpawn=0;
+ running=true;
+ overlay.classList.add('hidden');
+ startTime=performance.now();
+ lastFrame=startTime;
+ updateHUD();
+ animId=requestAnimationFrame(loop);
+}
+
+function endGame(){
+ running=false;
+ if(animId)cancelAnimationFrame(animId);
+ targets=[];
+ if(score>best){best=score;localStorage.setItem('agentReflexBest',String(best))}
+ document.getElementById('overlay-label').textContent='Mission Complete';
+ document.getElementById('overlay-score').style.display='block';
+ document.getElementById('overlay-score').textContent=score;
+ document.getElementById('final-stats').style.display='flex';
+ document.getElementById('fs-hits').textContent=hits;
+ document.getElementById('fs-miss').textContent=misses;
+ document.getElementById('fs-combo').textContent=maxCombo;
+ document.getElementById('fs-best').textContent=best;
+ startBtn.textContent='Reinitialize';
+ overlay.classList.remove('hidden');
+ updateHUD();
+}
+
+startBtn.addEventListener('click',startGame);
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/f585b9cfcaea/grok.png b/data/artifacts/f585b9cfcaea/grok.png
new file mode 100644
index 0000000..301e0a6
Binary files /dev/null and b/data/artifacts/f585b9cfcaea/grok.png differ
diff --git a/data/artifacts/f585b9cfcaea/hermes3-8b.html b/data/artifacts/f585b9cfcaea/hermes3-8b.html
new file mode 100644
index 0000000..81a6c3b
--- /dev/null
+++ b/data/artifacts/f585b9cfcaea/hermes3-8b.html
@@ -0,0 +1,183 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Agent Reflex</title>
+ <style>
+ body {
+ background: radial-gradient(circle at center, #000, #222);
+ margin: 0;
+ overflow: hidden;
+ }
+ canvas {
+ display: block;
+ }
+ .message {
+ font-family: monospace;
+ position: absolute;
+ top: 10px;
+ left: 10px;
+ color: #0f0;
+ }
+ .score-board {
+ position: absolute;
+ bottom: 10px;
+ right: 10px;
+ display: flex;
+ gap: 5px;
+ font-family: monospace;
+ }
+ .score, .combo, .misses {
+ color: #0f0;
+ }
+ .hits, .score-board {
+ color: #00f;
+ }
+ </style>
+</head>
+<body>
+ <canvas id="game"></canvas>
+ <div class="message">Press any key to start!</div>
+ <div class="score-board">
+ <span class="hits">0</span> hits,
+ <span class="misses">0</span> misses,
+ <span class="combo">x1</span>,
+ <span class="score">0</span> points
+ </div>
+ <script>
+ const canvas = document.getElementById('game');
+ const ctx = canvas.getContext('2d');
+
+ canvas.width = window.innerWidth;
+ canvas.height = window.innerHeight;
+
+ let score = 0, combo = 1, misses = 0;
+ const bestScore = localStorage.getItem('bestAgentReflex') || 0;
+ const targetColor = 'yellow';
+ const targetSizeMin = 20;
+ const targetSizeMax = 40;
+ const targetLifeTime = 3000;
+
+ class Target {
+ constructor(x, y, size) {
+ this.x = x;
+ this.y = y;
+ this.size = size;
+ this.lifeTime = Date.now() + targetLifeTime;
+ }
+
+ draw() {
+ ctx.beginPath();
+ ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
+ if (Date.now() < this.lifeTime) {
+ ctx.fillStyle = targetColor;
+ } else {
+ ctx.fillStyle = '#ccc';
+ }
+ ctx.fill();
+ }
+
+ update() {
+ if (this.lifeTime <= Date.now()) {
+ return true;
+ }
+ return false;
+ }
+ }
+
+ function getRandomTargetPosition() {
+ return {
+ x: Math.random() * canvas.width,
+ y: Math.random() * canvas.height
+ };
+ }
+
+ function drawScoreBoard() {
+ const scoreBoard = document.querySelector('.score-board');
+ scoreBoard.children[0].textContent = hits;
+ scoreBoard.children[1].textContent = misses;
+ scoreBoard.children[2].textContent = 'x' + combo;
+ scoreBoard.children[3].textContent = score;
+ }
+
+ function resetGame() {
+ score = 0, combo = 1, misses = 0;
+ drawScoreBoard();
+ }
+
+ let targets = [];
+ const targetSpawnInterval = 50;
+
+ function gameLoop() {
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+ for (let i = targets.length - 1; i >= 0; i--) {
+ const target = targets[i];
+ target.draw();
+ if (target.update()) {
+ targets.splice(i, 1);
+ }
+ }
+
+ if (hits % 5 === 4) {
+ combo++;
+ }
+
+ hits++;
+
+ if (targets.length === 0 && Date.now() % targetSpawnInterval === 0) {
+ const newPosition = getRandomTargetPosition();
+ targets.push(new Target(newPosition.x, newPosition.y, Math.random() * (targetSizeMax - targetSizeMin) + targetSizeMin));
+ }
+
+ drawScoreBoard();
+
+ if (hits >= score) {
+ score += combo;
+ misses = 0;
+ } else {
+ misses++;
+ }
+
+ if (score > bestScore) {
+ localStorage.setItem('bestAgentReflex', score);
+ }
+
+ if (misses === 5) {
+ resetGame();
+ ctx.fillStyle = 'red';
+ ctx.font = "48px monospace";
+ ctx.fillText(`GAME OVER!`, canvas.width / 2 - 100, canvas.height / 2);
+ }
+ }
+
+ document.addEventListener('click', function(event) {
+ for (let i = targets.length - 1; i >= 0; i--) {
+ const target = targets[i];
+ if (
+ event.clientX > target.x - target.size &&
+ event.clientX < target.x + target.size &&
+ event.clientY > target.y - target.size &&
+ event.clientY < target.y + target.size
+ ) {
+ targets.splice(i, 1);
+ score += combo;
+ combo++;
+ misses = 0;
+ break;
+ }
+ }
+ });
+
+ document.addEventListener('keydown', function() {
+ hits = 0;
+ misses = 0;
+ resetGame();
+ targets.push(new Target(Math.random() * canvas.width, Math.random() * canvas.height, targetSizeMax));
+ });
+
+ setInterval(gameLoop, 10);
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/f585b9cfcaea/hermes3-8b.png b/data/artifacts/f585b9cfcaea/hermes3-8b.png
new file mode 100644
index 0000000..f2d2658
Binary files /dev/null and b/data/artifacts/f585b9cfcaea/hermes3-8b.png differ
diff --git a/data/artifacts/f585b9cfcaea/hf-qwen-coder-32b.html b/data/artifacts/f585b9cfcaea/hf-qwen-coder-32b.html
new file mode 100644
index 0000000..b558c9d
--- /dev/null
+++ b/data/artifacts/f585b9cfcaea/hf-qwen-coder-32b.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Agent Reflex</title>
+<style>
+body { margin: 0; overflow: hidden; background: #0f1a2b; display: flex; justify-content: center; align-items: center; height: 100vh; color: #fff; font-family: 'Arial', sans-serif; }
+#game-container { position: relative; width: 600px; height: 400px; border: 2px solid #53d769; box-shadow: 0 0 20px rgba(83, 215, 105, 0.5); }
+.node { position: absolute; width: 50px; height: 50px; border-radius: 50%; background: #53d769; cursor: pointer; box-shadow: 0 0 10px rgba(83, 215, 105, 0.8); }
+.info { position: absolute; bottom: 10px; left: 10px; font-size: 14px; }
+.best-score { position: absolute; top: 10px; right: 10px; font-size: 14px; }
+button { position: absolute; bottom: 10px; right: 10px; background: #53d769; border: none; color: #fff; padding: 5px 10px; cursor: pointer; box-shadow: 0 0 10px rgba(83, 215, 105, 0.8); }
+button:hover { background: #46c25d; }
+</style>
+</head>
+<body>
+<div id="game-container">
+ <div class="info" id="info">Hits: 0 | Misses: 0 | Score: 0 | Combo: 1</div>
+ <div class="best-score" id="best-score">Best: 0</div>
+ <button onclick="restartGame()">Restart</button>
+</div>
+<script>
+const gameContainer = document.getElementById('game-container');
+const infoDisplay = document.getElementById('info');
+const bestScoreDisplay = document.getElementById('best-score');
+let score = 0;
+let hits = 0;
+let misses = 0;
+let comboMultiplier = 1;
+let nodes = [];
+let bestScore = localStorage.getItem('bestScore') || 0;
+bestScoreDisplay.textContent = `Best: ${bestScore}`;
+let gameInterval;
+
+function createNode() {
+ const node = document.createElement('div');
+ node.classList.add('node');
+ node.style.left = `${Math.random() * (gameContainer.offsetWidth - 50)}px`;
+ node.style.top = `${Math.random() * (gameContainer.offsetHeight - 50)}px`;
+ gameContainer.appendChild(node);
+ nodes.push(node);
+ setTimeout(() => {
+ node.remove();
+ misses++;
+ comboMultiplier = 1;
+ updateInfo();
+ }, 2000);
+}
+
+function handleClick(event) {
+ if (event.target.classList.contains('node')) {
+ event.target.remove();
+ hits++;
+ score += 10 * comboMultiplier;
+ comboMultiplier++;
+ updateInfo();
+ }
+}
+
+function updateInfo() {
+ infoDisplay.textContent = `Hits: ${hits} | Misses: ${misses} | Score: ${score} | Combo: ${comboMultiplier}`;
+}
+
+function startGame() {
+ gameInterval = setInterval(createNode, 1500);
+ setTimeout(endGame, 30000);
+}
+
+function endGame() {
+ clearInterval(gameInterval);
+ if (score > bestScore) {
+ localStorage.setItem('bestScore', score);
+ bestScoreDisplay.textContent = `Best: ${score}`;
+ }
+ alert(`Time's up! Your score: ${score}`);
+}
+
+function restartGame() {
+ hits = 0;
+ misses = 0;
+ score = 0;
+ comboMultiplier = 1;
+ nodes.forEach(node => node.remove());
+ updateInfo();
+ startGame();
+}
+
+gameContainer.addEventListener('click', handleClick);
+startGame();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/f585b9cfcaea/hf-qwen-coder-32b.png b/data/artifacts/f585b9cfcaea/hf-qwen-coder-32b.png
new file mode 100644
index 0000000..7c3a0c2
Binary files /dev/null and b/data/artifacts/f585b9cfcaea/hf-qwen-coder-32b.png differ
diff --git a/data/artifacts/f585b9cfcaea/kimi.html b/data/artifacts/f585b9cfcaea/kimi.html
new file mode 100644
index 0000000..d828074
--- /dev/null
+++ b/data/artifacts/f585b9cfcaea/kimi.html
@@ -0,0 +1,404 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Agent Reflex</title>
+<style>
+* { margin: 0; padding: 0; box-sizing: border-box; }
+body {
+ background: #000;
+ color: #0ff;
+ font-family: 'Courier New', monospace;
+ overflow: hidden;
+ position: relative;
+ height: 100vh;
+ user-select: none;
+}
+#gameCanvas {
+ display: block;
+ background: radial-gradient(circle at center, #0a0f1e 0%, #000 100%);
+ cursor: crosshair;
+}
+.ui-layer {
+ position: absolute;
+ top: 0; left: 0; width: 100%; height: 100%;
+ pointer-events: none;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ padding: 20px;
+ text-shadow: 0 0 10px #0ff, 0 0 20px #0ff;
+}
+.hud-top {
+ display: flex;
+ justify-content: space-between;
+ font-size: 22px;
+ font-weight: bold;
+ text-transform: uppercase;
+ flex-wrap: wrap;
+}
+.combo {
+ color: #f0f;
+ text-shadow: 0 0 10px #f0f, 0 0 20px #f0f;
+ transition: transform 0.1s;
+}
+.combo.burst { transform: scale(1.3); color: #ff0; text-shadow: 0 0 20px #ff0; }
+.center-screen {
+ position: absolute;
+ top: 50%; left: 50%;
+ transform: translate(-50%, -50%);
+ text-align: center;
+ pointer-events: auto;
+ background: rgba(0, 10, 20, 0.95);
+ border: 2px solid #0ff;
+ padding: 40px 60px;
+ box-shadow: 0 0 40px rgba(0, 255, 255, 0.3), inset 0 0 40px rgba(0, 255, 255, 0.05);
+ min-width: 300px;
+}
+button {
+ background: transparent;
+ border: 2px solid #0ff;
+ color: #0ff;
+ padding: 15px 40px;
+ font-size: 20px;
+ font-family: inherit;
+ text-transform: uppercase;
+ cursor: pointer;
+ margin-top: 25px;
+ box-shadow: 0 0 15px rgba(0, 255, 255, 0.3);
+ transition: all 0.2s;
+ letter-spacing: 2px;
+}
+button:hover {
+ background: #0ff;
+ color: #000;
+ box-shadow: 0 0 30px #0ff;
+}
+.hidden { display: none !important; }
+.stat-box { display: inline-block; margin: 5px 15px; }
+</style>
+</head>
+<body>
+<canvas id="gameCanvas"></canvas>
+
+<div class="ui-layer">
+ <div class="hud-top" id="hud">
+ <div class="stat-box">TIME: <span id="time">30</span>s</div>
+ <div class="stat-box">SCORE: <span id="score">0</span></div>
+ <div class="stat-box combo" id="comboBox">COMBO: <span id="combo">0</span>x</div>
+ <div class="stat-box">BEST: <span id="best">0</span></div>
+ </div>
+</div>
+
+<div id="startScreen" class="center-screen">
+ <h1 style="font-size: 46px; margin-bottom: 15px; text-shadow: 0 0 20px #0ff; letter-spacing: 3px;">AGENT REFLEX</h1>
+ <p style="color: #888; margin-bottom: 25px; font-size: 14px;">[ NEURAL INTERFACE // TARGET ACQUISITION ]</p>
+ <p style="color: #0ff; margin-bottom: 10px; font-size: 12px;">CLICK GLOWING NODES BEFORE FADE</p>
+ <button onclick="game.start()">INITIATE</button>
+</div>
+
+<div id="gameOverScreen" class="center-screen hidden">
+ <h1 style="font-size: 32px; margin-bottom: 20px; color: #f0f; text-shadow: 0 0 20px #f0f;">SEQUENCE END</h1>
+ <div style="font-size: 28px; margin: 15px 0; font-weight: bold;">SCORE: <span id="finalScore">0</span></div>
+ <div style="font-size: 16px; color: #ff0; margin: 10px 0;">MAX COMBO: <span id="finalCombo">0</span>x</div>
+ <div style="font-size: 14px; color: #888; margin: 10px 0;">ACCURACY: <span id="accuracy">0</span>%</div>
+ <button onclick="game.restart()">REBOOT</button>
+</div>
+
+<script>
+const canvas = document.getElementById('gameCanvas');
+const ctx = canvas.getContext('2d');
+
+function resize() {
+ canvas.width = window.innerWidth;
+ canvas.height = window.innerHeight;
+}
+window.addEventListener('resize', resize);
+resize();
+
+class Particle {
+ constructor(x, y, color) {
+ this.x = x;
+ this.y = y;
+ const angle = Math.random() * Math.PI * 2;
+ const speed = Math.random() * 5 + 2;
+ this.vx = Math.cos(angle) * speed;
+ this.vy = Math.sin(angle) * speed;
+ this.life = 1;
+ this.decay = 0.025;
+ this.color = color;
+ this.size = Math.random() * 3 + 2;
+ }
+
+ update() {
+ this.x += this.vx;
+ this.y += this.vy;
+ this.vx *= 0.95;
+ this.vy *= 0.95;
+ this.life -= this.decay;
+ }
+
+ draw() {
+ ctx.save();
+ ctx.globalAlpha = this.life;
+ ctx.fillStyle = this.color;
+ ctx.shadowBlur = 10;
+ ctx.shadowColor = this.color;
+ ctx.beginPath();
+ ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
+ ctx.fill();
+ ctx.restore();
+ }
+}
+
+class Target {
+ constructor() {
+ this.radius = 35;
+ this.x = this.radius + 20 + Math.random() * (canvas.width - this.radius * 2 - 40);
+ this.y = this.radius + 80 + Math.random() * (canvas.height - this.radius * 2 - 120);
+ this.created = Date.now();
+ this.lifespan = 1500 + Math.random() * 500;
+ this.scale = 0;
+ this.color = ['#00ffff', '#ff00ff', '#00ff00', '#ffff00'][Math.floor(Math.random() * 4)];
+ this.phase = Math.random() * Math.PI * 2;
+ this.active = true;
+ }
+
+ update() {
+ const age = Date.now() - this.created;
+ const progress = age / this.lifespan;
+
+ if (progress < 0.15) {
+ this.scale = (progress / 0.15);
+ } else if (progress > 0.7) {
+ this.scale = 1 - ((progress - 0.7) / 0.3);
+ } else {
+ this.scale = 1;
+ }
+
+ this.phase += 0.15;
+ return progress < 1;
+ }
+
+ draw() {
+ if (!this.active) return;
+ const r = this.radius * this.scale * (1 + Math.sin(this.phase) * 0.05);
+
+ ctx.save();
+ ctx.translate(this.x, this.y);
+
+ ctx.shadowBlur = 20;
+ ctx.shadowColor = this.color;
+ ctx.strokeStyle = this.color;
+ ctx.lineWidth = 2;
+
+ ctx.beginPath();
+ ctx.arc(0, 0, r, 0, Math.PI * 2);
+ ctx.stroke();
+
+ ctx.fillStyle = this.color;
+ ctx.globalAlpha = 0.3;
+ ctx.fill();
+
+ ctx.globalAlpha = 0.8;
+ ctx.beginPath();
+ ctx.arc(0, 0, r * 0.4, 0, Math.PI * 2);
+ ctx.fill();
+
+ ctx.globalAlpha = 0.4;
+ ctx.lineWidth = 1;
+ ctx.beginPath();
+ ctx.arc(0, 0, r * 0.7, 0, Math.PI * 2);
+ ctx.stroke();
+
+ ctx.restore();
+ }
+
+ checkHit(x, y) {
+ const dx = x - this.x;
+ const dy = y - this.y;
+ return Math.sqrt(dx*dx + dy*dy) < this.radius * this.scale;
+ }
+}
+
+const game = {
+ targets: [],
+ particles: [],
+ score: 0,
+ combo: 0,
+ maxCombo: 0,
+ time: 30,
+ hits: 0,
+ clicks: 0,
+ playing: false,
+ lastSpawn: 0,
+ spawnInterval: 500,
+ bestScore: 0,
+
+ init() {
+ this.bestScore = parseInt(localStorage.getItem('agentReflexBest')) || 0;
+ document.getElementById('best').textContent = this.bestScore;
+
+ canvas.addEventListener('mousedown', (e) => this.handleInput(e.clientX, e.clientY));
+ canvas.addEventListener('touchstart', (e) => {
+ e.preventDefault();
+ const t = e.touches[0];
+ this.handleInput(t.clientX, t.clientY);
+ }, {passive: false});
+
+ requestAnimationFrame(() => this.loop());
+ },
+
+ start() {
+ document.getElementById('startScreen').classList.add('hidden');
+ document.getElementById('gameOverScreen').classList.add('hidden');
+ this.reset();
+ this.playing = true;
+ this.lastSpawn = Date.now();
+ this.timer = setInterval(() => {
+ this.time--;
+ document.getElementById('time').textContent = this.time;
+ if (this.time <= 0) this.end();
+ }, 1000);
+ },
+
+ reset() {
+ this.targets = [];
+ this.particles = [];
+ this.score = 0;
+ this.combo = 0;
+ this.maxCombo = 0;
+ this.time = 30;
+ this.hits = 0;
+ this.clicks = 0;
+ this.spawnInterval = 500;
+ this.updateUI();
+ },
+
+ handleInput(x, y) {
+ if (!this.playing) return;
+ this.clicks++;
+
+ const rect = canvas.getBoundingClientRect();
+ const cx = x - rect.left;
+ const cy = y - rect.top;
+
+ let hit = false;
+ for (let i = this.targets.length - 1; i >= 0; i--) {
+ if (this.targets[i].checkHit(cx, cy)) {
+ this.hit(this.targets[i], i, cx, cy);
+ hit = true;
+ break;
+ }
+ }
+
+ if (!hit) {
+ this.combo = 0;
+ this.updateUI();
+ for (let i = 0; i < 3; i++) {
+ this.particles.push(new Particle(cx, cy, '#ff0000'));
+ }
+ }
+ },
+
+ hit(target, index, x, y) {
+ this.targets.splice(index, 1);
+ this.hits++;
+ this.combo++;
+ if (this.combo > this.maxCombo) this.maxCombo = this.combo;
+
+ this.score += 100 * this.combo;
+
+ for (let i = 0; i < 12; i++) {
+ this.particles.push(new Particle(target.x, target.y, target.color));
+ }
+
+ const cb = document.getElementById('comboBox');
+ cb.classList.remove('burst');
+ void cb.offsetWidth;
+ cb.classList.add('burst');
+
+ if (this.spawnInterval > 250) this.spawnInterval -= 8;
+
+ this.updateUI();
+ },
+
+ update() {
+ if (!this.playing) return;
+
+ const now = Date.now();
+ if (now - this.lastSpawn > this.spawnInterval && this.targets.length < 8) {
+ this.targets.push(new Target());
+ this.lastSpawn = now;
+ }
+
+ for (let i = this.targets.length - 1; i >= 0; i--) {
+ if (!this.targets[i].update()) {
+ this.targets.splice(i, 1);
+ this.combo = 0;
+ this.updateUI();
+ }
+ }
+
+ for (let i = this.particles.length - 1; i >= 0; i--) {
+ this.particles[i].update();
+ if (this.particles[i].life <= 0) this.particles.splice(i, 1);
+ }
+ },
+
+ draw() {
+ ctx.fillStyle = 'rgba(0, 0, 0, 0.25)';
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+
+ ctx.strokeStyle = 'rgba(0, 255, 255, 0.08)';
+ ctx.lineWidth = 1;
+ const g = 50;
+ for (let x = 0; x < canvas.width; x += g) {
+ ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, canvas.height); ctx.stroke();
+ }
+ for (let y = 0; y < canvas.height; y += g) {
+ ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(canvas.width, y); ctx.stroke();
+ }
+
+ this.targets.forEach(t => t.draw());
+ this.particles.forEach(p => p.draw());
+ },
+
+ loop() {
+ this.update();
+ this.draw();
+ requestAnimationFrame(() => this.loop());
+ },
+
+ updateUI() {
+ document.getElementById('score').textContent = this.score;
+ document.getElementById('combo').textContent = this.combo;
+ document.getElementById('best').textContent = Math.max(this.score, this.bestScore);
+ },
+
+ end() {
+ this.playing = false;
+ clearInterval(this.timer);
+
+ if (this.score > this.bestScore) {
+ this.bestScore = this.score;
+ localStorage.setItem('agentReflexBest', this.bestScore);
+ }
+
+ const acc = this.clicks > 0 ? Math.round((this.hits / this.clicks) * 100) : 0;
+ document.getElementById('finalScore').textContent = this.score;
+ document.getElementById('finalCombo').textContent = this.maxCombo;
+ document.getElementById('accuracy').textContent = acc;
+ document.getElementById('gameOverScreen').classList.remove('hidden');
+ },
+
+ restart() {
+ this.start();
+ }
+};
+
+game.init();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/f585b9cfcaea/kimi.png b/data/artifacts/f585b9cfcaea/kimi.png
new file mode 100644
index 0000000..47e6dfd
Binary files /dev/null and b/data/artifacts/f585b9cfcaea/kimi.png differ
diff --git a/data/artifacts/f585b9cfcaea/qwen3-14b.html b/data/artifacts/f585b9cfcaea/qwen3-14b.html
new file mode 100644
index 0000000..b6553aa
--- /dev/null
+++ b/data/artifacts/f585b9cfcaea/qwen3-14b.html
@@ -0,0 +1,167 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title>Agent Reflex</title>
+ <style>
+ * {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ }
+ html, body {
+ height: 100%;
+ width: 100%;
+ overflow: hidden;
+ background: linear-gradient(135deg, #0f0f23 0%, #1a1a3d 100%);
+ font-family: 'Courier New', Courier, monospace;
+ color: #00ffe8;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ user-select: none;
+ }
+ #game {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+ }
+ .target {
+ position: absolute;
+ width: 60px;
+ height: 60px;
+ border-radius: 50%;
+ background: radial-gradient(circle at 30% 30%, #00ffe8, #0077ff);
+ box-shadow: 0 0 20px #00ffe8;
+ pointer-events: auto;
+ transition: opacity 0.3s ease-out;
+ }
+ .target.hidden {
+ opacity: 0;
+ }
+ #hud {
+ position: absolute;
+ top: 20px;
+ left: 20px;
+ font-size: 18px;
+ z-index: 10;
+ }
+ #score, #combo, #time, #best {
+ display: inline-block;
+ margin-right: 20px;
+ }
+ #restart {
+ position: absolute;
+ bottom: 20px;
+ left: 50%;
+ transform: translateX(-50%);
+ padding: 10px 20px;
+ background: #0077ff;
+ color: #000;
+ border: none;
+ border-radius: 5px;
+ font-size: 18px;
+ cursor: pointer;
+ box-shadow: 0 0 10px #00ffe8;
+ transition: background 0.2s;
+ }
+ #restart:hover {
+ background: #0055cc;
+ }
+ </style>
+</head>
+<body>
+ <div id="game">
+ <div id="hud">
+ <div id="score">Score: 0</div>
+ <div id="combo">Combo: 1x</div>
+ <div id="time">Time: 30</div>
+ <div id="best">Best: 0</div>
+ </div>
+ <button id="restart">Restart</button>
+ </div>
+ <script>
+ const game = document.getElementById('game');
+ const scoreEl = document.getElementById('score');
+ const comboEl = document.getElementById('combo');
+ const timeEl = document.getElementById('time');
+ const bestEl = document.getElementById('best');
+ const restartBtn = document.getElementById('restart');
+
+ let score = 0;
+ let combo = 1;
+ let timeLeft = 30;
+ let bestScore = localStorage.getItem('agentReflexBest') ? parseInt(localStorage.getItem('agentReflexBest')) : 0;
+ let isRunning = false;
+ let targets = [];
+ let lastTargetTime = 0;
+
+ function spawnTarget() {
+ const target = document.createElement('div');
+ target.classList.add('target');
+ target.style.left = Math.random() * (window.innerWidth - 60) + 'px';
+ target.style.top = Math.random() * (window.innerHeight - 60) + 'px';
+ game.appendChild(target);
+ targets.push(target);
+ target.addEventListener('click', () => {
+ if (!isRunning) return;
+ score += 100 * combo;
+ combo += 1;
+ comboEl.textContent = 'Combo: ' + combo + 'x';
+ scoreEl.textContent = 'Score: ' + score;
+ target.classList.add('hidden');
+ target.addEventListener('transitionend', () => {
+ target.remove();
+ targets = targets.filter(t => t !== target);
+ });
+ });
+ }
+
+ function update() {
+ if (!isRunning) return;
+ timeLeft--;
+ timeEl.textContent = 'Time: ' + timeLeft;
+ if (timeLeft <= 0) {
+ endGame();
+ return;
+ }
+ if (Date.now() - lastTargetTime > 1000) {
+ spawnTarget();
+ lastTargetTime = Date.now();
+ }
+ requestAnimationFrame(update);
+ }
+
+ function startGame() {
+ score = 0;
+ combo = 1;
+ timeLeft = 30;
+ isRunning = true;
+ targets.forEach(t => t.remove());
+ targets = [];
+ lastTargetTime = 0;
+ scoreEl.textContent = 'Score: 0';
+ comboEl.textContent = 'Combo: 1x';
+ timeEl.textContent = 'Time: 30';
+ update();
+ }
+
+ function endGame() {
+ isRunning = false;
+ if (score > bestScore) {
+ bestScore = score;
+ localStorage.setItem('agentReflexBest', bestScore);
+ bestEl.textContent = 'Best: ' + bestScore;
+ }
+ }
+
+ restartBtn.addEventListener('click', () => {
+ startGame();
+ });
+
+ startGame();
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/f585b9cfcaea/qwen3-14b.png b/data/artifacts/f585b9cfcaea/qwen3-14b.png
new file mode 100644
index 0000000..a997911
Binary files /dev/null and b/data/artifacts/f585b9cfcaea/qwen3-14b.png differ
diff --git a/data/challenges.json b/data/challenges.json
index 9e5574e..71d60f3 100644
--- a/data/challenges.json
+++ b/data/challenges.json
@@ -13732,33 +13732,39 @@
"runs": [
{
"model": "qwen3-14b",
- "status": "running",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
+ "seconds": 31,
+ "cost": 0,
"started_at": "2026-07-25T07:27:14.055Z",
- "finished_at": null,
- "queued_at": "2026-07-25T07:27:10.161Z"
+ "finished_at": "2026-07-25T07:27:44.914Z",
+ "queued_at": "2026-07-25T07:27:10.161Z",
+ "bytes": 4330,
+ "thumb": true
},
{
"model": "gemma3-12b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:27:10.168Z"
+ "seconds": 39,
+ "cost": 0,
+ "started_at": "2026-07-25T07:27:44.920Z",
+ "finished_at": "2026-07-25T07:28:24.191Z",
+ "queued_at": "2026-07-25T07:27:10.168Z",
+ "bytes": 6070,
+ "thumb": true
},
{
"model": "hermes3-8b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:27:10.173Z"
+ "seconds": 19,
+ "cost": 0,
+ "started_at": "2026-07-25T07:28:24.195Z",
+ "finished_at": "2026-07-25T07:28:42.802Z",
+ "queued_at": "2026-07-25T07:27:10.173Z",
+ "bytes": 5454,
+ "thumb": true
},
{
"model": "qwen25-7b",
@@ -13774,55 +13780,66 @@
},
{
"model": "hf-qwen-coder-32b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:27:10.181Z"
+ "seconds": 45,
+ "cost": 0,
+ "started_at": "2026-07-25T07:28:42.809Z",
+ "finished_at": "2026-07-25T07:29:27.583Z",
+ "queued_at": "2026-07-25T07:27:10.181Z",
+ "bytes": 3122,
+ "thumb": true
},
{
"model": "claude-code",
- "status": "running",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
+ "seconds": 64,
+ "cost": 0,
"started_at": "2026-07-25T07:27:10.253Z",
- "finished_at": null,
- "queued_at": "2026-07-25T07:27:10.185Z"
+ "finished_at": "2026-07-25T07:28:14.077Z",
+ "queued_at": "2026-07-25T07:27:10.185Z",
+ "bytes": 12288,
+ "thumb": true
},
{
"model": "kimi",
- "status": "running",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
+ "seconds": 139,
+ "cost": 0.02,
"started_at": "2026-07-25T07:27:10.259Z",
- "finished_at": null,
- "queued_at": "2026-07-25T07:27:10.190Z"
+ "finished_at": "2026-07-25T07:29:29.470Z",
+ "queued_at": "2026-07-25T07:27:10.190Z",
+ "bytes": 10741,
+ "thumb": true
},
{
"model": "gpt",
- "status": "running",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
+ "seconds": 76,
+ "cost": 0.166,
"started_at": "2026-07-25T07:27:10.266Z",
- "finished_at": null,
- "queued_at": "2026-07-25T07:27:10.215Z"
+ "finished_at": "2026-07-25T07:28:26.734Z",
+ "queued_at": "2026-07-25T07:27:10.215Z",
+ "bytes": 46126,
+ "thumb": true
},
{
"model": "grok",
- "status": "running",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
+ "seconds": 65,
+ "cost": 0.0808,
"started_at": "2026-07-25T07:27:10.271Z",
- "finished_at": null,
- "queued_at": "2026-07-25T07:27:10.219Z"
+ "finished_at": "2026-07-25T07:28:15.456Z",
+ "queued_at": "2026-07-25T07:27:10.219Z",
+ "bytes": 14358,
+ "thumb": true
}
- ]
+ ],
+ "judging": true
},
{
"id": "ce24cf987953",
@@ -13835,93 +13852,107 @@
"runs": [
{
"model": "qwen3-14b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:27:10.300Z"
+ "seconds": 45,
+ "cost": 0,
+ "started_at": "2026-07-25T07:29:27.588Z",
+ "finished_at": "2026-07-25T07:30:13.000Z",
+ "queued_at": "2026-07-25T07:27:10.300Z",
+ "bytes": 6892,
+ "thumb": true
},
{
"model": "gemma3-12b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:27:10.302Z"
+ "seconds": 48,
+ "cost": 0,
+ "started_at": "2026-07-25T07:30:13.085Z",
+ "finished_at": "2026-07-25T07:31:00.920Z",
+ "queued_at": "2026-07-25T07:27:10.302Z",
+ "bytes": 7117,
+ "thumb": true
},
{
"model": "hermes3-8b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:27:10.304Z"
+ "seconds": 17,
+ "cost": 0,
+ "started_at": "2026-07-25T07:31:00.929Z",
+ "finished_at": "2026-07-25T07:31:17.970Z",
+ "queued_at": "2026-07-25T07:27:10.304Z",
+ "bytes": 4824,
+ "thumb": true
},
{
"model": "qwen25-7b",
- "status": "running",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
+ "seconds": 18,
+ "cost": 0,
"started_at": "2026-07-25T07:27:31.705Z",
- "finished_at": null,
- "queued_at": "2026-07-25T07:27:10.307Z"
+ "finished_at": "2026-07-25T07:27:49.998Z",
+ "queued_at": "2026-07-25T07:27:10.307Z",
+ "bytes": 3127,
+ "thumb": true
},
{
"model": "hf-qwen-coder-32b",
- "status": "queued",
+ "status": "running",
"error": null,
"seconds": null,
"cost": null,
- "started_at": null,
+ "started_at": "2026-07-25T07:31:17.972Z",
"finished_at": null,
"queued_at": "2026-07-25T07:27:10.308Z"
},
{
"model": "claude-code",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:27:10.311Z"
+ "seconds": 64,
+ "cost": 0,
+ "started_at": "2026-07-25T07:28:14.079Z",
+ "finished_at": "2026-07-25T07:29:18.080Z",
+ "queued_at": "2026-07-25T07:27:10.311Z",
+ "bytes": 11792,
+ "thumb": true
},
{
"model": "kimi",
- "status": "queued",
+ "status": "running",
"error": null,
"seconds": null,
"cost": null,
- "started_at": null,
+ "started_at": "2026-07-25T07:29:29.475Z",
"finished_at": null,
"queued_at": "2026-07-25T07:27:10.313Z"
},
{
"model": "gpt",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:27:10.315Z"
+ "seconds": 45,
+ "cost": 0.0848,
+ "started_at": "2026-07-25T07:28:26.741Z",
+ "finished_at": "2026-07-25T07:29:12.200Z",
+ "queued_at": "2026-07-25T07:27:10.315Z",
+ "bytes": 21035,
+ "thumb": true
},
{
"model": "grok",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:27:10.317Z"
+ "seconds": 38,
+ "cost": 0.0446,
+ "started_at": "2026-07-25T07:28:15.458Z",
+ "finished_at": "2026-07-25T07:28:53.205Z",
+ "queued_at": "2026-07-25T07:27:10.317Z",
+ "bytes": 8164,
+ "thumb": true
}
]
},
@@ -13966,13 +13997,15 @@
},
{
"model": "qwen25-7b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:27:10.403Z"
+ "seconds": 17,
+ "cost": 0,
+ "started_at": "2026-07-25T07:27:50.007Z",
+ "finished_at": "2026-07-25T07:28:07.296Z",
+ "queued_at": "2026-07-25T07:27:10.403Z",
+ "bytes": 2528,
+ "thumb": true
},
{
"model": "hf-qwen-coder-32b",
@@ -13986,13 +14019,15 @@
},
{
"model": "claude-code",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:27:10.408Z"
+ "seconds": 84,
+ "cost": 0,
+ "started_at": "2026-07-25T07:29:18.083Z",
+ "finished_at": "2026-07-25T07:30:42.261Z",
+ "queued_at": "2026-07-25T07:27:10.408Z",
+ "bytes": 15573,
+ "thumb": true
},
{
"model": "kimi",
@@ -14006,23 +14041,27 @@
},
{
"model": "gpt",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:27:10.412Z"
+ "seconds": 82,
+ "cost": 0.161,
+ "started_at": "2026-07-25T07:29:12.207Z",
+ "finished_at": "2026-07-25T07:30:34.266Z",
+ "queued_at": "2026-07-25T07:27:10.412Z",
+ "bytes": 38871,
+ "thumb": true
},
{
"model": "grok",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:27:10.414Z"
+ "seconds": 80,
+ "cost": 0.0981,
+ "started_at": "2026-07-25T07:28:53.214Z",
+ "finished_at": "2026-07-25T07:30:13.394Z",
+ "queued_at": "2026-07-25T07:27:10.414Z",
+ "bytes": 18675,
+ "thumb": true
}
]
},
@@ -14067,13 +14106,15 @@
},
{
"model": "qwen25-7b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:27:36.993Z"
+ "seconds": 9,
+ "cost": 0,
+ "started_at": "2026-07-25T07:28:07.305Z",
+ "finished_at": "2026-07-25T07:28:16.281Z",
+ "queued_at": "2026-07-25T07:27:36.993Z",
+ "bytes": 1163,
+ "thumb": true
},
{
"model": "hf-qwen-coder-32b",
@@ -14087,13 +14128,14 @@
},
{
"model": "claude-code",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:27:37.002Z"
+ "seconds": 89,
+ "cost": 0,
+ "started_at": "2026-07-25T07:30:42.264Z",
+ "finished_at": "2026-07-25T07:32:11.194Z",
+ "queued_at": "2026-07-25T07:27:37.002Z",
+ "bytes": 14393
},
{
"model": "kimi",
@@ -14107,23 +14149,27 @@
},
{
"model": "gpt",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:27:37.009Z"
+ "seconds": 42,
+ "cost": 0.0974,
+ "started_at": "2026-07-25T07:30:34.284Z",
+ "finished_at": "2026-07-25T07:31:16.270Z",
+ "queued_at": "2026-07-25T07:27:37.009Z",
+ "bytes": 21347,
+ "thumb": true
},
{
"model": "grok",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": null,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-25T07:27:37.013Z"
+ "seconds": 73,
+ "cost": 0.0934,
+ "started_at": "2026-07-25T07:30:13.420Z",
+ "finished_at": "2026-07-25T07:31:26.404Z",
+ "queued_at": "2026-07-25T07:27:37.013Z",
+ "bytes": 17468,
+ "thumb": true
}
]
}
diff --git a/data/costlog.jsonl b/data/costlog.jsonl
index 44362e2..f96e3b7 100644
--- a/data/costlog.jsonl
+++ b/data/costlog.jsonl
@@ -184,3 +184,12 @@
{"ts":"2026-07-25T07:19:20.933Z","provider":"xai","model":"grok-4.5","task":"model-arena","input_tokens":351,"output_tokens":4590,"cost_usd":0.069903}
{"ts":"2026-07-25T07:20:24.758Z","provider":"moonshot","model":"kimi-k2.5","task":"model-arena","input_tokens":159,"output_tokens":7063,"cost_usd":0.017753}
{"ts":"2026-07-25T07:22:17.980Z","provider":"moonshot","model":"kimi-k2.5","task":"model-arena","input_tokens":145,"output_tokens":5557,"cost_usd":0.01398}
+{"ts":"2026-07-25T07:28:15.455Z","provider":"xai","model":"grok-4.5","task":"model-arena","input_tokens":358,"output_tokens":5317,"cost_usd":0.080829}
+{"ts":"2026-07-25T07:28:26.729Z","provider":"openai","model":"gpt-5.1","task":"model-arena","input_tokens":149,"output_tokens":11835,"cost_usd":0.165951}
+{"ts":"2026-07-25T07:28:53.202Z","provider":"xai","model":"grok-4.5","task":"model-arena","input_tokens":351,"output_tokens":2905,"cost_usd":0.044628}
+{"ts":"2026-07-25T07:29:12.186Z","provider":"openai","model":"gpt-5.1","task":"model-arena","input_tokens":147,"output_tokens":6039,"cost_usd":0.084803}
+{"ts":"2026-07-25T07:29:29.467Z","provider":"moonshot","model":"kimi-k2.5","task":"model-arena","input_tokens":152,"output_tokens":7956,"cost_usd":0.019981}
+{"ts":"2026-07-25T07:30:13.379Z","provider":"xai","model":"grok-4.5","task":"model-arena","input_tokens":368,"output_tokens":6466,"cost_usd":0.098094}
+{"ts":"2026-07-25T07:30:34.261Z","provider":"openai","model":"gpt-5.1","task":"model-arena","input_tokens":160,"output_tokens":11481,"cost_usd":0.161014}
+{"ts":"2026-07-25T07:31:16.268Z","provider":"openai","model":"gpt-5.1","task":"model-arena","input_tokens":148,"output_tokens":6939,"cost_usd":0.097405}
+{"ts":"2026-07-25T07:31:26.402Z","provider":"xai","model":"grok-4.5","task":"model-arena","input_tokens":354,"output_tokens":6158,"cost_usd":0.093432}
diff --git a/data/landings/724633a205b0-grok.html b/data/landings/724633a205b0-grok.html
new file mode 100644
index 0000000..f458f93
--- /dev/null
+++ b/data/landings/724633a205b0-grok.html
@@ -0,0 +1,553 @@
+<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
+<title>Designer Wallcoverings — Texture Weave Simulator — built by Grok 4.5 · Model Arena</title>
+<style>*{box-sizing:border-box}html,body{margin:0;height:100%;background:#0b0d10;color:#e6ecf2;font:14px/1.5 ui-monospace,Menlo,monospace}
+header{display:flex;align-items:center;gap:14px;padding:13px 20px;border-bottom:1px solid #1c2430;background:#0e1116}
+header .k{color:#7cf;font-weight:700;letter-spacing:2px;text-transform:uppercase;font-size:12px;white-space:nowrap}
+header h1{font-size:15px;margin:0;font-weight:600}header .by{color:#8a93a0;font-size:12px;margin-left:auto;white-space:nowrap}
+.wrap{height:calc(100% - 51px)}iframe{width:100%;height:100%;border:0;background:#000;display:block}</style></head><body>
+<header><span class="k">⚔ Model Arena</span><h1>Designer Wallcoverings — Texture Weave Simulator</h1><span class="by">built by <b>Grok 4.5</b></span></header>
+<div class="wrap"><iframe sandbox="allow-scripts allow-pointer-lock" srcdoc="<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Grasscloth Weave Simulator</title>
+<style>
+ @import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@400;500&family=DM+Sans:wght@400;500&display=swap');
+ * { margin: 0; padding: 0; box-sizing: border-box; }
+ html, body {
+ width: 100%; height: 100%;
+ overflow: hidden;
+ background: #1a1814;
+ font-family: 'DM Sans', system-ui, sans-serif;
+ color: #e8e0d4;
+ }
+ .app {
+ display: grid;
+ grid-template-columns: 1fr 280px;
+ height: 100vh;
+ gap: 0;
+ }
+ .stage {
+ position: relative;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: radial-gradient(ellipse at 40% 35%, #2a2620 0%, #141210 70%);
+ overflow: hidden;
+ }
+ canvas {
+ display: block;
+ border-radius: 2px;
+ box-shadow:
+ 0 0 0 1px rgba(255,245,230,0.06),
+ 0 24px 80px rgba(0,0,0,0.55),
+ 0 4px 16px rgba(0,0,0,0.35);
+ max-width: calc(100% - 64px);
+ max-height: calc(100% - 64px);
+ }
+ .panel {
+ background: linear-gradient(180deg, #221f1a 0%, #1a1714 100%);
+ border-left: 1px solid rgba(232,224,212,0.08);
+ padding: 36px 28px;
+ display: flex;
+ flex-direction: column;
+ gap: 28px;
+ overflow-y: auto;
+ }
+ .brand {
+ margin-bottom: 8px;
+ }
+ .brand h1 {
+ font-family: 'Cormorant Garamond', Georgia, serif;
+ font-weight: 500;
+ font-size: 1.55rem;
+ letter-spacing: 0.04em;
+ color: #f0e8dc;
+ line-height: 1.2;
+ }
+ .brand p {
+ font-size: 0.7rem;
+ letter-spacing: 0.18em;
+ text-transform: uppercase;
+ color: #8a8070;
+ margin-top: 6px;
+ }
+ .control {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ }
+ .control label {
+ display: flex;
+ justify-content: space-between;
+ align-items: baseline;
+ font-size: 0.72rem;
+ letter-spacing: 0.12em;
+ text-transform: uppercase;
+ color: #a09888;
+ }
+ .control label span.val {
+ font-variant-numeric: tabular-nums;
+ color: #d4c8b4;
+ letter-spacing: 0.04em;
+ }
+ input[type="range"] {
+ -webkit-appearance: none;
+ appearance: none;
+ width: 100%;
+ height: 3px;
+ background: #3a342c;
+ border-radius: 2px;
+ outline: none;
+ cursor: pointer;
+ }
+ input[type="range"]::-webkit-slider-thumb {
+ -webkit-appearance: none;
+ appearance: none;
+ width: 14px;
+ height: 14px;
+ border-radius: 50%;
+ background: linear-gradient(145deg, #e8dcc8, #c4b49a);
+ box-shadow: 0 1px 4px rgba(0,0,0,0.4);
+ cursor: grab;
+ border: none;
+ }
+ input[type="range"]::-moz-range-thumb {
+ width: 14px;
+ height: 14px;
+ border-radius: 50%;
+ background: linear-gradient(145deg, #e8dcc8, #c4b49a);
+ box-shadow: 0 1px 4px rgba(0,0,0,0.4);
+ cursor: grab;
+ border: none;
+ }
+ .swatch-row {
+ display: flex;
+ gap: 10px;
+ align-items: center;
+ }
+ .swatch {
+ width: 28px;
+ height: 28px;
+ border-radius: 4px;
+ border: 1px solid rgba(255,255,255,0.12);
+ box-shadow: inset 0 1px 2px rgba(0,0,0,0.25);
+ flex-shrink: 0;
+ }
+ input[type="color"] {
+ -webkit-appearance: none;
+ appearance: none;
+ width: 100%;
+ height: 32px;
+ border: 1px solid rgba(232,224,212,0.12);
+ border-radius: 4px;
+ background: transparent;
+ cursor: pointer;
+ padding: 2px;
+ }
+ input[type="color"]::-webkit-color-swatch-wrapper { padding: 2px; }
+ input[type="color"]::-webkit-color-swatch {
+ border: none;
+ border-radius: 2px;
+ }
+ .divider {
+ height: 1px;
+ background: linear-gradient(90deg, transparent, rgba(232,224,212,0.1), transparent);
+ }
+ .hint {
+ font-size: 0.68rem;
+ color: #6a6258;
+ line-height: 1.55;
+ letter-spacing: 0.02em;
+ margin-top: auto;
+ }
+ @media (max-width: 720px) {
+ .app { grid-template-columns: 1fr; grid-template-rows: 1fr auto; }
+ .panel {
+ border-left: none;
+ border-top: 1px solid rgba(232,224,212,0.08);
+ padding: 20px 20px 28px;
+ max-height: 42vh;
+ }
+ }
+</style>
+</head>
+<body>
+<div class="app">
+ <div class="stage">
+ <canvas id="c" width="640" height="640"></canvas>
+ </div>
+ <aside class="panel">
+ <div class="brand">
+ <h1>Grasscloth</h1>
+ <p>Weave Texture Studio</p>
+ </div>
+ <div class="divider"></div>
+ <div class="control">
+ <label>Weave Density <span class="val" id="vDensity">48</span></label>
+ <input type="range" id="density" min="16" max="96" value="48" step="1">
+ </div>
+ <div class="control">
+ <label>Warp Fiber</label>
+ <div class="swatch-row">
+ <div class="swatch" id="sw1"></div>
+ <input type="color" id="color1" value="#c4a882">
+ </div>
+ </div>
+ <div class="control">
+ <label>Weft Fiber</label>
+ <div class="swatch-row">
+ <div class="swatch" id="sw2"></div>
+ <input type="color" id="color2" value="#8a7a62">
+ </div>
+ </div>
+ <div class="control">
+ <label>Sheen <span class="val" id="vSheen">35</span></label>
+ <input type="range" id="sheen" min="0" max="100" value="35" step="1">
+ </div>
+ <div class="control">
+ <label>Fiber Variation <span class="val" id="vVar">55</span></label>
+ <input type="range" id="variation" min="0" max="100" value="55" step="1">
+ </div>
+ <div class="divider"></div>
+ <p class="hint">Natural grasscloth wallcovering — handwoven fiber simulation with live specular sweep. Luxury earth palette.</p>
+ </aside>
+</div>
+<script>
+(function () {
+ const canvas = document.getElementById('c');
+ const ctx = canvas.getContext('2d', { alpha: false });
+ const W = canvas.width;
+ const H = canvas.height;
+
+ const densityEl = document.getElementById('density');
+ const color1El = document.getElementById('color1');
+ const color2El = document.getElementById('color2');
+ const sheenEl = document.getElementById('sheen');
+ const variationEl = document.getElementById('variation');
+ const vDensity = document.getElementById('vDensity');
+ const vSheen = document.getElementById('vSheen');
+ const vVar = document.getElementById('vVar');
+ const sw1 = document.getElementById('sw1');
+ const sw2 = document.getElementById('sw2');
+
+ let density = +densityEl.value;
+ let c1 = hexToRgb(color1El.value);
+ let c2 = hexToRgb(color2El.value);
+ let sheen = +sheenEl.value / 100;
+ let variation = +variationEl.value / 100;
+ let dirty = true;
+ let lightPhase = 0;
+
+ // Precomputed noise tables for fiber irregularity
+ const NOISE_N = 2048;
+ const fiberNoise = new Float32Array(NOISE_N);
+ const shadeNoise = new Float32Array(NOISE_N);
+ const twistNoise = new Float32Array(NOISE_N);
+ for (let i = 0; i < NOISE_N; i++) {
+ fiberNoise[i] = Math.random() * 2 - 1;
+ shadeNoise[i] = Math.random() * 2 - 1;
+ twistNoise[i] = Math.random();
+ }
+
+ // Offscreen buffer for base weave (rebuilt on param change)
+ const baseCanvas = document.createElement('canvas');
+ baseCanvas.width = W;
+ baseCanvas.height = H;
+ const baseCtx = baseCanvas.getContext('2d', { alpha: false });
+ const baseImg = baseCtx.createImageData(W, H);
+ const baseData = baseImg.data;
+
+ function hexToRgb(hex) {
+ const h = hex.replace('#', '');
+ return [
+ parseInt(h.slice(0, 2), 16),
+ parseInt(h.slice(2, 4), 16),
+ parseInt(h.slice(4, 6), 16)
+ ];
+ }
+
+ function lerp(a, b, t) { return a + (b - a) * t; }
+ function clamp(v, a, b) { return v < a ? a : v > b ? b : v; }
+ function smoothstep(e0, e1, x) {
+ const t = clamp((x - e0) / (e1 - e0), 0, 1);
+ return t * t * (3 - 2 * t);
+ }
+ function n1(i) { return fiberNoise[((i % NOISE_N) + NOISE_N) % NOISE_N]; }
+ function n2(i) { return shadeNoise[((i % NOISE_N) + NOISE_N) % NOISE_N]; }
+ function n3(i) { return twistNoise[((i % NOISE_N) + NOISE_N) % NOISE_N]; }
+
+ // Hash-ish for stable per-fiber seed
+ function fiberSeed(row, col) {
+ return ((row * 73856093) ^ (col * 19349663)) >>> 0;
+ }
+
+ function rebuildBase() {
+ const cell = Math.max(4, Math.floor(W / density));
+ const half = cell * 0.5;
+ const cols = Math.ceil(W / cell) + 2;
+ const rows = Math.ceil(H / cell) + 2;
+ const varAmt = variation;
+
+ // Clear to mid tone
+ const midR = (c1[0] + c2[0]) * 0.5;
+ const midG = (c1[1] + c2[1]) * 0.5;
+ const midB = (c1[2] + c2[2]) * 0.5;
+
+ for (let i = 0, len = W * H; i < len; i++) {
+ const pi = i * 4;
+ baseData[pi] = midR;
+ baseData[pi + 1] = midG;
+ baseData[pi + 2] = midB;
+ baseData[pi + 3] = 255;
+ }
+
+ // Draw interlaced plain weave: warp (vertical) and weft (horizontal)
+ // For each cell, alternate which yarn is on top
+ for (let ry = -1; ry < rows; ry++) {
+ for (let cx = -1; cx < cols; cx++) {
+ const x0 = cx * cell;
+ const y0 = ry * cell;
+ const overWarp = ((cx + ry) & 1) === 0;
+ const seedW = fiberSeed(ry, cx);
+ const seedF = fiberSeed(cx, ry + 17);
+
+ // Yarn thickness with natural variation
+ const warpThick = half * (0.72 + 0.28 * n3(seedW));
+ const weftThick = half * (0.70 + 0.30 * n3(seedF + 3));
+
+ // Color variation per fiber strand
+ const wVar = 1 + varAmt * 0.35 * n1(seedW);
+ const fVar = 1 + varAmt * 0.35 * n1(seedF);
+ const wShade = varAmt * 0.22 * n2(seedW + 5);
+ const fShade = varAmt * 0.22 * n2(seedF + 7);
+
+ const warpCol = [
+ clamp(c1[0] * wVar + wShade * 40, 0, 255),
+ clamp(c1[1] * wVar + wShade * 35, 0, 255),
+ clamp(c1[2] * wVar + wShade * 28, 0, 255)
+ ];
+ const weftCol = [
+ clamp(c2[0] * fVar + fShade * 40, 0, 255),
+ clamp(c2[1] * fVar + fShade * 35, 0, 255),
+ clamp(c2[2] * fVar + fShade * 28, 0, 255)
+ ];
+
+ // Micro-twist offset along fiber
+ const twistW = n3(seedW + 11) * 1.8;
+ const twistF = n3(seedF + 13) * 1.8;
+
+ // Draw both yarns; top yarn last for occlusion
+ if (overWarp) {
+ drawWeftSegment(x0, y0, cell, weftThick, weftCol, twistF, seedF, varAmt);
+ drawWarpSegment(x0, y0, cell, warpThick, warpCol, twistW, seedW, varAmt);
+ } else {
+ drawWarpSegment(x0, y0, cell, warpThick, warpCol, twistW, seedW, varAmt);
+ drawWeftSegment(x0, y0, cell, weftThick, weftCol, twistF, seedF, varAmt);
+ }
+ }
+ }
+
+ // Subtle paper/backing grain in gaps
+ for (let y = 0; y < H; y++) {
+ for (let x = 0; x < W; x++) {
+ const pi = (y * W + x) * 4;
+ const g = 0.92 + 0.08 * n1(x * 3 + y * 7);
+ // Soften only very dark interstitial pixels slightly
+ // Add fine vertical/horizontal striations of natural fiber hair
+ const hair = n2(x + y * 19) * varAmt * 6;
+ baseData[pi] = clamp(baseData[pi] * g + hair, 0, 255);
+ baseData[pi + 1] = clamp(baseData[pi + 1] * g + hair * 0.9, 0, 255);
+ baseData[pi + 2] = clamp(baseData[pi + 2] * g + hair * 0.75, 0, 255);
+ }
+ }
+
+ baseCtx.putImageData(baseImg, 0, 0);
+ dirty = false;
+ }
+
+ function drawWarpSegment(x0, y0, cell, thick, col, twist, seed, varAmt) {
+ // Vertical yarn through cell, cylindrical shading
+ const cx = x0 + cell * 0.5;
+ const yStart = Math.max(0, Math.floor(y0));
+ const yEnd = Math.min(H, Math.ceil(y0 + cell + 1));
+ const r = thick * 0.5;
+
+ for (let y = yStart; y < yEnd; y++) {
+ const ly = (y - y0) / cell;
+ // slight S-curve / natural bend
+ const bend = Math.sin(ly * Math.PI) * twist + n1(seed + y) * varAmt * 0.9;
+ const centerX = cx + bend;
+ const xStart = Math.max(0, Math.floor(centerX - r - 1));
+ const xEnd = Math.min(W, Math.ceil(centerX + r + 1));
+
+ for (let x = xStart; x < xEnd; x++) {
+ const dx = x - centerX;
+ const dist = Math.abs(dx);
+ if (dist > r) continue;
+
+ const u = dist / r; // 0 center → 1 edge
+ // Cylindrical lambert-ish profile
+ const profile = Math.sqrt(Math.max(0, 1 - u * u));
+ // Edge darkening + core highlight bias
+ const shade = 0.55 + 0.55 * profile;
+ // Longitudinal fiber striations
+ const stria = 1 + varAmt * 0.12 * n1((seed + Math.floor(y * 2.3) + Math.floor(dx * 3)) | 0);
+ // Soft edge falloff for anti-alias / fiber fringe
+ const edge = smoothstep(1.0, 0.82, u);
+ const a = edge;
+
+ const pi = (y * W + x) * 4;
+ const nr = col[0] * shade * stria;
+ const ng = col[1] * shade * stria;
+ const nb = col[2] * shade * stria;
+
+ baseData[pi] = clamp(lerp(baseData[pi], nr, a), 0, 255);
+ baseData[pi + 1] = clamp(lerp(baseData[pi + 1], ng, a), 0, 255);
+ baseData[pi + 2] = clamp(lerp(baseData[pi + 2], nb, a), 0, 255);
+ }
+ }
+ }
+
+ function drawWeftSegment(x0, y0, cell, thick, col, twist, seed, varAmt) {
+ // Horizontal yarn
+ const cy = y0 + cell * 0.5;
+ const xStart = Math.max(0, Math.floor(x0));
+ const xEnd = Math.min(W, Math.ceil(x0 + cell + 1));
+ const r = thick * 0.5;
+
+ for (let x = xStart; x < xEnd; x++) {
+ const lx = (x - x0) / cell;
+ const bend = Math.sin(lx * Math.PI) * twist + n1(seed + x + 40) * varAmt * 0.9;
+ const centerY = cy + bend;
+ const yStart = Math.max(0, Math.floor(centerY - r - 1));
+ const yEnd = Math.min(H, Math.ceil(centerY + r + 1));
+
+ for (let y = yStart; y < yEnd; y++) {
+ const dy = y - centerY;
+ const dist = Math.abs(dy);
+ if (dist > r) continue;
+
+ const u = dist / r;
+ const profile = Math.sqrt(Math.max(0, 1 - u * u));
+ const shade = 0.52 + 0.58 * profile;
+ const stria = 1 + varAmt * 0.12 * n1((seed + Math.floor(x * 2.1) + Math.floor(dy * 3) + 90) | 0);
+ const edge = smoothstep(1.0, 0.82, u);
+ const a = edge;
+
+ const pi = (y * W + x) * 4;
+ const nr = col[0] * shade * stria;
+ const ng = col[1] * shade * stria;
+ const nb = col[2] * shade * stria;
+
+ baseData[pi] = clamp(lerp(baseData[pi], nr, a), 0, 255);
+ baseData[pi + 1] = clamp(lerp(baseData[pi + 1], ng, a), 0, 255);
+ baseData[pi + 2] = clamp(lerp(baseData[pi + 2], nb, a), 0, 255);
+ }
+ }
+ }
+
+ // Composite frame: base + animated light sweep + sheen
+ const frameImg = ctx.createImageData(W, H);
+ const frameData = frameImg.data;
+
+ function render(time) {
+ if (dirty) rebuildBase();
+
+ lightPhase = (time * 0.00015) % 1;
+ // Sweep center moves slowly diagonally
+ const lx = (0.15 + 0.7 * (0.5 + 0.5 * Math.sin(lightPhase * Math.PI * 2))) * W;
+ const ly = (0.2 + 0.6 * (0.5 + 0.5 * Math.cos(lightPhase * Math.PI * 2 * 0.7 + 0.4))) * H;
+ const sheenStr = sheen;
+ const sweepRadius = W * 0.55;
+
+ // Copy base and apply lighting in one pass
+ const src = baseData;
+ const dst = frameData;
+
+ for (let y = 0; y < H; y++) {
+ for (let x = 0; x < W; x++) {
+ const i = (y * W + x) * 4;
+ let r = src[i];
+ let g = src[i + 1];
+ let b = src[i + 2];
+
+ // Distance to light center
+ const dx = x - lx;
+ const dy = y - ly;
+ const dist = Math.sqrt(dx * dx + dy * dy);
+ const fall = Math.exp(-(dist * dist) / (2 * sweepRadius * sweepRadius));
+
+ // Ambient occlusion-ish from local luminance (darker fibers recede)
+ const lum = (r * 0.3 + g * 0.59 + b * 0.11) / 255;
+ // Specular response stronger on lighter fiber ridges
+ const spec = sheenStr * fall * (0.35 + 0.65 * smoothstep(0.25, 0.75, lum));
+ // Warm luxury light tint
+ const warmR = 1.08;
+ const warmG = 1.02;
+ const warmB = 0.94;
+
+ // Soft directional fill
+ const fill = 0.88 + 0.14 * fall;
+ // Specular bloom (additive, warm ivory)
+ const bloom = spec * 55;
+
+ r = clamp(r * fill * warmR + bloom * 1.15, 0, 255);
+ g = clamp(g * fill * warmG + bloom * 1.05, 0, 255);
+ b = clamp(b * fill * warmB + bloom * 0.88, 0, 255);
+
+ // Very subtle vignette for depth
+ const vx = (x / W - 0.5) * 2;
+ const vy = (y / H - 0.5) * 2;
+ const vig = 1 - 0.12 * (vx * vx + vy * vy);
+ r *= vig; g *= vig; b *= vig;
+
+ dst[i] = r;
+ dst[i + 1] = g;
+ dst[i + 2] = b;
+ dst[i + 3] = 255;
+ }
+ }
+
+ ctx.putImageData(frameImg, 0, 0);
+
+ // Soft overlay gradient for gallery lighting feel
+ const grd = ctx.createRadialGradient(lx, ly, 0, lx, ly, sweepRadius * 1.2);
+ grd.addColorStop(0, 'rgba(255,248,235,' + (0.04 + sheenStr * 0.06) + ')');
+ grd.addColorStop(0.5, 'rgba(255,240,220,0.015)');
+ grd.addColorStop(1, 'rgba(0,0,0,0)');
+ ctx.fillStyle = grd;
+ ctx.fillRect(0, 0, W, H);
+
+ requestAnimationFrame(render);
+ }
+
+ function syncUI() {
+ density = +densityEl.value;
+ c1 = hexToRgb(color1El.value);
+ c2 = hexToRgb(color2El.value);
+ sheen = +sheenEl.value / 100;
+ variation = +variationEl.value / 100;
+ vDensity.textContent = densityEl.value;
+ vSheen.textContent = sheenEl.value;
+ vVar.textContent = variationEl.value;
+ sw1.style.background = color1El.value;
+ sw2.style.background = color2El.value;
+ dirty = true;
+ }
+
+ densityEl.addEventListener('input', syncUI);
+ color1El.addEventListener('input', syncUI);
+ color2El.addEventListener('input', syncUI);
+ sheenEl.addEventListener('input', syncUI);
+ variationEl.addEventListener('input', syncUI);
+
+ syncUI();
+ rebuildBase();
+ requestAnimationFrame(render);
+})();
+</script>
+</body>
+</html>" title="Designer Wallcoverings — Texture Weave Simulator"></iframe></div>
+</body></html>
\ No newline at end of file
← 59658e6 night-loop: cycle 00:27 — judged=59cdaeca7f55 · fired 1 →; F
·
back to Model Arena
·
Repoint loop to games + DW social-media idea pool (16 ideas: 5f0ddc0 →