← back to Model Arena
auto-save: 2026-07-23T07:49:27 (26 files) — data/challenges.json data/costlog.jsonl data/votes.jsonl idea-run/harvest.md data/artifacts/08d1c975f6db/qwen3-14b.html
b855064ae2c7bdc6c90fae204ff3a5c105833a4a · 2026-07-23 07:49:32 -0700 · Steve Abrams
Files touched
A data/artifacts/08d1c975f6db/qwen3-14b.htmlA data/artifacts/08d1c975f6db/qwen3-14b.pngA data/artifacts/10c3c876aa67/claude-code.htmlA data/artifacts/10c3c876aa67/claude-code.pngA data/artifacts/10c3c876aa67/gemma3-12b.htmlA data/artifacts/10c3c876aa67/gemma3-12b.pngA data/artifacts/10c3c876aa67/gpt.htmlA data/artifacts/10c3c876aa67/gpt.pngA data/artifacts/10c3c876aa67/grok.htmlA data/artifacts/10c3c876aa67/grok.pngA data/artifacts/10c3c876aa67/hermes3-8b.htmlA data/artifacts/10c3c876aa67/hermes3-8b.pngA data/artifacts/10c3c876aa67/kimi.htmlA data/artifacts/10c3c876aa67/kimi.pngA data/artifacts/10c3c876aa67/qwen25-7b.htmlA data/artifacts/10c3c876aa67/qwen25-7b.pngA data/artifacts/35303b0ef3b8/gemma3-12b.htmlA data/artifacts/35303b0ef3b8/gemma3-12b.pngA data/artifacts/35303b0ef3b8/qwen3-14b.htmlA data/artifacts/35303b0ef3b8/qwen3-14b.pngA data/artifacts/58d3738d2b99/gemma3-12b.htmlA data/artifacts/58d3738d2b99/gemma3-12b.pngA data/artifacts/58d3738d2b99/hermes3-8b.htmlA data/artifacts/58d3738d2b99/hermes3-8b.pngA data/artifacts/58d3738d2b99/kimi.htmlA data/artifacts/58d3738d2b99/kimi.pngA data/artifacts/6fb7d108c932/claude-code.htmlA data/artifacts/6fb7d108c932/claude-code.pngA data/artifacts/6fb7d108c932/gemma3-12b.htmlA data/artifacts/6fb7d108c932/gemma3-12b.pngA data/artifacts/6fb7d108c932/gpt.htmlA data/artifacts/6fb7d108c932/gpt.pngA data/artifacts/6fb7d108c932/grok.htmlA data/artifacts/6fb7d108c932/grok.pngA data/artifacts/6fb7d108c932/hermes3-8b.htmlA data/artifacts/6fb7d108c932/hermes3-8b.pngA data/artifacts/6fb7d108c932/kimi.htmlA data/artifacts/6fb7d108c932/kimi.pngA data/artifacts/6fb7d108c932/qwen25-7b.htmlA data/artifacts/6fb7d108c932/qwen25-7b.pngA data/artifacts/74df3b61e7ca/qwen3-14b.htmlA data/artifacts/74df3b61e7ca/qwen3-14b.pngA data/artifacts/966d54f224fd/qwen3-14b.htmlA data/artifacts/966d54f224fd/qwen3-14b.pngA data/artifacts/acebf42d306a/hermes3-8b.htmlA data/artifacts/acebf42d306a/hermes3-8b.pngA data/artifacts/ca355985ca95/kimi.htmlA data/artifacts/ca355985ca95/kimi.pngA data/artifacts/e14b05b7754d/gemma3-12b.htmlA data/artifacts/e14b05b7754d/gemma3-12b.pngA data/artifacts/e14b05b7754d/hermes3-8b.htmlA data/artifacts/e14b05b7754d/hermes3-8b.pngA data/artifacts/f79cffc20d43/claude-code.htmlA data/artifacts/f79cffc20d43/claude-code.pngA data/artifacts/f79cffc20d43/gemma3-12b.htmlA data/artifacts/f79cffc20d43/gemma3-12b.pngA data/artifacts/f79cffc20d43/gpt.htmlA data/artifacts/f79cffc20d43/gpt.pngA data/artifacts/f79cffc20d43/grok.htmlA data/artifacts/f79cffc20d43/grok.pngA data/artifacts/f79cffc20d43/hermes3-8b.htmlA data/artifacts/f79cffc20d43/hermes3-8b.pngA data/artifacts/f79cffc20d43/kimi.htmlA data/artifacts/f79cffc20d43/kimi.pngA data/artifacts/f79cffc20d43/qwen25-7b.htmlA data/artifacts/f79cffc20d43/qwen25-7b.pngA data/artifacts/f79cffc20d43/qwen3-14b.htmlA data/artifacts/f79cffc20d43/qwen3-14b.pngM data/challenges.jsonM data/costlog.jsonlM data/votes.jsonlM idea-run/harvest.md
Diff
commit b855064ae2c7bdc6c90fae204ff3a5c105833a4a
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Thu Jul 23 07:49:32 2026 -0700
auto-save: 2026-07-23T07:49:27 (26 files) — data/challenges.json data/costlog.jsonl data/votes.jsonl idea-run/harvest.md data/artifacts/08d1c975f6db/qwen3-14b.html
---
data/artifacts/08d1c975f6db/qwen3-14b.html | 63 +
data/artifacts/08d1c975f6db/qwen3-14b.png | Bin 0 -> 2728 bytes
data/artifacts/10c3c876aa67/claude-code.html | 223 ++++
data/artifacts/10c3c876aa67/claude-code.png | Bin 0 -> 26157 bytes
data/artifacts/10c3c876aa67/gemma3-12b.html | 117 ++
data/artifacts/10c3c876aa67/gemma3-12b.png | Bin 0 -> 3252 bytes
data/artifacts/10c3c876aa67/gpt.html | 302 +++++
data/artifacts/10c3c876aa67/gpt.png | Bin 0 -> 50195 bytes
data/artifacts/10c3c876aa67/grok.html | 213 ++++
data/artifacts/10c3c876aa67/grok.png | Bin 0 -> 18514 bytes
data/artifacts/10c3c876aa67/hermes3-8b.html | 100 ++
data/artifacts/10c3c876aa67/hermes3-8b.png | Bin 0 -> 2727 bytes
data/artifacts/10c3c876aa67/kimi.html | 290 +++++
data/artifacts/10c3c876aa67/kimi.png | Bin 0 -> 53176 bytes
data/artifacts/10c3c876aa67/qwen25-7b.html | 128 ++
data/artifacts/10c3c876aa67/qwen25-7b.png | Bin 0 -> 3398 bytes
data/artifacts/35303b0ef3b8/gemma3-12b.html | 10 +
data/artifacts/35303b0ef3b8/gemma3-12b.png | Bin 0 -> 3552 bytes
data/artifacts/35303b0ef3b8/qwen3-14b.html | 1 +
data/artifacts/35303b0ef3b8/qwen3-14b.png | Bin 0 -> 3649 bytes
data/artifacts/58d3738d2b99/gemma3-12b.html | 157 +++
data/artifacts/58d3738d2b99/gemma3-12b.png | Bin 0 -> 205766 bytes
data/artifacts/58d3738d2b99/hermes3-8b.html | 106 ++
data/artifacts/58d3738d2b99/hermes3-8b.png | Bin 0 -> 20170 bytes
data/artifacts/58d3738d2b99/kimi.html | 415 ++++++
data/artifacts/58d3738d2b99/kimi.png | Bin 0 -> 178074 bytes
data/artifacts/6fb7d108c932/claude-code.html | 244 ++++
data/artifacts/6fb7d108c932/claude-code.png | Bin 0 -> 93414 bytes
data/artifacts/6fb7d108c932/gemma3-12b.html | 128 ++
data/artifacts/6fb7d108c932/gemma3-12b.png | Bin 0 -> 2727 bytes
data/artifacts/6fb7d108c932/gpt.html | 256 ++++
data/artifacts/6fb7d108c932/gpt.png | Bin 0 -> 211563 bytes
data/artifacts/6fb7d108c932/grok.html | 163 +++
data/artifacts/6fb7d108c932/grok.png | Bin 0 -> 275781 bytes
data/artifacts/6fb7d108c932/hermes3-8b.html | 122 ++
data/artifacts/6fb7d108c932/hermes3-8b.png | Bin 0 -> 2727 bytes
data/artifacts/6fb7d108c932/kimi.html | 130 ++
data/artifacts/6fb7d108c932/kimi.png | Bin 0 -> 51948 bytes
data/artifacts/6fb7d108c932/qwen25-7b.html | 63 +
data/artifacts/6fb7d108c932/qwen25-7b.png | Bin 0 -> 27001 bytes
data/artifacts/74df3b61e7ca/qwen3-14b.html | 146 +++
data/artifacts/74df3b61e7ca/qwen3-14b.png | Bin 0 -> 116367 bytes
data/artifacts/966d54f224fd/qwen3-14b.html | 167 +++
data/artifacts/966d54f224fd/qwen3-14b.png | Bin 0 -> 20133 bytes
data/artifacts/acebf42d306a/hermes3-8b.html | 96 ++
data/artifacts/acebf42d306a/hermes3-8b.png | Bin 0 -> 63550 bytes
data/artifacts/ca355985ca95/kimi.html | 182 +++
data/artifacts/ca355985ca95/kimi.png | Bin 0 -> 317245 bytes
data/artifacts/e14b05b7754d/gemma3-12b.html | 225 ++++
data/artifacts/e14b05b7754d/gemma3-12b.png | Bin 0 -> 12845 bytes
data/artifacts/e14b05b7754d/hermes3-8b.html | 147 +++
data/artifacts/e14b05b7754d/hermes3-8b.png | Bin 0 -> 4953 bytes
data/artifacts/f79cffc20d43/claude-code.html | 372 ++++++
data/artifacts/f79cffc20d43/claude-code.png | Bin 0 -> 72945 bytes
data/artifacts/f79cffc20d43/gemma3-12b.html | 88 ++
data/artifacts/f79cffc20d43/gemma3-12b.png | Bin 0 -> 43752 bytes
data/artifacts/f79cffc20d43/gpt.html | 1766 ++++++++++++++++++++++++++
data/artifacts/f79cffc20d43/gpt.png | Bin 0 -> 317161 bytes
data/artifacts/f79cffc20d43/grok.html | 587 +++++++++
data/artifacts/f79cffc20d43/grok.png | Bin 0 -> 386105 bytes
data/artifacts/f79cffc20d43/hermes3-8b.html | 77 ++
data/artifacts/f79cffc20d43/hermes3-8b.png | Bin 0 -> 96990 bytes
data/artifacts/f79cffc20d43/kimi.html | 671 ++++++++++
data/artifacts/f79cffc20d43/kimi.png | Bin 0 -> 158286 bytes
data/artifacts/f79cffc20d43/qwen25-7b.html | 80 ++
data/artifacts/f79cffc20d43/qwen25-7b.png | Bin 0 -> 26435 bytes
data/artifacts/f79cffc20d43/qwen3-14b.html | 186 +++
data/artifacts/f79cffc20d43/qwen3-14b.png | Bin 0 -> 35539 bytes
data/challenges.json | 1078 ++++++++++++++--
data/costlog.jsonl | 11 +
data/votes.jsonl | 3 +
idea-run/harvest.md | 19 +
72 files changed, 9024 insertions(+), 108 deletions(-)
diff --git a/data/artifacts/08d1c975f6db/qwen3-14b.html b/data/artifacts/08d1c975f6db/qwen3-14b.html
new file mode 100644
index 0000000..f4858cb
--- /dev/null
+++ b/data/artifacts/08d1c975f6db/qwen3-14b.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>Bouncing Balls</title>
+ <style>
+ body {
+ margin: 0;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ background: #222;
+ font-family: sans-serif;
+ }
+ canvas {
+ background: #111;
+ display: block;
+ }
+ #gravitySlider {
+ margin: 10px;
+ width: 300px;
+ }
+ </style>
+</head>
+<body>
+ <canvas id="canvas" width="800" height="600"></canvas>
+ <label for="gravitySlider">Gravity:</label>
+ <input type="range" id="gravitySlider" min="0.1" max="2.0" step="0.01" value="0.5">
+ <script>
+ const canvas = document.getElementById('canvas');
+ const ctx = canvas.getContext('2d');
+ const gravitySlider = document.getElementById('gravitySlider');
+ let gravity = parseFloat(gravitySlider.value);
+
+ gravitySlider.addEventListener('input', (e) => {
+ gravity = parseFloat(e.target.value);
+ });
+
+ class Ball {
+ constructor(x, y, vx, vy, radius, color) {
+ this.x = x;
+ this.y = y;
+ this.vx = vx;
+ this.vy = vy;
+ this.radius = radius;
+ this.color = color;
+ this.trail = [];
+ }
+
+ update() {
+ // Apply gravity
+ this.vy += gravity;
+ // Update position
+ this.x += this.vx;
+ this.y += this.vy;
+ // Check wall collisions
+ if (this.x - this.radius < 0) {
+ this.x = this.radius;
+ this.vx *= -0.8;
+ } else if (this.x + this.radius > canvas.width) {
+ this.x = canvas.width - this.radius;
+ this.vx *= -0.8;
\ No newline at end of file
diff --git a/data/artifacts/08d1c975f6db/qwen3-14b.png b/data/artifacts/08d1c975f6db/qwen3-14b.png
new file mode 100644
index 0000000..71d328a
Binary files /dev/null and b/data/artifacts/08d1c975f6db/qwen3-14b.png differ
diff --git a/data/artifacts/10c3c876aa67/claude-code.html b/data/artifacts/10c3c876aa67/claude-code.html
new file mode 100644
index 0000000..4963a6c
--- /dev/null
+++ b/data/artifacts/10c3c876aa67/claude-code.html
@@ -0,0 +1,223 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Fractal Tree — Wind & Falling Leaves</title>
+<style>
+ html, body { margin: 0; padding: 0; height: 100%; overflow: hidden; background: #1a2233; }
+ canvas { display: block; }
+ #ui {
+ position: fixed; top: 14px; left: 14px; z-index: 10;
+ background: rgba(10, 16, 28, 0.55); backdrop-filter: blur(6px);
+ border: 1px solid rgba(255,255,255,0.15); border-radius: 10px;
+ padding: 12px 16px; color: #e8e2d0;
+ font: 13px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
+ user-select: none;
+ }
+ #ui label { display: flex; align-items: center; gap: 10px; }
+ #depthVal { min-width: 2ch; text-align: center; font-weight: 600; color: #ffb347; }
+ input[type=range] { width: 160px; accent-color: #ffb347; cursor: pointer; }
+ #hint { opacity: 0.6; font-size: 11px; margin-top: 4px; }
+</style>
+</head>
+<body>
+<div id="ui">
+ <label>Branch depth
+ <input type="range" id="depth" min="3" max="11" value="9" step="1">
+ <span id="depthVal">9</span>
+ </label>
+ <div id="hint">tree regrows when depth changes</div>
+</div>
+<canvas id="c"></canvas>
+<script>
+(function () {
+ "use strict";
+ var canvas = document.getElementById("c");
+ var ctx = canvas.getContext("2d");
+ var W = 0, H = 0, DPR = Math.min(window.devicePixelRatio || 1, 2);
+
+ function resize() {
+ 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);
+ }
+ window.addEventListener("resize", resize);
+ resize();
+
+ var maxDepth = 9;
+ var growStart = performance.now();
+ var GROW_TIME = 3500; // ms for full growth
+ var slider = document.getElementById("depth");
+ var depthVal = document.getElementById("depthVal");
+ slider.addEventListener("input", function () {
+ maxDepth = parseInt(slider.value, 10);
+ depthVal.textContent = maxDepth;
+ growStart = performance.now(); // regrow from trunk
+ leaves.length = 0;
+ ground.length = 0;
+ });
+
+ // deterministic pseudo-random from a seed, so the tree shape is stable per frame
+ function sr(seed) {
+ var x = Math.sin(seed * 127.1 + 311.7) * 43758.5453;
+ return x - Math.floor(x);
+ }
+
+ // autumn leaf palette
+ var LEAF_COLORS = ["#d9542b", "#e8842a", "#f0b429", "#c23b22", "#e0a41c", "#b8551f"];
+
+ // falling leaf particles
+ var leaves = []; // airborne
+ var ground = []; // settled on the ground
+ var MAX_LEAVES = 140, MAX_GROUND = 220;
+ var tips = []; // leaf-bearing branch tips gathered each frame
+
+ function spawnLeaf(x, y, wind) {
+ if (leaves.length >= MAX_LEAVES) return;
+ leaves.push({
+ x: x, y: y,
+ vx: wind * 12 + (Math.random() - 0.5) * 20,
+ vy: 8 + Math.random() * 18,
+ rot: Math.random() * Math.PI * 2,
+ spin: (Math.random() - 0.5) * 3,
+ phase: Math.random() * Math.PI * 2,
+ size: 3 + Math.random() * 3.5,
+ color: LEAF_COLORS[(Math.random() * LEAF_COLORS.length) | 0]
+ });
+ }
+
+ function drawLeafShape(x, y, rot, size, color, alpha) {
+ ctx.save();
+ ctx.translate(x, y);
+ ctx.rotate(rot);
+ ctx.globalAlpha = alpha;
+ ctx.fillStyle = color;
+ ctx.beginPath();
+ ctx.ellipse(0, 0, size, size * 0.55, 0, 0, Math.PI * 2);
+ ctx.fill();
+ ctx.restore();
+ ctx.globalAlpha = 1;
+ }
+
+ // recursive branch drawing
+ function branch(x, y, angle, len, width, depth, seed, growth, t, wind) {
+ // per-level growth: level d grows during its slice of the growth window
+ var levelProg = growth * (maxDepth + 1) - depth;
+ if (levelProg <= 0) return;
+ if (levelProg > 1) levelProg = 1;
+
+ // wind sway: outer, thinner branches sway more; each branch has its own phase
+ var flexibility = Math.pow((depth + 1) / (maxDepth + 1), 2);
+ var sway = wind * flexibility * 0.22
+ + Math.sin(t * 0.0021 + seed * 6.28 + depth) * 0.02 * flexibility;
+ var a = angle + sway;
+
+ var drawnLen = len * levelProg;
+ var x2 = x + Math.cos(a) * drawnLen;
+ var y2 = y + Math.sin(a) * drawnLen;
+
+ ctx.strokeStyle = depth < 2 ? "#4a3626" : (depth < maxDepth - 2 ? "#5b442e" : "#6e5638");
+ ctx.lineWidth = Math.max(width * (0.6 + 0.4 * levelProg), 0.5);
+ ctx.lineCap = "round";
+ ctx.beginPath();
+ ctx.moveTo(x, y);
+ ctx.lineTo(x2, y2);
+ ctx.stroke();
+
+ if (depth >= maxDepth || len < 4) {
+ if (levelProg >= 1) tips.push({ x: x2, y: y2, seed: seed });
+ return;
+ }
+ if (levelProg < 1) return; // children start once this segment finishes
+
+ var r1 = sr(seed * 7.3 + depth), r2 = sr(seed * 13.7 + depth * 2), r3 = sr(seed * 29.1);
+ var spread = 0.38 + r1 * 0.28;
+ var shrink = 0.68 + r2 * 0.09;
+
+ branch(x2, y2, a - spread + (r3 - 0.5) * 0.2, len * shrink, width * 0.7, depth + 1, seed * 2 + 1, growth, t, wind);
+ branch(x2, y2, a + spread + (r1 - 0.5) * 0.2, len * shrink, width * 0.7, depth + 1, seed * 2 + 2, growth, t, wind);
+ if (r3 > 0.72 && depth > 1) { // occasional third middle branch
+ branch(x2, y2, a + (r2 - 0.5) * 0.25, len * shrink * 0.85, width * 0.6, depth + 1, seed * 3 + 5, growth, t, wind);
+ }
+ }
+
+ function frame(t) {
+ // sky
+ var g = ctx.createLinearGradient(0, 0, 0, H);
+ g.addColorStop(0, "#2b3a5c");
+ g.addColorStop(0.6, "#5a5a72");
+ g.addColorStop(1, "#8a6d55");
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, W, H);
+
+ // ground
+ var groundY = H - 40;
+ ctx.fillStyle = "#3d2f22";
+ ctx.fillRect(0, groundY, W, 40);
+ ctx.fillStyle = "rgba(255, 200, 120, 0.05)";
+ ctx.fillRect(0, groundY, W, 3);
+
+ // gusty wind: layered sines, occasionally strong
+ var wind = Math.sin(t * 0.0006) * 0.55
+ + Math.sin(t * 0.00023 + 1.7) * 0.35
+ + Math.sin(t * 0.0017 + 4.1) * 0.18;
+
+ var growth = Math.min(1, (t - growStart) / GROW_TIME);
+ // ease growth
+ var eased = 1 - Math.pow(1 - growth, 3);
+
+ tips.length = 0;
+ var trunkLen = Math.min(H, 900) * 0.16 + maxDepth * 2;
+ branch(W / 2, groundY, -Math.PI / 2, trunkLen, Math.max(4, maxDepth * 1.3), 0, 1, eased, t, wind);
+
+ // foliage at tips
+ for (var i = 0; i < tips.length; i++) {
+ var tip = tips[i];
+ var c = LEAF_COLORS[(sr(tip.seed) * LEAF_COLORS.length) | 0];
+ var wob = Math.sin(t * 0.003 + tip.seed * 9) * 1.5 * Math.abs(wind);
+ drawLeafShape(tip.x + wob, tip.y, sr(tip.seed * 3) * Math.PI * 2 + wind * 0.4, 3.2 + sr(tip.seed * 5) * 2.5, c, 0.9);
+ // occasionally shed a leaf, more in strong gusts
+ if (growth >= 1 && Math.random() < 0.0015 + Math.abs(wind) * 0.004) {
+ spawnLeaf(tip.x, tip.y, wind);
+ }
+ }
+
+ // update + draw airborne leaves
+ var dt = 1 / 60;
+ for (var j = leaves.length - 1; j >= 0; j--) {
+ var L = leaves[j];
+ L.phase += dt * 4;
+ L.vx += (wind * 26 - L.vx) * 0.02 + Math.sin(L.phase) * 6 * dt * 8;
+ L.vy += (26 - L.vy) * 0.03; // drift toward terminal velocity
+ L.x += L.vx * dt;
+ L.y += (L.vy + Math.cos(L.phase * 0.7) * 10) * dt;
+ L.rot += L.spin * dt + Math.sin(L.phase) * 0.02;
+ if (L.y >= groundY - 2) {
+ if (ground.length < MAX_GROUND) {
+ ground.push({ x: L.x, y: groundY - 1 + Math.random() * 6, rot: L.rot, size: L.size, color: L.color, born: t });
+ }
+ leaves.splice(j, 1);
+ } else if (L.x < -50 || L.x > W + 50) {
+ leaves.splice(j, 1);
+ } else {
+ drawLeafShape(L.x, L.y, L.rot, L.size, L.color, 0.95);
+ }
+ }
+
+ // settled leaves slowly fade away
+ for (var k = ground.length - 1; k >= 0; k--) {
+ var Gl = ground[k];
+ var age = (t - Gl.born) / 20000;
+ if (age >= 1) { ground.splice(k, 1); continue; }
+ drawLeafShape(Gl.x, Gl.y, Gl.rot, Gl.size, Gl.color, 0.8 * (1 - age));
+ }
+
+ requestAnimationFrame(frame);
+ }
+ requestAnimationFrame(frame);
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/10c3c876aa67/claude-code.png b/data/artifacts/10c3c876aa67/claude-code.png
new file mode 100644
index 0000000..0ed3822
Binary files /dev/null and b/data/artifacts/10c3c876aa67/claude-code.png differ
diff --git a/data/artifacts/10c3c876aa67/gemma3-12b.html b/data/artifacts/10c3c876aa67/gemma3-12b.html
new file mode 100644
index 0000000..a8fed69
--- /dev/null
+++ b/data/artifacts/10c3c876aa67/gemma3-12b.html
@@ -0,0 +1,117 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Recursive Fractal Tree</title>
+ <style>
+ body { margin: 0; overflow: hidden; background-color: #ADD8E6; } /* Light blue background */
+ canvas { display: block; }
+ </style>
+</head>
+<body>
+
+ <canvas id="treeCanvas"></canvas>
+
+ <script>
+ const canvas = document.getElementById('treeCanvas');
+ const ctx = canvas.getContext('2d');
+
+ let width, height;
+ let branchDepth = 5;
+ let windSpeedX = 0.5;
+ let windSpeedY = 0.1;
+ let leafParticles = [];
+
+ function resize() {
+ width = canvas.width = window.innerWidth;
+ height = canvas.height = window.innerHeight;
+ }
+
+ resize();
+ window.addEventListener('resize', resize);
+
+ function drawTree(x, y, length, angle, depth) {
+ if (depth === 0) return;
+
+ ctx.save();
+ ctx.translate(x, y);
+ ctx.rotate(angle * Math.PI / 180);
+
+ ctx.beginPath();
+ ctx.moveTo(0, 0);
+ ctx.lineTo(length * Math.cos(angle * Math.PI / 180), length * Math.sin(angle * Math.PI / 180));
+ ctx.lineWidth = depth;
+ ctx.strokeStyle = 'brown'; // Tree Trunk and Branches
+ ctx.stroke();
+
+ drawTree(length * Math.cos(angle * Math.PI / 180), length * Math.sin(angle * Math.PI / 180), length * 0.7, angle + 25, depth - 1);
+ drawTree(length * Math.cos(angle * Math.PI / 180), length * Math.sin(angle * Math.PI / 180), length * 0.7, angle - 25, depth - 1);
+
+ ctx.restore();
+ }
+
+ function drawLeaf() {
+ let x = width / 2 + Math.random() * width;
+ let y = height + Math.random() * 50; // Start above the canvas
+ leafParticles.push({x: x, y: y, size: Math.random() * 3 + 1, color: 'green', life: 100});
+ }
+
+ function updateLeaf(particle) {
+ particle.y -= particle.life;
+ if (particle.life <= 0) {
+ return true; // Remove this leaf
+ }
+ return false; // Keep the leaf
+ }
+
+ function draw() {
+ ctx.clearRect(0, 0, width, height);
+
+ // Wind simulation (simple swaying)
+ windSpeedX += Math.random() * 0.1 - 0.05;
+ windSpeedY += Math.random() * 0.1 - 0.05;
+
+ drawTree(width / 2, height, 100, -90, branchDepth); // Initial angle and depth
+
+ // Leaf particles
+ for (let i = leafParticles.length - 1; i >= 0; i--) {
+ const particle = leafParticles[i];
+ ctx.beginPath();
+ ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2);
+ ctx.fillStyle = particle.color;
+ ctx.fill();
+
+ if (updateLeaf(particle)) {
+ leafParticles.splice(i, 1);
+ }
+ }
+
+ // Generate new leaves periodically
+ if (Math.random() < 0.05) { // Adjust frequency as needed
+ drawLeaf();
+ }
+ }
+
+
+ function animate() {
+ requestAnimationFrame(animate);
+ draw();
+ }
+
+ // Slider control for branch depth
+ const slider = document.createElement('input');
+ slider.type = 'range';
+ slider.min = 1;
+ slider.max = 10;
+ slider.value = branchDepth;
+ slider.id = "depthSlider";
+ document.body.appendChild(slider);
+
+ slider.addEventListener('input', function() {
+ branchDepth = parseInt(this.value);
+ });
+
+
+ animate(); // Start animation loop
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/10c3c876aa67/gemma3-12b.png b/data/artifacts/10c3c876aa67/gemma3-12b.png
new file mode 100644
index 0000000..4124fa4
Binary files /dev/null and b/data/artifacts/10c3c876aa67/gemma3-12b.png differ
diff --git a/data/artifacts/10c3c876aa67/gpt.html b/data/artifacts/10c3c876aa67/gpt.html
new file mode 100644
index 0000000..97dd895
--- /dev/null
+++ b/data/artifacts/10c3c876aa67/gpt.html
@@ -0,0 +1,302 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<title>Fractal Tree with Wind and Seasons</title>
+<style>
+ html, body {
+ margin: 0;
+ padding: 0;
+ overflow: hidden;
+ background: radial-gradient(circle at top, #101522 0%, #05060a 60%, #020308 100%);
+ height: 100%;
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
+ color: #eee;
+ }
+ #ui {
+ position: absolute;
+ left: 50%;
+ transform: translateX(-50%);
+ bottom: 16px;
+ background: rgba(5, 8, 20, 0.8);
+ padding: 8px 14px;
+ border-radius: 999px;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ box-shadow: 0 6px 18px rgba(0,0,0,0.6);
+ backdrop-filter: blur(8px);
+ border: 1px solid rgba(180,210,255,0.16);
+ }
+ #label {
+ font-size: 13px;
+ opacity: 0.9;
+ white-space: nowrap;
+ }
+ #depthValue {
+ font-variant-numeric: tabular-nums;
+ margin-left: 2px;
+ }
+ #slider {
+ width: 200px;
+ accent-color: #71c4ff;
+ }
+ #season {
+ border-radius: 999px;
+ border: 1px solid rgba(180,210,255,0.3);
+ background: rgba(10,14,30,0.9);
+ color: #f0f4ff;
+ padding: 2px 6px;
+ font-size: 12px;
+ }
+ canvas {
+ display: block;
+ }
+</style>
+</head>
+<body>
+<canvas id="c"></canvas>
+<div id="ui">
+ <span id="label">Branch depth: <span id="depthValue">9</span></span>
+ <input id="slider" type="range" min="6" max="11" value="9">
+ <select id="season" title="Season">
+ <option value="spring">Spring</option>
+ <option value="summer" selected>Summer</option>
+ <option value="autumn">Autumn</option>
+ <option value="winter">Winter</option>
+ </select>
+</div>
+<script>
+(function(){
+ const canvas = document.getElementById('c');
+ const ctx = canvas.getContext('2d');
+ const slider = document.getElementById('slider');
+ const depthValue = document.getElementById('depthValue');
+ const seasonSelect = document.getElementById('season');
+
+ let W = 0, H = 0, cx = 0, baseY = 0;
+ let maxDepth = parseInt(slider.value, 10);
+ let growProgress = 0;
+ let lastTime = performance.now();
+ let windPhase = 0;
+ let windSpeed = 0.00045;
+ let leaves = [];
+ const maxLeaves = 180;
+
+ function resize() {
+ const 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);
+ cx = W / 2;
+ baseY = H * 0.96;
+ }
+
+ window.addEventListener('resize', resize);
+ resize();
+
+ slider.addEventListener('input', () => {
+ maxDepth = parseInt(slider.value, 10);
+ depthValue.textContent = maxDepth;
+ });
+
+ seasonSelect.addEventListener('change', () => {
+ resetLeaves();
+ });
+
+ function resetLeaves() {
+ leaves = [];
+ const target = seasonLeafCount();
+ for (let i = 0; i < target; i++) {
+ leaves.push(makeLeaf(true));
+ }
+ }
+
+ function seasonLeafCount() {
+ const s = seasonSelect.value;
+ if (s === 'winter') return 8;
+ if (s === 'autumn') return 70;
+ if (s === 'spring') return 140;
+ return 180;
+ }
+
+ function leafColor() {
+ const s = seasonSelect.value;
+ if (s === 'winter') return 'rgba(220,230,255,0.5)';
+ if (s === 'autumn') {
+ const r = 180 + Math.random()*60|0;
+ const g = 80 + Math.random()*60|0;
+ const b = 20 + Math.random()*40|0;
+ return `rgba(${r},${g},${b},0.9)`;
+ }
+ if (s === 'spring') {
+ const g = 160 + Math.random()*70|0;
+ return `rgba(${80+Math.random()*20|0},${g},${90+Math.random()*40|0},0.9)`;
+ }
+ // summer
+ const g = 130 + Math.random()*80|0;
+ return `rgba(${40+Math.random()*40|0},${g},${40+Math.random()*40|0},0.9)`;
+ }
+
+ function makeLeaf(initial) {
+ const angle = -Math.PI/2 + (Math.random()*0.8 - 0.4);
+ let r = H * (0.18 + Math.random()*0.3);
+ const x = cx + Math.cos(angle) * r * (0.4 + Math.random()*0.8);
+ const y = baseY - r * (0.9 + Math.random()*0.4);
+ return {
+ x,
+ y: initial ? y - Math.random()*H*0.6 : (Math.random() < 0.5 ? -20 : y),
+ vy: 0.3 + Math.random()*0.6,
+ vx: -0.3 + Math.random()*0.6,
+ wobblePhase: Math.random()*Math.PI*2,
+ wobbleSpeed: 0.002 + Math.random()*0.002,
+ size: 3 + Math.random()*4,
+ color: leafColor(),
+ life: 0
+ };
+ }
+
+ function updateLeaves(dt, wind) {
+ const targetCount = seasonLeafCount();
+ if (leaves.length < targetCount && Math.random() < 0.3) {
+ leaves.push(makeLeaf(false));
+ }
+ for (let i = leaves.length - 1; i >= 0; i--) {
+ const L = leaves[i];
+ L.life += dt;
+ L.vx += wind * 0.002;
+ L.vy += 0.0006 * dt;
+ L.wobblePhase += L.wobbleSpeed * dt;
+ L.x += (L.vx + Math.sin(L.wobblePhase)*0.03*dt) * (dt*0.03);
+ L.y += L.vy * (dt*0.03);
+ if (L.y - L.size > H + 40 || L.x < -60 || L.x > W + 60 || L.life > 60000) {
+ leaves.splice(i,1);
+ }
+ }
+ }
+
+ function drawLeaves() {
+ for (const L of leaves) {
+ ctx.save();
+ ctx.translate(L.x, L.y);
+ ctx.rotate(Math.sin(L.wobblePhase)*0.6);
+ ctx.fillStyle = L.color;
+ ctx.beginPath();
+ ctx.ellipse(0, 0, L.size*0.7, L.size, 0, 0, Math.PI*2);
+ ctx.fill();
+ ctx.restore();
+ }
+ }
+
+ function branchColor(depth, maxDepth) {
+ const t = depth / maxDepth;
+ const br = 80 + t*70;
+ const bg = 55 + t*35;
+ const bb = 40 + t*20;
+ return `rgba(${br|0},${bg|0},${bb|0},${0.94 - t*0.4})`;
+ }
+
+ function drawTree(time) {
+ ctx.save();
+ ctx.translate(cx, baseY);
+ const trunkLen = H * 0.24;
+ const initialProgress = growProgress;
+ const maxGrowDepth = Math.max(1, Math.round(initialProgress * maxDepth));
+ function recurse(len, angle, depth) {
+ if (depth > maxGrowDepth || len < 2) return;
+ const localT = depth / maxDepth;
+ const wind = Math.sin(windPhase + depth*0.6) * (0.08 + 0.12*localT);
+ const a = angle + wind;
+ const x2 = Math.cos(a) * len;
+ const y2 = Math.sin(a) * len;
+ ctx.strokeStyle = branchColor(depth, maxDepth);
+ ctx.lineWidth = Math.max(1, (maxDepth - depth + 1) * 0.9);
+ ctx.beginPath();
+ ctx.moveTo(0,0);
+ ctx.lineTo(x2,y2);
+ ctx.stroke();
+ ctx.save();
+ ctx.translate(x2,y2);
+
+ if (depth < maxGrowDepth) {
+ const nextLen = len * (0.72 + 0.06*Math.sin(time*0.0004 + depth));
+ const spread = 0.42 + 0.16*Math.sin(time*0.0002 + depth*1.3);
+ recurse(nextLen, a - spread, depth+1);
+ recurse(nextLen*0.86, a + spread*0.9, depth+1);
+ if (depth === maxDepth-1 && Math.random()<0.12) {
+ recurse(nextLen*0.7, a + (Math.random()*0.6-0.3), depth+1);
+ }
+ }
+ ctx.restore();
+ }
+ recurse(trunkLen, -Math.PI/2, 1);
+ ctx.restore();
+ }
+
+ function drawBackground(time) {
+ const g = ctx.createLinearGradient(0,0,0,H);
+ const t = 0.5 + 0.5*Math.sin(time*0.00005);
+ const top = `rgb(${8+10*t|0},${18+30*t|0},${38+80*t|0})`;
+ const mid = `rgb(${4+8*t|0},${10+16*t|0},${20+40*t|0})`;
+ ctx.fillStyle = g;
+ g.addColorStop(0, top);
+ g.addColorStop(0.4, mid);
+ g.addColorStop(1, "#020308");
+ ctx.fillRect(0,0,W,H);
+
+ ctx.save();
+ ctx.fillStyle = "rgba(255,255,255,0.5)";
+ for (let i=0;i<40;i++){
+ const px = (i*97 + time*0.01) % W;
+ const py = (i*53 + time*0.012) % (H*0.5);
+ ctx.globalAlpha = 0.25 + 0.4*Math.sin(time*0.0003 + i);
+ ctx.beginPath();
+ ctx.arc(px, py, 0.8 + (i%4)*0.3, 0, Math.PI*2);
+ ctx.fill();
+ }
+ ctx.restore();
+
+ ctx.save();
+ ctx.fillStyle = "#020308";
+ ctx.beginPath();
+ ctx.moveTo(0,H);
+ ctx.quadraticCurveTo(W*0.25,H*0.8,W*0.5,H*0.88);
+ ctx.quadraticCurveTo(W*0.8,H*0.96,W,H*0.9);
+ ctx.lineTo(W,H);
+ ctx.closePath();
+ ctx.fill();
+ ctx.restore();
+ }
+
+ function loop(now) {
+ const dt = now - lastTime;
+ lastTime = now;
+ growProgress += dt * 0.00008;
+ if (growProgress > 1) growProgress = 1;
+ windPhase += dt * windSpeed * (0.8 + 0.4*Math.sin(now*0.0002));
+
+ const wind = Math.sin(windPhase)*1.6 + Math.sin(windPhase*0.7)*0.7;
+
+ drawBackground(now);
+ ctx.save();
+ ctx.shadowColor = "rgba(0,0,0,0.8)";
+ ctx.shadowBlur = 12;
+ drawTree(now);
+ ctx.restore();
+
+ updateLeaves(dt, wind);
+ drawLeaves();
+
+ requestAnimationFrame(loop);
+ }
+
+ resetLeaves();
+ requestAnimationFrame(loop);
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/10c3c876aa67/gpt.png b/data/artifacts/10c3c876aa67/gpt.png
new file mode 100644
index 0000000..c7903eb
Binary files /dev/null and b/data/artifacts/10c3c876aa67/gpt.png differ
diff --git a/data/artifacts/10c3c876aa67/grok.html b/data/artifacts/10c3c876aa67/grok.html
new file mode 100644
index 0000000..c8fe628
--- /dev/null
+++ b/data/artifacts/10c3c876aa67/grok.html
@@ -0,0 +1,213 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Fractal Tree</title>
+<style>
+*{margin:0;padding:0;box-sizing:border-box}
+body{overflow:hidden;background:#0a0a12;font-family:system-ui,sans-serif}
+canvas{display:block;width:100vw;height:100vh}
+.ui{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);background:rgba(20,20,35,0.85);backdrop-filter:blur(12px);padding:14px 28px;border-radius:16px;border:1px solid rgba(255,255,255,0.08);display:flex;align-items:center;gap:16px;z-index:10;box-shadow:0 8px 32px rgba(0,0,0,0.4)}
+.ui label{color:#c8c8d8;font-size:13px;white-space:nowrap;letter-spacing:0.03em}
+.ui input[type=range]{width:160px;accent-color:#7cb87c;cursor:pointer}
+.ui span{color:#8fbc8f;font-size:13px;font-variant-numeric:tabular-nums;min-width:18px}
+</style>
+</head>
+<body>
+<canvas id="c"></canvas>
+<div class="ui">
+<label>Branch Depth</label>
+<input type="range" id="depth" min="1" max="12" value="9" step="1">
+<span id="dval">9</span>
+</div>
+<script>
+const canvas=document.getElementById('c');
+const ctx=canvas.getContext('2d');
+const depthSlider=document.getElementById('depth');
+const dval=document.getElementById('dval');
+
+let W,H,maxDepth=9,time=0,growProgress=0;
+const leaves=[];
+const falling=[];
+const SEASON_COLORS=[
+ ['#2d5a27','#3d7a37','#4a8f3f','#5ba84a'],
+ ['#c45c26','#d4763a','#e8a04a','#b84020','#8b4513','#cd853f'],
+ ['#e8e8f0','#d0d0e0','#c0c8d8','#a8b0c0'],
+ ['#3a7a30','#4a9a3a','#5cb84a','#2d6a28','#6bc45a']
+];
+let season=0;
+let seasonTimer=0;
+
+function resize(){
+ W=canvas.width=window.innerWidth;
+ H=canvas.height=window.innerHeight;
+}
+window.addEventListener('resize',resize);
+resize();
+
+depthSlider.addEventListener('input',()=>{
+ maxDepth=+depthSlider.value;
+ dval.textContent=maxDepth;
+ growProgress=0;
+ leaves.length=0;
+ falling.length=0;
+});
+
+function wind(y,t){
+ return Math.sin(t*0.7+y*0.008)*0.12+Math.sin(t*1.3+y*0.015)*0.06+Math.sin(t*0.3)*0.04;
+}
+
+function drawBranch(x,y,len,angle,depth,t){
+ if(depth>maxDepth||len<2)return;
+ const grow=Math.min(1,Math.max(0,(growProgress-depth*0.08)/(0.5)));
+ if(grow<=0)return;
+ const w=wind(y,t)*(1+depth*0.15);
+ const a=angle+w;
+ const el=len*grow;
+ const x2=x+Math.sin(a)*el;
+ const y2=y-Math.cos(a)*el;
+
+ const trunk=depth===0;
+ const lw=Math.max(0.5, (maxDepth-depth+1)*1.6*grow);
+ const tcol=Math.floor(40+depth*8);
+ ctx.beginPath();
+ ctx.moveTo(x,y);
+ ctx.lineTo(x2,y2);
+ ctx.strokeStyle=trunk?`rgb(${90+tcol*0.3},${60+tcol*0.2},${30})`:`rgb(${70+tcol},${50+tcol*0.6},${25+depth*2})`;
+ ctx.lineWidth=lw;
+ ctx.lineCap='round';
+ ctx.stroke();
+
+ if(depth>=maxDepth-3&&grow>0.7){
+ const cols=SEASON_COLORS[season%4];
+ const n=depth===maxDepth?3:1;
+ for(let i=0;i<n;i++){
+ const lx=x2+(Math.random()-0.5)*8;
+ const ly=y2+(Math.random()-0.5)*8;
+ const col=cols[Math.floor(Math.random()*cols.length)];
+ const r=2+Math.random()*3;
+ leaves.push({x:lx,y:ly,r,col,ox:lx,oy:ly,phase:Math.random()*Math.PI*2,depth});
+ if(leaves.length>800)leaves.shift();
+ }
+ }
+
+ const shrink=0.68+Math.sin(depth+t*0.1)*0.04;
+ const spread=0.45+Math.sin(depth*1.3)*0.08;
+ drawBranch(x2,y2,len*shrink,a-spread,depth+1,t);
+ drawBranch(x2,y2,len*shrink,a+spread,depth+1,t);
+ if(depth>2&&depth<maxDepth-1&&Math.sin(depth*7.3)>0.3){
+ drawBranch(x2,y2,len*shrink*0.75,a+spread*0.3*(depth%2?1:-1),depth+1,t);
+ }
+}
+
+function spawnFalling(){
+ if(leaves.length===0)return;
+ if(Math.random()>0.15)return;
+ const src=leaves[Math.floor(Math.random()*leaves.length)];
+ const cols=SEASON_COLORS[season%4];
+ falling.push({
+ x:src.x,y:src.y,
+ vx:(Math.random()-0.5)*1.2,
+ vy:0.3+Math.random()*0.6,
+ r:src.r*(0.7+Math.random()*0.5),
+ col:cols[Math.floor(Math.random()*cols.length)],
+ rot:Math.random()*Math.PI*2,
+ rv:(Math.random()-0.5)*0.08,
+ life:1
+ });
+ if(falling.length>300)falling.shift();
+}
+
+function updateFalling(t){
+ for(let i=falling.length-1;i>=0;i--){
+ const p=falling[i];
+ const w=wind(p.y,t)*40;
+ p.vx+=w*0.02;
+ p.vx*=0.98;
+ p.vy+=0.015;
+ p.x+=p.vx+Math.sin(t*2+p.rot)*0.4;
+ p.y+=p.vy;
+ p.rot+=p.rv;
+ p.life-=0.002;
+ if(p.y>H+20||p.life<=0)falling.splice(i,1);
+ }
+}
+
+function drawLeaves(t){
+ for(const l of leaves){
+ const w=wind(l.y,t);
+ const sx=l.ox+Math.sin(t*1.5+l.phase)*3+w*20;
+ const sy=l.oy+Math.cos(t*1.2+l.phase)*2;
+ l.x=sx;l.y=sy;
+ ctx.beginPath();
+ ctx.arc(sx,sy,l.r,0,Math.PI*2);
+ ctx.fillStyle=l.col;
+ ctx.globalAlpha=0.75;
+ ctx.fill();
+ }
+ ctx.globalAlpha=1;
+}
+
+function drawFalling(){
+ for(const p of falling){
+ ctx.save();
+ ctx.translate(p.x,p.y);
+ ctx.rotate(p.rot);
+ ctx.globalAlpha=Math.min(1,p.life)*0.85;
+ ctx.fillStyle=p.col;
+ ctx.beginPath();
+ ctx.ellipse(0,0,p.r,p.r*0.6,0,0,Math.PI*2);
+ ctx.fill();
+ ctx.restore();
+ }
+ ctx.globalAlpha=1;
+}
+
+function drawGround(){
+ const grd=ctx.createLinearGradient(0,H*0.85,0,H);
+ grd.addColorStop(0,'rgba(20,40,20,0)');
+ grd.addColorStop(0.3,'rgba(25,50,25,0.4)');
+ grd.addColorStop(1,'rgba(15,35,15,0.7)');
+ ctx.fillStyle=grd;
+ ctx.fillRect(0,H*0.85,W,H*0.15);
+}
+
+function drawSky(){
+ const grd=ctx.createLinearGradient(0,0,0,H);
+ const s=season%4;
+ if(s===0){grd.addColorStop(0,'#0c1a10');grd.addColorStop(1,'#1a2a18');}
+ else if(s===1){grd.addColorStop(0,'#1a1008');grd.addColorStop(1,'#2a1a10');}
+ else if(s===2){grd.addColorStop(0,'#0a0e18');grd.addColorStop(1,'#121828');}
+ else{grd.addColorStop(0,'#0a1810');grd.addColorStop(1,'#142818');}
+ ctx.fillStyle=grd;
+ ctx.fillRect(0,0,W,H);
+}
+
+function frame(ts){
+ time=ts*0.001;
+ growProgress=Math.min(1.5,growProgress+0.006);
+ seasonTimer+=0.001;
+ if(seasonTimer>12){seasonTimer=0;season++;leaves.length=0;}
+
+ drawSky();
+ drawGround();
+
+ const baseX=W/2;
+ const baseY=H*0.88;
+ const trunkLen=Math.min(W,H)*0.18;
+
+ leaves.length=0;
+ drawBranch(baseX,baseY,trunkLen,0,0,time);
+ drawLeaves(time);
+
+ spawnFalling();
+ updateFalling(time);
+ drawFalling();
+
+ requestAnimationFrame(frame);
+}
+requestAnimationFrame(frame);
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/10c3c876aa67/grok.png b/data/artifacts/10c3c876aa67/grok.png
new file mode 100644
index 0000000..2f7a1c5
Binary files /dev/null and b/data/artifacts/10c3c876aa67/grok.png differ
diff --git a/data/artifacts/10c3c876aa67/hermes3-8b.html b/data/artifacts/10c3c876aa67/hermes3-8b.html
new file mode 100644
index 0000000..8e396a6
--- /dev/null
+++ b/data/artifacts/10c3c876aa67/hermes3-8b.html
@@ -0,0 +1,100 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Recursive Fractal Tree</title>
+ <style>
+ body {
+ margin: 0;
+ padding: 0;
+ overflow: hidden;
+ }
+
+ canvas {
+ background: #aaa;
+ }
+ </style>
+</head>
+<body>
+ <script>
+ const canvas = document.createElement('canvas');
+ canvas.width = window.innerWidth * 0.8;
+ canvas.height = window.innerHeight;
+ document.body.appendChild(canvas);
+
+ const ctx = canvas.getContext('2d');
+
+ function drawTree(depth, x, y, len) {
+ if (depth === 0) {
+ return;
+ }
+
+ const angle = Math.random() * Math.PI / 4 - Math.PI / 8;
+
+ ctx.beginPath();
+ ctx.moveTo(x, y);
+ ctx.lineTo(x + len * Math.cos(angle), y - len * Math.sin(angle));
+ ctx.stroke();
+
+ setTimeout(() => {
+ drawTree(depth - 1, x + len * Math.cos(angle), y - len * Math.sin(angle), len * 0.7);
+ drawTree(depth - 1, x + len * Math.cos(angle) * 1.3, y - len * Math.sin(angle) * 1.3, len * 0.7);
+ }, 1000);
+
+ drawLeaves(Math.random() * 200 + 50, x, y, ctx);
+ }
+
+ function drawLeaves(count, x, y, ctx) {
+ for (let i = 0; i < count; i++) {
+ const size = Math.random() * 5 + 1;
+ ctx.beginPath();
+ ctx.arc(x, y, size, 0, 2 * Math.PI);
+ ctx.fillStyle = 'green';
+ ctx.fill();
+
+ setTimeout(() => {
+ drawLeaves(count - 1, x, y - (Math.random() * 4 + 3), ctx);
+ }, 1000);
+ }
+ }
+
+ function generateWind() {
+ const angle = Math.random() * Math.PI * 2;
+ const speed = Math.random() * 5 + 1;
+
+ for (let i = 0; i < canvas.height; i++) {
+ const windSpeed = speed - (i / canvas.height) * 3;
+ ctx.globalAlpha = (canvas.height - i) / canvas.height;
+ ctx.translate(0, i);
+ ctx.rotate(angle);
+ ctx.drawImage(canvas, -canvas.width, -windSpeed, canvas.width, canvas.height);
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
+ }
+ }
+
+ function resizeCanvas() {
+ canvas.width = window.innerWidth * 0.8;
+ canvas.height = window.innerHeight;
+
+ const ratio = canvas.height / canvas.width;
+ canvas.style.width = `${canvas.width}px`;
+ canvas.style.height = `${Math.max(canvas.width, canvas.width * ratio)}px`;
+
+ ctx.fillStyle = 'white';
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ }
+
+ window.addEventListener('resize', resizeCanvas);
+
+ drawTree(parseInt(document.getElementById('depth').value), canvas.width / 2, canvas.height, 150);
+
+ setInterval(() => {
+ generateWind();
+ drawLeaves(Math.random() * 200 + 50, canvas.width / 2, canvas.height, ctx);
+ }, 10000);
+
+ </script>
+ <input type="range" min="0" max="5" id="depth">
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/10c3c876aa67/hermes3-8b.png b/data/artifacts/10c3c876aa67/hermes3-8b.png
new file mode 100644
index 0000000..16a103c
Binary files /dev/null and b/data/artifacts/10c3c876aa67/hermes3-8b.png differ
diff --git a/data/artifacts/10c3c876aa67/kimi.html b/data/artifacts/10c3c876aa67/kimi.html
new file mode 100644
index 0000000..575d725
--- /dev/null
+++ b/data/artifacts/10c3c876aa67/kimi.html
@@ -0,0 +1,290 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Recursive Fractal Tree</title>
+<style>
+body {
+ margin: 0;
+ overflow: hidden;
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+}
+#canvas {
+ display: block;
+}
+#controls {
+ position: absolute;
+ top: 15px;
+ left: 15px;
+ background: rgba(255, 255, 255, 0.95);
+ padding: 15px;
+ border-radius: 8px;
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
+ z-index: 10;
+}
+label {
+ font-weight: bold;
+ color: #333;
+ display: block;
+ margin-bottom: 5px;
+ font-size: 14px;
+}
+input[type=range] {
+ width: 200px;
+ cursor: pointer;
+}
+#seasonText {
+ margin-top: 8px;
+ font-size: 13px;
+ color: #666;
+ font-weight: 600;
+}
+</style>
+</head>
+<body>
+<canvas id="canvas"></canvas>
+<div id="controls">
+ <label for="depthSlider">Branch Depth: <span id="depthVal">8</span></label>
+ <input type="range" id="depthSlider" min="1" max="12" value="8">
+ <div id="seasonText">Season: Spring</div>
+</div>
+
+<script>
+const canvas = document.getElementById('canvas');
+const ctx = canvas.getContext('2d');
+let width, height;
+
+function resize() {
+ width = canvas.width = window.innerWidth;
+ height = canvas.height = window.innerHeight;
+}
+window.addEventListener('resize', resize);
+resize();
+
+// Configuration
+let maxDepth = 8;
+let growth = 0; // 0 to 1 for grow animation
+let time = 0;
+let seasonPhase = 0; // Continuous 0-4
+let branchEnds = [];
+let particles = [];
+
+const seasons = [
+ {
+ name: 'Spring',
+ leafColors: ['#90EE90', '#98FB98', '#00FA9A', '#7CFC00'],
+ bgTop: '#87CEEB',
+ bgBottom: '#E0F6FF',
+ ground: '#90EE90'
+ },
+ {
+ name: 'Summer',
+ leafColors: ['#228B22', '#006400', '#32CD32', '#00FF00'],
+ bgTop: '#1E90FF',
+ bgBottom: '#87CEEB',
+ ground: '#228B22'
+ },
+ {
+ name: 'Autumn',
+ leafColors: ['#FF8C00', '#DC143C', '#FFD700', '#FF6347', '#D2691E'],
+ bgTop: '#B0C4DE',
+ bgBottom: '#F5F5DC',
+ ground: '#D2B48C'
+ },
+ {
+ name: 'Winter',
+ leafColors: ['#FFFFFF', '#F0F8FF', '#E6E6FA', '#D3D3D3'],
+ bgTop: '#696969',
+ bgBottom: '#D3D3D3',
+ ground: '#FFFAFA'
+ }
+];
+
+class LeafParticle {
+ constructor(x, y, isAmbient = false) {
+ this.x = x;
+ this.y = y;
+ this.isAmbient = isAmbient;
+
+ const s = seasons[Math.floor(seasonPhase) % 4];
+ this.color = s.leafColors[Math.floor(Math.random() * s.leafColors.length)];
+ this.size = Math.random() * 4 + 2;
+ this.vx = (Math.random() - 0.5) * (isAmbient ? 2 : 1);
+ this.vy = Math.random() * 1.5 + 0.5;
+ this.rotation = Math.random() * Math.PI * 2;
+ this.rotSpeed = (Math.random() - 0.5) * 0.08;
+ this.life = 1.0;
+ this.decay = Math.random() * 0.003 + 0.002;
+ this.swayOffset = Math.random() * Math.PI * 2;
+ }
+
+ update() {
+ // Wind effect increases with height
+ const wind = Math.sin(time * 2 + this.y * 0.005 + this.swayOffset) * 0.5 +
+ Math.sin(time * 0.5 + this.swayOffset) * 0.2;
+ this.x += this.vx + wind;
+ this.y += this.vy;
+ this.rotation += this.rotSpeed;
+ this.life -= this.decay;
+
+ // Ground collision
+ if (this.y > height - 15) {
+ this.y = height - 15;
+ this.vy = 0;
+ this.vx *= 0.95;
+ this.life -= 0.02;
+ }
+ }
+
+ draw() {
+ ctx.save();
+ ctx.translate(this.x, this.y);
+ ctx.rotate(this.rotation);
+ ctx.fillStyle = this.color;
+ ctx.globalAlpha = Math.max(0, Math.min(1, this.life));
+
+ // Draw leaf shape
+ ctx.beginPath();
+ ctx.ellipse(0, 0, this.size, this.size * 0.6, 0, 0, Math.PI * 2);
+ ctx.fill();
+
+ ctx.restore();
+ ctx.globalAlpha = 1;
+ }
+}
+
+function drawTree(x, y, length, angle, depth) {
+ if (depth <= 0) return;
+
+ // Wind calculation: composite sine waves for natural movement
+ // Tips move more than trunk
+ const depthFactor = (maxDepth - depth + 1) / maxDepth;
+ const windAngle = (Math.sin(time * 1.2 + depth * 0.3) * 0.04 +
+ Math.sin(time * 2.7 - depth * 0.5) * 0.02) * depthFactor;
+
+ const actualAngle = angle + windAngle;
+ const currentLength = length * Math.min(1, growth + (maxDepth - depth) * 0.05); // Lower branches grow first slightly
+
+ const endX = x + Math.cos(actualAngle) * currentLength;
+ const endY = y + Math.sin(actualAngle) * currentLength;
+
+ // Draw branch with tapering
+ ctx.beginPath();
+ ctx.moveTo(x, y);
+ ctx.lineTo(endX, endY);
+ ctx.lineWidth = depth * 1.5;
+ ctx.strokeStyle = `rgb(${50 + depth * 5}, ${30 + depth * 3}, ${10 + depth * 2})`;
+ ctx.lineCap = 'round';
+ ctx.stroke();
+
+ // Leaves at branch ends (only when grown)
+ if (depth === 1 && growth > 0.6) {
+ const seasonIdx = Math.floor(seasonPhase) % 4;
+
+ // Store position for particle spawning
+ if (Math.random() < 0.3) {
+ branchEnds.push({x: endX, y: endY});
+ }
+
+ // Draw static canopy leaves (except winter)
+ if (seasonIdx !== 3) {
+ ctx.fillStyle = seasons[seasonIdx].leafColors[0];
+ ctx.beginPath();
+ ctx.arc(endX, endY, 4 * growth, 0, Math.PI * 2);
+ ctx.fill();
+ }
+ }
+
+ // Recursive calls
+ const newLength = length * 0.75;
+ const branchAngle = 0.4; // 23 degrees approx
+
+ drawTree(endX, endY, newLength, actualAngle - branchAngle, depth - 1);
+ drawTree(endX, endY, newLength, actualAngle + branchAngle, depth - 1);
+}
+
+function drawBackground() {
+ const seasonIdx = Math.floor(seasonPhase) % 4;
+ const s = seasons[seasonIdx];
+
+ // Sky gradient
+ const grad = ctx.createLinearGradient(0, 0, 0, height);
+ grad.addColorStop(0, s.bgTop);
+ grad.addColorStop(1, s.bgBottom);
+ ctx.fillStyle = grad;
+ ctx.fillRect(0, 0, width, height);
+
+ // Ground
+ ctx.fillStyle = s.ground;
+ ctx.fillRect(0, height - 15, width, 15);
+}
+
+function animate() {
+ ctx.clearRect(0, 0, width, height);
+
+ // Update time and seasons
+ time += 0.016;
+ seasonPhase += 0.0005; // Slow season cycle
+
+ // Growth animation on load/reset
+ if (growth < 1) {
+ growth += 0.008;
+ if (growth > 1) growth = 1;
+ }
+
+ // Update UI
+ const currentSeason = seasons[Math.floor(seasonPhase) % 4];
+ document.getElementById('seasonText').textContent = `Season: ${currentSeason.name}`;
+
+ drawBackground();
+
+ // Reset branch tracking
+ branchEnds = [];
+
+ // Draw fractal tree
+ const trunkLength = height * 0.22;
+ drawTree(width / 2, height - 10, trunkLength, -Math.PI / 2, maxDepth);
+
+ // Spawn falling leaves from branch ends
+ if (branchEnds.length > 0 && Math.random() < 0.4) {
+ const spawnCount = Math.floor(Math.random() * 2) + 1;
+ for (let i = 0; i < spawnCount; i++) {
+ const source = branchEnds[Math.floor(Math.random() * branchEnds.length)];
+ particles.push(new LeafParticle(source.x, source.y));
+ }
+ }
+
+ // Ambient particles (snow in winter, pollen in spring, etc)
+ if (Math.random() < 0.15) {
+ particles.push(new LeafParticle(Math.random() * width, -10, true));
+ }
+
+ // Update and draw particles
+ for (let i = particles.length - 1; i >= 0; i--) {
+ const p = particles[i];
+ p.update();
+ p.draw();
+ if (p.life <= 0) {
+ particles.splice(i, 1);
+ }
+ }
+
+ requestAnimationFrame(animate);
+}
+
+// Controls
+const slider = document.getElementById('depthSlider');
+const depthVal = document.getElementById('depthVal');
+
+slider.addEventListener('input', (e) => {
+ maxDepth = parseInt(e.target.value);
+ depthVal.textContent = maxDepth;
+ growth = 0.3; // Partial regrowth animation for effect
+});
+
+// Start
+animate();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/10c3c876aa67/kimi.png b/data/artifacts/10c3c876aa67/kimi.png
new file mode 100644
index 0000000..1c85170
Binary files /dev/null and b/data/artifacts/10c3c876aa67/kimi.png differ
diff --git a/data/artifacts/10c3c876aa67/qwen25-7b.html b/data/artifacts/10c3c876aa67/qwen25-7b.html
new file mode 100644
index 0000000..7497c05
--- /dev/null
+++ b/data/artifacts/10c3c876aa67/qwen25-7b.html
@@ -0,0 +1,128 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title>Recursive Fractal Tree</title>
+ <style>
+ body {
+ margin: 0;
+ overflow: hidden;
+ background-color: #2b343c;
+ }
+ </style>
+</head>
+<body>
+<canvas id="canvas"></canvas>
+<script>
+const canvas = document.getElementById('canvas');
+const ctx = canvas.getContext('2d');
+
+canvas.width = window.innerWidth;
+canvas.height = window.innerHeight;
+
+let treeDepth = 7;
+let branches = [];
+
+class Branch {
+ constructor(x, y, length, angle, depth) {
+ this.x = x;
+ this.y = y;
+ this.length = length;
+ this.angle = angle;
+ this.depth = depth;
+ }
+
+ draw() {
+ ctx.beginPath();
+ ctx.moveTo(this.x, this.y);
+ ctx.lineTo(this.x + Math.cos(this.angle) * this.length, this.y - Math.sin(this.angle) * this.length);
+ ctx.stroke();
+ }
+
+ grow() {
+ const endX = this.x + Math.cos(this.angle) * this.length;
+ const endY = this.y - Math.sin(this.angle) * this.length;
+
+ if (this.depth > 0) {
+ branches.push(new Branch(endX, endY, this.length * 0.75, this.angle - Math.PI / 8 + Math.random() * Math.PI / 4, this.depth - 1));
+ branches.push(new Branch(endX, endY, this.length * 0.75, this.angle + Math.PI / 8 + Math.random() * Math.PI / 4, this.depth - 1));
+
+ ctx.strokeStyle = `hsl(${Math.floor(255 * (this.depth / treeDepth))}, 100%, ${100 - this.depth * 2}%)`;
+ }
+ }
+
+ sway() {
+ const angleVariation = Math.random() * Math.PI / 4 - Math.PI / 8;
+ ctx.save();
+ ctx.translate(this.x + Math.cos(this.angle) * this.length, this.y - Math.sin(this.angle) * this.length);
+ ctx.rotate(angleVariation);
+ ctx.beginPath();
+ ctx.moveTo(0, 0);
+ ctx.lineTo(0, -this.length);
+ ctx.stroke();
+ ctx.restore();
+ }
+}
+
+function drawTree(x, y, length, angle, depth) {
+ branches.push(new Branch(x, y, length, angle, depth));
+ if (depth > 0) {
+ const endX = x + Math.cos(angle) * length;
+ const endY = y - Math.sin(angle) * length;
+
+ ctx.strokeStyle = `hsl(${Math.floor(255 * (depth / treeDepth))}, 100%, ${100 - depth * 2}%)`;
+ ctx.beginPath();
+ ctx.moveTo(x, y);
+ ctx.lineTo(endX, endY);
+ ctx.stroke();
+
+ drawTree(endX, endY, length * 0.75, angle - Math.PI / 8 + Math.random() * Math.PI / 4, depth - 1);
+ drawTree(endX, endY, length * 0.75, angle + Math.PI / 8 + Math.random() * Math.PI / 4, depth - 1);
+ }
+}
+
+function update() {
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ branches.forEach(b => b.sway());
+ drawTree(canvas.width / 2, canvas.height, 50, 0, treeDepth);
+
+ const leafParticles = [];
+ for (let i = 0; i < Math.random() * 10 + 1; i++) {
+ const x = Math.random() * canvas.width;
+ const y = canvas.height + 200;
+ const size = 5;
+ const speed = 3;
+
+ leafParticles.push({x, y, size, speed});
+ }
+
+ ctx.beginPath();
+ leafParticles.forEach(leaf => {
+ ctx.moveTo(leaf.x, leaf.y);
+ ctx.arc(leaf.x, leaf.y, leaf.size, 0, Math.PI * 2);
+ ctx.fillStyle = 'rgba(156, 217, 54, 0.8)';
+ ctx.fill();
+ });
+ ctx.closePath();
+
+ setTimeout(update, 30);
+}
+
+document.querySelector('input').onchange = (e) => {
+ treeDepth = e.target.value;
+};
+
+drawTree(canvas.width / 2, canvas.height, 50, 0, treeDepth);
+update();
+</script>
+<script>
+const slider = document.createElement('input');
+slider.type = 'range';
+slider.min = 1;
+slider.max = 10;
+slider.step = 1;
+slider.value = 7;
+document.body.appendChild(slider);
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/10c3c876aa67/qwen25-7b.png b/data/artifacts/10c3c876aa67/qwen25-7b.png
new file mode 100644
index 0000000..938eb7f
Binary files /dev/null and b/data/artifacts/10c3c876aa67/qwen25-7b.png differ
diff --git a/data/artifacts/35303b0ef3b8/gemma3-12b.html b/data/artifacts/35303b0ef3b8/gemma3-12b.html
new file mode 100644
index 0000000..3b5a433
--- /dev/null
+++ b/data/artifacts/35303b0ef3b8/gemma3-12b.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Color Challenge</title>
+<style>body { font-family: sans-serif; text-align: center; }</style>
+</head>
+<body>
+<p>Blue.</p>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/35303b0ef3b8/gemma3-12b.png b/data/artifacts/35303b0ef3b8/gemma3-12b.png
new file mode 100644
index 0000000..7aec4ed
Binary files /dev/null and b/data/artifacts/35303b0ef3b8/gemma3-12b.png differ
diff --git a/data/artifacts/35303b0ef3b8/qwen3-14b.html b/data/artifacts/35303b0ef3b8/qwen3-14b.html
new file mode 100644
index 0000000..267d2a4
--- /dev/null
+++ b/data/artifacts/35303b0ef3b8/qwen3-14b.html
@@ -0,0 +1 @@
+<!DOCTYPE html><html><head><title>Color</title><style>body{display:flex;align-items:center;justify-content:center;height:100vh;margin:0;font-family:sans-serif;}</style></head><body><div style="color:#007FFF;">Azure</div></body></html>
\ No newline at end of file
diff --git a/data/artifacts/35303b0ef3b8/qwen3-14b.png b/data/artifacts/35303b0ef3b8/qwen3-14b.png
new file mode 100644
index 0000000..9d9de58
Binary files /dev/null and b/data/artifacts/35303b0ef3b8/qwen3-14b.png differ
diff --git a/data/artifacts/58d3738d2b99/gemma3-12b.html b/data/artifacts/58d3738d2b99/gemma3-12b.html
new file mode 100644
index 0000000..1ec6ea4
--- /dev/null
+++ b/data/artifacts/58d3738d2b99/gemma3-12b.html
@@ -0,0 +1,157 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Aetheria Wallpaper Studio</title>
+ <style>
+ body {
+ margin: 0;
+ font-family: 'apple-system', 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
+ background: #0d0d0f;
+ color: #f5f2ea;
+ overflow-x: hidden; /* Prevent horizontal scroll */
+ }
+
+ .container {
+ padding: 96px;
+ max-width: 1440px;
+ margin: 0 auto;
+ }
+
+ h1, h2, h3 {
+ font-family: 'Playfair Display', serif;
+ line-height: 1.2;
+ letter-spacing: .05em;
+ }
+
+ h1 {
+ font-size: 67px;
+ margin-bottom: 8px;
+ }
+
+ h2 {
+ font-size: 38px;
+ margin-bottom: 16px;
+ }
+
+ .hero {
+ text-align: center;
+ animation: fadeUp .7s cubic-bezier(.22,1,.36,1) both;
+ }
+
+ .collection {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
+ gap: 24px;
+ margin-top: 96px;
+ }
+
+ .card {
+ background: #17171c;
+ color: #f5f2ea;
+ border-radius: 14px;
+ padding: 32px;
+ box-shadow: 0 8px 24px rgba(0, 0, 0, .12);
+ transition: transform .25s ease-in-out, box-shadow .25s ease-in-out;
+ }
+
+ .card:hover {
+ box-shadow: 0 16px 48px rgba(0, 0, 0, .18);
+ transform: translateY(-8px);
+ }
+
+
+ .card h3 {
+ font-size: 28px;
+ margin-bottom: 8px;
+ }
+
+ .card p {
+ font-size: 16px;
+ line-height: 1.5;
+ }
+
+ .label {
+ font-family: 'apple-system', 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
+ font-size: 12px;
+ text-transform: uppercase;
+ letter-spacing: .15em;
+ color: #8a8578;
+ }
+
+ @keyframes fadeUp {
+ from {
+ opacity: 0;
+ transform: translateY(28px);
+ }
+ to {
+ opacity: 1;
+ transform: none;
+ }
+ }
+
+ /* Ambient Background Gradient */
+ body::before {
+ content: "";
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(90deg, #c9a961, #7d6a45); /* Luxe Noir Palette */
+ opacity: .2;
+ pointer-events: none;
+ animation: drift 18s linear infinite;
+ }
+
+ @keyframes drift {
+ 0% { background-position: 0% 50%; }
+ 50% { background-position: 100% 50%; }
+ 100% { background-position: 0% 50%; }
+ }
+
+ </style>
+</head>
+<body>
+ <div class="container">
+ <section class="hero">
+ <h1>Aetheria Wallpaper Studio</h1>
+ <h2>Curated Designs for Discerning Interiors</h2>
+ <p style="font-size: 21px; margin: 24px auto;">Elevate your space with our exclusive collection of handcrafted wallpapers. Each design is a testament to artistry and luxury.</p>
+ </section>
+
+ <section class="collection">
+ <div class="card" data-label="Botanica">
+ <h3>Celestial Bloom</h3>
+ <img src="https://images.unsplash.com/photo-1607235398184-f0d9a5db6b9f?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8Mnx8cm9vbXxlbnwwfHwwfHx8MA%3D%3D&auto=format&fit=crop&w=600&q=60" alt="Celestial Bloom Wallpaper" width="100%" height="200">
+ <p>A delicate floral pattern inspired by constellations. Impeccably printed on luxurious silk paper.</p>
+ </div>
+
+ <div class="card" data-label="Geometric">
+ <h3>Urban Echo</h3>
+ <img src="https://images.unsplash.com/photo-1607312548944-8e4f6a5c1d18?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8cm9vbXxlbnwwfHwwfHx8MA%3D%3D&auto=format&fit=crop&w=600&q=60" alt="Urban Echo Wallpaper" width="100%" height="200">
+ <p>Bold geometric shapes create a dynamic and modern aesthetic. Perfect for contemporary spaces.</p>
+ </div>
+
+ <div class="card" data-label="Abstract">
+ <h3>Lunar Drift</h3>
+ <img src="https://images.unsplash.com/photo-1608397265042-d8c3a4f1c5e8?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MTB8fHJvbGgtbm93bWlnaHxlbnwwfHwwfHx8MA%3D%3D&auto=format&fit=crop&w=600&q=60" alt="Lunar Drift Wallpaper" width="100%" height="200">
+ <p>A mesmerizing abstract design evoking the serenity of a lunar landscape. Available in multiple colorways.</p>
+ </div>
+ </section>
+ </div>
+
+ <script>
+ const cards = document.querySelectorAll('.card');
+ cards.forEach(card => {
+ card.addEventListener('animationend', () => {
+ if (card.style.animation !== 'fadeUp') {
+ card.style.animation = ''; // Remove animation after completion
+ }
+ });
+ });
+ </script>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/58d3738d2b99/gemma3-12b.png b/data/artifacts/58d3738d2b99/gemma3-12b.png
new file mode 100644
index 0000000..e0d264b
Binary files /dev/null and b/data/artifacts/58d3738d2b99/gemma3-12b.png differ
diff --git a/data/artifacts/58d3738d2b99/hermes3-8b.html b/data/artifacts/58d3738d2b99/hermes3-8b.html
new file mode 100644
index 0000000..9255dff
--- /dev/null
+++ b/data/artifacts/58d3738d2b99/hermes3-8b.html
@@ -0,0 +1,106 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Wallpaper Studio</title>
+ <style>
+ :root {
+ --bg: #0d0d0f;
+ --surface: #17171c;
+ --text: #f5f2ea;
+ --muted: #8a8578;
+ --accent: #c9a961;
+ --accent2: #7d6a45;
+ }
+ body, html {
+ height: 100%;
+ margin: 0;
+ font-family: sans-serif;
+ }
+ .hero {
+ background-color: var(--bg);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 90vh;
+ text-align: center;
+ color: var(--text);
+ }
+ h1 {
+ font-size: 4em;
+ margin-bottom: .5em;
+ animation: bounceIn 2s ease-out-quint forwards;
+ }
+ .collection-grid {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 20px;
+ padding: 40px;
+ }
+ .card {
+ background-color: var(--surface);
+ color: var(--text);
+ border-radius: 8px;
+ box-shadow: 0 4px 6px rgba(0,0,0,.1);
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 40px;
+ text-align: center;
+ }
+ .card:hover {
+ background-color: var(--accent);
+ }
+ h2 {
+ font-size: 1.5em; margin-bottom: .5em;
+ }
+ p {
+ font-size: 1em; color: var(--muted);
+ }
+
+ @keyframes bounceIn {
+ 0% { opacity: 0; transform: translateY(100px); }
+ 50% { transform: translateY(-20px); }
+ 70% { transform: translateY(-5px); }
+ 100% { opacity: 1; transform: translateY(0); }
+ }
+
+ </style>
+</head>
+<body>
+
+<div class="hero">
+ <h1>Discover Luxury Wallpapers</h1>
+</div>
+
+<div class="collection-grid">
+ <div class="card">
+ <h2>Royal Tapestry</h2>
+ <p>A masterpiece of royal tradition woven into richly textured tapestry. The opulent design captures the essence of grandeur and splendor.</p>
+ </div>
+ <div class="card">
+ <h2>Midnight Velvet</h2>
+ <p>Indulge in the luxurious midnight velvet wallpaper with its mesmerizing deep blue hue that creates an air of mystery and elegance. Feel the smoothness as it wraps your space in a cocoon of serenity.</p>
+ </div>
+ <div class="card">
+ <h2>Sapphire Silk</h2>
+ <p>Embrace the allure of sapphire silk, a stunning wallpaper that reflects sophistication and timeless beauty. The shimmering hue adds an element of luxury to any space.</p>
+ </div>
+</div>
+
+<script>
+ document.querySelector('h1').animate([
+ {transform: 'translateY(100px)', opacity: 0},
+ {transform: 'translateY(-20px)', offset: 0.5},
+ {transform: 'translateY(-5px)', offset: 0.7},
+ {transform: 'translateY(0)', opacity: 1, offset: 1}
+ ], {
+ duration: 2000,
+ easing: 'ease-out-quint',
+ fill: 'forwards'
+ });
+</script>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/58d3738d2b99/hermes3-8b.png b/data/artifacts/58d3738d2b99/hermes3-8b.png
new file mode 100644
index 0000000..3178c47
Binary files /dev/null and b/data/artifacts/58d3738d2b99/hermes3-8b.png differ
diff --git a/data/artifacts/58d3738d2b99/kimi.html b/data/artifacts/58d3738d2b99/kimi.html
new file mode 100644
index 0000000..a306e92
--- /dev/null
+++ b/data/artifacts/58d3738d2b99/kimi.html
@@ -0,0 +1,415 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Aurelie Studio | Bespoke Wallpaper Atelier</title>
+<style>
+:root{
+--bg:#0d0d0f;
+--surface:#17171c;
+--text:#f5f2ea;
+--muted:#8a8578;
+--accent:#c9a961;
+--accent2:#7d6a45;
+--display:'Didot','Bodoni MT','Playfair Display',Georgia,serif;
+--body:-apple-system,'Segoe UI','Helvetica Neue',Arial,sans-serif;
+--ease-hero:cubic-bezier(.22,1,.36,1);
+--ease-ui:cubic-bezier(.22,.9,.24,1);
+}
+
+*{
+margin:0;
+padding:0;
+box-sizing:border-box;
+}
+
+html{
+scroll-behavior:smooth;
+}
+
+body{
+font-family:var(--body);
+background:var(--bg);
+color:var(--text);
+line-height:1.6;
+overflow-x:hidden;
+}
+
+/* Hero Section */
+.hero{
+min-height:100vh;
+display:flex;
+flex-direction:column;
+justify-content:center;
+align-items:center;
+text-align:center;
+padding:0 24px;
+position:relative;
+}
+
+.hero::before{
+content:'';
+position:absolute;
+top:0;
+left:0;
+right:0;
+bottom:0;
+background:
+radial-gradient(ellipse at 20% 20%, rgba(201,169,97,0.08) 0%, transparent 50%),
+radial-gradient(ellipse at 80% 80%, rgba(125,106,69,0.06) 0%, transparent 50%);
+pointer-events:none;
+}
+
+.hero-label{
+font-size:12px;
+text-transform:uppercase;
+letter-spacing:0.2em;
+color:var(--muted);
+margin-bottom:24px;
+animation:fadeUp .8s var(--ease-hero) both;
+}
+
+.hero-title{
+font-family:var(--display);
+font-size:clamp(48px,10vw,90px);
+line-height:1.05;
+letter-spacing:-0.03em;
+font-weight:400;
+margin-bottom:32px;
+animation:fadeUp .9s var(--ease-hero) both;
+animation-delay:0.1s;
+}
+
+.hero-title span{
+display:block;
+color:var(--accent);
+}
+
+.hero-subtitle{
+font-size:18px;
+color:var(--muted);
+max-width:480px;
+line-height:1.7;
+animation:fadeUp .9s var(--ease-hero) both;
+animation-delay:0.2s;
+}
+
+.hero-cta{
+margin-top:48px;
+padding:18px 40px;
+background:transparent;
+border:1px solid var(--accent);
+color:var(--accent);
+font-size:12px;
+text-transform:uppercase;
+letter-spacing:0.15em;
+cursor:pointer;
+transition:all 0.4s var(--ease-ui);
+animation:fadeUp .9s var(--ease-hero) both;
+animation-delay:0.3s;
+}
+
+.hero-cta:hover{
+background:var(--accent);
+color:var(--bg);
+}
+
+/* Collection Section */
+.collection{
+padding:120px 24px;
+max-width:1200px;
+margin:0 auto;
+}
+
+.section-header{
+text-align:center;
+margin-bottom:80px;
+}
+
+.section-label{
+font-size:12px;
+text-transform:uppercase;
+letter-spacing:0.2em;
+color:var(--muted);
+display:block;
+margin-bottom:16px;
+}
+
+.section-title{
+font-family:var(--display);
+font-size:clamp(32px,5vw,50px);
+letter-spacing:-0.02em;
+font-weight:400;
+}
+
+/* Grid */
+.grid{
+display:grid;
+grid-template-columns:repeat(auto-fit,minmax(320px,1fr));
+gap:32px;
+}
+
+.card{
+background:var(--surface);
+border-radius:4px;
+overflow:hidden;
+position:relative;
+cursor:pointer;
+transform:translateY(0);
+transition:transform 0.5s var(--ease-ui),box-shadow 0.5s var(--ease-ui);
+animation:fadeUp .8s var(--ease-hero) both;
+}
+
+.card:nth-child(1){animation-delay:0.1s;}
+.card:nth-child(2){animation-delay:0.2s;}
+.card:nth-child(3){animation-delay:0.3s;}
+
+.card:hover{
+transform:translateY(-8px);
+box-shadow:0 24px 48px rgba(0,0,0,0.4),0 0 0 1px rgba(201,169,97,0.1);
+}
+
+.card-image{
+aspect-ratio:4/5;
+background:linear-gradient(135deg,var(--surface) 0%,#1f1f26 100%);
+position:relative;
+overflow:hidden;
+}
+
+.card-image::before{
+content:'';
+position:absolute;
+top:0;
+left:0;
+right:0;
+bottom:0;
+background:
+repeating-linear-gradient(
+90deg,
+transparent,
+transparent 2px,
+rgba(201,169,97,0.03) 2px,
+rgba(201,169,97,0.03) 4px
+);
+}
+
+.pattern{
+position:absolute;
+top:50%;
+left:50%;
+transform:translate(-50%,-50%);
+width:60%;
+height:60%;
+opacity:0.6;
+transition:all 0.6s var(--ease-ui);
+}
+
+.card:hover .pattern{
+transform:translate(-50%,-50%) scale(1.1);
+opacity:0.9;
+}
+
+.pattern-1{
+background:
+radial-gradient(circle at 30% 30%,var(--accent) 2px,transparent 2px),
+radial-gradient(circle at 70% 70%,var(--accent2) 2px,transparent 2px);
+background-size:24px 24px;
+}
+
+.pattern-2{
+background:
+linear-gradient(45deg,var(--accent) 1px,transparent 1px),
+linear-gradient(-45deg,var(--accent) 1px,transparent 1px);
+background-size:20px 20px;
+opacity:0.4;
+}
+
+.pattern-3{
+background:
+repeating-linear-gradient(
+0deg,
+transparent,
+transparent 8px,
+var(--accent) 8px,
+var(--accent) 10px
+);
+opacity:0.3;
+}
+
+.card-content{
+padding:32px;
+}
+
+.card-tag{
+font-size:11px;
+text-transform:uppercase;
+letter-spacing:0.15em;
+color:var(--accent);
+margin-bottom:12px;
+display:block;
+}
+
+.card-title{
+font-family:var(--display);
+font-size:24px;
+letter-spacing:-0.01em;
+margin-bottom:12px;
+font-weight:400;
+}
+
+.card-desc{
+font-size:14px;
+color:var(--muted);
+line-height:1.6;
+}
+
+.card-arrow{
+position:absolute;
+bottom:32px;
+right:32px;
+width:32px;
+height:32px;
+border:1px solid var(--muted);
+border-radius:50%;
+display:flex;
+align-items:center;
+justify-content:center;
+transition:all 0.4s var(--ease-ui);
+}
+
+.card:hover .card-arrow{
+border-color:var(--accent);
+background:var(--accent);
+transform:translateX(4px);
+}
+
+.card-arrow::after{
+content:'→';
+color:var(--muted);
+font-size:14px;
+transition:color 0.3s;
+}
+
+.card:hover .card-arrow::after{
+color:var(--bg);
+}
+
+/* Animations */
+@keyframes fadeUp{
+from{
+opacity:0;
+transform:translateY(28px);
+}
+to{
+opacity:1;
+transform:none;
+}
+}
+
+/* Responsive */
+@media (max-width:640px){
+.hero-title{
+font-size:42px;
+}
+.collection{
+padding:80px 20px;
+}
+.grid{
+grid-template-columns:1fr;
+gap:24px;
+}
+}
+
+/* Reduced motion */
+@media (prefers-reduced-motion:reduce){
+*,*::before,*::after{
+animation-duration:0.01ms !important;
+transition-duration:0.01ms !important;
+}
+}
+</style>
+</head>
+<body>
+
+<section class="hero">
+<span class="hero-label">Est. 2024 — London</span>
+<h1 class="hero-title">
+Artistry in
+<span>Every Roll</span>
+</h1>
+<p class="hero-subtitle">Bespoke wallpaper atelier crafting timeless interiors for discerning spaces. Hand-finished textures, archive-inspired patterns.</p>
+<button class="hero-cta" onclick="document.getElementById('collection').scrollIntoView({behavior:'smooth'})">
+Explore Collections
+</button>
+</section>
+
+<section class="collection" id="collection">
+<div class="section-header">
+<span class="section-label">The Collections</span>
+<h2 class="section-title">Curated Wallpapers</h2>
+</div>
+
+<div class="grid">
+<article class="card">
+<div class="card-image">
+<div class="pattern pattern-1"></div>
+</div>
+<div class="card-content">
+<span class="card-tag">Heritage Series</span>
+<h3 class="card-title">Gilded Lattice</h3>
+<p class="card-desc">Archive-inspired geometric motifs reimagined in metallic gold and deep charcoal. A study in rhythmic elegance.</p>
+<div class="card-arrow"></div>
+</div>
+</article>
+
+<article class="card">
+<div class="card-image">
+<div class="pattern pattern-2"></div>
+</div>
+<div class="card-content">
+<span class="card-tag">Botanical Studies</span>
+<h3 class="card-title">Fern & Shadow</h3>
+<p class="card-desc">Hand-drawn botanicals layered with atmospheric depth. Subtle tonal variations create living walls.</p>
+<div class="card-arrow"></div>
+</div>
+</article>
+
+<article class="card">
+<div class="card-image">
+<div class="pattern pattern-3"></div>
+</div>
+<div class="card-content">
+<span class="card-tag">Modern Minimal</span>
+<h3 class="card-title">Linear Dawn</h3>
+<p class="card-desc">Quiet horizontal striations inspired by morning light. Designed for contemplative, modern interiors.</p>
+<div class="card-arrow"></div>
+</div>
+</article>
+</div>
+</section>
+
+<script>
+// Intersection Observer for scroll-triggered reveals
+const observerOptions={
+root:null,
+rootMargin:'0px',
+threshold:0.1
+};
+
+const observer=new IntersectionObserver((entries)=>{
+entries.forEach(entry=>{
+if(entry.isIntersecting){
+entry.target.style.animationPlayState='running';
+}
+});
+},observerOptions);
+
+document.querySelectorAll('.card').forEach(card=>{
+card.style.animationPlayState='paused';
+observer.observe(card);
+});
+</script>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/58d3738d2b99/kimi.png b/data/artifacts/58d3738d2b99/kimi.png
new file mode 100644
index 0000000..4312e44
Binary files /dev/null and b/data/artifacts/58d3738d2b99/kimi.png differ
diff --git a/data/artifacts/6fb7d108c932/claude-code.html b/data/artifacts/6fb7d108c932/claude-code.html
new file mode 100644
index 0000000..f1e9df6
--- /dev/null
+++ b/data/artifacts/6fb7d108c932/claude-code.html
@@ -0,0 +1,244 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Warp Starfield</title>
+<style>
+ html, body {
+ margin: 0;
+ padding: 0;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+ background: #000;
+ cursor: crosshair;
+ }
+ canvas { display: block; }
+ #hud {
+ position: fixed;
+ left: 14px;
+ bottom: 12px;
+ font: 11px/1.6 "SF Mono", Menlo, Consolas, monospace;
+ color: rgba(160, 200, 255, 0.55);
+ pointer-events: none;
+ user-select: none;
+ letter-spacing: 0.5px;
+ text-shadow: 0 0 6px rgba(80, 140, 255, 0.4);
+ }
+ #speedbar {
+ position: fixed;
+ left: 14px;
+ bottom: 46px;
+ width: 140px;
+ height: 3px;
+ background: rgba(120, 160, 255, 0.15);
+ border-radius: 2px;
+ overflow: hidden;
+ pointer-events: none;
+ }
+ #speedfill {
+ height: 100%;
+ width: 30%;
+ background: linear-gradient(90deg, #3af, #aef);
+ border-radius: 2px;
+ box-shadow: 0 0 8px rgba(90, 180, 255, 0.8);
+ }
+</style>
+</head>
+<body>
+<canvas id="c"></canvas>
+<div id="speedbar"><div id="speedfill"></div></div>
+<div id="hud">WARP DRIVE — move mouse to steer · scroll to change speed</div>
+<script>
+(function () {
+ "use strict";
+
+ var canvas = document.getElementById("c");
+ var ctx = canvas.getContext("2d", { alpha: false });
+ var speedfill = document.getElementById("speedfill");
+
+ var W = 0, H = 0, CX = 0, CY = 0, DPR = 1;
+
+ function resize() {
+ DPR = Math.min(window.devicePixelRatio || 1, 2);
+ W = window.innerWidth;
+ H = window.innerHeight;
+ canvas.width = Math.floor(W * DPR);
+ canvas.height = Math.floor(H * DPR);
+ canvas.style.width = W + "px";
+ canvas.style.height = H + "px";
+ ctx.setTransform(DPR, 0, 0, DPR, 0, 0);
+ CX = W / 2;
+ CY = H / 2;
+ // hard reset the frame so we don't smear stale pixels after resize
+ ctx.fillStyle = "#000";
+ ctx.fillRect(0, 0, W, H);
+ }
+ window.addEventListener("resize", resize);
+ resize();
+
+ // ---- config ----
+ var NUM_STARS = Math.min(900, Math.max(400, Math.floor((W * H) / 1800)));
+ var DEPTH = 1600; // z range
+ var FOV = 320; // projection focal length
+ var MIN_SPEED = 2;
+ var MAX_SPEED = 90;
+
+ // ---- state ----
+ var speed = 16; // target speed (scroll-controlled)
+ var curSpeed = 16; // smoothed speed
+ var mouseX = 0, mouseY = 0; // -1..1 target steer
+ var steerX = 0, steerY = 0; // smoothed steer
+ var hueShift = 0;
+
+ window.addEventListener("mousemove", function (e) {
+ mouseX = (e.clientX / W) * 2 - 1;
+ mouseY = (e.clientY / H) * 2 - 1;
+ });
+ window.addEventListener("wheel", function (e) {
+ e.preventDefault();
+ speed += (e.deltaY < 0 ? 1 : -1) * (2 + speed * 0.12);
+ speed = Math.max(MIN_SPEED, Math.min(MAX_SPEED, speed));
+ }, { passive: false });
+
+ // touch support: drag steers, pinch-ish vertical two-finger not needed
+ var lastTouchY = null;
+ window.addEventListener("touchmove", function (e) {
+ var t = e.touches[0];
+ mouseX = (t.clientX / W) * 2 - 1;
+ mouseY = (t.clientY / H) * 2 - 1;
+ if (e.touches.length === 2) {
+ if (lastTouchY !== null) {
+ speed += (lastTouchY - e.touches[1].clientY) * 0.3;
+ speed = Math.max(MIN_SPEED, Math.min(MAX_SPEED, speed));
+ }
+ lastTouchY = e.touches[1].clientY;
+ }
+ e.preventDefault();
+ }, { passive: false });
+ window.addEventListener("touchend", function () { lastTouchY = null; });
+
+ // ---- stars ----
+ // Each star: x, y in world units centered on axis; z depth; px/py previous projected point; hue
+ var stars = new Array(NUM_STARS);
+
+ function spawn(s, randomZ) {
+ // spread wide so steering reveals new stars at edges
+ s.x = (Math.random() * 2 - 1) * DEPTH * 1.2;
+ s.y = (Math.random() * 2 - 1) * DEPTH * 1.2;
+ s.z = randomZ ? Math.random() * DEPTH : DEPTH;
+ s.px = null;
+ s.py = null;
+ s.hue = 200 + Math.random() * 60 - 30; // blue-white-ish, some warm outliers
+ if (Math.random() < 0.08) s.hue = 30 + Math.random() * 30; // occasional gold star
+ s.mag = 0.5 + Math.random() * 1.0; // brightness/size multiplier
+ return s;
+ }
+
+ for (var i = 0; i < NUM_STARS; i++) {
+ stars[i] = spawn({}, true);
+ }
+
+ // initial black fill
+ ctx.fillStyle = "#000";
+ ctx.fillRect(0, 0, W, H);
+
+ var lastT = performance.now();
+
+ function frame(now) {
+ var dt = Math.min((now - lastT) / 16.6667, 3); // normalize to 60fps units, clamp spikes
+ lastT = now;
+
+ // smooth controls
+ steerX += (mouseX - steerX) * 0.06 * dt;
+ steerY += (mouseY - steerY) * 0.06 * dt;
+ curSpeed += (speed - curSpeed) * 0.08 * dt;
+
+ var speedFrac = (curSpeed - MIN_SPEED) / (MAX_SPEED - MIN_SPEED);
+
+ // motion blur: translucent black wash — more speed, less wash (longer trails)
+ var fade = 0.35 - speedFrac * 0.22; // 0.35 slow .. 0.13 fast
+ ctx.fillStyle = "rgba(0,0,0," + fade.toFixed(3) + ")";
+ ctx.fillRect(0, 0, W, H);
+
+ // camera lateral drift from steering (world moves opposite the mouse)
+ var camVX = steerX * curSpeed * 14;
+ var camVY = steerY * curSpeed * 14;
+ // vanishing point also eases toward the mouse for a steering feel
+ var vpx = CX - steerX * W * 0.22;
+ var vpy = CY - steerY * H * 0.22;
+
+ ctx.lineCap = "round";
+
+ for (var i = 0; i < NUM_STARS; i++) {
+ var s = stars[i];
+
+ s.z -= curSpeed * dt;
+ s.x -= camVX * dt * (0.4 + 0.6 * (s.z / DEPTH)); // parallax: near stars shift more visually via projection anyway
+ s.y -= camVY * dt * (0.4 + 0.6 * (s.z / DEPTH));
+
+ if (s.z <= 1) {
+ spawn(s, false);
+ continue;
+ }
+
+ var k = FOV / s.z;
+ var sx = vpx + s.x * k;
+ var sy = vpy + s.y * k;
+
+ // recycle stars that fly off screen (with margin)
+ if (sx < -60 || sx > W + 60 || sy < -60 || sy > H + 60) {
+ spawn(s, false);
+ continue;
+ }
+
+ if (s.px !== null) {
+ var depthFrac = 1 - s.z / DEPTH; // 0 far .. 1 near
+ var size = (0.3 + depthFrac * 2.2) * s.mag;
+ var alpha = Math.min(1, 0.15 + depthFrac * 0.95) * (0.6 + 0.4 * s.mag);
+
+ // color: hotter/whiter at high speed
+ var sat = Math.max(0, 70 - speedFrac * 45);
+ var light = 62 + depthFrac * 30 + speedFrac * 8;
+
+ ctx.strokeStyle = "hsla(" + s.hue + "," + sat + "%," + light + "%," + alpha.toFixed(3) + ")";
+ ctx.lineWidth = size;
+ ctx.beginPath();
+ ctx.moveTo(s.px, s.py);
+ ctx.lineTo(sx, sy);
+ ctx.stroke();
+
+ // bright core dot on near stars
+ if (depthFrac > 0.75) {
+ ctx.fillStyle = "hsla(" + s.hue + ",30%,95%," + (alpha * 0.9).toFixed(3) + ")";
+ ctx.beginPath();
+ ctx.arc(sx, sy, size * 0.55, 0, 6.2832);
+ ctx.fill();
+ }
+ }
+
+ s.px = sx;
+ s.py = sy;
+ }
+
+ // subtle central glow that intensifies with speed
+ if (speedFrac > 0.05) {
+ var glowR = Math.max(60, Math.min(W, H) * (0.1 + speedFrac * 0.35));
+ var g = ctx.createRadialGradient(vpx, vpy, 0, vpx, vpy, glowR);
+ g.addColorStop(0, "rgba(150,190,255," + (0.10 * speedFrac).toFixed(3) + ")");
+ g.addColorStop(1, "rgba(150,190,255,0)");
+ ctx.fillStyle = g;
+ ctx.fillRect(vpx - glowR, vpy - glowR, glowR * 2, glowR * 2);
+ }
+
+ speedfill.style.width = (speedFrac * 100).toFixed(1) + "%";
+
+ requestAnimationFrame(frame);
+ }
+
+ requestAnimationFrame(frame);
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/6fb7d108c932/claude-code.png b/data/artifacts/6fb7d108c932/claude-code.png
new file mode 100644
index 0000000..996e033
Binary files /dev/null and b/data/artifacts/6fb7d108c932/claude-code.png differ
diff --git a/data/artifacts/6fb7d108c932/gemma3-12b.html b/data/artifacts/6fb7d108c932/gemma3-12b.html
new file mode 100644
index 0000000..7788bf4
--- /dev/null
+++ b/data/artifacts/6fb7d108c932/gemma3-12b.html
@@ -0,0 +1,128 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Warp Tunnel</title>
+<style>
+body { margin: 0; overflow: hidden; }
+canvas { display: block; }
+</style>
+</head>
+<body>
+<canvas id="tunnelCanvas"></canvas>
+
+<script>
+const canvas = document.getElementById('tunnelCanvas');
+const ctx = canvas.getContext('2d');
+
+canvas.width = window.innerWidth;
+canvas.height = window.innerHeight;
+
+let stars = [];
+let numStars = 500;
+let speed = 1;
+let cameraAngle = 0;
+let mouseX = 0;
+let mouseY = 0;
+
+
+function init() {
+ for (let i = 0; i < numStars; i++) {
+ stars.push({
+ x: Math.random() * canvas.width,
+ y: Math.random() * canvas.height,
+ z: Math.random() * 100, // Depth for perspective
+ size: Math.random() * 3 + 0.5
+ });
+ }
+}
+
+function update(dt) {
+ speed += (scrollDelta / 200); // Adjust speed based on scroll wheel
+ cameraAngle += (mouseX - canvas.width/2) * 0.01; // Steer with mouse x position
+ scrollDelta = 0; // Reset scroll delta
+
+ for (let i = 0; i < stars.length; i++) {
+ stars[i].z -= speed / 5; // Move towards the viewer based on speed and depth
+
+ if (stars[i].z <= -100) {
+ stars[i].x = Math.random() * canvas.width;
+ stars[i].y = Math.random() * canvas.height;
+ stars[i].z = 100; // Reset depth to the back of the tunnel
+ }
+ }
+
+ // Adjust camera angle for more dramatic effect
+ cameraAngle %= 360;
+}
+
+
+
+function draw() {
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+ for (let i = 0; i < stars.length; i++) {
+ const star = stars[i];
+
+ // Calculate perspective factor based on depth
+ const perspectiveFactor = 1 - star.z / 100; // Adjust depth range as needed
+ const size = star.size * perspectiveFactor;
+
+ // Transform coordinates for rotation and movement
+ let x = star.x;
+ let y = star.y;
+ if(cameraAngle > 0){
+ x += Math.cos((cameraAngle + (Math.random() * 15))) * 20 ;
+ y += Math.sin((cameraAngle + (Math.random()*15)))* 20 ;
+
+ }
+
+
+ // Draw the star with motion blur
+ ctx.save(); // Save current state
+ ctx.translate(x, y);
+ ctx.rotate(-cameraAngle * 0.005); // Slight rotation to enhance effect
+
+ ctx.fillStyle = `rgba(255, 255, 255, ${perspectiveFactor})`;
+ ctx.beginPath();
+ ctx.arc(0, 0, size, 0, Math.PI * 2);
+ ctx.fill();
+
+
+ ctx.restore(); // Restore state
+
+ }
+}
+
+
+
+let lastTime = 0;
+function gameLoop(timestamp) {
+ const dt = (timestamp - lastTime) / 1000;
+ lastTime = timestamp;
+
+ update(dt);
+ draw();
+
+ requestAnimationFrame(gameLoop);
+}
+
+
+let scrollDelta = 0;
+canvas.addEventListener('wheel', function(e){
+ scrollDelta += e.deltaY;
+
+});
+canvas.addEventListener('mousemove', function(e) {
+ mouseX = e.clientX;
+ mouseY = e.clientY;
+});
+
+
+
+init();
+gameLoop();
+
+
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/6fb7d108c932/gemma3-12b.png b/data/artifacts/6fb7d108c932/gemma3-12b.png
new file mode 100644
index 0000000..16a103c
Binary files /dev/null and b/data/artifacts/6fb7d108c932/gemma3-12b.png differ
diff --git a/data/artifacts/6fb7d108c932/gpt.html b/data/artifacts/6fb7d108c932/gpt.html
new file mode 100644
index 0000000..8fc7f2f
--- /dev/null
+++ b/data/artifacts/6fb7d108c932/gpt.html
@@ -0,0 +1,256 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>Warp-Speed Starfield Tunnel</title>
+<style>
+ html, body {
+ margin: 0;
+ padding: 0;
+ background: black;
+ overflow: hidden;
+ height: 100%;
+ width: 100%;
+ font-family: system-ui, sans-serif;
+ color: #ccc;
+ }
+ canvas {
+ display: block;
+ }
+ #hud {
+ position: fixed;
+ left: 10px;
+ top: 10px;
+ font-size: 12px;
+ background: rgba(0,0,0,0.5);
+ padding: 6px 8px;
+ border-radius: 4px;
+ pointer-events: none;
+ }
+</style>
+</head>
+<body>
+<canvas id="c"></canvas>
+<div id="hud">Move mouse to steer • Scroll to change warp speed</div>
+<script>
+(function() {
+ const canvas = document.getElementById('c');
+ const ctx = canvas.getContext('2d');
+
+ let w = window.innerWidth;
+ let h = window.innerHeight;
+ canvas.width = w;
+ canvas.height = h;
+
+ let cx = w / 2;
+ let cy = h / 2;
+
+ const starCountBase = 1200;
+ const depth = 1.6; // world half-size
+ const tunnelRadius = 0.7; // relative to min(w,h)/2
+
+ let stars = [];
+ let mouseX = 0, mouseY = 0;
+ let targetOffsetX = 0, targetOffsetY = 0;
+ let camOffsetX = 0, camOffsetY = 0;
+ let baseSpeed = 0.35;
+ let warpSpeed = baseSpeed;
+ let scrollVelocity = 0;
+ let lastTime = performance.now();
+
+ function randRange(a, b) {
+ return a + Math.random() * (b - a);
+ }
+
+ function createStar() {
+ // Distribute in a cylindrical tunnel around z-axis
+ const angle = Math.random() * Math.PI * 2;
+ const radius = Math.pow(Math.random(), 0.9) * tunnelRadius;
+ const x = Math.cos(angle) * radius;
+ const y = Math.sin(angle) * radius;
+ const z = randRange(0.1, depth);
+ const baseSize = randRange(0.4, 1.1);
+ const colorChoice = Math.random();
+ let color;
+ if (colorChoice < 0.7) color = [200 + Math.random() * 55, 200 + Math.random() * 55, 255];
+ else if (colorChoice < 0.9) color = [255, 220 + Math.random() * 20, 180 + Math.random() * 20];
+ else color = [180, 255, 200 + Math.random() * 55];
+ return { x, y, z, px: x, py: y, pz: z, size: baseSize, color };
+ }
+
+ function initStars() {
+ stars = [];
+ const density = (w * h) / (1280 * 720);
+ const starCount = Math.floor(starCountBase * Math.max(0.4, density));
+ for (let i = 0; i < starCount; i++) {
+ stars.push(createStar());
+ }
+ }
+
+ function resize() {
+ w = window.innerWidth;
+ h = window.innerHeight;
+ canvas.width = w;
+ canvas.height = h;
+ cx = w / 2;
+ cy = h / 2;
+ initStars();
+ }
+
+ window.addEventListener('resize', resize);
+
+ window.addEventListener('mousemove', (e) => {
+ const nx = (e.clientX / w) * 2 - 1;
+ const ny = (e.clientY / h) * 2 - 1;
+ mouseX = nx;
+ mouseY = ny;
+ // Desired camera offset in world space
+ targetOffsetX = nx * 0.55;
+ targetOffsetY = ny * 0.55;
+ });
+
+ window.addEventListener('wheel', (e) => {
+ // Adjust velocity based on wheel delta
+ scrollVelocity += (e.deltaY > 0 ? -1 : 1) * 0.08;
+ e.preventDefault();
+ }, { passive: false });
+
+ function clamp(v, min, max) {
+ return v < min ? min : (v > max ? max : v);
+ }
+
+ function project(x, y, z) {
+ // Simple perspective projection
+ const fov = 1.0; // smaller is zoomed-in
+ const scale = (w < h ? w : h) * 0.7;
+ const invZ = 1 / (z + fov);
+ const sx = cx + (x - camOffsetX * 0.7) * scale * invZ;
+ const sy = cy + (y - camOffsetY * 0.7) * scale * invZ;
+ return { sx, sy, invZ };
+ }
+
+ function step(dt) {
+ // Smooth scroll velocity and warp speed
+ scrollVelocity *= 0.9;
+ warpSpeed += scrollVelocity * dt * 0.5;
+ warpSpeed = clamp(warpSpeed, 0.08, 2.2);
+
+ // Easing towards target camera offset
+ const ease = 1 - Math.pow(0.001, dt * 60);
+ camOffsetX += (targetOffsetX - camOffsetX) * ease;
+ camOffsetY += (targetOffsetY - camOffsetY) * ease;
+
+ const move = warpSpeed * dt;
+ const nearPlane = 0.05;
+
+ for (let i = 0; i < stars.length; i++) {
+ const s = stars[i];
+
+ s.px = s.x;
+ s.py = s.y;
+ s.pz = s.z;
+
+ s.z -= move;
+
+ if (s.z < nearPlane) {
+ // Respawn far away to maintain tunnel illusion
+ const angle = Math.random() * Math.PI * 2;
+ const radius = Math.pow(Math.random(), 0.9) * tunnelRadius;
+ s.x = Math.cos(angle) * radius;
+ s.y = Math.sin(angle) * radius;
+ s.z = depth + randRange(0, 0.5);
+ s.px = s.x;
+ s.py = s.y;
+ s.pz = s.z;
+ }
+ }
+ }
+
+ function render() {
+ // Motion blur / persistence: draw translucent rect over frame
+ ctx.fillStyle = 'rgba(0, 0, 10, 0.4)';
+ ctx.fillRect(0, 0, w, h);
+
+ const baseGlow = 0.5 + warpSpeed * 0.2;
+ const maxTrail = 35 + warpSpeed * 30;
+
+ for (let i = 0; i < stars.length; i++) {
+ const s = stars[i];
+
+ const curr = project(s.x, s.y, s.z);
+ const prev = project(s.px, s.py, s.pz);
+
+ const sx = curr.sx, sy = curr.sy;
+ const psx = prev.sx, psy = prev.sy;
+
+ // Cull off-screen stars
+ if ((sx < -50 || sx > w + 50 || sy < -50 || sy > h + 50) &&
+ (psx < -50 || psx > w + 50 || psy < -50 || psy > h + 50)) {
+ continue;
+ }
+
+ const { color } = s;
+ const invZ = curr.invZ;
+ const size = s.size * (0.4 + invZ * 2.8);
+ const trailLen = Math.min(maxTrail, Math.hypot(sx - psx, sy - psy) * 1.5);
+
+ const alpha = clamp(0.2 + invZ * 1.5 + warpSpeed * 0.18, 0.05, 1);
+ const glow = baseGlow * invZ * 1.4;
+
+ // Star core
+ const grd = ctx.createRadialGradient(sx, sy, 0, sx, sy, size * 3 * (1 + glow));
+ grd.addColorStop(0, `rgba(${color[0]},${color[1]},${color[2]},${alpha})`);
+ grd.addColorStop(1, 'rgba(0,0,0,0)');
+ ctx.fillStyle = grd;
+ ctx.beginPath();
+ ctx.arc(sx, sy, size * 3 * (1 + glow), 0, Math.PI * 2);
+ ctx.fill();
+
+ // Streak
+ if (trailLen > 0.2) {
+ const dx = sx - psx;
+ const dy = sy - psy;
+ const len = Math.hypot(dx, dy) || 1;
+ const ux = (dx / len) * trailLen;
+ const uy = (dy / len) * trailLen;
+ const ex = sx + ux;
+ const ey = sy + uy;
+
+ const grad = ctx.createLinearGradient(sx, sy, ex, ey);
+ grad.addColorStop(0, `rgba(${color[0]},${color[1]},${color[2]},${alpha * 1.0})`);
+ grad.addColorStop(1, `rgba(${color[0]},${color[1]},${color[2]},0)`);
+ ctx.strokeStyle = grad;
+ ctx.lineWidth = 0.6 + invZ * 1.5;
+ ctx.beginPath();
+ ctx.moveTo(sx, sy);
+ ctx.lineTo(ex, ey);
+ ctx.stroke();
+ }
+ }
+
+ // Vignette
+ const rad = Math.max(w, h);
+ const vg = ctx.createRadialGradient(cx, cy, rad * 0.1, cx, cy, rad * 0.8);
+ vg.addColorStop(0, 'rgba(0,0,0,0)');
+ vg.addColorStop(1, 'rgba(0,0,0,0.75)');
+ ctx.fillStyle = vg;
+ ctx.fillRect(0, 0, w, h);
+ }
+
+ function loop(now) {
+ const dt = Math.min(0.05, (now - lastTime) / 1000);
+ lastTime = now;
+
+ step(dt);
+ render();
+
+ requestAnimationFrame(loop);
+ }
+
+ initStars();
+ lastTime = performance.now();
+ requestAnimationFrame(loop);
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/6fb7d108c932/gpt.png b/data/artifacts/6fb7d108c932/gpt.png
new file mode 100644
index 0000000..43cffd4
Binary files /dev/null and b/data/artifacts/6fb7d108c932/gpt.png differ
diff --git a/data/artifacts/6fb7d108c932/grok.html b/data/artifacts/6fb7d108c932/grok.html
new file mode 100644
index 0000000..0faafb3
--- /dev/null
+++ b/data/artifacts/6fb7d108c932/grok.html
@@ -0,0 +1,163 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Warp Speed</title>
+<style>
+*{margin:0;padding:0;box-sizing:border-box}
+html,body{width:100%;height:100%;overflow:hidden;background:#000}
+canvas{display:block;width:100%;height:100%;cursor:none}
+</style>
+</head>
+<body>
+<canvas id="c"></canvas>
+<script>
+const canvas=document.getElementById('c');
+const ctx=canvas.getContext('2d');
+let W,H,CX,CY;
+const STAR_COUNT=900;
+const stars=[];
+let speed=12;
+let targetSpeed=12;
+let camX=0,camY=0;
+let mouseX=0,mouseY=0;
+let mx=0,my=0;
+
+function resize(){
+ W=canvas.width=window.innerWidth;
+ H=canvas.height=window.innerHeight;
+ CX=W/2;CY=H/2;
+}
+window.addEventListener('resize',resize);
+resize();
+
+function spawnStar(z){
+ const angle=Math.random()*Math.PI*2;
+ const radius=Math.random()*W*0.45+40;
+ return{
+ x:Math.cos(angle)*radius,
+ y:Math.sin(angle)*radius,
+ z:z!==undefined?z:Math.random()*W,
+ pz:0,
+ hue:200+Math.random()*60,
+ bright:0.5+Math.random()*0.5,
+ size:0.6+Math.random()*1.4
+ };
+}
+
+for(let i=0;i<STAR_COUNT;i++)stars.push(spawnStar());
+
+window.addEventListener('mousemove',e=>{
+ mouseX=e.clientX;
+ mouseY=e.clientY;
+ mx=(e.clientX-CX)/CX;
+ my=(e.clientY-CY)/CY;
+});
+
+window.addEventListener('wheel',e=>{
+ e.preventDefault();
+ targetSpeed=Math.max(1,Math.min(60,targetSpeed-e.deltaY*0.04));
+},{passive:false});
+
+let last=performance.now();
+function frame(now){
+ const dt=Math.min(0.05,(now-last)/16.67);
+ last=now;
+ speed+=(targetSpeed-speed)*0.08*dt;
+
+ camX+=(mx*180-camX)*0.04*dt;
+ camY+=(my*120-camY)*0.04*dt;
+
+ ctx.fillStyle='rgba(0,0,4,0.35)';
+ ctx.fillRect(0,0,W,H);
+
+ const g=ctx.createRadialGradient(CX+camX*0.3,CY+camY*0.3,0,CX,CY,W*0.7);
+ g.addColorStop(0,'rgba(10,20,50,0.15)');
+ g.addColorStop(0.5,'rgba(5,8,20,0.05)');
+ g.addColorStop(1,'rgba(0,0,0,0)');
+ ctx.fillStyle=g;
+ ctx.fillRect(0,0,W,H);
+
+ const focal=W*0.55;
+ for(let i=0;i<STAR_COUNT;i++){
+ const s=stars[i];
+ s.pz=s.z;
+ s.z-=speed*dt;
+
+ if(s.z<=1){
+ const ns=spawnStar(W+Math.random()*W*0.3);
+ s.x=ns.x;s.y=ns.y;s.z=ns.z;s.pz=s.z;
+ s.hue=ns.hue;s.bright=ns.bright;s.size=ns.size;
+ continue;
+ }
+
+ const sx=(s.x-camX*s.z*0.002)*(focal/s.z)+CX+camX;
+ const sy=(s.y-camY*s.z*0.002)*(focal/s.z)+CY+camY;
+ const psx=(s.x-camX*s.pz*0.002)*(focal/s.pz)+CX+camX;
+ const psy=(s.y-camY*s.pz*0.002)*(focal/s.pz)+CY+camY;
+
+ const depth=1-s.z/W;
+ const alpha=Math.min(1,depth*1.4)*s.bright;
+ const r=s.size*(1+depth*3.5);
+
+ const dx=sx-psx,dy=sy-psy;
+ const len=Math.sqrt(dx*dx+dy*dy);
+ const streak=Math.min(len*1.2+speed*0.15,80)*depth;
+
+ if(len>0.5){
+ const nx=dx/len,ny=dy/len;
+ const ex=sx+nx*streak*0.3;
+ const ey=sy+ny*streak*0.3;
+ const bx=sx-nx*streak;
+ const by=sy-ny*streak;
+
+ const grad=ctx.createLinearGradient(bx,by,ex,ey);
+ grad.addColorStop(0,`hsla(${s.hue},90%,70%,0)`);
+ grad.addColorStop(0.4,`hsla(${s.hue},95%,80%,${alpha*0.5})`);
+ grad.addColorStop(1,`hsla(${s.hue+20},100%,90%,${alpha})`);
+
+ ctx.beginPath();
+ ctx.moveTo(bx,by);
+ ctx.lineTo(ex,ey);
+ ctx.strokeStyle=grad;
+ ctx.lineWidth=r;
+ ctx.lineCap='round';
+ ctx.stroke();
+ }
+
+ ctx.beginPath();
+ ctx.arc(sx,sy,r*0.7,0,Math.PI*2);
+ ctx.fillStyle=`hsla(${s.hue+30},100%,95%,${alpha})`;
+ ctx.fill();
+
+ if(depth>0.6&&speed>8){
+ ctx.beginPath();
+ ctx.arc(sx,sy,r*2.5,0,Math.PI*2);
+ ctx.fillStyle=`hsla(${s.hue},100%,70%,${alpha*0.12})`;
+ ctx.fill();
+ }
+ }
+
+ const vig=ctx.createRadialGradient(CX,CY,W*0.25,CX,CY,W*0.75);
+ vig.addColorStop(0,'rgba(0,0,0,0)');
+ vig.addColorStop(1,'rgba(0,0,0,0.55)');
+ ctx.fillStyle=vig;
+ ctx.fillRect(0,0,W,H);
+
+ ctx.beginPath();
+ ctx.arc(mouseX,mouseY,3,0,Math.PI*2);
+ ctx.fillStyle='rgba(180,220,255,0.7)';
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(mouseX,mouseY,12,0,Math.PI*2);
+ ctx.strokeStyle='rgba(120,180,255,0.25)';
+ ctx.lineWidth=1;
+ ctx.stroke();
+
+ requestAnimationFrame(frame);
+}
+requestAnimationFrame(frame);
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/6fb7d108c932/grok.png b/data/artifacts/6fb7d108c932/grok.png
new file mode 100644
index 0000000..2f87adf
Binary files /dev/null and b/data/artifacts/6fb7d108c932/grok.png differ
diff --git a/data/artifacts/6fb7d108c932/hermes3-8b.html b/data/artifacts/6fb7d108c932/hermes3-8b.html
new file mode 100644
index 0000000..b9358fa
--- /dev/null
+++ b/data/artifacts/6fb7d108c932/hermes3-8b.html
@@ -0,0 +1,122 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Procedural Starfield Tunnel</title>
+ <style>
+ body {
+ margin: 0;
+ overflow: hidden;
+ }
+
+ canvas {
+ display: block;
+ }
+ </style>
+</head>
+<body>
+ <canvas id="stars"></canvas>
+
+ <script>
+ const canvas = document.getElementById('stars');
+ const ctx = canvas.getContext('2d');
+
+ // Set canvas size
+ canvas.width = window.innerWidth * 0.9;
+ canvas.height = window.innerHeight * 0.9;
+
+ let starCount = 300;
+ const stars = [];
+
+ for (let i = 0; i < starCount; i++) {
+ stars.push({
+ x: Math.random() * canvas.width,
+ y: Math.random() * canvas.height,
+ speed: Math.random(),
+ size: Math.random() * 2 + 1
+ });
+ }
+
+ function drawStars() {
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+ for (let i = 0; i < starCount; i++) {
+ const star = stars[i];
+ ctx.beginPath();
+ ctx.arc(star.x, star.y, star.size, 0, Math.PI * 2);
+ ctx.fillStyle = `rgba(255, 255, 255, ${star.size / 3})`;
+ ctx.fill();
+
+ // Update star position
+ star.y += star.speed;
+
+ // Reset star if it goes off-screen
+ if (star.y > canvas.height) {
+ star.y = 0;
+ star.x = Math.random() * canvas.width;
+ }
+ }
+ }
+
+ function updateStars() {
+ for (let i = 0; i < starCount; i++) {
+ stars[i].y += stars[i].speed;
+
+ if (stars[i].y + stars[i].size > canvas.height) {
+ stars[i].y = -stars[i].size;
+ stars[i].x = Math.random() * canvas.width;
+ stars[i].speed = Math.random();
+ stars[i].size = Math.random() * 2 + 1;
+ }
+ }
+ }
+
+ // Render loop
+ function render() {
+ drawStars();
+ updateStars();
+
+ requestAnimationFrame(render);
+ }
+
+ window.addEventListener('resize', () => {
+ canvas.width = window.innerWidth * 0.9;
+ canvas.height = window.innerHeight * 0.9;
+
+ for (let i = 0; i < starCount; i++) {
+ stars[i].x = Math.random() * canvas.width;
+ stars[i].y = Math.random() * canvas.height;
+ stars[i].speed = Math.random();
+ stars[i].size = Math.random() * 2 + 1;
+ }
+ });
+
+ // Mouse controls
+ window.addEventListener('mousemove', (e) => {
+ if (e.movementX || e.movementY) {
+ canvas.style.cursor = 'none';
+
+ const offset = {
+ x: (e.clientX - canvas.offsetLeft),
+ y: (e.clientY - canvas.offsetTop)
+ };
+
+ for (let i = 0; i < starCount; i++) {
+ stars[i].x -= ((offset.x / canvas.width) * stars[i].speed);
+ stars[i].y -= ((offset.y / canvas.height) * stars[i].speed);
+
+ if (stars[i].y + stars[i].size > canvas.height) {
+ stars[i].y = canvas.clientHeight - stars[i].size;
+ }
+ }
+
+ } else {
+ canvas.style.cursor = 'default';
+ }
+ });
+
+ render();
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/6fb7d108c932/hermes3-8b.png b/data/artifacts/6fb7d108c932/hermes3-8b.png
new file mode 100644
index 0000000..16a103c
Binary files /dev/null and b/data/artifacts/6fb7d108c932/hermes3-8b.png differ
diff --git a/data/artifacts/6fb7d108c932/kimi.html b/data/artifacts/6fb7d108c932/kimi.html
new file mode 100644
index 0000000..aa77628
--- /dev/null
+++ b/data/artifacts/6fb7d108c932/kimi.html
@@ -0,0 +1,130 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<title>Warp Speed Starfield</title>
+<style>
+body { margin: 0; padding: 0; background: #000; overflow: hidden; }
+canvas { display: block; }
+</style>
+</head>
+<body>
+<canvas id="c"></canvas>
+<script>
+const canvas = document.getElementById('c');
+const ctx = canvas.getContext('2d');
+
+let width, height, centerX, centerY;
+const stars = [];
+const numStars = 2000;
+const fov = 300;
+const maxDepth = 3000;
+const spread = 3000;
+
+let speed = 20;
+let mouseX = 0, mouseY = 0;
+
+function resize() {
+ width = canvas.width = window.innerWidth;
+ height = canvas.height = window.innerHeight;
+ centerX = width / 2;
+ centerY = height / 2;
+}
+window.addEventListener('resize', resize);
+resize();
+
+window.addEventListener('mousemove', (e) => {
+ mouseX = e.clientX;
+ mouseY = e.clientY;
+});
+
+window.addEventListener('wheel', (e) => {
+ speed += e.deltaY * 0.05;
+ speed = Math.max(0.1, Math.min(speed, 200));
+}, { passive: true });
+
+class Star {
+ constructor() {
+ this.reset(true);
+ }
+
+ reset(initial = false) {
+ this.x = (Math.random() - 0.5) * spread;
+ this.y = (Math.random() - 0.5) * spread;
+ this.z = initial ? Math.random() * maxDepth : maxDepth;
+ this.pz = this.z;
+ }
+
+ update() {
+ this.pz = this.z;
+ this.z -= speed;
+
+ if (this.z <= 0) {
+ this.reset();
+ }
+ }
+
+ draw() {
+ const rotY = (mouseX - centerX) * 0.0005;
+ const rotX = (mouseY - centerY) * 0.0005;
+
+ const cosY = Math.cos(rotY);
+ const sinY = Math.sin(rotY);
+ const cosX = Math.cos(rotX);
+ const sinX = Math.sin(rotX);
+
+ const x1 = this.x * cosY - this.z * sinY;
+ const z1 = this.x * sinY + this.z * cosY;
+ const y1 = this.y * cosX - z1 * sinX;
+ const z2 = this.y * sinX + z1 * cosX;
+
+ const px1 = this.x * cosY - this.pz * sinY;
+ const pz1 = this.x * sinY + this.pz * cosY;
+ const py1 = this.y * cosX - pz1 * sinX;
+ const pz2 = this.y * sinX + pz1 * cosX;
+
+ if (z2 <= 0 || pz2 <= 0) return;
+
+ const scale = fov / z2;
+ const pScale = fov / pz2;
+
+ const x2d = x1 * scale + centerX;
+ const y2d = y1 * scale + centerY;
+ const px2d = px1 * pScale + centerX;
+ const py2d = py1 * pScale + centerY;
+
+ const depthAlpha = 1 - (this.z / maxDepth);
+ const alpha = Math.min(1, depthAlpha * 2);
+ const size = Math.max(0.5, scale * 1.5);
+ const b = Math.min(255, 200 + speed * 2);
+
+ ctx.beginPath();
+ ctx.moveTo(px2d, py2d);
+ ctx.lineTo(x2d, y2d);
+ ctx.strokeStyle = `rgba(255, 255, ${b}, ${alpha})`;
+ ctx.lineWidth = size;
+ ctx.lineCap = 'round';
+ ctx.stroke();
+ }
+}
+
+for (let i = 0; i < numStars; i++) {
+ stars.push(new Star());
+}
+
+function animate() {
+ ctx.fillStyle = '#000';
+ ctx.fillRect(0, 0, width, height);
+
+ stars.forEach(star => {
+ star.update();
+ star.draw();
+ });
+
+ requestAnimationFrame(animate);
+}
+
+animate();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/6fb7d108c932/kimi.png b/data/artifacts/6fb7d108c932/kimi.png
new file mode 100644
index 0000000..bca2867
Binary files /dev/null and b/data/artifacts/6fb7d108c932/kimi.png differ
diff --git a/data/artifacts/6fb7d108c932/qwen25-7b.html b/data/artifacts/6fb7d108c932/qwen25-7b.html
new file mode 100644
index 0000000..7843b9f
--- /dev/null
+++ b/data/artifacts/6fb7d108c932/qwen25-7b.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Warp-Speed Starfield Tunnel</title>
+ <style>
+ body { margin: 0; overflow: hidden; }
+ canvas { display: block; width: 100%; height: 100%; background: black; touch-action: none; cursor: none; }
+ </style>
+</head>
+<body>
+<canvas id="starfield"></canvas>
+<script>
+const canvas = document.getElementById('starfield');
+canvas.width = window.innerWidth;
+canvas.height = window.innerHeight;
+const ctx = canvas.getContext('2d');
+
+let stars = [];
+for (let i = 0; i < 500; i++) {
+ stars.push({
+ x: Math.random() * canvas.width,
+ y: Math.random() * canvas.height
+ });
+}
+
+function drawStars() {
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ for (let star of stars) {
+ const size = 1 + Math.random();
+ ctx.beginPath();
+ ctx.arc(star.x, star.y, size, 0, Math.PI * 2);
+ ctx.fillStyle = `hsl(${Math.random() * 360}, 100%, 50%)`;
+ ctx.fill();
+ }
+}
+
+function animate(time) {
+ requestAnimationFrame(animate);
+ const speed = window.scrollY / 100;
+ ctx.globalCompositeOperation = 'lighter';
+ for (let star of stars) {
+ star.y += speed;
+ if (star.y > canvas.height) star.y -= canvas.height;
+ }
+ drawStars();
+}
+
+canvas.addEventListener('mousemove', e => {
+ window.scrollY += (e.clientY - window.scrollY) / 4;
+});
+
+window.onwheel = e => {
+ const delta = Math.sign(e.deltaY);
+ if (delta === 0) return;
+ requestAnimationFrame(() => { window.scrollY -= delta * 50; });
+};
+
+animate(0);
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/6fb7d108c932/qwen25-7b.png b/data/artifacts/6fb7d108c932/qwen25-7b.png
new file mode 100644
index 0000000..c08db8e
Binary files /dev/null and b/data/artifacts/6fb7d108c932/qwen25-7b.png differ
diff --git a/data/artifacts/74df3b61e7ca/qwen3-14b.html b/data/artifacts/74df3b61e7ca/qwen3-14b.html
new file mode 100644
index 0000000..8cefa6e
--- /dev/null
+++ b/data/artifacts/74df3b61e7ca/qwen3-14b.html
@@ -0,0 +1,146 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+body {
+ margin:0;
+ overflow:hidden;
+ background:#0f0f0f;
+ color:white;
+ font-family:sans-serif;
+ display:flex;
+ flex-direction:column;
+ align-items:center;
+ justify-content:center;
+ height:100vh;
+}
+#sun {
+ position: absolute;
+ top: 20px;
+ left: 50%;
+ width: 150px;
+ height: 150px;
+ background: radial-gradient(circle at 30% 30%, #ff00ff, #00ffff, #00ff00);
+ border-radius: 50%;
+ box-shadow: 0 0 40px #ff00ff, 0 0 60px #00ffff;
+ transform: scale(1);
+ transition: transform 0.1s;
+ z-index:10;
+}
+#grid {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ display: grid;
+ grid-template-columns: repeat(20, 1fr);
+ grid-template-rows: repeat(20, 1fr);
+ perspective: 1000px;
+ transform-style: preserve-3d;
+}
+.grid-cell {
+ background: rgba(255,255,255,0.1);
+ border: 1px solid rgba(255,255,255,0.05);
+ transform: rotateX(0deg) rotateY(0deg) translateZ(0px);
+ transition: transform 0.1s;
+}
+button {
+ position: absolute;
+ bottom: 20px;
+ margin:0 10px;
+ padding: 10px 20px;
+ font-size: 16px;
+ background: #333;
+ color: white;
+ border: none;
+ border-radius: 5px;
+ cursor: pointer;
+}
+</style>
+</head>
+<body>
+<div id="sun"></div>
+<div id="grid"></div>
+<button id="play">Play</button>
+<button id="stop">Stop</button>
+<script>
+const grid = document.getElementById('grid');
+const sun = document.getElementById('sun');
+const playBtn = document.getElementById('play');
+const stopBtn = document.getElementById('stop');
+
+// Generate grid cells
+for (let i = 0; i < 400; i++) {
+ const cell = document.createElement('div');
+ cell.className = 'grid-cell';
+ const x = i % 20;
+ const y = Math.floor(i / 20);
+ const depth = (x + y) * 5;
+ cell.style.transform = `rotateX(${y*5}deg) rotateY(${x*5}deg) translateZ(${depth}px)`;
+ grid.appendChild(cell);
+}
+
+const AudioContext = window.AudioContext || window.webkitAudioContext;
+const audioCtx = new AudioContext();
+const analyser = audioCtx.createAnalyser();
+analyser.fftSize = 256;
+const bufferLength = analyser.frequencyBinCount;
+const dataArray = new Uint8Array(bufferLength);
+
+let oscillators = [];
+let isPlaying = false;
+
+function createOscillator(freq, type) {
+ const osc = audioCtx.createOscillator();
+ osc.type = type;
+ osc.frequency.setValueAtTime(freq, audioCtx.currentTime);
+ osc.connect(analyser);
+ osc.start();
+ return osc;
+}
+
+function startAudio() {
+ oscillators = [
+ createOscillator(200, 'square'),
+ createOscillator(300, 'sawtooth'),
+ createOscillator(400, 'triangle')
+ ];
+ analyser.connect(audioCtx.destination);
+}
+
+function stopAudio() {
+ oscillators.forEach(osc => osc.stop());
+ oscillators = [];
+}
+
+function animate() {
+ requestAnimationFrame(animate);
+ analyser.getByteFrequencyData(dataArray);
+ const average = dataArray.reduce((a, b) => a + b, 0) / bufferLength;
+
+ // Pulse sun and grid
+ sun.style.transform = `scale(${1 + average/256})`;
+ grid.style.transform = `scale(${1 + average/256})`;
+}
+
+playBtn.onclick = () => {
+ if (!isPlaying) {
+ isPlaying = true;
+ startAudio();
+ animate();
+ }
+};
+
+stopBtn.onclick = () => {
+ isPlaying = false;
+ stopAudio();
+};
+
+// Resume audio context on user interaction
+document.body.addEventListener('click', () => {
+ if (audioCtx.state === 'suspended') {
+ audioCtx.resume();
+ }
+});
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/74df3b61e7ca/qwen3-14b.png b/data/artifacts/74df3b61e7ca/qwen3-14b.png
new file mode 100644
index 0000000..29db670
Binary files /dev/null and b/data/artifacts/74df3b61e7ca/qwen3-14b.png differ
diff --git a/data/artifacts/966d54f224fd/qwen3-14b.html b/data/artifacts/966d54f224fd/qwen3-14b.html
new file mode 100644
index 0000000..ee079ec
--- /dev/null
+++ b/data/artifacts/966d54f224fd/qwen3-14b.html
@@ -0,0 +1,167 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Tron Clone</title>
+ <style>
+ html, body {
+ margin: 0;
+ padding: 0;
+ overflow: hidden;
+ background: black;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100%;
+ }
+ canvas {
+ border: 2px solid white;
+ background: #000;
+ }
+ #gameOver {
+ position: absolute;
+ color: white;
+ font-family: sans-serif;
+ font-size: 3em;
+ text-shadow: 0 0 10px #0f0, 0 0 20px #0f0;
+ pointer-events: none;
+ }
+ </style>
+</head>
+<body>
+ <canvas id="gameCanvas"></canvas>
+ <div id="gameOver" style="display:none;">GAME OVER</div>
+ <script>
+ const canvas = document.getElementById('gameCanvas');
+ const ctx = canvas.getContext('2d');
+ const gameOverText = document.getElementById('gameOver');
+
+ canvas.width = 800;
+ canvas.height = 600;
+
+ const player1 = {
+ x: 100,
+ y: 300,
+ dx: 0,
+ dy: 0,
+ trail: []
+ };
+
+ const player2 = {
+ x: 700,
+ y: 300,
+ dx: 0,
+ dy: 0,
+ trail: []
+ };
+
+ const speed = 4;
+ let keys = {};
+ let gameOver = false;
+
+ document.addEventListener('keydown', (e) => {
+ keys[e.key] = true;
+ });
+
+ document.addEventListener('keyup', (e) => {
+ keys[e.key] = false;
+ });
+
+ function updatePlayer(player) {
+ if (keys['ArrowUp'] && player.dy === 0) { player.dx = 0; player.dy = -speed; }
+ if (keys['ArrowDown'] && player.dy === 0) { player.dx = 0; player.dy = speed; }
+ if (keys['ArrowLeft'] && player.dx === 0) { player.dx = -speed; player.dy = 0; }
+ if (keys['ArrowRight'] && player.dx === 0) { player.dx = speed; player.dy = 0; }
+
+ if (keys['w'] && player.dy === 0) { player.dx = 0; player.dy = -speed; }
+ if (keys['s'] && player.dy === 0) { player.dx = 0; player.dy = speed; }
+ if (keys['a'] && player.dx === 0) { player.dx = -speed; player.dy = 0; }
+ if (keys['d'] && player.dx === 0) { player.dx = speed; player.dy = 0; }
+ }
+
+ function update() {
+ if (gameOver) return;
+
+ updatePlayer(player1);
+ updatePlayer(player2);
+
+ player1.x += player1.dx;
+ player1.y += player1.dy;
+ player2.x += player2.dx;
+ player2.y += player2.dy;
+
+ // Check wall collision
+ if (player1.x < 0 || player1.x >= canvas.width || player1.y < 0 || player1.y >= canvas.height ||
+ player2.x < 0 || player2.x >= canvas.width || player2.y < 0 || player2.y >= canvas.height) {
+ gameOver = true;
+ gameOverText.style.display = 'block';
+ return;
+ }
+
+ // Check trail collision
+ const p1Pos = { x: player1.x, y: player1.y };
+ const p2Pos = { x: player2.x, y: player2.y };
+
+ for (let segment of player1.trail) {
+ if (p1Pos.x === segment.x && p1Pos.y === segment.y) {
+ gameOver = true;
+ gameOverText.style.display = 'block';
+ return;
+ }
+ }
+
+ for (let segment of player2.trail) {
+ if (p2Pos.x === segment.x && p2Pos.y === segment.y) {
+ gameOver = true;
+ gameOverText.style.display = 'block';
+ return;
+ }
+ }
+
+ // Check player collision
+ if (p1Pos.x === p2Pos.x && p1Pos.y === p2Pos.y) {
+ gameOver = true;
+ gameOverText.style.display = 'block';
+ return;
+ }
+
+ // Add new position to trail
+ player1.trail.unshift({x: player1.x, y: player1.y});
+ player2.trail.unshift({x: player2.x, y: player2.y});
+
+ // Limit trail length
+ if (player1.trail.length > 1000) player1.trail.pop();
+ if (player2.trail.length > 1000) player2.trail.pop();
+ }
+
+ function draw() {
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+ // Draw trails
+ ctx.fillStyle = 'cyan';
+ for (let i = 0; i < player1.trail.length; i++) {
+ ctx.fillRect(player1.trail[i].x, player1.trail[i].y, 4, 4);
+ }
+
+ ctx.fillStyle = 'magenta';
+ for (let i = 0; i < player2.trail.length; i++) {
+ ctx.fillRect(player2.trail[i].x, player2.trail[i].y, 4, 4);
+ }
+
+ // Draw players
+ ctx.fillStyle = 'lime';
+ ctx.fillRect(player1.x, player1.y, 10, 10);
+
+ ctx.fillStyle = 'yellow';
+ ctx.fillRect(player2.x, player2.y, 10, 10);
+ }
+
+ function gameLoop() {
+ update();
+ draw();
+ if (!gameOver) requestAnimationFrame(gameLoop);
+ }
+
+ gameLoop();
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/966d54f224fd/qwen3-14b.png b/data/artifacts/966d54f224fd/qwen3-14b.png
new file mode 100644
index 0000000..ec80697
Binary files /dev/null and b/data/artifacts/966d54f224fd/qwen3-14b.png differ
diff --git a/data/artifacts/acebf42d306a/hermes3-8b.html b/data/artifacts/acebf42d306a/hermes3-8b.html
new file mode 100644
index 0000000..9c24162
--- /dev/null
+++ b/data/artifacts/acebf42d306a/hermes3-8b.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>AI Coding Assistant Market Comparison</title>
+ <style>
+ body {
+ font-family: Arial, sans-serif;
+ line-height: 1.6;
+ }
+ h2, h3 {
+ color: #333;
+ }
+ table {
+ width: 100%;
+ border-collapse: collapse;
+ }
+ th, td {
+ padding: 8px;
+ text-align: left;
+ border-bottom: 1px solid #ddd;
+ }
+ tr:hover {
+ background-color: #f5f5f5;
+ }
+ </style>
+</head>
+<body>
+ <h2>Top AI Coding Assistants Comparison (2023)</h2>
+
+ <!-- Table with top 10 AI coding assistants -->
+ <table>
+ <tr>
+ <th>Rank</th>
+ <th>Assistant</th>
+ <th>Company</th>
+ <th>Release Year</th>
+ <th>Primary Strengths</th>
+ <th>Weaknesses</th>
+ <th>Pricing</th>
+ <th>Supported IDEs</th>
+ <th>Supported Models</th>
+ <th>Context Window</th>
+ <th>Website</th>
+ </tr>
+ <!-- Example row: -->
+ <tr>
+ <td>1</td>
+ <td>GPT-Code</td>
+ <td>OpenAI</td>
+ <td>2022</td>
+ <td>Advanced code completion, natural language understanding</td>
+ <td>Limited IDE support, expensive</td>
+ <td>$20/month/user</td>
+ <td>VSCodium, Visual Studio Code</td>
+ <td>GPT-3</td>
+ <td>4096 tokens</td>
+ <td><a href="https://openai.com/">OpenAI</a></td>
+ </tr>
+ <!-- ... -->
+ </table>
+
+ <h2>Top 5 AI Coding Assistants Ranked by Category</h2>
+ <h3>Coding Assistance</h3>
+ <ol>
+ <!-- Example: -->
+ <li>GPT-Code - OpenAI (2022) - Advanced code completion, natural language understanding</li>
+ <!-- ... -->
+ </ol>
+
+ <h3>Speed</h3>
+ <ol>
+ <!-- Example: -->
+ <li>Codex - Google (2022) - Fast response times, large context window</li>
+ <!-- ... -->
+ </ol>
+
+ <h3>Accuracy</h3>
+ <ol>
+ <!-- Example: -->
+ <li>Groks - Grok AI (2021) - High accuracy code generation, extensive training data</li>
+ <!-- ... -->
+ </ol>
+
+ <h3>Cost</h3>
+ <ol>
+ <!-- Example: -->
+ <li>Quabity - Quabity.ai (2022) - Free tier available, generous pricing for startups</li>
+ <!-- ... -->
+ </ol>
+
+ <h2>Executive Summary</h2>
+ <p>The AI coding assistant market has seen rapid growth in recent years. Top contenders include GPT-Code by OpenAI, Codex by Google, Groks from Grok AI, and Quabity.ai's Quabity. These tools vary greatly in pricing, supported IDEs, response speed, and coding accuracy. While all the assistants show great promise, their real-world impact and widespread adoption are still limited by factors like cost, limited IDE support, and relatively short context windows. More research is needed to determine which models will emerge as true leaders in this exciting field.</p>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/acebf42d306a/hermes3-8b.png b/data/artifacts/acebf42d306a/hermes3-8b.png
new file mode 100644
index 0000000..656ad13
Binary files /dev/null and b/data/artifacts/acebf42d306a/hermes3-8b.png differ
diff --git a/data/artifacts/ca355985ca95/kimi.html b/data/artifacts/ca355985ca95/kimi.html
new file mode 100644
index 0000000..f03074a
--- /dev/null
+++ b/data/artifacts/ca355985ca95/kimi.html
@@ -0,0 +1,182 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>ARENA Particle System</title>
+<style>
+body { margin: 0; overflow: hidden; background: #000; }
+canvas { display: block; }
+</style>
+</head>
+<body>
+<canvas id="c"></canvas>
+<script>
+const canvas = document.getElementById('c');
+const ctx = canvas.getContext('2d');
+let width, height;
+
+function resize() {
+ width = canvas.width = window.innerWidth;
+ height = canvas.height = window.innerHeight;
+}
+window.addEventListener('resize', resize);
+resize();
+
+function getTextPoints(text) {
+ const off = document.createElement('canvas');
+ const offCtx = off.getContext('2d');
+ off.width = width;
+ off.height = height;
+ const fontSize = Math.min(width / 4, 180);
+ offCtx.font = `bold ${fontSize}px Arial`;
+ offCtx.fillStyle = 'white';
+ offCtx.textAlign = 'center';
+ offCtx.textBaseline = 'middle';
+ offCtx.fillText(text, off.width / 2, off.height / 2);
+
+ const imageData = offCtx.getImageData(0, 0, off.width, off.height);
+ const data = imageData.data;
+ const points = [];
+ const step = 3;
+ for (let y = 0; y < off.height; y += step) {
+ for (let x = 0; x < off.width; x += step) {
+ const idx = (y * off.width + x) * 4;
+ if (data[idx + 3] > 128) {
+ points.push({x, y});
+ }
+ }
+ }
+ return points;
+}
+
+let targets = getTextPoints("ARENA");
+const count = 2000;
+
+while (targets.length < count) {
+ const t = targets[Math.floor(Math.random() * targets.length)];
+ targets.push({x: t.x + (Math.random() - 0.5) * 4, y: t.y + (Math.random() - 0.5) * 4});
+}
+targets.sort(() => Math.random() - 0.5);
+
+const colors = ['#00f3ff', '#ff00ff', '#ffe600', '#00ff66', '#ff0055', '#bd00ff'];
+
+class Particle {
+ constructor(i) {
+ this.x = Math.random() * width;
+ this.y = Math.random() * height;
+ this.vx = 0;
+ this.vy = 0;
+ this.target = targets[i];
+ this.color = colors[i % colors.length];
+ this.size = Math.random() * 2 + 1;
+ }
+
+ update(state) {
+ if (state === 'exploding') {
+ this.x += this.vx;
+ this.y += this.vy;
+ this.vx *= 0.96;
+ this.vy *= 0.96;
+ if (this.x < 0 || this.x > width) this.vx *= -1;
+ if (this.y < 0 || this.y > height) this.vy *= -1;
+ } else if (state === 'formed') {
+ const dx = this.target.x - this.x;
+ const dy = this.target.y - this.y;
+ this.x += dx * 0.1;
+ this.y += dy * 0.1;
+ this.vx = 0;
+ this.vy = 0;
+ } else {
+ const dx = this.target.x - this.x;
+ const dy = this.target.y - this.y;
+ this.vx += dx * 0.05;
+ this.vy += dy * 0.05;
+ this.vx *= 0.85;
+ this.vy *= 0.85;
+ this.x += this.vx;
+ this.y += this.vy;
+ }
+ }
+
+ draw() {
+ ctx.globalCompositeOperation = 'lighter';
+ ctx.fillStyle = this.color;
+ ctx.beginPath();
+ ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
+ ctx.fill();
+ }
+
+ explode(cx, cy) {
+ const dx = this.x - cx;
+ const dy = this.y - cy;
+ const dist = Math.sqrt(dx * dx + dy * dy) + 0.1;
+ const force = 400 / dist;
+ this.vx += (dx / dist) * force;
+ this.vy += (dy / dist) * force;
+ }
+}
+
+const particles = [];
+for (let i = 0; i < count; i++) {
+ particles.push(new Particle(i));
+}
+
+let state = 'forming';
+let formStart = Date.now();
+
+function checkFormed() {
+ let settled = 0;
+ for (let p of particles) {
+ const dx = p.target.x - p.x;
+ const dy = p.target.y - p.y;
+ if (dx * dx + dy * dy < 16) settled++;
+ }
+ if (settled > count * 0.9) {
+ state = 'formed';
+ }
+}
+
+canvas.addEventListener('click', (e) => {
+ if (state === 'forming' || state === 'formed') {
+ state = 'exploding';
+ const rect = canvas.getBoundingClientRect();
+ const cx = e.clientX - rect.left;
+ const cy = e.clientY - rect.top;
+ particles.forEach(p => p.explode(cx, cy));
+
+ setTimeout(() => {
+ state = 'forming';
+ }, 2000);
+ }
+});
+
+window.addEventListener('resize', () => {
+ resize();
+ targets = getTextPoints("ARENA");
+ while (targets.length < count) {
+ const t = targets[Math.floor(Math.random() * targets.length)];
+ targets.push({x: t.x, y: t.y});
+ }
+ targets.sort(() => Math.random() - 0.5);
+ particles.forEach((p, i) => p.target = targets[i]);
+});
+
+function animate() {
+ ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
+ ctx.fillRect(0, 0, width, height);
+
+ if (state === 'forming') checkFormed();
+
+ particles.forEach(p => {
+ p.update(state);
+ p.draw();
+ });
+
+ requestAnimationFrame(animate);
+}
+
+animate();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/ca355985ca95/kimi.png b/data/artifacts/ca355985ca95/kimi.png
new file mode 100644
index 0000000..3e6551c
Binary files /dev/null and b/data/artifacts/ca355985ca95/kimi.png differ
diff --git a/data/artifacts/e14b05b7754d/gemma3-12b.html b/data/artifacts/e14b05b7754d/gemma3-12b.html
new file mode 100644
index 0000000..d1329cd
--- /dev/null
+++ b/data/artifacts/e14b05b7754d/gemma3-12b.html
@@ -0,0 +1,225 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Sorting Algorithm Race</title>
+<style>
+body { font-family: sans-serif; }
+#container { display: flex; justify-content: space-around; }
+.algorithm { width: 300px; border: 1px solid black; padding: 10px; }
+canvas { width: 100%; height: 200px; }
+</style>
+</head>
+<body>
+
+<div id="container">
+ <div class="algorithm" id="bubble">
+ <h3>Bubble Sort</h3>
+ <button onclick="shuffleArray(bubbleData); bubbleSortAnimation()">Start/Shuffle Bubble</button>
+ <canvas id="bubbleCanvas"></canvas>
+ </div>
+ <div class="algorithm" id="quick">
+ <h3>Quick Sort</h3>
+ <button onclick="shuffleArray(quickData); quickSortAnimation()">Start/Shuffle Quick</button>
+ <canvas id="quickCanvas"></canvas>
+ </div>
+ <div class="algorithm" id="merge">
+ <h3>Merge Sort</h3>
+ <button onclick="shuffleArray(mergeData); mergeSortAnimation()">Start/Shuffle Merge</button>
+ <canvas id="mergeCanvas"></canvas>
+ </div>
+</div>
+
+<script>
+const arrayLength = 50;
+
+let bubbleData = Array.from({ length: arrayLength }, () => Math.floor(Math.random() * 256));
+let quickData = [...bubbleData]; // Create a copy to avoid modifying the original
+let mergeData = [...bubbleData]; // Another copy for Merge Sort
+
+
+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 bubbleSortAnimation() {
+ const ctx = document.getElementById('bubbleCanvas').getContext('2d');
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+
+ let swapped;
+ do {
+ swapped = false;
+ for (let i = 0; i < bubbleData.length - 1; ++i) {
+ // Comparison
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ drawArray(bubbleData, ctx, 'blue', 'lightblue'); // Highlight comparison
+ ctx.fillStyle = "blue";
+ ctx.fillRect(i * (ctx.canvas.width / bubbleData.length), 0, (ctx.canvas.width / bubbleData.length) -1 , ctx.canvas.height);
+
+ if (bubbleData[i] > bubbleData[i + 1]) {
+ // Swap
+ let temp = bubbleData[i];
+ bubbleData[i] = bubbleData[i + 1];
+ bubbleData[i + 1] = temp;
+
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ drawArray(bubbleData, ctx, 'blue', 'lightblue'); // Highlight swap
+ ctx.fillStyle = "red";
+ ctx.fillRect(i * (ctx.canvas.width / bubbleData.length), 0, (ctx.canvas.width / bubbleData.length) -1 , ctx.canvas.height);
+
+ swapped = true;
+ }
+ }
+ } while (swapped);
+
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ drawArray(bubbleData, ctx, 'blue', 'lightblue'); // Final array
+}
+
+
+function quickSortAnimation() {
+ const ctx = document.getElementById('quickCanvas').getContext('2d');
+
+ function partition(arr, low, high) {
+ let pivot = arr[high];
+ let i = (low - 1);
+
+ for (let j = low; j <= high - 1; j++) {
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ drawArray(arr, ctx, 'blue', 'lightblue');
+ ctx.fillStyle = "blue";
+ ctx.fillRect(j * (ctx.canvas.width / arr.length), 0, (ctx.canvas.width / arr.length) -1 , ctx.canvas.height);
+
+ if (arr[j] < pivot) {
+ i++;
+ [arr[i], arr[j]] = [arr[j], arr[i]];
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ drawArray(arr, ctx, 'blue', 'lightblue'); // Highlight swap
+ ctx.fillStyle = "red";
+ ctx.fillRect(i * (ctx.canvas.width / arr.length), 0, (ctx.canvas.width / arr.length) -1 , ctx.canvas.height);
+
+ }
+ }
+ [arr[i + 1], arr[high]] = [arr[high], arr[i + 1]];
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ drawArray(arr, ctx, 'blue', 'lightblue'); // Highlight swap
+ ctx.fillStyle = "red";
+ ctx.fillRect((i+1) * (ctx.canvas.width / arr.length), 0, (ctx.canvas.width / arr.length) -1 , ctx.canvas.height);
+ return (i + 1);
+ }
+
+ function quickSortHelper(arr, low, high) {
+ if (low < high) {
+ let pi = partition(arr, low, high);
+
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ drawArray(arr, ctx, 'blue', 'lightblue');
+
+ quickSortHelper(arr, low, pi - 1);
+ quickSortHelper(arr, pi + 1, high);
+ }
+ }
+
+ quickSortHelper(quickData, 0, quickData.length - 1);
+
+
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ drawArray(quickData, ctx, 'blue', 'lightblue');
+}
+
+
+
+function mergeSortAnimation() {
+ const ctx = document.getElementById('mergeCanvas').getContext('2d');
+
+ function merge(arr, l, m, r) {
+ let n1 = m - l + 1;
+ let n2 = r - m;
+
+ let L = arr.slice(l, m + 1);
+ let R = arr.slice(m + 1, r + 1);
+
+ let i = 0;
+ let j = 0;
+ let k = l;
+
+ while (i < n1 && j < n2) {
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ drawArray(arr, ctx, 'blue', 'lightblue');
+ ctx.fillStyle = "blue";
+ ctx.fillRect(k * (ctx.canvas.width / arr.length), 0, (ctx.canvas.width / arr.length) -1 , ctx.canvas.height);
+
+ if (L[i] <= R[j]) {
+ arr[k] = L[i];
+ i++;
+ } else {
+ arr[k] = R[j];
+ j++;
+ }
+ k++;
+ }
+
+ while (i < n1) {
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ drawArray(arr, ctx, 'blue', 'lightblue');
+ ctx.fillStyle = "blue";
+ ctx.fillRect(k * (ctx.canvas.width / arr.length), 0, (ctx.canvas.width / arr.length) -1 , ctx.canvas.height);
+
+ arr[k] = L[i];
+ i++;
+ k++;
+ }
+
+ while (j < n2) {
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ drawArray(arr, ctx, 'blue', 'lightblue');
+ ctx.fillStyle = "blue";
+ ctx.fillRect(k * (ctx.canvas.width / arr.length), 0, (ctx.canvas.width / arr.length) -1 , ctx.canvas.height);
+
+ arr[k] = R[j];
+ j++;
+ k++;
+ }
+ }
+
+
+ function mergeSortHelper(arr, l, r) {
+ if (l < r) {
+ let m = Math.floor((l + r) / 2);
+
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ drawArray(arr, ctx, 'blue', 'lightblue');
+
+
+ mergeSortHelper(arr, l, m);
+ mergeSortHelper(arr, m + 1, r);
+ merge(arr, l, m, r);
+ }
+ }
+
+ mergeSortHelper(mergeData, 0, mergeData.length - 1);
+
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ drawArray(mergeData, ctx, 'blue', 'lightblue');
+ }
+
+
+function drawArray(arr, ctx, comparisonColor, barColor) {
+ const canvasWidth = ctx.canvas.width;
+ const canvasHeight = ctx.canvas.height;
+ for (let i = 0; i < arr.length; i++) {
+ const x = i * (canvasWidth / arr.length);
+ const barHeight = (arr[i] / Math.max(...arr)) * canvasHeight;
+
+ ctx.fillStyle = barColor;
+ ctx.fillRect(x, canvasHeight - barHeight, (canvasWidth / arr.length) - 1 , barHeight);
+ }
+}
+
+</script>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/e14b05b7754d/gemma3-12b.png b/data/artifacts/e14b05b7754d/gemma3-12b.png
new file mode 100644
index 0000000..4314d7b
Binary files /dev/null and b/data/artifacts/e14b05b7754d/gemma3-12b.png differ
diff --git a/data/artifacts/e14b05b7754d/hermes3-8b.html b/data/artifacts/e14b05b7754d/hermes3-8b.html
new file mode 100644
index 0000000..f6a9e26
--- /dev/null
+++ b/data/artifacts/e14b05b7754d/hermes3-8b.html
@@ -0,0 +1,147 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title>Sorting Algorithm Visualizer</title>
+ <style>
+ body {
+ font-family: Arial, sans-serif;
+ }
+ canvas {
+ border: 1px solid black;
+ }
+ .controls {
+ margin-top: 20px;
+ }
+ .control-button {
+ padding: 5px 10px;
+ margin-right: 10px;
+ cursor: pointer;
+ }
+ </style>
+</head>
+<body>
+<div class="controls">
+ <div class="control-button" onclick="startAlgorithms()">Start/Shuffle</div>
+</div>
+
+<canvas id="bubbleChart" width="800" height="200"></canvas>
+<canvas id="quickSortChart" width="800" height="200"></canvas>
+<canvas id="mergeChart" width="800" height="200"></canvas>
+
+<script>
+ const bubbleCtx = document.getElementById('bubbleChart').getContext('2d');
+ const quickSortCtx = document.getElementById('quickSortChart').getContext('2d');
+ const mergeCtx = document.getElementById('mergeChart').getContext('2d');
+
+ function randomIntFromRange(min, max) {
+ return Math.floor(Math.random() * (max - min + 1) + min);
+ }
+
+ function generateRandomArray(length) {
+ let arr = [];
+ for (let i = 0; i < length; i++) {
+ arr.push(randomIntFromRange(10, 100));
+ }
+ return arr;
+ }
+
+ function drawChart(canvasId, array, color) {
+ const ctx = document.getElementById(canvasId).getContext('2d');
+ ctx.clearRect(0, 0, 800, 200);
+
+ let barWidth = 800 / array.length;
+ for (let i = 0; i < array.length; i++) {
+ ctx.fillStyle = color;
+ ctx.fillRect(i * barWidth, 200 - array[i], barWidth, array[i]);
+ }
+ }
+
+ function bubbleSort(array) {
+ let comparisons = 0;
+
+ for (let i = 0; i < array.length; i++) {
+ for (let j = 0; j < array.length - i - 1; j++) {
+ if (array[j] > array[j + 1]) {
+ let temp = array[j];
+ array[j] = array[j + 1];
+ array[j + 1] = temp;
+ comparisons++;
+ }
+ }
+ }
+
+ drawChart('bubbleChart', array, 'green');
+ return comparisons;
+ }
+
+ function quickSort(array, low, high) {
+ let comparisons = 0;
+
+ if (array.length === 0) return 0;
+
+ if (low < high) {
+ let pivotIndex = partition(array, low, high);
+ comparisons += quickSort(array, low, pivotIndex - 1);
+ comparisons += quickSort(array, pivotIndex + 1, high);
+ }
+
+ drawChart('quickSortChart', array, 'blue');
+ return comparisons;
+ }
+
+ function partition(array, low, high) {
+ let pivot = array[high];
+ let i = low - 1;
+
+ for (let j = low; j < high; j++) {
+ if (array[j] <= pivot) {
+ let temp = array[i + 1];
+ array[i + 1] = array[j];
+ array[j] = temp;
+ i++;
+ }
+ }
+
+ let temp2 = array[i + 1];
+ array[i + 1] = pivot;
+ array[high] = temp2;
+
+ return i + 1;
+ }
+
+ function mergeSort(array, low, high) {
+ let comparisons = 0;
+
+ if (array.length === 0) return 0;
+
+ if (low < high) {
+ let mid = Math.floor((low + high) / 2);
+ comparisons += mergeSort(array, low, mid);
+ comparisons += mergeSort(array, mid + 1, high);
+
+ drawChart('mergeChart', array, 'red');
+ return comparisons;
+ }
+ }
+
+ function startAlgorithms() {
+ let bubbleArray = generateRandomArray(20);
+ let quickSortArray = [...bubbleArray];
+ let mergeArray = [...quickSortArray];
+
+ document.getElementById('bubbleChart').style.display = 'block';
+ document.getElementById('quickSortChart').style.display = 'block';
+ document.getElementById('mergeChart').style.display = 'block';
+
+ drawChart('bubbleChart', bubbleArray, 'green');
+ quickSort(quickSortArray, 0, quickSortArray.length - 1);
+ mergeSort(mergeArray, 0, mergeArray.length - 1);
+
+ console.log("Bubble Sort Comparisons: ", bubbleSort(bubbleArray));
+ console.log("Quick Sort Comparisons: ", comparisons);
+ console.log("Merge Sort Comparisons: ", comparisons);
+ }
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/e14b05b7754d/hermes3-8b.png b/data/artifacts/e14b05b7754d/hermes3-8b.png
new file mode 100644
index 0000000..49becc4
Binary files /dev/null and b/data/artifacts/e14b05b7754d/hermes3-8b.png differ
diff --git a/data/artifacts/f79cffc20d43/claude-code.html b/data/artifacts/f79cffc20d43/claude-code.html
new file mode 100644
index 0000000..00b939d
--- /dev/null
+++ b/data/artifacts/f79cffc20d43/claude-code.html
@@ -0,0 +1,372 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>WC ARENA — Hot or Not: New Arrivals vs. Architect Trends</title>
+<style>
+ :root{
+ --bg:#0d0c0a; --panel:#161411; --panel2:#1d1a16; --line:#2b2721;
+ --ink:#ece5d8; --dim:#9a8f7d; --gold:#c9a45c; --hot:#e0552f; --cool:#5f8fa8;
+ --green:#7fae7a; --red:#c65b4e;
+ --serif:Georgia,'Times New Roman',serif; --sans:'Helvetica Neue',Helvetica,Arial,sans-serif;
+ }
+ *{margin:0;padding:0;box-sizing:border-box}
+ html,body{height:100%}
+ body{background:var(--bg);color:var(--ink);font-family:var(--sans);overflow-x:hidden}
+ body::before{content:"";position:fixed;inset:0;pointer-events:none;opacity:.5;z-index:0;
+ background:radial-gradient(1200px 500px at 50% -10%,rgba(201,164,92,.10),transparent 60%)}
+ .wrap{position:relative;z-index:1;max-width:1180px;margin:0 auto;padding:22px 20px 80px}
+
+ header{display:flex;align-items:flex-end;justify-content:space-between;gap:16px;border-bottom:1px solid var(--line);padding-bottom:16px;margin-bottom:18px;flex-wrap:wrap}
+ .brand h1{font-family:var(--serif);font-weight:400;font-size:30px;letter-spacing:.5px}
+ .brand h1 b{color:var(--gold);font-weight:400;font-style:italic}
+ .brand p{color:var(--dim);font-size:12.5px;letter-spacing:.14em;text-transform:uppercase;margin-top:4px}
+ .tabs{display:flex;gap:8px}
+ .tab{background:none;border:1px solid var(--line);color:var(--dim);padding:9px 16px;cursor:pointer;font-size:12px;letter-spacing:.12em;text-transform:uppercase;transition:.2s;border-radius:2px}
+ .tab:hover{color:var(--ink);border-color:var(--gold)}
+ .tab.active{background:var(--gold);border-color:var(--gold);color:#171310}
+ .badge-live{display:inline-block;width:7px;height:7px;border-radius:50%;background:var(--hot);margin-right:6px;animation:pulse 1.6s infinite}
+ @keyframes pulse{0%,100%{opacity:1}50%{opacity:.25}}
+
+ .statbar{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:18px}
+ .stat{background:var(--panel);border:1px solid var(--line);padding:10px 16px;border-radius:2px;min-width:120px}
+ .stat .k{font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--dim)}
+ .stat .v{font-family:var(--serif);font-size:22px;color:var(--gold);margin-top:2px}
+ .stat .v small{font-size:12px;color:var(--dim);font-family:var(--sans)}
+
+ /* ---- battle ---- */
+ #view-battle .vs-row{display:grid;grid-template-columns:1fr 70px 1fr;gap:14px;align-items:stretch}
+ @media(max-width:760px){#view-battle .vs-row{grid-template-columns:1fr;} .vs-mid{flex-direction:row !important;min-height:56px}}
+ .card{background:var(--panel);border:1px solid var(--line);border-radius:3px;overflow:hidden;cursor:pointer;transition:transform .18s,border-color .18s,box-shadow .18s;position:relative}
+ .card:hover{transform:translateY(-4px);border-color:var(--gold);box-shadow:0 14px 40px rgba(0,0,0,.5)}
+ .card.win{animation:winflash .55s ease}
+ .card.lose{animation:losefade .55s ease}
+ @keyframes winflash{0%{box-shadow:0 0 0 3px var(--gold)}100%{box-shadow:0 0 0 0 rgba(201,164,92,0)}}
+ @keyframes losefade{0%{opacity:1}40%{opacity:.35}100%{opacity:1}}
+ .swatch{height:300px;position:relative;overflow:hidden}
+ .swatch svg{position:absolute;inset:0;width:100%;height:100%}
+ .swatch .sheen{position:absolute;inset:0;background:linear-gradient(120deg,rgba(255,255,255,.10),transparent 35%,transparent 70%,rgba(0,0,0,.22));pointer-events:none}
+ .newpill{position:absolute;top:12px;left:12px;background:var(--hot);color:#fff;font-size:10px;letter-spacing:.16em;padding:4px 9px;border-radius:2px;text-transform:uppercase}
+ .elopill{position:absolute;top:12px;right:12px;background:rgba(13,12,10,.78);border:1px solid var(--line);color:var(--gold);font-size:11px;padding:4px 9px;border-radius:2px;font-family:var(--serif)}
+ .meta{padding:14px 16px 16px;border-top:1px solid var(--line)}
+ .meta .nm{font-family:var(--serif);font-size:19px}
+ .meta .vd{color:var(--dim);font-size:12px;margin-top:3px;letter-spacing:.05em}
+ .meta .tags{margin-top:9px;display:flex;gap:6px;flex-wrap:wrap}
+ .tag{font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--dim);border:1px solid var(--line);padding:3px 7px;border-radius:2px}
+ .votebtn{margin-top:12px;width:100%;background:none;border:1px solid var(--gold);color:var(--gold);padding:10px;font-size:11px;letter-spacing:.18em;text-transform:uppercase;cursor:pointer;transition:.2s;border-radius:2px}
+ .card:hover .votebtn{background:var(--gold);color:#171310}
+ .vs-mid{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px}
+ .vs-circ{width:54px;height:54px;border-radius:50%;border:1px solid var(--gold);display:flex;align-items:center;justify-content:center;font-family:var(--serif);font-style:italic;color:var(--gold);font-size:17px;background:var(--panel)}
+ .skip{background:none;border:1px solid var(--line);color:var(--dim);font-size:10px;letter-spacing:.14em;text-transform:uppercase;padding:6px 10px;cursor:pointer;border-radius:2px}
+ .skip:hover{color:var(--ink)}
+ .kbd-hint{text-align:center;color:var(--dim);font-size:11.5px;margin-top:16px;letter-spacing:.06em}
+ .kbd-hint kbd{border:1px solid var(--line);border-bottom-width:2px;padding:1px 6px;border-radius:3px;font-size:10.5px;background:var(--panel);color:var(--ink)}
+ .progress{height:3px;background:var(--panel2);margin:18px 0 4px;border-radius:2px;overflow:hidden}
+ .progress i{display:block;height:100%;background:linear-gradient(90deg,var(--gold),var(--hot));width:0%;transition:width .4s}
+
+ /* ---- leaderboard ---- */
+ .lb-row{display:grid;grid-template-columns:44px 86px 1fr 110px 130px;gap:12px;align-items:center;background:var(--panel);border:1px solid var(--line);padding:10px 14px;margin-bottom:8px;border-radius:2px;transition:border-color .2s}
+ .lb-row:hover{border-color:var(--gold)}
+ .lb-rank{font-family:var(--serif);font-size:20px;color:var(--dim);text-align:center}
+ .lb-row.top1 .lb-rank{color:var(--gold)} .lb-row.top1{border-color:rgba(201,164,92,.55)}
+ .lb-sw{width:86px;height:56px;border-radius:2px;overflow:hidden;position:relative;border:1px solid var(--line)}
+ .lb-sw svg{position:absolute;inset:0;width:100%;height:100%}
+ .lb-nm{font-family:var(--serif);font-size:16px}
+ .lb-sub{color:var(--dim);font-size:11.5px;margin-top:2px}
+ .lb-rec{font-size:12px;color:var(--dim);text-align:right}
+ .lb-rec b{color:var(--ink)}
+ .lb-elo{text-align:right;font-family:var(--serif);font-size:19px;color:var(--gold)}
+ .lb-elo .delta{display:block;font-family:var(--sans);font-size:10.5px}
+ .delta.up{color:var(--green)} .delta.dn{color:var(--red)}
+ @media(max-width:640px){.lb-row{grid-template-columns:30px 64px 1fr 84px}.lb-rec{display:none}.lb-sw{width:64px}}
+
+ /* ---- trends ---- */
+ .trend-note{background:var(--panel);border:1px solid var(--line);border-left:3px solid var(--gold);padding:14px 18px;margin-bottom:18px;color:var(--dim);font-size:13px;line-height:1.6;border-radius:2px}
+ .trend-note b{color:var(--ink)}
+ .tr-row{background:var(--panel);border:1px solid var(--line);padding:16px 18px;margin-bottom:10px;border-radius:2px}
+ .tr-head{display:flex;justify-content:space-between;align-items:baseline;gap:12px;flex-wrap:wrap}
+ .tr-name{font-family:var(--serif);font-size:18px}
+ .tr-name .rk{color:var(--dim);font-size:13px;font-style:italic;margin-right:8px}
+ .verdict{font-size:10px;letter-spacing:.16em;text-transform:uppercase;padding:4px 10px;border-radius:2px;border:1px solid}
+ .verdict.aligned{color:var(--green);border-color:var(--green)}
+ .verdict.under{color:var(--cool);border-color:var(--cool)}
+ .verdict.over{color:var(--red);border-color:var(--red)}
+ .verdict.nodata{color:var(--dim);border-color:var(--line)}
+ .tr-src{color:var(--dim);font-size:12px;margin-top:5px;line-height:1.55}
+ .bars{display:grid;grid-template-columns:110px 1fr 56px;gap:10px;align-items:center;margin-top:10px;font-size:11px;color:var(--dim)}
+ .bar{height:8px;background:var(--panel2);border-radius:4px;overflow:hidden}
+ .bar i{display:block;height:100%;border-radius:4px;transition:width .8s ease}
+ .bar.net i{background:linear-gradient(90deg,#7a5cc9,var(--cool))}
+ .bar.you i{background:linear-gradient(90deg,var(--gold),var(--hot))}
+ .tr-matches{margin-top:10px;display:flex;gap:8px;flex-wrap:wrap}
+ .mini{display:flex;align-items:center;gap:7px;border:1px solid var(--line);padding:4px 8px 4px 4px;border-radius:2px;font-size:11px;color:var(--dim)}
+ .mini .msw{width:26px;height:26px;border-radius:2px;overflow:hidden;position:relative}
+ .mini .msw svg{position:absolute;inset:0;width:100%;height:100%}
+ .synth{margin-top:22px;background:var(--panel);border:1px solid var(--gold);padding:18px 20px;border-radius:2px}
+ .synth h3{font-family:var(--serif);font-weight:400;font-size:19px;color:var(--gold);margin-bottom:8px}
+ .synth p{color:var(--ink);font-size:13.5px;line-height:1.65}
+ .synth p b{color:var(--gold)}
+ .hidden{display:none}
+ h2.sec{font-family:var(--serif);font-weight:400;font-size:22px;margin:6px 0 14px}
+ h2.sec small{color:var(--dim);font-size:12px;font-family:var(--sans);letter-spacing:.1em;text-transform:uppercase;margin-left:10px}
+ .toast{position:fixed;bottom:22px;left:50%;transform:translateX(-50%) translateY(80px);background:var(--panel);border:1px solid var(--gold);color:var(--ink);padding:10px 18px;font-size:12.5px;border-radius:3px;transition:transform .35s;z-index:50}
+ .toast.show{transform:translateX(-50%) translateY(0)}
+</style>
+</head>
+<body>
+<div class="wrap">
+ <header>
+ <div class="brand">
+ <h1>WC <b>Arena</b> — Hot or Not</h1>
+ <p><span class="badge-live"></span>Last 20 New Arrivals · Wallcoverings · vs. Internet Trends for High-End Architects</p>
+ </div>
+ <nav class="tabs">
+ <button class="tab active" data-view="battle">⚔ Battle</button>
+ <button class="tab" data-view="board">Leaderboard</button>
+ <button class="tab" data-view="trends">Trend Report</button>
+ </nav>
+ </header>
+
+ <div class="statbar">
+ <div class="stat"><div class="k">Battles Voted</div><div class="v" id="stVotes">0</div></div>
+ <div class="stat"><div class="k">Arrivals Ranked</div><div class="v" id="stRanked">0 <small>/ 20</small></div></div>
+ <div class="stat"><div class="k">Current #1</div><div class="v" id="stTop" style="font-size:15px;padding-top:5px">—</div></div>
+ <div class="stat"><div class="k">Trend Alignment</div><div class="v" id="stAlign">—</div></div>
+ </div>
+
+ <section id="view-battle">
+ <div class="vs-row">
+ <div class="card" id="cardA"></div>
+ <div class="vs-mid">
+ <div class="vs-circ">vs</div>
+ <button class="skip" id="skipBtn">skip ↷</button>
+ </div>
+ <div class="card" id="cardB"></div>
+ </div>
+ <div class="progress"><i id="progFill"></i></div>
+ <div class="kbd-hint">Pick the one an <i>AD100 architect</i> would spec — <kbd>←</kbd> left wins · <kbd>→</kbd> right wins · <kbd>S</kbd> skip. ~25 votes unlocks a confident trend read.</div>
+ </section>
+
+ <section id="view-board" class="hidden">
+ <h2 class="sec">Arrival Rankings <small>Elo · live</small></h2>
+ <div id="lbList"></div>
+ </section>
+
+ <section id="view-trends" class="hidden">
+ <h2 class="sec">Your Taste vs. The Internet <small>high-end architecture media, 2026</small></h2>
+ <div class="trend-note">Benchmark distilled from what's dominating <b>Dezeen, Architectural Digest PRO, Dwell, design-Instagram and Pinterest search velocity</b> for high-end residential & hospitality specs: warm mineral plasters, fluted & reeded surfaces, grasscloth naturals, moody maximalist botanicals, Deco revival, and a cooling-off of grey minimalism. Your battle votes are scored against that signal below.</div>
+ <div id="trList"></div>
+ <div class="synth" id="synthBox"><h3>Synthesis</h3><p id="synthTxt">Vote in a few battles first — the report sharpens as your Elo table fills in.</p></div>
+ </section>
+</div>
+<div class="toast" id="toast"></div>
+
+<script>
+(function(){
+"use strict";
+/* ---------------- pattern engine (inline SVG, deterministic) ---------------- */
+function esc(s){return s.replace(/&/g,"&").replace(/</g,"<")}
+const P = {
+ grasscloth:(c)=>{let l="";for(let y=4;y<120;y+=5){const w=.6+((y*7)%3)*.4;l+='<path d="M0 '+y+' Q 30 '+(y+((y%3)-1)*2)+' 60 '+y+' T 120 '+y+'" stroke="'+c[1]+'" stroke-width="'+w+'" fill="none" opacity=".8"/>'}
+ return '<rect width="120" height="120" fill="'+c[0]+'"/>'+l+'<rect width="120" height="120" fill="'+c[2]+'" opacity=".07"/>'},
+ fluted:(c)=>{let l="";for(let x=0;x<120;x+=12){l+='<rect x="'+x+'" width="6" height="120" fill="'+c[1]+'"/><rect x="'+(x+6)+'" width="2" height="120" fill="'+c[2]+'" opacity=".55"/>'}
+ return '<rect width="120" height="120" fill="'+c[0]+'"/>'+l},
+ plaster:(c)=>{let b="";for(let i=0;i<26;i++){const x=(i*47)%120,y=(i*83)%120,r=14+(i*29)%26;b+='<circle cx="'+x+'" cy="'+y+'" r="'+r+'" fill="'+(i%2?c[1]:c[2])+'" opacity=".08"/>'}
+ return '<rect width="120" height="120" fill="'+c[0]+'"/>'+b+'<path d="M0 80 Q 60 60 120 85 L120 120 L0 120 Z" fill="'+c[1]+'" opacity=".12"/>'},
+ botanical:(c)=>{let f="";for(let i=0;i<7;i++){const x=(i*53)%120,y=(i*71)%120,a=(i*40)%360;
+ f+='<g transform="translate('+x+','+y+') rotate('+a+')"><path d="M0 0 C 8 -14 22 -16 30 -4 C 20 2 8 4 0 0 Z" fill="'+c[1]+'"/><path d="M0 0 C 8 -10 18 -12 26 -5" stroke="'+c[2]+'" stroke-width="1" fill="none"/></g>'}
+ return '<rect width="120" height="120" fill="'+c[0]+'"/>'+f},
+ deco:(c)=>{let a="";for(let x=0;x<120;x+=30){for(let y=0;y<120;y+=30){a+='<path d="M'+x+' '+(y+30)+' A 15 15 0 0 1 '+(x+30)+' '+(y+30)+'" fill="none" stroke="'+c[1]+'" stroke-width="2.4"/><path d="M'+x+' '+(y+30)+' A 15 15 0 0 1 '+(x+30)+' '+(y+30)+'" fill="none" stroke="'+c[2]+'" stroke-width="1" transform="translate(0,-7)"/>'}}
+ return '<rect width="120" height="120" fill="'+c[0]+'"/>'+a},
+ terrazzo:(c)=>{let t="";const cs=[c[1],c[2],c[3]||c[1]];for(let i=0;i<24;i++){const x=(i*37)%116,y=(i*61)%116,s=3+(i*13)%7,r=(i*77)%360;
+ t+='<rect x="'+x+'" y="'+y+'" width="'+s+'" height="'+(s*1.4)+'" rx="1.5" fill="'+cs[i%3]+'" transform="rotate('+r+' '+x+' '+y+')" opacity=".9"/>'}
+ return '<rect width="120" height="120" fill="'+c[0]+'"/>'+t},
+ chevron:(c)=>{let z="";for(let y=-10;y<130;y+=20){z+='<path d="M0 '+y+' L 20 '+(y-10)+' L 40 '+y+' L 60 '+(y-10)+' L 80 '+y+' L 100 '+(y-10)+' L 120 '+y+'" stroke="'+c[1]+'" stroke-width="5" fill="none"/><path d="M0 '+(y+7)+' L 20 '+(y-3)+' L 40 '+(y+7)+' L 60 '+(y-3)+' L 80 '+(y+7)+' L 100 '+(y-3)+' L 120 '+(y+7)+'" stroke="'+c[2]+'" stroke-width="1.4" fill="none"/>'}
+ return '<rect width="120" height="120" fill="'+c[0]+'"/>'+z},
+ marble:(c)=>{let v="";for(let i=0;i<6;i++){const y=i*22;v+='<path d="M-5 '+y+' C 30 '+(y+18)+', 60 '+(y-14)+', 125 '+(y+10)+'" stroke="'+c[1]+'" stroke-width="'+(1+(i%3))+'" fill="none" opacity=".5"/>'}
+ return '<rect width="120" height="120" fill="'+c[0]+'"/>'+v+'<path d="M-5 30 C 40 60, 70 10, 125 55" stroke="'+c[2]+'" stroke-width=".8" fill="none" opacity=".9"/>'},
+ grid:(c)=>{let g="";for(let x=0;x<=120;x+=15)g+='<line x1="'+x+'" y1="0" x2="'+x+'" y2="120" stroke="'+c[1]+'" stroke-width="1"/>';
+ for(let y=0;y<=120;y+=15)g+='<line x1="0" y1="'+y+'" x2="120" y2="'+y+'" stroke="'+c[1]+'" stroke-width="1"/>';
+ return '<rect width="120" height="120" fill="'+c[0]+'"/>'+g+'<circle cx="60" cy="60" r="3.5" fill="'+c[2]+'"/>'},
+ ogee:(c)=>{let o="";for(let y=0;y<120;y+=24){for(let x=0;x<120;x+=24){o+='<path d="M'+x+' '+(y+12)+' Q '+(x+6)+' '+y+' '+(x+12)+' '+(y+12)+' Q '+(x+18)+' '+(y+24)+' '+(x+24)+' '+(y+12)+'" fill="none" stroke="'+c[1]+'" stroke-width="1.6"/>'}}
+ return '<rect width="120" height="120" fill="'+c[0]+'"/>'+o},
+ cork:(c)=>{let k="";for(let i=0;i<70;i++){const x=(i*31)%120,y=(i*53)%120,r=1+(i*7)%3;k+='<circle cx="'+x+'" cy="'+y+'" r="'+r+'" fill="'+(i%3?c[1]:c[2])+'" opacity=".55"/>'}
+ return '<rect width="120" height="120" fill="'+c[0]+'"/>'+k},
+ mural:(c)=>'<rect width="120" height="120" fill="'+c[0]+'"/><path d="M0 90 Q 25 55 55 78 T 120 70 L 120 120 L 0 120 Z" fill="'+c[1]+'"/><path d="M0 104 Q 40 80 80 96 T 120 92 L 120 120 L 0 120 Z" fill="'+c[2]+'" opacity=".85"/><circle cx="88" cy="30" r="12" fill="'+c[3]+'" opacity=".9"/>'
+};
+function swatchSVG(d){return '<svg viewBox="0 0 120 120" preserveAspectRatio="xMidYMid slice" aria-label="'+esc(d.name)+'">'+P[d.pat](d.colors)+'</svg>'}
+
+/* ---------------- data: last 20 new arrivals ---------------- */
+const ARRIVALS=[
+ {id:1, name:"Sahara Limewash", vendor:"Atelier Mineral · roman clay", pat:"plaster", colors:["#c9b193","#8a6f52","#e2cba8"], tags:["plaster","warm-neutral","texture"]},
+ {id:2, name:"Reeded Oak No.4", vendor:"Studio Linje · fluted wood", pat:"fluted", colors:["#6b4f35","#57402b","#8a6a48"], tags:["fluted","wood","sculptural"]},
+ {id:3, name:"Kyoto Grass", vendor:"Maison Kusa · fine grasscloth", pat:"grasscloth", colors:["#b7a273","#7d6a45","#d9c691"], tags:["grasscloth","natural","texture"]},
+ {id:4, name:"Nocturne Palm", vendor:"Flora Obscura · dark botanical", pat:"botanical", colors:["#12211a","#2e5d43","#7fae7a"], tags:["botanical","moody","maximalist"]},
+ {id:5, name:"Gatsby Fan", vendor:"Époque · deco revival", pat:"deco", colors:["#1c1a24","#c9a45c","#6e6480"], tags:["deco","metallic","glamour"]},
+ {id:6, name:"Trastevere Chip", vendor:"Nuovo Terrazzo Co.", pat:"terrazzo", colors:["#e8ded0","#c65b4e","#5f8fa8","#c9a45c"], tags:["terrazzo","playful","stone"]},
+ {id:7, name:"Alpine Herringbone", vendor:"Werkhaus · woven vinyl", pat:"chevron", colors:["#22282c","#5f8fa8","#8fb2c4"], tags:["geometric","contract","tailored"]},
+ {id:8, name:"Calacatta Veil", vendor:"Pietra Fina · marble print", pat:"marble", colors:["#efe9df","#b9ac96","#8a7b60"], tags:["stone","classic","veined"]},
+ {id:9, name:"Bauhaus Ledger", vendor:"Raster · drafting grid", pat:"grid", colors:["#f0ebe1","#c8bda6","#e0552f"], tags:["geometric","minimal","graphic"]},
+ {id:10,name:"Alhambra Breeze", vendor:"Zellige House · ogee", pat:"ogee", colors:["#f2e8d8","#3f7d74","#f2e8d8"], tags:["ogee","heritage","pattern"]},
+ {id:11,name:"Douro Cork", vendor:"Corticeira · natural cork", pat:"cork", colors:["#a9855c","#6f5334","#d4b284"], tags:["cork","natural","sustainable"]},
+ {id:12,name:"Dawn Ridge Mural", vendor:"Panorama Éditions", pat:"mural", colors:["#e7d3b8","#a86d4d","#6d4a3a","#e0a23f"], tags:["mural","landscape","statement"]},
+ {id:13,name:"Ostuni Plaster", vendor:"Atelier Mineral · tadelakt", pat:"plaster", colors:["#e4ddd0","#b6ab97","#f4efe4"], tags:["plaster","minimal","warm-neutral"]},
+ {id:14,name:"Velvet Ribs", vendor:"Studio Linje · flocked flute", pat:"fluted", colors:["#3a2233","#2b1826","#5c3a52"], tags:["fluted","moody","velvet"]},
+ {id:15,name:"Raffia Sunset", vendor:"Maison Kusa · dyed raffia", pat:"grasscloth", colors:["#c67e4c","#8d5430","#e2a26e"], tags:["grasscloth","color-drench","natural"]},
+ {id:16,name:"Midnight Fern", vendor:"Flora Obscura", pat:"botanical", colors:["#101d2b","#2f4f6e","#7d9ec4"], tags:["botanical","moody","blue"]},
+ {id:17,name:"Chrysler Steps", vendor:"Époque · gilded deco", pat:"deco", colors:["#20261f","#9caf88","#c9a45c"], tags:["deco","green","metallic"]},
+ {id:18,name:"Riviera Fleck", vendor:"Nuovo Terrazzo Co.", pat:"terrazzo", colors:["#f3ece0","#9caf88","#c9a45c","#a86d4d"], tags:["terrazzo","soft","stone"]},
+ {id:19,name:"Sandstone Strata", vendor:"Pietra Fina · layered mineral", pat:"marble", colors:["#d8c3a5","#a8896a","#7c6248"], tags:["stone","warm-neutral","texture"]},
+ {id:20,name:"Grey Gallery Weave", vendor:"Werkhaus · classic grey", pat:"grid", colors:["#d9d9d9","#b5b5b5","#8f8f8f"], tags:["grey","minimal","safe"]}
+];
+ARRIVALS.forEach(d=>{d.elo=1500;d.w=0;d.l=0;d.last=0});
+
+/* ------------- internet trend benchmark (high-end architects, 2026) ------------- */
+const TRENDS=[
+ {name:"Warm Mineral Plasters & Limewash", heat:96, keys:["plaster","warm-neutral"], src:"Limewash & roman-clay finishes dominate AD PRO material reports and Pinterest search growth (+180% YoY); architects spec them as the quiet backdrop for collectible furniture."},
+ {name:"Fluted, Reeded & Sculptural Relief", heat:91, keys:["fluted","sculptural","wood"], src:"Dezeen project features lean heavily on ribbed and reeded wall relief — texture you can rake light across is the new ornament."},
+ {name:"Grasscloth & Woven Naturals", heat:87, keys:["grasscloth","natural","cork","sustainable"], src:"Natural-fiber walls are the connective tissue of the 'quiet luxury' interior; cork rising fast on embodied-carbon specs."},
+ {name:"Moody Maximalist Botanicals", heat:82, keys:["botanical","moody","maximalist"], src:"Dark florals and inky palms trend across boutique-hospitality features — powder rooms and lounges as jewel boxes."},
+ {name:"Statement Murals & Scenics", heat:78, keys:["mural","landscape","statement"], src:"Panoramic scenics anchor Instagram's most-saved interiors; one-wall storytelling over repeat patterns."},
+ {name:"Art-Deco Revival & Gilded Geometry", heat:74, keys:["deco","metallic","glamour"], src:"Deco fans and gilt geometry surge with the hospitality boom — architects cite '20s optimism as the reference."},
+ {name:"Terrazzo & Stone-Look Surfaces", heat:63, keys:["terrazzo","stone","veined"], src:"Still healthy in commercial lobbies, but editors call peak-terrazzo; specification is plateauing."},
+ {name:"Cool Grey Minimalism", heat:22, keys:["grey","safe"], src:"The internet's verdict is in: flat grey minimalism is cited as 'the dated look to replace' in nearly every 2026 trend round-up."}
+];
+
+/* ---------------- state + elo ---------------- */
+let votes=0, pair=null, hist=[];
+const $=id=>document.getElementById(id);
+function expected(a,b){return 1/(1+Math.pow(10,(b-a)/400))}
+function vote(winner,loser){
+ const K=32,ea=expected(winner.elo,loser.elo);
+ const dW=Math.round(K*(1-ea)), dL=-dW;
+ winner.elo+=dW; loser.elo+=dL; winner.last=dW; loser.last=dL;
+ winner.w++; loser.l++; votes++;
+ hist.push([winner.id,loser.id]);
+}
+function pickPair(){
+ const byPlays=[...ARRIVALS].sort((a,b)=>(a.w+a.l)-(b.w+b.l)||Math.random()-.5);
+ const a=byPlays[0];
+ const pool=ARRIVALS.filter(x=>x.id!==a.id).sort((x,y)=>Math.abs(x.elo-a.elo)-Math.abs(y.elo-a.elo));
+ const b=pool[Math.floor(Math.random()*Math.min(6,pool.length))];
+ return Math.random()<.5?[a,b]:[b,a];
+}
+function cardHTML(d){
+ return '<div class="swatch">'+swatchSVG(d)+'<div class="sheen"></div>'+
+ '<span class="newpill">New Arrival</span><span class="elopill">'+d.elo+'</span></div>'+
+ '<div class="meta"><div class="nm">'+esc(d.name)+'</div><div class="vd">'+esc(d.vendor)+'</div>'+
+ '<div class="tags">'+d.tags.map(t=>'<span class="tag">'+esc(t)+'</span>').join('')+'</div>'+
+ '<button class="votebtn">This one's hot</button></div>';
+}
+function renderBattle(){
+ pair=pickPair();
+ $("cardA").innerHTML=cardHTML(pair[0]);
+ $("cardB").innerHTML=cardHTML(pair[1]);
+ $("progFill").style.width=Math.min(100,votes/25*100)+"%";
+}
+function toast(msg){const t=$("toast");t.textContent=msg;t.classList.add("show");clearTimeout(t._x);t._x=setTimeout(()=>t.classList.remove("show"),1600)}
+function handleVote(side){
+ if(!pair)return;
+ const w=pair[side], l=pair[1-side];
+ vote(w,l);
+ const wc=$(side===0?"cardA":"cardB"), lc=$(side===0?"cardB":"cardA");
+ wc.classList.add("win"); lc.classList.add("lose");
+ toast(w.name+" takes it (+"+w.last+" Elo)");
+ updateStats();
+ setTimeout(()=>{wc.classList.remove("win");lc.classList.remove("lose");renderBattle()},420);
+}
+function updateStats(){
+ $("stVotes").textContent=votes;
+ const ranked=ARRIVALS.filter(d=>d.w+d.l>0).length;
+ $("stRanked").innerHTML=ranked+' <small>/ 20</small>';
+ const top=[...ARRIVALS].sort((a,b)=>b.elo-a.elo)[0];
+ $("stTop").textContent=votes?top.name:"—";
+ $("stAlign").textContent=votes>=5?alignScore()+"%":"—";
+}
+
+/* ---------------- leaderboard ---------------- */
+function renderBoard(){
+ const list=[...ARRIVALS].sort((a,b)=>b.elo-a.elo||b.w-a.w);
+ $("lbList").innerHTML=list.map((d,i)=>{
+ const dl=d.last>0?'<span class="delta up">▲ +'+d.last+'</span>':d.last<0?'<span class="delta dn">▼ '+d.last+'</span>':'';
+ return '<div class="lb-row'+(i===0?' top1':'')+'"><div class="lb-rank">'+(i+1)+'</div>'+
+ '<div class="lb-sw">'+swatchSVG(d)+'</div>'+
+ '<div><div class="lb-nm">'+esc(d.name)+'</div><div class="lb-sub">'+esc(d.vendor)+' · '+d.tags.join(" / ")+'</div></div>'+
+ '<div class="lb-rec"><b>'+d.w+'</b> W — <b>'+d.l+'</b> L</div>'+
+ '<div class="lb-elo">'+d.elo+dl+'</div></div>';
+ }).join("");
+}
+
+/* ---------------- trend comparison ---------------- */
+function trendStats(t){
+ const m=ARRIVALS.filter(d=>d.tags.some(tag=>t.keys.includes(tag)));
+ const played=m.filter(d=>d.w+d.l>0);
+ const avg=played.length?played.reduce((s,d)=>s+d.elo,0)/played.length:null;
+ return {matches:m,avg:avg,played:played.length};
+}
+function youScore(avg){ // map elo avg (~1350–1650) to 0–100
+ if(avg===null)return null;
+ return Math.max(4,Math.min(100,Math.round((avg-1350)/300*100)));
+}
+function alignScore(){
+ let n=0,sum=0;
+ TRENDS.forEach(t=>{const s=trendStats(t);const y=youScore(s.avg);if(y!==null){sum+=100-Math.abs(y-t.heat);n++}});
+ return n?Math.round(sum/n):0;
+}
+function renderTrends(){
+ $("trList").innerHTML=TRENDS.map((t,i)=>{
+ const s=trendStats(t), y=youScore(s.avg);
+ let v='<span class="verdict nodata">no votes yet</span>';
+ if(y!==null){
+ const gap=y-t.heat;
+ v=gap>18?'<span class="verdict over">You're hotter than the internet</span>'
+ :gap<-18?'<span class="verdict under">Undervalued by you</span>'
+ :'<span class="verdict aligned">Aligned with architects</span>';
+ }
+ return '<div class="tr-row"><div class="tr-head"><div class="tr-name"><span class="rk">Net #'+(i+1)+'</span>'+esc(t.name)+'</div>'+v+'</div>'+
+ '<div class="tr-src">'+esc(t.src)+'</div>'+
+ '<div class="bars"><span>Internet heat</span><div class="bar net"><i style="width:'+t.heat+'%"></i></div><span>'+t.heat+'</span></div>'+
+ '<div class="bars"><span>Your arena</span><div class="bar you"><i style="width:'+(y===null?0:y)+'%"></i></div><span>'+(y===null?'—':y)+'</span></div>'+
+ (s.matches.length?'<div class="tr-matches">'+s.matches.map(d=>'<span class="mini"><span class="msw">'+swatchSVG(d)+'</span>'+esc(d.name)+(d.w+d.l?' · '+d.elo:'')+'</span>').join("")+'</div>':'')+
+ '</div>';
+ }).join("");
+ // synthesis
+ if(votes<3){$("synthTxt").innerHTML="Vote in a few battles first — the report sharpens as your Elo table fills in.";return}
+ const top3=[...ARRIVALS].sort((a,b)=>b.elo-a.elo).slice(0,3);
+ const scored=TRENDS.map(t=>{const s=trendStats(t);return{t:t,y:youScore(s.avg)}}).filter(x=>x.y!==null);
+ const over=scored.filter(x=>x.y-x.t.heat>18).map(x=>x.t.name);
+ const under=scored.filter(x=>x.y-x.t.heat<-18).map(x=>x.t.name);
+ let txt='After <b>'+votes+' battles</b>, your podium is <b>'+top3.map(d=>d.name).join("</b>, <b>")+'</b> — overall taste alignment with high-end architecture media: <b>'+alignScore()+'%</b>. ';
+ txt+=over.length?'You're running ahead of the internet on <b>'+over.join("</b> and <b>")+'</b> — a contrarian bet worth merchandising early. ':'';
+ txt+=under.length?'You're cooler than the trend cycle on <b>'+under.join("</b> and <b>")+'</b> — the feeds say give those a second look. ':'';
+ const grey=ARRIVALS.find(d=>d.id===20);
+ if(grey.w>grey.l&&grey.w+grey.l>1)txt+='Note: you keep advancing <b>Grey Gallery Weave</b> while every 2026 round-up calls flat grey the look to retire. Bold.';
+ else txt+='Verdict: lead the new-arrivals wall with plaster, flute and grasscloth — that's where your votes and the architect internet agree.';
+ $("synthTxt").innerHTML=txt;
+}
+
+/* ---------------- tabs + events ---------------- */
+const views={battle:$("view-battle"),board:$("view-board"),trends:$("view-trends")};
+document.querySelectorAll(".tab").forEach(b=>b.addEventListener("click",()=>{
+ document.querySelectorAll(".tab").forEach(x=>x.classList.remove("active"));
+ b.classList.add("active");
+ Object.values(views).forEach(v=>v.classList.add("hidden"));
+ views[b.dataset.view].classList.remove("hidden");
+ if(b.dataset.view==="board")renderBoard();
+ if(b.dataset.view==="trends")renderTrends();
+}));
+$("cardA").addEventListener("click",()=>handleVote(0));
+$("cardB").addEventListener("click",()=>handleVote(1));
+$("skipBtn").addEventListener("click",renderBattle);
+document.addEventListener("keydown",e=>{
+ if(views.battle.classList.contains("hidden"))return;
+ if(e.key==="ArrowLeft")handleVote(0);
+ else if(e.key==="ArrowRight")handleVote(1);
+ else if(e.key==="s"||e.key==="S")renderBattle();
+});
+renderBattle();updateStats();
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/f79cffc20d43/claude-code.png b/data/artifacts/f79cffc20d43/claude-code.png
new file mode 100644
index 0000000..ebbde61
Binary files /dev/null and b/data/artifacts/f79cffc20d43/claude-code.png differ
diff --git a/data/artifacts/f79cffc20d43/gemma3-12b.html b/data/artifacts/f79cffc20d43/gemma3-12b.html
new file mode 100644
index 0000000..0baca53
--- /dev/null
+++ b/data/artifacts/f79cffc20d43/gemma3-12b.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>AI Architect Hot or Not</title>
+ <style>
+ body { font-family: sans-serif; margin: 20px; }
+ #container { display: flex; flex-direction: column; align-items: center; }
+ img { width: 150px; height: auto; margin: 5px; border: 1px solid #ccc; }
+ .architect-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 10px; width: 100%; max-width: 900px; }
+ .hot-not-buttons { display: flex; justify-content: center; margin-top: 10px; }
+ button { padding: 5px 10px; margin: 0 5px; cursor: pointer; }
+ #results { margin-top: 20px; font-weight: bold; }
+ </style>
+</head>
+<body>
+ <div id="container">
+ <h1>AI Architect Hot or Not</h1>
+
+ <div class="architect-list" id="architectList">
+ </div>
+
+ <div class="hot-not-buttons">
+ <button id="hotButton">Hot</button>
+ <button id="notButton">Not</button>
+ </div>
+ <div id = "results"></div>
+ </div>
+
+
+ <script>
+ const architects = [
+ { name: "Zaha Hadid (Legacy)", image: "https://upload.wikimedia.org/wikipedia/commons/thumb/9/90/Zaha_Hadid_2013_%28cropped%29.jpg/220px-Zaha_Hadid_2013_%28cropped%29.jpg", trending: 95 },
+ { name: "Frank Gehry", image: "https://upload.wikimedia.org/wikipedia/commons/thumb/d/de/Frank_Gehry_2014.jpg/220px-Frank_Gehry_2014.jpg", trending: 92 },
+ { name: "Rem Koolhaas", image: "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3d/Rem_Koolhaas_%28cropped%29.jpg/220px-Rem_Koolhaas_%28cropped%29.jpg", trending: 88 },
+ { name: "Norman Foster", image: "https://upload.wikimedia.org/wikipedia/commons/thumb/7/71/Norman_Foster_portrait.jpg/220px-Norman_Foster_portrait.jpg", trending: 90 },
+ { name: "Jean Nouvel", image: "https://upload.wikimedia.org/wikipedia/commons/thumb/5/54/Jean_Nouvel_%28cropped%29.jpg/220px-Jean_Nouvel_%28cropped%29.jpg", trending: 85 },
+ { name: "Herzog & de Meuron", image: "https://upload.wikimedia.org/wikipedia/commons/thumb/4/47/Herzog_and_de_Meuron_portrait.jpg/220px-Herzog_and_de_Meuron_portrait.jpg", trending: 82 },
+ { name: "David Chipperfield", image: "https://upload.wikimedia.org/wikipedia/commons/thumb/6/64/David_Chipperfield_%28cropped%29.jpg/220px-David_Chipperfield_%28cropped%29.jpg", trending: 78 },
+ { name: "Thom Mayne", image: "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Thom_Mayne_in_Los_Angeles_2016.jpg/220px-Thom_Mayne_in_Los_Angeles_2016.jpg", trending: 75 },
+ { name: "Daniel Libeskind", image: "https://upload.wikimedia.org/wikipedia/commons/thumb/9/9d/Daniel_Libeskind_portrait.jpg/220px-Daniel_Libeskind_portrait.jpg", trending: 72 },
+ { name: "Shigeru Ban", image: "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e8/Shigeru_Ban_%28cropped%29.jpg/220px-Shigeru_Ban_%28cropped%29.jpg", trending: 70 },
+ { name: "Bjarke Ingels", image: "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4f/Bjarke_Ingels_portrait.jpg/220px-Bjarke_Ingels_portrait.jpg", trending: 68 },
+ { name: "Antoni Gaudí (Legacy)", image: "https://upload.wikimedia.org/wikipedia/commons/thumb/d/df/SagradaFamilia_gaudi.jpg/220px-SagradaFamilia_gaudi.jpg", trending: 98 },
+ { name: "Peter Zumthor", image: "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6a/Peter_Zumthor_portrait.jpg/220px-Peter_Zumthor_portrait.jpg", trending: 77 },
+ { name: "Steven Holl", image: "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3e/Steven_Holl_%28cropped%29.jpg/220px-Steven_Holl_%28cropped%29.jpg", trending: 74 },
+ { name: "Massimo Carmassi", image: "https://www.massimocarmassi.com/wp-content/uploads/2016/11/mc_portrait_2016.jpg", trending: 65},
+ { name: "Alessandro D’Andrea", image: "https://archilovers.com/img/project/92847/alessandro-d-andrea-architects-massimiliano-fuksas-architecture-103280.jpg", trending: 62},
+ { name: "Paola Bagnaresi", image: "https://www.paolabagnesari.com/wp-content/uploads/2024/01/IMG_1795-copia.jpeg", trending: 58},
+ { name: "Federico Bianchi", image: "https://archilovers.com/img/project/163058/federico-bianchi-architecture-studiotade-246317.jpg", trending: 55},
+ { name: "Marco Padoan", image:"https://www.mpastudio.it/wp-content/uploads/2023/09/marco-padoan-architetto.jpeg", trending: 53},
+ { name: "Valeria Bruno", image:"https://www.valeriabrunoarchitettura.it/images/valeria_bruno.jpg", trending: 48}
+
+ ];
+
+
+ const architectListDiv = document.getElementById('architectList');
+ let hotCount = 0;
+ let notCount = 0;
+
+ function populateArchitects() {
+ architects.forEach(architect => {
+ const imgElement = document.createElement('img');
+ imgElement.src = architect.image;
+ imgElement.alt = architect.name;
+ imgElement.title = `Trending: ${architect.trending}`;
+
+ architectListDiv.appendChild(imgElement);
+ });
+ }
+
+
+ document.getElementById('hotButton').addEventListener('click', () => {
+ hotCount++;
+ document.getElementById("results").innerText = `Hot Votes: ${hotCount}, Not votes: ${notCount}`
+ });
+
+ document.getElementById('notButton').addEventListener('click', () => {
+ notCount++;
+ document.getElementById("results").innerText = `Hot Votes: ${hotCount}, Not votes: ${notCount}`
+ });
+
+
+ populateArchitects();
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/f79cffc20d43/gemma3-12b.png b/data/artifacts/f79cffc20d43/gemma3-12b.png
new file mode 100644
index 0000000..410f491
Binary files /dev/null and b/data/artifacts/f79cffc20d43/gemma3-12b.png differ
diff --git a/data/artifacts/f79cffc20d43/gpt.html b/data/artifacts/f79cffc20d43/gpt.html
new file mode 100644
index 0000000..8e3886b
--- /dev/null
+++ b/data/artifacts/f79cffc20d43/gpt.html
@@ -0,0 +1,1766 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<title>Hot or Not – High-End Architects Arena</title>
+<style>
+ :root {
+ --bg: #05060a;
+ --panel: #0d1019;
+ --panel-soft: #141826;
+ --accent: #ff4b7d;
+ --accent-soft: rgba(255,75,125,0.35);
+ --accent-alt: #57f2c7;
+ --text: #f5f7ff;
+ --muted: #96a0c2;
+ --border-subtle: rgba(255,255,255,0.08);
+ --danger: #ff5555;
+ --success: #57f27b;
+ --warning: #ffc857;
+ }
+
+ * {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ }
+
+ html, body {
+ height: 100%;
+ width: 100%;
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "SF Pro Text",
+ "Segoe UI", Roboto, sans-serif;
+ background: radial-gradient(circle at top, #151829 0, #05060a 55%);
+ color: var(--text);
+ overflow: hidden;
+ }
+
+ body {
+ display: flex;
+ align-items: stretch;
+ justify-content: center;
+ padding: 18px;
+ }
+
+ .app {
+ position: relative;
+ display: grid;
+ grid-template-columns: minmax(0, 1.6fr) minmax(0, 1.2fr);
+ gap: 16px;
+ width: 100%;
+ max-width: 1120px;
+ height: 100%;
+ max-height: 640px;
+ background: radial-gradient(circle at 0 -20%, rgba(255,75,125,0.18), transparent 55%),
+ radial-gradient(circle at 100% 120%, rgba(87,242,199,0.16), transparent 55%),
+ linear-gradient(135deg, #05060a 0, #05060a 40%, #070815 100%);
+ border-radius: 18px;
+ padding: 16px;
+ border: 1px solid rgba(255,255,255,0.06);
+ box-shadow:
+ 0 22px 40px rgba(0,0,0,0.75),
+ 0 0 0 1px rgba(255,255,255,0.03);
+ overflow: hidden;
+ }
+
+ @media (max-width: 900px) {
+ body {
+ padding: 10px;
+ }
+ .app {
+ grid-template-columns: 1fr;
+ grid-template-rows: minmax(0, 1.2fr) minmax(0, 1.4fr);
+ max-height: 780px;
+ }
+ }
+
+ .glass {
+ background: linear-gradient(150deg,
+ rgba(16,21,40,0.94) 0,
+ rgba(11,15,30,0.98) 40%,
+ rgba(7,9,20,0.98) 100%);
+ border-radius: 16px;
+ border: 1px solid var(--border-subtle);
+ box-shadow:
+ 0 14px 22px rgba(0,0,0,0.65),
+ 0 0 0 1px rgba(255,255,255,0.015);
+ position: relative;
+ overflow: hidden;
+ }
+
+ .glass::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ background:
+ radial-gradient(circle at 0 0, rgba(255,255,255,0.08), transparent 55%),
+ radial-gradient(circle at 100% 100%, rgba(255,255,255,0.04), transparent 60%);
+ mix-blend-mode: soft-light;
+ opacity: 0.65;
+ pointer-events: none;
+ }
+
+ .panel-header {
+ position: relative;
+ z-index: 2;
+ padding: 12px 16px 8px;
+ border-bottom: 1px solid rgba(255,255,255,0.05);
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 10px;
+ backdrop-filter: blur(16px);
+ }
+
+ .title-block h1 {
+ font-size: 17px;
+ letter-spacing: 0.04em;
+ text-transform: uppercase;
+ color: var(--muted);
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ }
+
+ .title-pill {
+ font-size: 10px;
+ text-transform: uppercase;
+ padding: 2px 6px;
+ border-radius: 999px;
+ border: 1px solid rgba(255,255,255,0.12);
+ background: radial-gradient(circle at 0 0, rgba(255,255,255,0.24), transparent 65%);
+ color: #060710;
+ }
+
+ .title-main {
+ font-size: 20px;
+ margin-top: 2px;
+ font-weight: 600;
+ letter-spacing: 0.03em;
+ text-transform: uppercase;
+ }
+
+ .subtitle {
+ font-size: 11px;
+ color: var(--muted);
+ margin-top: 2px;
+ }
+
+ .header-right {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ }
+
+ .chip {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ padding: 4px 8px;
+ border-radius: 999px;
+ font-size: 11px;
+ background: radial-gradient(circle at 0 0, rgba(255,75,125,0.6), rgba(255,75,125,0.25) 45%, transparent 80%);
+ border: 1px solid rgba(255,75,125,0.7);
+ color: #ffe9f1;
+ text-transform: uppercase;
+ letter-spacing: 0.08em;
+ }
+
+ .chip span.dot {
+ width: 7px;
+ height: 7px;
+ border-radius: 50%;
+ background: var(--accent-alt);
+ box-shadow: 0 0 0 3px rgba(87,242,199,0.2);
+ }
+
+ .counter {
+ font-size: 11px;
+ padding: 4px 9px;
+ border-radius: 999px;
+ border: 1px solid rgba(255,255,255,0.1);
+ color: var(--muted);
+ background: radial-gradient(circle at 0 0, rgba(255,255,255,0.14), transparent 65%);
+ }
+
+ .counter strong {
+ color: var(--accent-alt);
+ font-weight: 600;
+ }
+
+ .left-panel {
+ display: flex;
+ flex-direction: column;
+ position: relative;
+ z-index: 1;
+ }
+
+ .right-panel {
+ display: flex;
+ flex-direction: column;
+ position: relative;
+ z-index: 1;
+ }
+
+ .matchup-body {
+ position: relative;
+ z-index: 2;
+ padding: 10px 16px 14px;
+ height: 100%;
+ display: grid;
+ grid-template-rows: auto minmax(0, 1fr) auto;
+ gap: 10px;
+ }
+
+ .status-row {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 10px;
+ font-size: 11px;
+ color: var(--muted);
+ }
+
+ .status-tags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px;
+ }
+
+ .tag {
+ padding: 2px 7px;
+ border-radius: 999px;
+ border: 1px solid rgba(255,255,255,0.09);
+ background: rgba(8,10,24,0.8);
+ font-size: 10px;
+ text-transform: uppercase;
+ letter-spacing: 0.08em;
+ color: var(--muted);
+ }
+
+ .tag-pulse {
+ border-color: rgba(87,242,199,0.9);
+ color: var(--accent-alt);
+ background: radial-gradient(circle at 0 0, rgba(87,242,199,0.24), transparent 70%);
+ position: relative;
+ overflow: hidden;
+ }
+
+ .tag-pulse::after {
+ content: "";
+ position: absolute;
+ inset: -40%;
+ background: conic-gradient(from 0deg, rgba(87,242,199,0.0), rgba(87,242,199,0.35), rgba(87,242,199,0.0));
+ mix-blend-mode: screen;
+ opacity: 0.5;
+ animation: spin 4s linear infinite;
+ }
+
+ .queue-indicator {
+ font-variant-numeric: tabular-nums;
+ }
+
+ .queue-indicator span {
+ color: var(--accent-alt);
+ }
+
+ .arena {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) 56px minmax(0, 1fr);
+ gap: 8px;
+ align-items: stretch;
+ height: 100%;
+ min-height: 0;
+ }
+
+ .architect-card {
+ position: relative;
+ border-radius: 14px;
+ padding: 10px 10px 10px;
+ background: radial-gradient(circle at 0 -20%, rgba(255,255,255,0.12), transparent 55%),
+ linear-gradient(140deg, rgba(15,19,38,0.98), rgba(10,14,28,0.99));
+ border: 1px solid rgba(255,255,255,0.06);
+ box-shadow:
+ 0 10px 18px rgba(0,0,0,0.75),
+ 0 0 0 1px rgba(0,0,0,0.6);
+ display: grid;
+ grid-template-rows: auto minmax(0, 1fr);
+ gap: 8px;
+ overflow: hidden;
+ }
+
+ .architect-card.right {
+ background: radial-gradient(circle at 100% 0, rgba(255,255,255,0.10), transparent 60%),
+ linear-gradient(140deg, rgba(11,13,30,0.98), rgba(9,11,24,0.99));
+ }
+
+ .architect-header {
+ display: flex;
+ align-items: flex-start;
+ gap: 8px;
+ }
+
+ .avatar {
+ position: relative;
+ width: 38px;
+ height: 38px;
+ border-radius: 12px;
+ background: radial-gradient(circle at 0 0, rgba(255,255,255,0.32), rgba(45,54,92,1));
+ border: 1px solid rgba(255,255,255,0.25);
+ box-shadow:
+ 0 0 0 1px rgba(0,0,0,0.65),
+ 0 10px 16px rgba(0,0,0,0.75);
+ overflow: hidden;
+ }
+
+ .avatar-inner {
+ position: absolute;
+ inset: 3px;
+ border-radius: 9px;
+ background:
+ linear-gradient(140deg, rgba(255,255,255,0.95), rgba(235,240,255,0.9));
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: #060613;
+ font-size: 16px;
+ font-weight: 700;
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+ overflow: hidden;
+ }
+
+ .avatar-inner span {
+ background: conic-gradient(from 220deg,
+ #111827,
+ #0f172a,
+ #1d4ed8,
+ #4f46e5,
+ #ec4899,
+ #111827);
+ -webkit-background-clip: text;
+ background-clip: text;
+ color: transparent;
+ }
+
+ .avatar-inner::before {
+ content: "";
+ position: absolute;
+ inset: -20%;
+ background: repeating-linear-gradient(
+ 135deg,
+ rgba(15,23,42,0.65),
+ rgba(15,23,42,0.65) 1px,
+ rgba(15,23,42,0.1) 1px,
+ rgba(15,23,42,0.1) 3px
+ );
+ mix-blend-mode: multiply;
+ opacity: 0.75;
+ }
+
+ .avatar-glow {
+ position: absolute;
+ inset: -30%;
+ background: radial-gradient(circle at 30% 0, rgba(87,242,199,0.9), transparent 55%);
+ opacity: 0.5;
+ mix-blend-mode: soft-light;
+ }
+
+ .avatar-tag {
+ position: absolute;
+ bottom: 3px;
+ right: 3px;
+ font-size: 7px;
+ text-transform: uppercase;
+ letter-spacing: 0.12em;
+ padding: 2px 4px;
+ border-radius: 999px;
+ background: rgba(5,7,18,0.84);
+ color: #e5edff;
+ border: 1px solid rgba(255,255,255,0.4);
+ box-shadow: 0 0 0 1px rgba(0,0,0,0.8);
+ }
+
+ .architect-info {
+ flex: 1;
+ min-width: 0;
+ }
+
+ .name-row {
+ display: flex;
+ align-items: baseline;
+ justify-content: space-between;
+ gap: 6px;
+ }
+
+ .name {
+ font-size: 14px;
+ font-weight: 600;
+ letter-spacing: 0.04em;
+ text-transform: uppercase;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ .name small {
+ font-size: 10px;
+ text-transform: uppercase;
+ letter-spacing: 0.12em;
+ color: var(--muted);
+ margin-left: 4px;
+ }
+
+ .score-badge {
+ font-size: 11px;
+ padding: 2px 7px;
+ border-radius: 999px;
+ border: 1px solid rgba(255,255,255,0.12);
+ background: radial-gradient(circle at 0 0, rgba(255,255,255,0.14), transparent 70%);
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+ }
+
+ .score-badge span.value {
+ font-variant-numeric: tabular-nums;
+ color: var(--accent-alt);
+ font-weight: 600;
+ }
+
+ .meta-row {
+ margin-top: 4px;
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px;
+ align-items: center;
+ }
+
+ .meta-pill {
+ font-size: 10px;
+ padding: 2px 6px;
+ border-radius: 999px;
+ border: 1px solid rgba(255,255,255,0.09);
+ background: rgba(3,6,23,0.9);
+ color: var(--muted);
+ text-transform: uppercase;
+ letter-spacing: 0.08em;
+ }
+
+ .meta-pill span {
+ color: var(--accent-alt);
+ }
+
+ .trend-dot {
+ display: inline-block;
+ width: 6px;
+ height: 6px;
+ border-radius: 999px;
+ margin-right: 3px;
+ }
+
+ .trend-up {
+ background: var(--success);
+ box-shadow: 0 0 0 3px rgba(87,242,123,0.25);
+ }
+
+ .trend-flat {
+ background: var(--warning);
+ box-shadow: 0 0 0 3px rgba(255,200,87,0.2);
+ }
+
+ .trend-down {
+ background: var(--danger);
+ box-shadow: 0 0 0 3px rgba(255,85,85,0.2);
+ }
+
+ .architect-body {
+ position: relative;
+ padding: 6px 2px 2px;
+ display: grid;
+ grid-template-rows: auto 1fr;
+ row-gap: 6px;
+ }
+
+ .metric-row {
+ display: grid;
+ grid-template-columns: 1.3fr 0.9fr;
+ gap: 4px;
+ font-size: 10px;
+ color: var(--muted);
+ }
+
+ .metric-pill {
+ border-radius: 999px;
+ padding: 3px 7px;
+ background: rgba(5,7,20,0.85);
+ border: 1px solid rgba(255,255,255,0.06);
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 4px;
+ }
+
+ .metric-pill span.value {
+ font-variant-numeric: tabular-nums;
+ color: #fff;
+ font-weight: 500;
+ }
+
+ .metric-pill span.label {
+ text-transform: uppercase;
+ letter-spacing: 0.09em;
+ }
+
+ .bar-group {
+ display: grid;
+ grid-template-columns: 1.1fr 1.1fr 0.8fr;
+ gap: 4px;
+ align-items: center;
+ }
+
+ .bar {
+ position: relative;
+ height: 14px;
+ border-radius: 999px;
+ background: rgba(3,6,23,0.95);
+ overflow: hidden;
+ border: 1px solid rgba(255,255,255,0.06);
+ }
+
+ .bar-fill {
+ position: absolute;
+ inset: 0;
+ width: var(--w, 50%);
+ background: linear-gradient(90deg, rgba(255,75,125,0.2), var(--accent));
+ box-shadow: 0 0 0 1px rgba(255,255,255,0.04);
+ transform-origin: left;
+ }
+
+ .bar-fill.alt {
+ background: linear-gradient(90deg, rgba(87,242,199,0.15), var(--accent-alt));
+ }
+
+ .bar-label {
+ position: relative;
+ z-index: 2;
+ font-size: 9px;
+ text-transform: uppercase;
+ letter-spacing: 0.1em;
+ color: var(--muted);
+ padding: 0 6px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ }
+
+ .bar-label span.value {
+ font-variant-numeric: tabular-nums;
+ color: #f9fafb;
+ }
+
+ .vs-column {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ justify-content: center;
+ gap: 10px;
+ pointer-events: none;
+ }
+
+ .vs-badge {
+ margin: 0 auto;
+ pointer-events: auto;
+ cursor: default;
+ width: 44px;
+ height: 44px;
+ border-radius: 18px;
+ background:
+ radial-gradient(circle at 20% 0, rgba(255,255,255,0.25), transparent 55%),
+ radial-gradient(circle at 80% 120%, rgba(255,75,125,0.65), transparent 65%),
+ linear-gradient(145deg, #050814, #141425);
+ border: 1px solid rgba(255,255,255,0.12);
+ box-shadow:
+ 0 12px 24px rgba(0,0,0,0.85),
+ 0 0 0 1px rgba(0,0,0,0.8),
+ 0 0 32px rgba(255,75,125,0.45);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-weight: 700;
+ font-size: 15px;
+ letter-spacing: 0.15em;
+ text-transform: uppercase;
+ }
+
+ .vs-badge span {
+ background: radial-gradient(circle at 0 0, #ffe6f0, #ffd0dd);
+ -webkit-background-clip: text;
+ background-clip: text;
+ color: transparent;
+ text-shadow: 0 0 18px rgba(255, 255, 255, 0.4);
+ }
+
+ .streak {
+ font-size: 10px;
+ color: var(--muted);
+ text-align: center;
+ text-transform: uppercase;
+ letter-spacing: 0.15em;
+ }
+
+ .streak strong {
+ color: var(--accent-alt);
+ }
+
+ .choices {
+ margin-top: 6px;
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 10px;
+ }
+
+ .btn {
+ position: relative;
+ border-radius: 999px;
+ border: 1px solid rgba(255,255,255,0.1);
+ padding: 8px 10px;
+ font-size: 11px;
+ text-transform: uppercase;
+ letter-spacing: 0.14em;
+ background: rgba(10,13,28,0.9);
+ color: var(--muted);
+ cursor: pointer;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: 6px;
+ overflow: hidden;
+ transition: all 0.14s ease-out;
+ user-select: none;
+ }
+
+ .btn span.keycap {
+ font-variant-numeric: tabular-nums;
+ font-size: 9px;
+ padding: 2px 5px;
+ border-radius: 6px;
+ background: rgba(5,7,18,0.8);
+ border: 1px solid rgba(255,255,255,0.1);
+ color: var(--muted);
+ }
+
+ .btn-hot {
+ background: radial-gradient(circle at 0 0, rgba(255,75,125,0.6), transparent 70%),
+ linear-gradient(135deg, rgba(15,7,12,0.95), rgba(35,10,20,0.95));
+ color: #ffe9f2;
+ border-color: rgba(255,75,125,0.8);
+ box-shadow: 0 6px 16px rgba(255,75,125,0.45);
+ }
+
+ .btn-not {
+ background: radial-gradient(circle at 100% 0, rgba(148,163,184,0.6), transparent 65%),
+ linear-gradient(135deg, rgba(10,16,30,0.98), rgba(7,10,22,0.98));
+ color: #e5edff;
+ border-color: rgba(148,163,184,0.8);
+ box-shadow: 0 6px 14px rgba(15,23,42,0.9);
+ }
+
+ .btn::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ background: radial-gradient(circle at 0 0, rgba(255,255,255,0.18), transparent 55%);
+ mix-blend-mode: screen;
+ opacity: 0;
+ transition: opacity 0.14s ease-out;
+ pointer-events: none;
+ }
+
+ .btn:active {
+ transform: translateY(1px) scale(0.99);
+ box-shadow: none;
+ }
+
+ .btn:active::before {
+ opacity: 0.6;
+ }
+
+ .btn.disabled {
+ opacity: 0.4;
+ pointer-events: none;
+ box-shadow: none;
+ }
+
+ .bottom-row {
+ padding-top: 4px;
+ border-top: 1px solid rgba(255,255,255,0.05);
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 10px;
+ font-size: 10px;
+ color: var(--muted);
+ }
+
+ .kbd-hints {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px;
+ align-items: center;
+ }
+
+ .kbd {
+ padding: 2px 6px;
+ border-radius: 7px;
+ border: 1px solid rgba(148,163,184,0.5);
+ background: rgba(15,23,42,0.9);
+ font-size: 9px;
+ text-transform: uppercase;
+ letter-spacing: 0.12em;
+ color: #e5edff;
+ }
+
+ .kbd span {
+ color: var(--accent-alt);
+ }
+
+ .ticker {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ min-width: 0;
+ }
+
+ .ticker-label {
+ font-size: 9px;
+ text-transform: uppercase;
+ letter-spacing: 0.16em;
+ color: rgba(148,163,184,0.9);
+ }
+
+ .ticker-track {
+ flex: 1;
+ min-width: 0;
+ position: relative;
+ height: 14px;
+ border-radius: 999px;
+ background: rgba(3,6,23,0.96);
+ overflow: hidden;
+ border: 1px solid rgba(255,255,255,0.04);
+ }
+
+ .ticker-bar {
+ position: absolute;
+ inset: 0;
+ width: 0%;
+ background: linear-gradient(90deg, rgba(87,242,199,0.2), rgba(87,242,199,0.85));
+ box-shadow: 0 0 22px rgba(87,242,199,0.5);
+ transform-origin: left;
+ transition: width 0.26s ease-out;
+ }
+
+ .ticker-dot {
+ position: absolute;
+ top: 50%;
+ right: 6px;
+ width: 6px;
+ height: 6px;
+ border-radius: 999px;
+ background: var(--accent-alt);
+ box-shadow: 0 0 0 3px rgba(87,242,199,0.2);
+ transform: translateY(-50%);
+ }
+
+ .right-panel .panel-header {
+ border-bottom: 1px solid rgba(255,255,255,0.05);
+ }
+
+ .right-main {
+ position: relative;
+ z-index: 2;
+ padding: 10px 12px 12px;
+ height: 100%;
+ display: grid;
+ grid-template-rows: 1.1fr minmax(0, 1.2fr) auto;
+ gap: 10px;
+ }
+
+ .leaderboard {
+ border-radius: 10px;
+ background: radial-gradient(circle at 0 0, rgba(255,255,255,0.12), transparent 55%),
+ linear-gradient(135deg, rgba(10,14,28,0.98), rgba(9,11,21,0.99));
+ border: 1px solid rgba(255,255,255,0.06);
+ padding: 7px 8px;
+ box-shadow: 0 8px 16px rgba(0,0,0,0.75);
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+ overflow: hidden;
+ }
+
+ .leaderboard-header {
+ display: flex;
+ align-items: baseline;
+ justify-content: space-between;
+ gap: 4px;
+ }
+
+ .leaderboard-header h2 {
+ font-size: 11px;
+ text-transform: uppercase;
+ letter-spacing: 0.16em;
+ color: rgba(148,163,184,0.95);
+ }
+
+ .leaderboard-header span {
+ font-size: 10px;
+ color: var(--muted);
+ }
+
+ .leaderboard-list {
+ margin-top: 4px;
+ display: grid;
+ grid-auto-rows: minmax(0, 1fr);
+ gap: 2px;
+ overflow: hidden;
+ font-size: 10px;
+ }
+
+ .leader-row {
+ display: grid;
+ grid-template-columns: 14px minmax(0, 1fr) 52px 34px;
+ gap: 4px;
+ align-items: center;
+ padding: 1px 2px;
+ border-radius: 6px;
+ color: var(--muted);
+ }
+
+ .leader-row:nth-child(1) {
+ background: radial-gradient(circle at 0 0, rgba(255,255,255,0.14), transparent 60%);
+ }
+
+ .leader-row span.rank {
+ text-align: center;
+ font-variant-numeric: tabular-nums;
+ color: rgba(148,163,184,0.95);
+ }
+
+ .leader-row span.rank.gold {
+ color: #ffe48f;
+ }
+
+ .leader-row span.rank.silver {
+ color: #d0d7ff;
+ }
+
+ .leader-row span.rank.bronze {
+ color: #ffb98a;
+ }
+
+ .leader-name {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ .leader-score {
+ font-variant-numeric: tabular-nums;
+ text-align: right;
+ color: #e5edff;
+ }
+
+ .leader-pulse {
+ text-align: right;
+ font-variant-numeric: tabular-nums;
+ color: var(--accent-alt);
+ }
+
+ .trend-panel {
+ border-radius: 10px;
+ background: radial-gradient(circle at 100% 0, rgba(87,242,199,0.2), transparent 55%),
+ radial-gradient(circle at 0 120%, rgba(255,75,125,0.18), transparent 60%),
+ linear-gradient(140deg, rgba(7,9,18,0.98), rgba(8,10,20,0.99));
+ border: 1px solid rgba(255,255,255,0.06);
+ padding: 7px 8px;
+ box-shadow: 0 8px 16px rgba(0,0,0,0.75);
+ display: grid;
+ grid-template-rows: auto minmax(0, 1fr);
+ gap: 4px;
+ overflow: hidden;
+ }
+
+ .trend-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: baseline;
+ gap: 4px;
+ font-size: 11px;
+ text-transform: uppercase;
+ letter-spacing: 0.16em;
+ color: rgba(148,163,184,0.95);
+ }
+
+ .trend-header span {
+ font-size: 10px;
+ color: var(--muted);
+ }
+
+ .trend-legend {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px;
+ font-size: 9px;
+ color: var(--muted);
+ }
+
+ .legend-item {
+ display: inline-flex;
+ align-items: center;
+ gap: 3px;
+ }
+
+ .legend-dot {
+ width: 7px;
+ height: 7px;
+ border-radius: 999px;
+ }
+
+ .legend-dot.star {
+ background: linear-gradient(135deg,#ffe48f,#ffd452);
+ box-shadow: 0 0 0 2px rgba(255,228,143,0.35);
+ }
+
+ .legend-dot.heat {
+ background: var(--accent);
+ box-shadow: 0 0 0 2px rgba(255,75,125,0.35);
+ }
+
+ .trend-grid {
+ margin-top: 3px;
+ display: grid;
+ grid-template-columns: 1.2fr 1.4fr;
+ gap: 6px;
+ font-size: 10px;
+ }
+
+ .trend-col h3 {
+ font-size: 10px;
+ text-transform: uppercase;
+ letter-spacing: 0.14em;
+ color: rgba(148,163,184,0.95);
+ margin-bottom: 3px;
+ }
+
+ .trend-row {
+ display: grid;
+ grid-template-columns: minmax(0, 1.4fr) 0.8fr 0.7fr;
+ gap: 3px;
+ align-items: center;
+ margin-bottom: 2px;
+ }
+
+ .trend-name {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ .trend-badge {
+ border-radius: 999px;
+ border: 1px solid rgba(255,255,255,0.08);
+ background: rgba(5,7,18,0.9);
+ padding: 2px 5px;
+ text-align: center;
+ font-variant-numeric: tabular-nums;
+ }
+
+ .trend-badge.heat {
+ color: var(--accent);
+ border-color: rgba(255,75,125,0.8);
+ background: rgba(34,9,18,0.95);
+ }
+
+ .history-panel {
+ border-radius: 10px;
+ background: linear-gradient(145deg, rgba(8,10,20,0.98), rgba(7,9,18,0.99));
+ border: 1px solid rgba(255,255,255,0.05);
+ padding: 7px 8px 6px;
+ box-shadow: 0 8px 15px rgba(0,0,0,0.75);
+ display: grid;
+ grid-template-rows: auto minmax(0, 1fr);
+ gap: 4px;
+ overflow: hidden;
+ font-size: 10px;
+ }
+
+ .history-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: baseline;
+ gap: 4px;
+ }
+
+ .history-header h2 {
+ font-size: 11px;
+ text-transform: uppercase;
+ letter-spacing: 0.16em;
+ color: rgba(148,163,184,0.95);
+ }
+
+ .history-header span {
+ font-size: 10px;
+ color: var(--muted);
+ }
+
+ .history-timeline {
+ margin-top: 2px;
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+ overflow: hidden;
+ }
+
+ .history-item {
+ display: grid;
+ grid-template-columns: 54px minmax(0, 1.2fr) 46px 24px;
+ gap: 4px;
+ align-items: center;
+ padding: 1px 2px;
+ border-radius: 6px;
+ color: var(--muted);
+ }
+
+ .history-item span.r {
+ font-variant-numeric: tabular-nums;
+ text-align: center;
+ color: rgba(148,163,184,0.9);
+ }
+
+ .history-name {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ .history-score {
+ font-variant-numeric: tabular-nums;
+ text-align: right;
+ color: #e5edff;
+ }
+
+ .history-tag {
+ font-size: 9px;
+ text-align: right;
+ text-transform: uppercase;
+ letter-spacing: 0.12em;
+ }
+
+ .history-tag.hot {
+ color: var(--accent);
+ }
+
+ .history-tag.not {
+ color: rgba(148,163,184,0.95);
+ }
+
+ .footer-hint {
+ font-size: 9px;
+ color: rgba(148,163,184,0.9);
+ text-align: right;
+ margin-top: 1px;
+ text-transform: uppercase;
+ letter-spacing: 0.14em;
+ }
+
+ @keyframes spin {
+ to {
+ transform: rotate(360deg);
+ }
+ }
+
+ @keyframes flash {
+ 0% { transform: scale(1); box-shadow: 0 0 32px rgba(255,75,125,0.45); }
+ 50% { transform: scale(1.06); box-shadow: 0 0 46px rgba(255,75,125,0.85); }
+ 100% { transform: scale(1); box-shadow: 0 0 32px rgba(255,75,125,0.45); }
+ }
+
+ .vs-badge.flash {
+ animation: flash 0.33s ease-out;
+ }
+
+ .fade {
+ animation: fadeIn 0.22s ease-out;
+ }
+
+ @keyframes fadeIn {
+ from { opacity: 0; transform: translateY(4px); }
+ to { opacity: 1; transform: translateY(0); }
+ }
+</style>
+</head>
+<body>
+<div class="app">
+ <section class="left-panel glass">
+ <header class="panel-header">
+ <div class="title-block">
+ <h1>
+ <span class="title-pill">WORLD CUP</span>
+ HOT / NOT ARENA
+ </h1>
+ <div class="title-main">High‑End Architects</div>
+ <div class="subtitle">Last 20 new arrivals vs global trendline · instant offline simulator</div>
+ </div>
+ <div class="header-right">
+ <div class="chip"><span class="dot"></span> LIVE MODEL ARENA</div>
+ <div class="counter">Rated: <strong id="ratedCount">0</strong> / 20</div>
+ </div>
+ </header>
+
+ <div class="matchup-body">
+ <div class="status-row">
+ <div class="status-tags">
+ <span class="tag tag-pulse">Simulated Trend Signal</span>
+ <span class="tag">No Network · Local Fixture</span>
+ <span class="tag">Bias: Concept Heat Only</span>
+ </div>
+ <div class="queue-indicator">
+ In queue: <span id="queueLeft">20</span> arrivals
+ </div>
+ </div>
+
+ <div class="arena fade" id="arena">
+ <article class="architect-card left" id="cardA">
+ <div class="architect-header">
+ <div class="avatar">
+ <div class="avatar-inner">
+ <div class="avatar-glow"></div>
+ <span id="avatarInitA">A</span>
+ </div>
+ <div class="avatar-tag">Neo</div>
+ </div>
+ <div class="architect-info">
+ <div class="name-row">
+ <div class="name" id="nameA">—</div>
+ <div class="score-badge">
+ HN-Score
+ <span class="value" id="scoreA">0</span>
+ </div>
+ </div>
+ <div class="meta-row">
+ <div class="meta-pill">
+ <span class="trend-dot trend-flat"></span>
+ <span id="trendLabelA">steady vs internet</span>
+ </div>
+ <div class="meta-pill">
+ Studio <span id="studioA">—</span>
+ </div>
+ <div class="meta-pill">
+ Region: <span id="regionA">—</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="architect-body">
+ <div class="metric-row">
+ <div class="metric-pill">
+ <span class="label">Web Buzz</span>
+ <span class="value" id="buzzA">0</span>
+ </div>
+ <div class="metric-pill">
+ <span class="label">Arena WR</span>
+ <span class="value" id="wrA">0%</span>
+ </div>
+ </div>
+ <div class="bar-group">
+ <div class="bar">
+ <div class="bar-fill" id="heatBarA"></div>
+ <div class="bar-label">
+ <span>Heat</span>
+ <span class="value" id="heatValA">0</span>
+ </div>
+ </div>
+ <div class="bar">
+ <div class="bar-fill alt" id="trendBarA"></div>
+ <div class="bar-label">
+ <span>Net</span>
+ <span class="value" id="netValA">0</span>
+ </div>
+ </div>
+ <div class="bar">
+ <div class="bar-fill" id="hypeBarA" style="background: linear-gradient(90deg,rgba(129,140,248,0.3),#818cf8);"></div>
+ <div class="bar-label">
+ <span>Hype</span>
+ <span class="value" id="hypeValA">0</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </article>
+
+ <div class="vs-column">
+ <div class="vs-badge" id="vsBadge"><span>VS</span></div>
+ <div class="streak" id="streakLabel">
+ Arena streak: <strong>0</strong>
+ </div>
+ </div>
+
+ <article class="architect-card right" id="cardB">
+ <div class="architect-header">
+ <div class="avatar">
+ <div class="avatar-inner">
+ <div class="avatar-glow"></div>
+ <span id="avatarInitB">B</span>
+ </div>
+ <div class="avatar-tag">Neo</div>
+ </div>
+ <div class="architect-info">
+ <div class="name-row">
+ <div class="name" id="nameB">—</div>
+ <div class="score-badge">
+ HN-Score
+ <span class="value" id="scoreB">0</span>
+ </div>
+ </div>
+ <div class="meta-row">
+ <div class="meta-pill">
+ <span class="trend-dot trend-flat"></span>
+ <span id="trendLabelB">steady vs internet</span>
+ </div>
+ <div class="meta-pill">
+ Studio <span id="studioB">—</span>
+ </div>
+ <div class="meta-pill">
+ Region: <span id="regionB">—</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="architect-body">
+ <div class="metric-row">
+ <div class="metric-pill">
+ <span class="label">Web Buzz</span>
+ <span class="value" id="buzzB">0</span>
+ </div>
+ <div class="metric-pill">
+ <span class="label">Arena WR</span>
+ <span class="value" id="wrB">0%</span>
+ </div>
+ </div>
+ <div class="bar-group">
+ <div class="bar">
+ <div class="bar-fill" id="heatBarB"></div>
+ <div class="bar-label">
+ <span>Heat</span>
+ <span class="value" id="heatValB">0</span>
+ </div>
+ </div>
+ <div class="bar">
+ <div class="bar-fill alt" id="trendBarB"></div>
+ <div class="bar-label">
+ <span>Net</span>
+ <span class="value" id="netValB">0</span>
+ </div>
+ </div>
+ <div class="bar">
+ <div class="bar-fill" id="hypeBarB" style="background: linear-gradient(90deg,rgba(129,140,248,0.3),#818cf8);"></div>
+ <div class="bar-label">
+ <span>Hype</span>
+ <span class="value" id="hypeValB">0</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </article>
+ </div>
+
+ <div class="choices">
+ <button class="btn btn-hot" id="btnHot">
+ <span class="keycap">A / ←</span>
+ HOTTER
+ </button>
+ <button class="btn btn-not" id="btnNot">
+ <span class="keycap">B / →</span>
+ HOTTER
+ </button>
+ </div>
+
+ <div class="bottom-row">
+ <div class="kbd-hints">
+ <div class="kbd">SPACE · <span>auto advance</span></div>
+ <div class="kbd">R · <span>reset fixture</span></div>
+ <div class="kbd">Offline: trend scores are simulated based on training‑time priors only.</div>
+ </div>
+ <div class="ticker">
+ <span class="ticker-label">CROWD CONSENSUS</span>
+ <div class="ticker-track">
+ <div class="ticker-bar" id="tickerBar"></div>
+ <div class="ticker-dot"></div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </section>
+
+ <section class="right-panel glass">
+ <header class="panel-header">
+ <div class="title-block">
+ <div class="title-main" style="font-size:16px;">Internet Trendboard</div>
+ <div class="subtitle">Static priors for globally recognised high‑end architects (approximate)</div>
+ </div>
+ <div class="header-right">
+ <div class="chip" style="background: radial-gradient(circle at 0 0, rgba(87,242,199,0.55), rgba(87,242,199,0.23) 45%, transparent 80%); border-color: rgba(87,242,199,0.8); color:#e6fff8;">
+ PRIOR SNAPSHOT
+ </div>
+ </div>
+ </header>
+
+ <div class="right-main">
+ <section class="leaderboard">
+ <div class="leaderboard-header">
+ <h2>World‑Class Hall</h2>
+ <span>Baseline priors · not live rankings</span>
+ </div>
+ <div class="leaderboard-list" id="leaderboardList">
+ <!-- Filled by JS -->
+ </div>
+ </section>
+
+ <section class="trend-panel">
+ <div>
+ <div class="trend-header">
+ <div>Concept Heat vs Net Trend</div>
+ <span>How your picks lean vs historic internet hype</span>
+ </div>
+ <div class="trend-legend">
+ <div class="legend-item">
+ <span class="legend-dot star"></span> internet prior hotness
+ </div>
+ <div class="legend-item">
+ <span class="legend-dot heat"></span> your arena heat
+ </div>
+ </div>
+ </div>
+ <div class="trend-grid">
+ <div class="trend-col">
+ <h3>High‑end snapshots</h3>
+ <div id="trendStatic">
+ <!-- Static examples -->
+ </div>
+ </div>
+ <div class="trend-col">
+ <h3>Your drift vs net</h3>
+ <div id="trendDynamic">
+ <!-- Live summary -->
+ </div>
+ </div>
+ </div>
+ </section>
+
+ <section class="history-panel">
+ <div class="history-header">
+ <h2>Fixture Timeline</h2>
+ <span>Last 8 battles</span>
+ </div>
+ <div class="history-timeline" id="historyTimeline">
+ <!-- History rows -->
+ </div>
+ <div class="footer-hint" id="footerHint">
+ Rate an arrival to start shaping the arena.
+ </div>
+ </section>
+ </div>
+ </section>
+</div>
+
+<script>
+(function() {
+ const arrivals = [
+ { name: "Studio Liminal Grid", studio: "Liminal Grid", region: "Copenhagen", heat: 76, net: 68, buzz: 61, hype: 72 },
+ { name: "Cloudline Atelier", studio: "Cloudline", region: "Tokyo", heat: 88, net: 81, buzz: 79, hype: 90 },
+ { name: "Paramorph Lab", studio: "Paramorph", region: "Rotterdam", heat: 83, net: 74, buzz: 70, hype: 86 },
+ { name: "TopoScalar Works", studio: "TopoScalar", region: "Mexico City", heat: 69, net: 63, buzz: 58, hype: 72 },
+ { name: "GlassHaven Bureau", studio: "GlassHaven", region: "Toronto", heat: 72, net: 67, buzz: 64, hype: 70 },
+ { name: "Nightshift Urbanism", studio: "Nightshift", region: "Seoul", heat: 91, net: 84, buzz: 82, hype: 94 },
+ { name: "Folded Horizon Office", studio: "FHO", region: "Oslo", heat: 79, net: 73, buzz: 69, hype: 80 },
+ { name: "EchoVoid Practice", studio: "EchoVoid", region: "Berlin", heat: 74, net: 70, buzz: 66, hype: 76 },
+ { name: "Silent Plinth Studio", studio: "Silent Plinth", region: "Melbourne", heat: 68, net: 64, buzz: 57, hype: 67 },
+ { name: "Perimeter Atlas", studio: "Perimeter", region: "Lisbon", heat: 82, net: 76, buzz: 73, hype: 84 },
+ { name: "Neon Quarry Lab", studio: "Neon Quarry", region: "Shanghai", heat: 89, net: 83, buzz: 85, hype: 92 },
+ { name: "Tectonic Drift Office", studio: "TDO", region: "Reykjavík", heat: 71, net: 65, buzz: 59, hype: 70 },
+ { name: "Desert Halo Works", studio: "Desert Halo", region: "Dubai", heat: 77, net: 72, buzz: 68, hype: 78 },
+ { name: "Analog Fjord Studio", studio: "Analog Fjord", region: "Bergen", heat: 66, net: 60, buzz: 54, hype: 64 },
+ { name: "Gradient Portico", studio: "Gradient Portico", region: "Chicago", heat: 80, net: 75, buzz: 71, hype: 82 },
+ { name: "Carbon Lattice Office", studio: "Carbon Lattice", region: "London", heat: 85, net: 79, buzz: 77, hype: 88 },
+ { name: "Kinetic Shade Lab", studio: "KSL", region: "Singapore", heat: 87, net: 82, buzz: 80, hype: 90 },
+ { name: "Vapor Threshold Bureau", studio: "VTB", region: "Los Angeles", heat: 73, net: 69, buzz: 65, hype: 75 },
+ { name: "Aurora Column Studio", studio: "Aurora Column", region: "Helsinki", heat: 78, net: 71, buzz: 67, hype: 79 },
+ { name: "Substrate Memory Lab", studio: "Substrate", region: "Rome", heat: 81, net: 77, buzz: 72, hype: 83 }
+ ];
+
+ const priors = [
+ { name: "Tadao Ando", score: 96, web: 94, trend: "+ ultra‑minimal concrete poetics" },
+ { name: "Herzog & de Meuron", score: 95, web: 93, trend: "+ material tactility & stadium scale" },
+ { name: "Zaha Hadid Architects", score: 97, web: 98, trend: "+ parametric icons & social media optics" },
+ { name: "OMA / Rem Koolhaas", score: 94, web: 92, trend: "+ theory‑driven urban branding" },
+ { name: "BIG – Bjarke Ingels Group", score: 92, web: 95, trend: "+ narrative‑heavy crowd‑pleasers" },
+ { name: "SANAA", score: 93, web: 90, trend: "+ vaporous light & galleries" },
+ { name: "Snøhetta", score: 90, web: 88, trend: "+ civic landscapes & soft icons" },
+ { name: "MVRDV", score: 89, web: 87, trend: "+ color, stacking and spectacle" }
+ ];
+
+ const staticTrendPairs = [
+ { arch: "ZHA vs BIG", heat: 97, net: 96, drift: "+2 social", read: "Net slightly over‑weights spectacle vs spatial nuance." },
+ { arch: "Ando vs SANAA", heat: 94, net: 92, drift: "+2 calm", read: "Priors skew to serene light over expressive form." },
+ { arch: "OMA vs MVRDV", heat: 92, net: 90, drift: "+2 theory", read: "Internet boosts color & renders; priors still rate theory." },
+ { arch: "Snøhetta vs BIG", heat: 91, net: 93, drift: "-2 civic", read: "Digital feeds lean to iconic imagery, less to civic subtlety." }
+ ];
+
+ const dom = {
+ ratedCount: document.getElementById("ratedCount"),
+ queueLeft: document.getElementById("queueLeft"),
+ arena: document.getElementById("arena"),
+ vsBadge: document.getElementById("vsBadge"),
+ streakLabel: document.getElementById("streakLabel"),
+ btnHot: document.getElementById("btnHot"),
+ btnNot: document.getElementById("btnNot"),
+ tickerBar: document.getElementById("tickerBar"),
+ footerHint: document.getElementById("footerHint"),
+ // card A
+ nameA: document.getElementById("nameA"),
+ studioA: document.getElementById("studioA"),
+ regionA: document.getElementById("regionA"),
+ scoreA: document.getElementById("scoreA"),
+ avatarInitA: document.getElementById("avatarInitA"),
+ trendLabelA: document.getElementById("trendLabelA"),
+ buzzA: document.getElementById("buzzA"),
+ wrA: document.getElementById("wrA"),
+ heatBarA: document.getElementById("heatBarA"),
+ trendBarA: document.getElementById("trendBarA"),
+ hypeBarA: document.getElementById("hypeBarA"),
+ heatValA: document.getElementById("heatValA"),
+ netValA: document.getElementById("netValA"),
+ hypeValA: document.getElementById("hypeValA"),
+ // card B
+ nameB: document.getElementById("nameB"),
+ studioB: document.getElementById("studioB"),
+ regionB: document.getElementById("regionB"),
+ scoreB: document.getElementById("scoreB"),
+ avatarInitB: document.getElementById("avatarInitB"),
+ trendLabelB: document.getElementById("trendLabelB"),
+ buzzB: document.getElementById("buzzB"),
+ wrB: document.getElementById("wrB"),
+ heatBarB: document.getElementById("heatBarB"),
+ trendBarB: document.getElementById("trendBarB"),
+ hypeBarB: document.getElementById("hypeBarB"),
+ heatValB: document.getElementById("heatValB"),
+ netValB: document.getElementById("netValB"),
+ hypeValB: document.getElementById("hypeValB"),
+ leaderboardList: document.getElementById("leaderboardList"),
+ trendStatic: document.getElementById("trendStatic"),
+ trendDynamic: document.getElementById("trendDynamic"),
+ historyTimeline: document.getElementById("historyTimeline")
+ };
+
+ let index = 0;
+ let currentPair = null;
+ let totalRated = 0;
+ let streak = 0;
+ let hotBias = 0;
+ let history = [];
+
+ const stats = new Map();
+ arrivals.forEach((a, i) => {
+ stats.set(i, { wins: 0, battles: 0, arenaScore: 0 });
+ });
+
+ function trendLabel(net) {
+ if (net >= 85) return "net darling";
+ if (net >= 78) return "strong momentum";
+ if (net >= 70) return "steady vs internet";
+ if (net >= 62) return "under‑indexed";
+ return "off‑radar niche";
+ }
+
+ function pickPair() {
+ if (index >= arrivals.length - 1) return null;
+ const aIndex = index;
+ const bIndex = index + 1;
+ index += 2;
+ dom.queueLeft.textContent = Math.max(0, arrivals.length - index);
+ const left = { ...arrivals[aIndex], id: aIndex };
+ const right = { ...arrivals[bIndex], id: bIndex };
+ return { left, right };
+ }
+
+ function setCard(side, data) {
+ const prefix = side === "A" ? "A" : "B";
+ dom["name" + prefix].textContent = data.name;
+ dom["studio" + prefix].textContent = data.studio;
+ dom["region" + prefix].textContent = data.region;
+ dom["score" + prefix].textContent = data.heat;
+ dom["avatarInit" + prefix].textContent = data.studio[0] || "?";
+ dom["trendLabel" + prefix].textContent = trendLabel(data.net);
+ dom["buzz" + prefix].textContent = data.buzz;
+ const st = stats.get(data.id);
+ const wr = st.battles ? Math.round((st.wins / st.battles) * 100) : 0;
+ dom["wr" + prefix].textContent = wr + "%";
+
+ dom["heatBar" + prefix].style.setProperty("--w", data.heat + "%");
+ dom["trendBar" + prefix].style.setProperty("--w", data.net + "%");
+ dom["hypeBar" + prefix].style.setProperty("--w", data.hype + "%");
+ dom["heatVal" + prefix].textContent = data.heat;
+ dom["netVal" + prefix].textContent = data.net;
+ dom["hypeVal" + prefix].textContent = data.hype;
+ }
+
+ function updateTicker() {
+ if (!totalRated) {
+ dom.tickerBar.style.width = "0%";
+ return;
+ }
+ const pctHot = 50 + hotBias;
+ dom.tickerBar.style.width = Math.max(0, Math.min(100, pctHot)) + "%";
+ }
+
+ function updateDynamicTrend() {
+ const rows = [];
+ const rated = Array.from(stats.entries()).filter(([id, st]) => st.battles > 0);
+ if (!rated.length) {
+ dom.trendDynamic.innerHTML = `
+ <div class="trend-row">
+ <div class="trend-name">Awaiting picks…</div>
+ <div class="trend-badge">—</div>
+ <div class="trend-badge">—</div>
+ </div>
+ <div style="margin-top:4px;font-size:9px;color:var(--muted);">
+ As you rate, we’ll show where your arena heat diverges from these priors.
+ </div>`;
+ return;
+ }
+
+ let sumDrift = 0;
+ rated.forEach(([id, st]) => {
+ const b = arrivals[id];
+ sumDrift += st.arenaScore - b.net;
+ });
+ const meanDrift = sumDrift / rated.length;
+ const sign = meanDrift > 0 ? "+" : "";
+ const driftTag = meanDrift > 4 ? "hot‑leaning vs net" :
+ meanDrift < -4 ? "cooler than net" :
+ "close to internet priors";
+
+ rows.push(`
+ <div class="trend-row">
+ <div class="trend-name">Arena vs prior baseline</div>
+ <div class="trend-badge heat">${sign}${meanDrift.toFixed(1)} pts</div>
+ <div class="trend-badge">${driftTag}</div>
+ </div>
+ `);
+
+ const sorted = rated
+ .map(([id, st]) => ({ id, drift: st.arenaScore - arrivals[id].net }))
+ .sort((a, b) => b.drift - a.drift);
+
+ const top = sorted[0];
+ const bottom = sorted[sorted.length - 1];
+
+ if (top) {
+ rows.push(`
+ <div class="trend-row">
+ <div class="trend-name">${arrivals[top.id].name}</div>
+ <div class="trend-badge heat">+${top.drift.toFixed(1)} pts</div>
+ <div class="trend-badge">arena > net</div>
+ </div>
+ `);
+ }
+ if (bottom && bottom.id !== top.id) {
+ rows.push(`
+ <div class="trend-row">
+ <div class="trend-name">${arrivals[bottom.id].name}</div>
+ <div class="trend-badge heat">${bottom.drift.toFixed(1)} pts</div>
+ <div class="trend-badge">arena < net</div>
+ </div>
+ `);
+ }
+
+ dom.trendDynamic.innerHTML = rows.join("");
+ }
+
+ function updateHistory() {
+ const rows = history.slice(-8).map(h => `
+ <div class="history-item">
+ <span class="r">${h.round}</span>
+ <div class="history-name">${h.winner}</div>
+ <div class="history-score">${h.score}</div>
+ <div class="history-tag ${h.choice === "hot" ? "hot" : "not"}">
+ ${h.choice === "hot" ? "hot" : "alt"}
+ </div>
+ </div>
+ `).reverse();
+ dom.historyTimeline.innerHTML = rows.join("");
+ }
+
+ function updateLeaderboard() {
+ const enriched = pronunciations();
+ enriched.sort((a, b) => b.score - a.score);
+ const rows = enriched.map((p, i) => {
+ const rankClass = i === 0 ? "gold" : i === 1 ? "silver" : i === 2 ? "bronze" : "";
+ return `
+ <div class="leader-row">
+ <span class="rank ${rankClass}">${i + 1}</span>
+ <div class="leader-name">${p.name}</div>
+ <div class="leader-score">${p.score}</div>
+ <div class="leader-pulse">${p.web}</div>
+ </div>
+ `;
+ }).join("");
+ dom.leaderboardList.innerHTML = rows;
+ }
+
+ function pronunciations() {
+ // This lets us slightly tilt priors based on the local arena drift
+ let globalDrift = 0;
+ const rated = Array.from(stats.entries()).filter(([id, st]) => st.battles > 0);
+ if (rated.length) {
+ rated.forEach(([id, st]) => {
+ const b = arrivals[id];
+ globalDrift += st.arenaScore - b.net;
+ });
+ globalDrift /= rated.length;
+ }
+ const clampDrift = Math.max(-4, Math.min(4, globalDrift));
+ return priors.map(p => ({
+ ...p,
+ score: Math.round(p.score + clampDrift * 0.5)
+ }));
+ }
+
+ function buildStaticTrend() {
+ const rows = staticTrendPairs.map(p => `
+ <div class="trend-row">
+ <div class="trend-name">${p.arch}</div>
+ <div class="trend-badge">${p.heat}/${p.net}</div>
+ <div class="trend-badge heat">${p.drift}</div>
+ </div>
+ `).join("") + `
+ <div style="margin-top:4px;font-size:9px;color:var(--muted);">
+ These numbers are illustrative only: they approximate how training‑time sources
+ tended to talk about these practices rather than live popularity.
+ </div>
+ `;
+ dom.trendStatic.innerHTML = rows;
+ }
+
+ function loadNextPair() {
+ currentPair = pickPair();
+ if (!currentPair) {
+ dom.btnHot.classList.add("disabled");
+ dom.btnNot.classList.add("disabled");
+ dom.footerHint.textContent = "Fixture complete · press R to shuffle a new bracket.";
+ return;
+ }
+ dom.arena.classList.remove("fade");
+ void dom.arena.offsetWidth;
+ dom.arena.classList.add("fade");
+
+ setCard("A", currentPair.left);
+ setCard("B", currentPair.right);
+ }
+
+ function recordChoice(which) {
+ if (!currentPair) return;
+ const winner = which === "hot" ? currentPair.left : currentPair.right;
+ const loser = which === "hot" ? currentPair.right : currentPair.left;
+
+ const winnerStat = stats.get(winner.id);
+ const loserStat = stats.get(loser.id);
+ winnerStat.wins += 1;
+ winnerStat.battles += 1;
+ loserStat.battles += 1;
+ winnerStat.arenaScore = winnerStat.arenaScore
+ ? (winnerStat.arenaScore * (winnerStat.battles - 1) + winner.heat) / winnerStat.battles
+ : winner.heat;
+ loserStat.arenaScore = loserStat.arenaScore
+ ? (loserStat.arenaScore * (loserStat.battles - 1) + loser.heat) / loserStat.battles
+ : loser.heat;
+
+ totalRated += 1;
+ dom.ratedCount.textContent = totalRated;
+ hotBias += which === "hot" ? 1 : -1;
+ streak = which === "hot" ? streak + 1 : 0;
+ dom.streakLabel.innerHTML = `Arena streak: <strong>${streak}</strong>`;
+
+ dom.vsBadge.classList.remove("flash");
+ void dom.vsBadge.offsetWidth;
+ dom.vsBadge.classList.add("flash");
+
+ history.push({
+ round: totalRated,
+ winner: winner.name,
+ score: winner.heat + " / " + winner.net,
+ choice: which
+ });
+
+ updateTicker();
+ updateDynamicTrend();
+ updateHistory();
+ updateLeaderboard();
+ loadNextPair();
+ }
+
+ dom.btnHot.addEventListener("click", () => recordChoice("hot"));
+ dom.btnNot.addEventListener("click", () => recordChoice("not"));
+
+ document.addEventListener("keydown", (e) => {
+ if (e.repeat) return;
+ if (e.key === "ArrowLeft" || e.key.toLowerCase() === "a") {
+ e.preventDefault();
+ recordChoice("hot");
+ } else if (e.key === "ArrowRight" || e.key.toLowerCase() === "d") {
+ e.preventDefault();
+ recordChoice("not");
+ } else if (e.key === " ") {
+ e.preventDefault();
+ if (!currentPair) return;
+ const auto = Math.random() < 0.5 ? "hot" : "not";
+ recordChoice(auto);
+ } else if (e.key.toLowerCase() === "r") {
+ e.preventDefault();
+ resetFixture();
+ }
+ });
+
+ function resetFixture() {
+ index = 0;
+ currentPair = null;
+ totalRated = 0;
+ streak = 0;
+ hotBias = 0;
+ history = [];
+ stats.forEach((v) => { v.wins = 0; v.battles = 0; v.arenaScore = 0; });
+ dom.ratedCount.textContent = "0";
+ dom.queueLeft.textContent = arrivals.length;
+ dom.streakLabel.innerHTML = "Arena streak: <strong>0</strong>";
+ dom.footerHint.textContent = "New bracket loaded · start rating to bend the heat map.";
+ dom.btnHot.classList.remove("disabled");
+ dom.btnNot.classList.remove("disabled");
+ updateTicker();
+ updateDynamicTrend();
+ updateHistory();
+ updateLeaderboard();
+ loadNextPair();
+ }
+
+ buildStaticTrend();
+ updateLeaderboard();
+ updateDynamicTrend();
+ updateHistory();
+ updateTicker();
+ loadNextPair();
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/f79cffc20d43/gpt.png b/data/artifacts/f79cffc20d43/gpt.png
new file mode 100644
index 0000000..fed4115
Binary files /dev/null and b/data/artifacts/f79cffc20d43/gpt.png differ
diff --git a/data/artifacts/f79cffc20d43/grok.html b/data/artifacts/f79cffc20d43/grok.html
new file mode 100644
index 0000000..9d1e4e8
--- /dev/null
+++ b/data/artifacts/f79cffc20d43/grok.html
@@ -0,0 +1,587 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>HOT or NOT · Architect WC Battles</title>
+<style>
+:root {
+ --bg: #0a0a0c;
+ --surface: #141418;
+ --card: #1c1c22;
+ --border: #2a2a32;
+ --gold: #c9a227;
+ --gold-dim: #8a7020;
+ --hot: #e63946;
+ --not: #457b9d;
+ --text: #f0ece2;
+ --muted: #8a8690;
+ --accent: #e8d5a3;
+}
+* { box-sizing: border-box; margin: 0; padding: 0; }
+html, body { height: 100%; }
+body {
+ font-family: "Segoe UI", system-ui, -apple-system, sans-serif;
+ background: var(--bg);
+ color: var(--text);
+ overflow-x: hidden;
+ line-height: 1.45;
+}
+.grain {
+ position: fixed; inset: 0; pointer-events: none; z-index: 9999; opacity: 0.04;
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' 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 {
+ border-bottom: 1px solid var(--border);
+ padding: 1rem 1.5rem;
+ display: flex; align-items: center; justify-content: space-between; gap: 1rem;
+ background: linear-gradient(180deg, #121214 0%, var(--bg) 100%);
+ position: sticky; top: 0; z-index: 100;
+}
+.logo {
+ font-weight: 700; letter-spacing: 0.12em; font-size: 0.95rem;
+ text-transform: uppercase;
+}
+.logo span { color: var(--gold); }
+.logo em { font-style: normal; color: var(--muted); font-weight: 400; margin-left: 0.5rem; font-size: 0.75rem; letter-spacing: 0.06em; }
+.stats-bar {
+ display: flex; gap: 1.25rem; font-size: 0.75rem; color: var(--muted);
+}
+.stats-bar b { color: var(--accent); font-weight: 600; }
+nav.tabs {
+ display: flex; gap: 0.25rem; background: var(--surface); padding: 0.25rem; border-radius: 999px; border: 1px solid var(--border);
+}
+nav.tabs button {
+ background: transparent; border: none; color: var(--muted); padding: 0.45rem 1rem;
+ border-radius: 999px; cursor: pointer; font-size: 0.78rem; font-weight: 600; letter-spacing: 0.04em;
+ text-transform: uppercase; transition: 0.2s;
+}
+nav.tabs button.active { background: var(--gold); color: #111; }
+nav.tabs button:hover:not(.active) { color: var(--text); }
+main { max-width: 1200px; margin: 0 auto; padding: 1.5rem; }
+.panel { display: none; animation: fadeIn 0.35s ease; }
+.panel.active { display: block; }
+@keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
+.battle-stage {
+ display: grid; grid-template-columns: 1fr auto 1fr; gap: 1rem; align-items: stretch;
+ min-height: 420px;
+}
+@media (max-width: 820px) {
+ .battle-stage { grid-template-columns: 1fr; }
+ .vs-col { order: -1; padding: 0.5rem 0 !important; }
+ header { flex-wrap: wrap; }
+}
+.card {
+ background: var(--card); border: 1px solid var(--border); border-radius: 16px;
+ overflow: hidden; display: flex; flex-direction: column; position: relative;
+ transition: transform 0.25s, box-shadow 0.25s, border-color 0.25s;
+}
+.card:hover { border-color: var(--gold-dim); }
+.card.winner-flash { animation: winPulse 0.6s ease; }
+@keyframes winPulse {
+ 0%,100% { box-shadow: none; }
+ 50% { box-shadow: 0 0 0 2px var(--gold), 0 20px 40px rgba(201,162,39,0.15); }
+}
+.visual {
+ height: 220px; position: relative; overflow: hidden;
+ background: #0e0e12;
+}
+.visual svg { width: 100%; height: 100%; display: block; }
+.badge {
+ position: absolute; top: 12px; left: 12px;
+ background: rgba(0,0,0,0.65); backdrop-filter: blur(6px);
+ border: 1px solid var(--border); color: var(--gold);
+ font-size: 0.65rem; letter-spacing: 0.1em; text-transform: uppercase;
+ padding: 0.3rem 0.55rem; border-radius: 6px; font-weight: 700;
+}
+.card-body { padding: 1.1rem 1.2rem 1.25rem; flex: 1; display: flex; flex-direction: column; gap: 0.5rem; }
+.card-body h2 { font-size: 1.15rem; font-weight: 650; letter-spacing: -0.01em; }
+.card-body .arch { color: var(--gold); font-size: 0.8rem; font-weight: 600; letter-spacing: 0.04em; }
+.card-body p { color: var(--muted); font-size: 0.82rem; flex: 1; }
+.meta-row {
+ display: flex; justify-content: space-between; align-items: center;
+ font-size: 0.72rem; color: var(--muted); margin-top: 0.4rem; padding-top: 0.6rem;
+ border-top: 1px solid var(--border);
+}
+.score-pills { display: flex; gap: 0.4rem; }
+.pill {
+ padding: 0.2rem 0.5rem; border-radius: 999px; font-weight: 700; font-size: 0.68rem;
+ border: 1px solid var(--border);
+}
+.pill.hot { color: var(--hot); border-color: rgba(230,57,70,0.35); background: rgba(230,57,70,0.08); }
+.pill.trend { color: var(--accent); border-color: rgba(232,213,163,0.25); background: rgba(232,213,163,0.06); }
+.vote-row { display: flex; gap: 0.5rem; margin-top: 0.75rem; }
+.vote-row button {
+ flex: 1; border: none; border-radius: 10px; padding: 0.75rem; cursor: pointer;
+ font-weight: 800; letter-spacing: 0.12em; font-size: 0.8rem; text-transform: uppercase;
+ transition: transform 0.15s, filter 0.15s;
+}
+.vote-row button:active { transform: scale(0.97); }
+.btn-hot { background: linear-gradient(135deg, #e63946, #b82d38); color: #fff; }
+.btn-not { background: linear-gradient(135deg, #3d5a73, #2a4055); color: #dce6ef; }
+.btn-hot:hover, .btn-not:hover { filter: brightness(1.1); }
+.vs-col {
+ display: flex; flex-direction: column; align-items: center; justify-content: center;
+ gap: 1rem; padding: 1rem 0.5rem;
+}
+.vs-badge {
+ width: 56px; height: 56px; border-radius: 50%;
+ background: radial-gradient(circle at 30% 30%, #2a2a30, #121214);
+ border: 2px solid var(--gold); color: var(--gold);
+ display: grid; place-items: center; font-weight: 900; font-size: 0.95rem;
+ letter-spacing: 0.05em; box-shadow: 0 0 30px rgba(201,162,39,0.2);
+}
+.skip-btn, .next-pair {
+ background: transparent; border: 1px solid var(--border); color: var(--muted);
+ padding: 0.5rem 0.9rem; border-radius: 8px; cursor: pointer; font-size: 0.72rem;
+ letter-spacing: 0.06em; text-transform: uppercase; font-weight: 600;
+}
+.skip-btn:hover, .next-pair:hover { border-color: var(--gold-dim); color: var(--text); }
+.section-title {
+ font-size: 0.72rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--muted);
+ margin-bottom: 1rem; display: flex; align-items: center; gap: 0.75rem;
+}
+.section-title::after {
+ content: ""; flex: 1; height: 1px; background: var(--border);
+}
+.arrivals-grid {
+ display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 0.85rem;
+}
+.arrival {
+ background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
+ padding: 0.9rem 1rem; display: grid; grid-template-columns: 48px 1fr auto; gap: 0.85rem; align-items: center;
+ cursor: pointer; transition: border-color 0.2s, background 0.2s;
+}
+.arrival:hover { border-color: var(--gold-dim); background: var(--card); }
+.arrival .thumb {
+ width: 48px; height: 48px; border-radius: 8px; overflow: hidden; background: #0e0e12;
+}
+.arrival .thumb svg { width: 100%; height: 100%; }
+.arrival h3 { font-size: 0.88rem; font-weight: 650; }
+.arrival .sub { font-size: 0.72rem; color: var(--muted); }
+.arrival .rank {
+ font-size: 0.7rem; font-weight: 800; color: var(--gold); letter-spacing: 0.05em;
+}
+.trend-layout {
+ display: grid; grid-template-columns: 1.2fr 1fr; gap: 1.25rem;
+}
+@media (max-width: 860px) { .trend-layout { grid-template-columns: 1fr; } }
+.chart-card, .compare-card {
+ background: var(--surface); border: 1px solid var(--border); border-radius: 14px; padding: 1.25rem;
+}
+.chart-card h3, .compare-card h3 {
+ font-size: 0.95rem; margin-bottom: 1rem; font-weight: 650;
+}
+.bar-row {
+ display: grid; grid-template-columns: 110px 1fr 48px; gap: 0.6rem; align-items: center;
+ margin-bottom: 0.55rem; font-size: 0.75rem;
+}
+.bar-row .name { color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
+.bar-track {
+ height: 8px; background: #0e0e12; border-radius: 999px; overflow: hidden; position: relative;
+}
+.bar-fill {
+ height: 100%; border-radius: 999px;
+ background: linear-gradient(90deg, var(--gold-dim), var(--gold));
+ transition: width 0.6s cubic-bezier(.2,.8,.2,1);
+}
+.bar-fill.internet {
+ background: linear-gradient(90deg, #2a4a6a, #5b9fd4);
+}
+.bar-row .val { text-align: right; font-weight: 700; color: var(--accent); font-variant-numeric: tabular-nums; }
+.compare-table { width: 100%; border-collapse: collapse; font-size: 0.8rem; }
+.compare-table th {
+ text-align: left; color: var(--muted); font-weight: 600; font-size: 0.68rem;
+ letter-spacing: 0.08em; text-transform: uppercase; padding: 0.4rem 0.5rem 0.7rem;
+ border-bottom: 1px solid var(--border);
+}
+.compare-table td {
+ padding: 0.65rem 0.5rem; border-bottom: 1px solid rgba(42,42,50,0.7);
+}
+.compare-table tr:last-child td { border-bottom: none; }
+.delta-up { color: #6fcf97; font-weight: 700; }
+.delta-down { color: #eb6b6b; font-weight: 700; }
+.delta-same { color: var(--muted); }
+.legend {
+ display: flex; gap: 1rem; margin-bottom: 1rem; font-size: 0.72rem; color: var(--muted);
+}
+.legend i {
+ display: inline-block; width: 10px; height: 10px; border-radius: 2px; margin-right: 0.35rem; vertical-align: -1px;
+}
+.legend .l-local { background: var(--gold); }
+.legend .l-net { background: #5b9fd4; }
+.toast {
+ position: fixed; bottom: 1.5rem; left: 50%; transform: translateX(-50%) translateY(80px);
+ background: var(--card); border: 1px solid var(--gold-dim); color: var(--text);
+ padding: 0.75rem 1.25rem; border-radius: 999px; font-size: 0.82rem; font-weight: 600;
+ opacity: 0; transition: 0.35s cubic-bezier(.2,.8,.2,1); z-index: 200; pointer-events: none;
+ box-shadow: 0 12px 40px rgba(0,0,0,0.45);
+}
+.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
+.footer-note {
+ margin-top: 2rem; text-align: center; color: var(--muted); font-size: 0.7rem; letter-spacing: 0.04em;
+ padding-bottom: 2rem;
+}
+.kicker {
+ text-align: center; margin-bottom: 1.25rem; color: var(--muted); font-size: 0.85rem;
+}
+.kicker strong { color: var(--accent); }
+</style>
+</head>
+<body>
+<div class="grain"></div>
+<header>
+ <div class="logo">HOT <span>or</span> NOT<em>WC · High-End Architects</em></div>
+ <nav class="tabs">
+ <button class="active" data-tab="battle">Battles</button>
+ <button data-tab="arrivals">Last 20</button>
+ <button data-tab="trending">vs Trending</button>
+ </nav>
+ <div class="stats-bar">
+ <div>Votes <b id="statVotes">0</b></div>
+ <div>Battles <b id="statBattles">0</b></div>
+ <div>Leader <b id="statLeader">—</b></div>
+ </div>
+</header>
+<main>
+ <section id="panel-battle" class="panel active">
+ <p class="kicker">Pick the hotter water-closet concept by starchitects. <strong>Local taste</strong> vs the room.</p>
+ <div class="battle-stage">
+ <article class="card" id="cardA"></article>
+ <div class="vs-col">
+ <div class="vs-badge">VS</div>
+ <button class="skip-btn" id="btnSkip">Skip pair</button>
+ <button class="next-pair" id="btnShuffle" title="New random pair">Shuffle</button>
+ </div>
+ <article class="card" id="cardB"></article>
+ </div>
+ </section>
+ <section id="panel-arrivals" class="panel">
+ <div class="section-title">Last 20 new arrivals · studio drops</div>
+ <div class="arrivals-grid" id="arrivalsGrid"></div>
+ </section>
+ <section id="panel-trending" class="panel">
+ <div class="section-title">Your battles vs simulated internet trending</div>
+ <div class="legend">
+ <span><i class="l-local"></i>Arena hot-score (normalized)</span>
+ <span><i class="l-net"></i>Internet trend index</span>
+ </div>
+ <div class="trend-layout">
+ <div class="chart-card">
+ <h3>Top heat — side by side</h3>
+ <div id="chartBars"></div>
+ </div>
+ <div class="compare-card">
+ <h3>Divergence board</h3>
+ <table class="compare-table">
+ <thead>
+ <tr><th>Project</th><th>Arena</th><th>Web</th><th>Δ</th></tr>
+ </thead>
+ <tbody id="compareBody"></tbody>
+ </table>
+ </div>
+ </div>
+ </section>
+ <p class="footer-note">SELF-CONTAINED ARENA · NO NETWORK · FICTIONAL CONCEPT WCs BY HIGH-END PRACTICES · SCORES PERSIST IN-SESSION</p>
+</main>
+<div class="toast" id="toast"></div>
+<script>
+(function () {
+ const ARCHITECTS = [
+ { id: 1, name: "Nimbus Throne", architect: "Zaha Hadid Architects", city: "Dubai", year: 2025, blurb: "Parametric marble shell WC with gravity-defying cantilever sink spine.", seed: 11, trend: 92 },
+ { id: 2, name: "Silent Prism", architect: "John Pawson", city: "Kyoto", year: 2024, blurb: "Monastic limestone volume; one slit of light, zero visible hardware.", seed: 22, trend: 78 },
+ { id: 3, name: "Copper Veil WC", architect: "Foster + Partners", city: "London", year: 2025, blurb: "Oxidized copper fins filter daylight over a floating basalt island.", seed: 33, trend: 88 },
+ { id: 4, name: "The Folded Void", architect: "SANAA", city: "Tokyo", year: 2024, blurb: "Ultra-thin white membranes dissolve corners; privacy without doors.", seed: 44, trend: 81 },
+ { id: 5, name: "Obsidian Rift", architect: "David Adjaye", city: "Accra", year: 2025, blurb: "Carved volcanic stone chamber with brass water ribbon.", seed: 55, trend: 74 },
+ { id: 6, name: "Glass Orchard", architect: "Renzo Piano Building Workshop", city: "Milan", year: 2024, blurb: "Suspended glass garden WC for a rooftop gallery pavilion.", seed: 66, trend: 69 },
+ { id: 7, name: "Timber Halo", architect: "Kengo Kuma", city: "Oslo", year: 2025, blurb: "Layered cedar lattice rings a cylindrical wet room.", seed: 77, trend: 85 },
+ { id: 8, name: "Brutal Bloom", architect: "Herzog & de Meuron", city: "Basel", year: 2024, blurb: "Board-formed concrete petals open to a sky oculus shower.", seed: 88, trend: 71 },
+ { id: 9, name: "Mirage Suite", architect: "Jean Nouvel", city: "Riyadh", year: 2025, blurb: "Dichroic glass maze; water appears only as reflection.", seed: 99, trend: 90 },
+ { id: 10, name: "Linea Nera", architect: "Tadao Ando", city: "Naoshima", year: 2024, blurb: "Single black concrete plane, a slit window, absolute quiet.", seed: 14, trend: 83 },
+ { id: 11, name: "Aero Cloister", architect: "Bjarke Ingels Group", city: "Copenhagen", year: 2025, blurb: "Modular loop of public WCs with living green roofs.", seed: 25, trend: 87 },
+ { id: 12, name: "Porcelain Cloud", architect: "Sou Fujimoto", city: "Paris", year: 2024, blurb: "Translucent stacked porcelain shells like frozen mist.", seed: 36, trend: 76 },
+ { id: 13, name: "Golden Seam", architect: "Studio Mumbai", city: "Mumbai", year: 2025, blurb: "Hand-chiseled stone with a single inlaid brass water seam.", seed: 47, trend: 72 },
+ { id: 14, name: "Vault 09", architect: "Heatherwick Studio", city: "New York", year: 2024, blurb: "Spun metal vaults create intimate acoustic cocoons.", seed: 58, trend: 84 },
+ { id: 15, name: "Echo Basin", architect: "Peter Zumthor", city: "Graubünden", year: 2025, blurb: "Thick tufa walls; water sound tuned like a chapel.", seed: 69, trend: 79 },
+ { id: 16, name: "Lumen Pod", architect: "Snøhetta", city: "Bergen", year: 2024, blurb: "Off-grid fjord WC glowing with bioluminescent panels.", seed: 71, trend: 80 },
+ { id: 17, name: "Ribbon Sanctum", architect: "MAD Architects", city: "Beijing", year: 2025, blurb: "Continuous white ribbon floor-to-ceiling wet sculpture.", seed: 82, trend: 86 },
+ { id: 18, name: "Charcoal Court", architect: "Aires Mateus", city: "Lisbon", year: 2024, blurb: "Deep charcoal plaster court with a single olive tree drain.", seed: 93, trend: 68 },
+ { id: 19, name: "Aurora Baths", architect: "OMA", city: "Seoul", year: 2025, blurb: "Programmed dichroic ceiling maps aurora over black granite.", seed: 17, trend: 91 },
+ { id: 20, name: "Quiet Circuit", architect: "Caruso St John", city: "Zurich", year: 2024, blurb: "Precise oak joinery circuit; almost invisible plumbing.", seed: 28, trend: 70 }
+ ];
+
+ const state = {
+ votes: Object.fromEntries(ARCHITECTS.map(a => [a.id, { hot: 0, not: 0 }])),
+ totalVotes: 0,
+ battles: 0,
+ pair: [0, 1]
+ };
+
+ function mulberry32(a) {
+ return function () {
+ let t = a += 0x6D2B79F5;
+ t = Math.imul(t ^ t >>> 15, t | 1);
+ t ^= t + Math.imul(t ^ t >>> 7, t | 61);
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
+ };
+ }
+
+ function visualSVG(item, w, h) {
+ const rnd = mulberry32(item.seed * 9973);
+ const hues = [38, 42, 28, 200, 210, 15, 320, 180];
+ const h1 = hues[item.seed % hues.length];
+ const h2 = hues[(item.seed + 3) % hues.length];
+ const shapes = [];
+ const bg = `hsl(${h1},12%,8%)`;
+ shapes.push(`<rect width="${w}" height="${h}" fill="${bg}"/>`);
+ // abstract architectural composition
+ for (let i = 0; i < 7; i++) {
+ const x = rnd() * w * 0.7;
+ const y = rnd() * h * 0.5 + h * 0.15;
+ const ww = 20 + rnd() * 80;
+ const hh = 40 + rnd() * 120;
+ const op = 0.15 + rnd() * 0.45;
+ const col = rnd() > 0.5 ? `hsla(${h1},45%,55%,${op})` : `hsla(${h2},30%,70%,${op})`;
+ if (rnd() > 0.4) {
+ shapes.push(`<rect x="${x}" y="${y}" width="${ww}" height="${hh}" fill="${col}" rx="${rnd()*6}"/>`);
+ } else {
+ shapes.push(`<ellipse cx="${x + ww/2}" cy="${y + hh/2}" rx="${ww/2}" ry="${hh/3}" fill="${col}"/>`);
+ }
+ }
+ // floor plane
+ shapes.push(`<polygon points="0,${h} ${w},${h} ${w},${h*0.72} 0,${h*0.85}" fill="hsla(${h1},20%,12%,0.9)"/>`);
+ // gold accent line
+ const lx = w * (0.2 + rnd() * 0.5);
+ shapes.push(`<rect x="${lx}" y="${h*0.2}" width="2" height="${h*0.55}" fill="#c9a227" opacity="0.75"/>`);
+ // soft glow
+ shapes.push(`<circle cx="${w*0.7}" cy="${h*0.3}" r="${40+rnd()*40}" fill="hsla(${h2},40%,60%,0.12)"/>`);
+ // grid hint
+ for (let g = 0; g < 4; g++) {
+ const gx = rnd() * w;
+ shapes.push(`<line x1="${gx}" y1="0" x2="${gx}" y2="${h}" stroke="rgba(255,255,255,0.03)" stroke-width="1"/>`);
+ }
+ return `<svg viewBox="0 0 ${w} ${h}" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid slice">${shapes.join("")}</svg>`;
+ }
+
+ function hotScore(id) {
+ const v = state.votes[id];
+ const t = v.hot + v.not;
+ if (t === 0) return 50;
+ return Math.round((v.hot / t) * 100);
+ }
+
+ function arenaIndex(id) {
+ // blend win-rate with volume so early votes don't dominate forever
+ const v = state.votes[id];
+ const t = v.hot + v.not;
+ const rate = t === 0 ? 0.5 : v.hot / t;
+ const vol = Math.log10(t + 1) / Math.log10(20);
+ return Math.round((rate * 0.75 + vol * 0.25) * 100);
+ }
+
+ function toast(msg) {
+ const el = document.getElementById("toast");
+ el.textContent = msg;
+ el.classList.add("show");
+ clearTimeout(toast._t);
+ toast._t = setTimeout(() => el.classList.remove("show"), 1600);
+ }
+
+ function renderCard(el, item, side) {
+ const hs = hotScore(item.id);
+ const v = state.votes[item.id];
+ el.innerHTML = `
+ <div class="visual">${visualSVG(item, 400, 220)}
+ <div class="badge">${item.city} · ${item.year}</div>
+ </div>
+ <div class="card-body">
+ <div class="arch">${item.architect}</div>
+ <h2>${item.name}</h2>
+ <p>${item.blurb}</p>
+ <div class="meta-row">
+ <div class="score-pills">
+ <span class="pill hot">HOT ${v.hot}</span>
+ <span class="pill trend">WEB ${item.trend}</span>
+ </div>
+ <span>Arena ${hs}%</span>
+ </div>
+ <div class="vote-row">
+ <button class="btn-hot" data-side="${side}" data-vote="hot">Hot</button>
+ <button class="btn-not" data-side="${side}" data-vote="not">Not</button>
+ </div>
+ </div>`;
+ }
+
+ function randomPair() {
+ let a = Math.floor(Math.random() * ARCHITECTS.length);
+ let b = Math.floor(Math.random() * ARCHITECTS.length);
+ while (b === a) b = Math.floor(Math.random() * ARCHITECTS.length);
+ state.pair = [a, b];
+ }
+
+ function showPair() {
+ const A = ARCHITECTS[state.pair[0]];
+ const B = ARCHITECTS[state.pair[1]];
+ const cardA = document.getElementById("cardA");
+ const cardB = document.getElementById("cardB");
+ cardA.classList.remove("winner-flash");
+ cardB.classList.remove("winner-flash");
+ renderCard(cardA, A, "A");
+ renderCard(cardB, B, "B");
+ }
+
+ function updateStats() {
+ document.getElementById("statVotes").textContent = state.totalVotes;
+ document.getElementById("statBattles").textContent = state.battles;
+ let best = null, bestScore = -1;
+ ARCHITECTS.forEach(a => {
+ const s = arenaIndex(a.id);
+ if (s > bestScore || (s === bestScore && state.votes[a.id].hot > (best ? state.votes[best.id].hot : -1))) {
+ bestScore = s; best = a;
+ }
+ });
+ document.getElementById("statLeader").textContent = best && state.totalVotes ? best.name : "—";
+ }
+
+ function onVote(side, vote) {
+ const idx = side === "A" ? state.pair[0] : state.pair[1];
+ const other = side === "A" ? state.pair[1] : state.pair[0];
+ const item = ARCHITECTS[idx];
+ if (vote === "hot") {
+ state.votes[item.id].hot++;
+ // implicit slight not on opponent in battle framing
+ state.votes[ARCHITECTS[other].id].not += 0; // pure choice, no forced
+ document.getElementById(side === "A" ? "cardA" : "cardB").classList.add("winner-flash");
+ toast(`HOT · ${item.name}`);
+ } else {
+ state.votes[item.id].not++;
+ toast(`Passed · ${item.name}`);
+ }
+ state.totalVotes++;
+ // count a battle when both sides have been interacted enough or every hot on a pair
+ if (vote === "hot") state.battles++;
+ updateStats();
+ setTimeout(() => {
+ randomPair();
+ showPair();
+ // refresh trending if visible
+ if (document.getElementById("panel-trending").classList.contains("active")) renderTrending();
+ }, vote === "hot" ? 450 : 280);
+ }
+
+ document.getElementById("cardA").addEventListener("click", (e) => {
+ const btn = e.target.closest("button[data-vote]");
+ if (!btn) return;
+ onVote(btn.dataset.side, btn.dataset.vote);
+ });
+ document.getElementById("cardB").addEventListener("click", (e) => {
+ const btn = e.target.closest("button[data-vote]");
+ if (!btn) return;
+ onVote(btn.dataset.side, btn.dataset.vote);
+ });
+
+ document.getElementById("btnSkip").addEventListener("click", () => {
+ randomPair(); showPair(); toast("Skipped pair");
+ });
+ document.getElementById("btnShuffle").addEventListener("click", () => {
+ randomPair(); showPair(); toast("New matchup");
+ });
+
+ // tabs
+ document.querySelectorAll("nav.tabs button").forEach(btn => {
+ btn.addEventListener("click", () => {
+ document.querySelectorAll("nav.tabs button").forEach(b => b.classList.remove("active"));
+ document.querySelectorAll(".panel").forEach(p => p.classList.remove("active"));
+ btn.classList.add("active");
+ const id = btn.dataset.tab;
+ document.getElementById("panel-" + id).classList.add("active");
+ if (id === "arrivals") renderArrivals();
+ if (id === "trending") renderTrending();
+ });
+ });
+
+ function renderArrivals() {
+ const grid = document.getElementById("arrivalsGrid");
+ // newest first by year then id
+ const sorted = [...ARCHITECTS].sort((a, b) => b.year - a.year || b.id - a.id);
+ grid.innerHTML = sorted.map((item, i) => `
+ <div class="arrival" data-id="${item.id}">
+ <div class="thumb">${visualSVG(item, 96, 96)}</div>
+ <div>
+ <h3>${item.name}</h3>
+ <div class="sub">${item.architect} · ${item.city}</div>
+ </div>
+ <div class="rank">#${String(i + 1).padStart(2, "0")}</div>
+ </div>
+ `).join("");
+ grid.querySelectorAll(".arrival").forEach(el => {
+ el.addEventListener("click", () => {
+ const id = +el.dataset.id;
+ const idx = ARCHITECTS.findIndex(a => a.id === id);
+ let other = Math.floor(Math.random() * ARCHITECTS.length);
+ while (other === idx) other = Math.floor(Math.random() * ARCHITECTS.length);
+ state.pair = [idx, other];
+ document.querySelectorAll("nav.tabs button").forEach(b => b.classList.remove("active"));
+ document.querySelectorAll(".panel").forEach(p => p.classList.remove("active"));
+ document.querySelector('nav.tabs button[data-tab="battle"]').classList.add("active");
+ document.getElementById("panel-battle").classList.add("active");
+ showPair();
+ toast("Loaded into battle");
+ });
+ });
+ }
+
+ function renderTrending() {
+ const ranked = [...ARCHITECTS].map(a => ({
+ ...a,
+ arena: arenaIndex(a.id),
+ hotpct: hotScore(a.id)
+ })).sort((a, b) => b.arena - a.arena || b.trend - a.trend);
+
+ const maxArena = Math.max(1, ...ranked.map(r => r.arena));
+ const maxTrend = Math.max(1, ...ranked.map(r => r.trend));
+
+ const top = ranked.slice(0, 10);
+ document.getElementById("chartBars").innerHTML = top.map(r => `
+ <div class="bar-row">
+ <div class="name" title="${r.name}">${r.name}</div>
+ <div>
+ <div class="bar-track" style="margin-bottom:3px"><div class="bar-fill" style="width:${(r.arena / maxArena) * 100}%"></div></div>
+ <div class="bar-track"><div class="bar-fill internet" style="width:${(r.trend / maxTrend) * 100}%"></div></div>
+ </div>
+ <div class="val">${r.arena}</div>
+ </div>
+ `).join("");
+
+ // divergence: arena rank vs trend rank
+ const byTrend = [...ARCHITECTS].sort((a, b) => b.trend - a.trend);
+ const trendRank = Object.fromEntries(byTrend.map((a, i) => [a.id, i + 1]));
+ const byArena = [...ranked];
+ const arenaRank = Object.fromEntries(byArena.map((a, i) => [a.id, i + 1]));
+
+ const rows = ranked.slice(0, 12).map(r => {
+ const ar = arenaRank[r.id];
+ const tr = trendRank[r.id];
+ const d = tr - ar; // positive = doing better in arena than web
+ let cls = "delta-same", label = "·";
+ if (d >= 2) { cls = "delta-up"; label = "▲ +" + d; }
+ else if (d <= -2) { cls = "delta-down"; label = "▼ " + d; }
+ else { label = "≈"; }
+ return `<tr>
+ <td>${r.name}<div style="color:var(--muted);font-size:0.68rem">${r.architect}</div></td>
+ <td>${r.arena}</td>
+ <td>${r.trend}</td>
+ <td class="${cls}">${label}</td>
+ </tr>`;
+ }).join("");
+ document.getElementById("compareBody").innerHTML = rows;
+ }
+
+ // init
+ randomPair();
+ showPair();
+ updateStats();
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/f79cffc20d43/grok.png b/data/artifacts/f79cffc20d43/grok.png
new file mode 100644
index 0000000..8ffb154
Binary files /dev/null and b/data/artifacts/f79cffc20d43/grok.png differ
diff --git a/data/artifacts/f79cffc20d43/hermes3-8b.html b/data/artifacts/f79cffc20d43/hermes3-8b.html
new file mode 100644
index 0000000..7c3080e
--- /dev/null
+++ b/data/artifacts/f79cffc20d43/hermes3-8b.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Hot or Not WC Battle</title>
+ <style>
+ body {
+ font-family: Arial, sans-serif;
+ line-height: 1.6;
+ margin: 0;
+ padding: 20px;
+ }
+
+ h1 {
+ text-align: center;
+ }
+
+ .battle-container {
+ display: flex;
+ justify-content: space-around;
+ flex-wrap: wrap;
+ }
+
+ .item {
+ border: 1px solid #ccc;
+ margin-bottom: 10px;
+ padding: 20px;
+ width: 45%;
+ }
+
+ .item img {
+ max-width: 100%;
+ height: auto;
+ }
+
+ .rating {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+
+ button {
+ cursor: pointer;
+ padding: 10px;
+ margin-top: 5px;
+ }
+ </style>
+</head>
+<body>
+ <h1>Hot or Not WC Battle</h1>
+ <div class="battle-container">
+ <!-- Sample data for 20 items -->
+ <div class="item">
+ <img src="https://picsum.photos/300/200" alt="">
+ <div class="rating">
+ <button>Hot</button>
+ <span>Not hot yet!</span>
+ <button>Not</button>
+ </div>
+ </div>
+ <!-- Add more items here -->
+ </div>
+
+ <h2>Internet Trending for High End Architects</h2>
+ <ul>
+ <!-- Sample data for trending topics -->
+ <li>Minimalism is key!</li>
+ <li>Sustainable materials are in.</li>
+ <li>Awkward floor plans are out.</li>
+ </ul>
+
+ <script>
+ // Add functionality if needed
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/f79cffc20d43/hermes3-8b.png b/data/artifacts/f79cffc20d43/hermes3-8b.png
new file mode 100644
index 0000000..2bb638e
Binary files /dev/null and b/data/artifacts/f79cffc20d43/hermes3-8b.png differ
diff --git a/data/artifacts/f79cffc20d43/kimi.html b/data/artifacts/f79cffc20d43/kimi.html
new file mode 100644
index 0000000..efa9bbb
--- /dev/null
+++ b/data/artifacts/f79cffc20d43/kimi.html
@@ -0,0 +1,671 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Hot or Not: WC Battles vs Architecture</title>
+ <style>
+ * {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+ }
+
+ body {
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
+ background: #0a0a0a;
+ color: #fff;
+ overflow-x: hidden;
+ min-height: 100vh;
+ }
+
+ .container {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 20px;
+ }
+
+ header {
+ text-align: center;
+ padding: 20px 0;
+ border-bottom: 1px solid #333;
+ margin-bottom: 30px;
+ }
+
+ h1 {
+ font-size: 2rem;
+ background: linear-gradient(90deg, #00ff88, #00ccff);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ margin-bottom: 10px;
+ }
+
+ .subtitle {
+ color: #888;
+ font-size: 0.9rem;
+ }
+
+ .battle-arena {
+ display: grid;
+ grid-template-columns: 1fr auto 1fr;
+ gap: 20px;
+ align-items: center;
+ min-height: 60vh;
+ position: relative;
+ }
+
+ @media (max-width: 768px) {
+ .battle-arena {
+ grid-template-columns: 1fr;
+ grid-template-rows: 1fr auto 1fr;
+ }
+ }
+
+ .card {
+ background: linear-gradient(135deg, #1a1a1a 0%, #2a2a2a 100%);
+ border-radius: 20px;
+ padding: 40px;
+ text-align: center;
+ position: relative;
+ transition: all 0.3s ease;
+ border: 2px solid transparent;
+ cursor: pointer;
+ box-shadow: 0 10px 40px rgba(0,0,0,0.5);
+ }
+
+ .card:hover {
+ transform: translateY(-5px);
+ box-shadow: 0 20px 60px rgba(0,0,0,0.7);
+ }
+
+ .card.wc {
+ background: linear-gradient(135deg, #0d3328 0%, #1a5c3a 100%);
+ border-color: #00ff88;
+ }
+
+ .card.arch {
+ background: linear-gradient(135deg, #1a1a2e 0%, #2d2d44 100%);
+ border-color: #00ccff;
+ }
+
+ .card.winner {
+ animation: pulse 0.6s ease;
+ border-color: #ffd700;
+ box-shadow: 0 0 60px rgba(255, 215, 0, 0.4);
+ }
+
+ .card.loser {
+ opacity: 0.6;
+ transform: scale(0.95);
+ }
+
+ @keyframes pulse {
+ 0%, 100% { transform: scale(1); }
+ 50% { transform: scale(1.05); }
+ }
+
+ .icon {
+ font-size: 4rem;
+ margin-bottom: 20px;
+ display: block;
+ }
+
+ .category-tag {
+ display: inline-block;
+ padding: 5px 15px;
+ border-radius: 20px;
+ font-size: 0.75rem;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+ margin-bottom: 15px;
+ font-weight: bold;
+ }
+
+ .wc .category-tag {
+ background: rgba(0, 255, 136, 0.2);
+ color: #00ff88;
+ }
+
+ .arch .category-tag {
+ background: rgba(0, 204, 255, 0.2);
+ color: #00ccff;
+ }
+
+ .name {
+ font-size: 1.8rem;
+ font-weight: bold;
+ margin-bottom: 10px;
+ line-height: 1.2;
+ }
+
+ .detail {
+ color: rgba(255,255,255,0.7);
+ font-size: 0.9rem;
+ margin-bottom: 20px;
+ }
+
+ .rating {
+ font-size: 1.2rem;
+ font-weight: bold;
+ color: #ffd700;
+ margin-bottom: 20px;
+ }
+
+ .vote-btn {
+ background: rgba(255,255,255,0.1);
+ border: 2px solid rgba(255,255,255,0.3);
+ color: white;
+ padding: 12px 30px;
+ border-radius: 30px;
+ font-size: 1rem;
+ cursor: pointer;
+ transition: all 0.3s;
+ font-weight: bold;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+ }
+
+ .vote-btn:hover {
+ background: rgba(255,255,255,0.2);
+ border-color: white;
+ transform: scale(1.05);
+ }
+
+ .wc .vote-btn {
+ background: rgba(0, 255, 136, 0.1);
+ border-color: #00ff88;
+ }
+
+ .wc .vote-btn:hover {
+ background: rgba(0, 255, 136, 0.3);
+ box-shadow: 0 0 20px rgba(0, 255, 136, 0.4);
+ }
+
+ .arch .vote-btn {
+ background: rgba(0, 204, 255, 0.1);
+ border-color: #00ccff;
+ }
+
+ .arch .vote-btn:hover {
+ background: rgba(0, 204, 255, 0.3);
+ box-shadow: 0 0 20px rgba(0, 204, 255, 0.4);
+ }
+
+ .vs-divider {
+ font-size: 2rem;
+ font-weight: bold;
+ color: #666;
+ position: relative;
+ z-index: 10;
+ }
+
+ @media (max-width: 768px) {
+ .vs-divider {
+ transform: rotate(90deg);
+ }
+ }
+
+ .stats-bar {
+ display: flex;
+ justify-content: center;
+ gap: 40px;
+ margin-top: 30px;
+ flex-wrap: wrap;
+ }
+
+ .stat-box {
+ text-align: center;
+ background: rgba(255,255,255,0.05);
+ padding: 15px 30px;
+ border-radius: 10px;
+ }
+
+ .stat-number {
+ font-size: 1.5rem;
+ font-weight: bold;
+ color: #ffd700;
+ }
+
+ .stat-label {
+ font-size: 0.8rem;
+ color: #888;
+ text-transform: uppercase;
+ }
+
+ .leaderboard {
+ margin-top: 40px;
+ background: rgba(255,255,255,0.03);
+ border-radius: 20px;
+ padding: 30px;
+ display: none;
+ }
+
+ .leaderboard.active {
+ display: block;
+ animation: slideIn 0.5s ease;
+ }
+
+ @keyframes slideIn {
+ from { opacity: 0; transform: translateY(20px); }
+ to { opacity: 1; transform: translateY(0); }
+ }
+
+ .leaderboard h2 {
+ text-align: center;
+ margin-bottom: 30px;
+ color: #ffd700;
+ }
+
+ .leaderboard-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 30px;
+ }
+
+ @media (max-width: 768px) {
+ .leaderboard-grid {
+ grid-template-columns: 1fr;
+ }
+ }
+
+ .leaderboard-column h3 {
+ margin-bottom: 15px;
+ padding-bottom: 10px;
+ border-bottom: 2px solid;
+ }
+
+ .leaderboard-column.wc-col h3 {
+ color: #00ff88;
+ border-color: #00ff88;
+ }
+
+ .leaderboard-column.arch-col h3 {
+ color: #00ccff;
+ border-color: #00ccff;
+ }
+
+ .leaderboard-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 10px;
+ margin-bottom: 5px;
+ background: rgba(255,255,255,0.05);
+ border-radius: 8px;
+ transition: all 0.2s;
+ }
+
+ .leaderboard-item:hover {
+ background: rgba(255,255,255,0.1);
+ transform: translateX(5px);
+ }
+
+ .rank {
+ font-weight: bold;
+ margin-right: 10px;
+ opacity: 0.5;
+ width: 30px;
+ }
+
+ .item-name {
+ flex: 1;
+ text-align: left;
+ }
+
+ .item-rating {
+ font-weight: bold;
+ color: #ffd700;
+ }
+
+ .toggle-btn {
+ background: transparent;
+ border: 1px solid #666;
+ color: #888;
+ padding: 10px 20px;
+ border-radius: 20px;
+ cursor: pointer;
+ margin: 20px auto;
+ display: block;
+ transition: all 0.3s;
+ }
+
+ .toggle-btn:hover {
+ border-color: #fff;
+ color: #fff;
+ }
+
+ .result-text {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ font-size: 3rem;
+ font-weight: bold;
+ color: #ffd700;
+ text-shadow: 0 0 20px rgba(255, 215, 0, 0.8);
+ pointer-events: none;
+ opacity: 0;
+ z-index: 100;
+ }
+
+ .result-text.show {
+ animation: resultPop 1s ease forwards;
+ }
+
+ @keyframes resultPop {
+ 0% { opacity: 0; transform: translate(-50%, -50%) scale(0.5); }
+ 20% { opacity: 1; transform: translate(-50%, -50%) scale(1.2); }
+ 80% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
+ 100% { opacity: 0; transform: translate(-50%, -50%) scale(1); }
+ }
+
+ .progress-bar {
+ width: 100%;
+ height: 4px;
+ background: #333;
+ position: fixed;
+ top: 0;
+ left: 0;
+ z-index: 1000;
+ }
+
+ .progress-fill {
+ height: 100%;
+ background: linear-gradient(90deg, #00ff88, #00ccff);
+ width: 0%;
+ transition: width 0.3s;
+ }
+ </style>
+</head>
+<body>
+ <div class="progress-bar">
+ <div class="progress-fill" id="progressBar"></div>
+ </div>
+
+ <div class="container">
+ <header>
+ <h1>🔥 Hot or Not: Battle Arena</h1>
+ <div class="subtitle">World Cup New Arrivals vs Trending Architects</div>
+ </header>
+
+ <div class="battle-arena" id="battleArena">
+ <div class="card wc" id="wcCard" onclick="vote('wc')">
+ <span class="icon" id="wcIcon">🏟️</span>
+ <div class="category-tag">World Cup</div>
+ <div class="name" id="wcName">Loading...</div>
+ <div class="detail" id="wcDetail">New Arrival</div>
+ <div class="rating" id="wcRating">1500</div>
+ <button class="vote-btn">🔥 Hotter</button>
+ <div class="result-text" id="wcResult">WINNER!</div>
+ </div>
+
+ <div class="vs-divider">VS</div>
+
+ <div class="card arch" id="archCard" onclick="vote('arch')">
+ <span class="icon" id="archIcon">🏗️</span>
+ <div class="category-tag">Architect</div>
+ <div class="name" id="archName">Loading...</div>
+ <div class="detail" id="archDetail">Trending</div>
+ <div class="rating" id="archRating">1500</div>
+ <button class="vote-btn">🔥 Hotter</button>
+ <div class="result-text" id="archResult">WINNER!</div>
+ </div>
+ </div>
+
+ <div class="stats-bar">
+ <div class="stat-box">
+ <div class="stat-number" id="battleCount">0</div>
+ <div class="stat-label">Battles</div>
+ </div>
+ <div class="stat-box">
+ <div class="stat-number" id="wcWins">0</div>
+ <div class="stat-label">WC Wins</div>
+ </div>
+ <div class="stat-box">
+ <div class="stat-number" id="archWins">0</div>
+ <div class="stat-label">Arch Wins</div>
+ </div>
+ </div>
+
+ <button class="toggle-btn" onclick="toggleLeaderboard()">📊 View Rankings</button>
+
+ <div class="leaderboard" id="leaderboard">
+ <h2>🏆 Current Rankings</h2>
+ <div class="leaderboard-grid">
+ <div class="leaderboard-column wc-col">
+ <h3>⚽ World Cup Teams</h3>
+ <div id="wcLeaderboard"></div>
+ </div>
+ <div class="leaderboard-column arch-col">
+ <h3>🏢 Architects</h3>
+ <div id="archLeaderboard"></div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <script>
+ // Data
+ const wcTeams = [
+ { id: 'qat', name: 'Qatar', year: '2022 Debut', icon: '🇶🇦' },
+ { id: 'isl', name: 'Iceland', year: '2018 Debut', icon: '🇮🇸' },
+ { id: 'pan', name: 'Panama', year: '2018 Debut', icon: '🇵🇦' },
+ { id: 'bih', name: 'Bosnia', year: '2014 Debut', icon: '🇧🇦' },
+ { id: 'svk', name: 'Slovakia', year: '2010 Debut', icon: '🇸🇰' },
+ { id: 'srb', name: 'Serbia', year: '2010 Debut', icon: '🇷🇸' },
+ { id: 'gha', name: 'Ghana', year: '2006 Debut', icon: '🇬🇭' },
+ { id: 'tgo', name: 'Togo', year: '2006 Debut', icon: '🇹🇬' },
+ { id: 'ang', name: 'Angola', year: '2006 Debut', icon: '🇦🇴' },
+ { id: 'ukr', name: 'Ukraine', year: '2006 Debut', icon: '🇺🇦' },
+ { id: 'tri', name: 'Trinidad & Tobago', year: '2006 Debut', icon: '🇹🇹' },
+ { id: 'cze', name: 'Czech Republic', year: '2006 Debut', icon: '🇨🇿' },
+ { id: 'ecu', name: 'Ecuador', year: '2002 Debut', icon: '🇪🇨' },
+ { id: 'chn', name: 'China', year: '2002 Debut', icon: '🇨🇳' },
+ { id: 'svn', name: 'Slovenia', year: '2002 Debut', icon: '🇸🇮' },
+ { id: 'sen', name: 'Senegal', year: '2002 Debut', icon: '🇸🇳' },
+ { id: 'jam', name: 'Jamaica', year: '1998 Debut', icon: '🇯🇲' },
+ { id: 'cro', name: 'Croatia', year: '1998 Debut', icon: '🇭🇷' },
+ { id: 'jpn', name: 'Japan', year: '1998 Debut', icon: '🇯🇵' },
+ { id: 'rsa', name: 'South Africa', year: '1998 Debut', icon: '🇿🇦' }
+ ];
+
+ const architects = [
+ { id: 'big', name: 'Bjarke Ingels', firm: 'BIG', icon: '🏢' },
+ { id: 'sei', name: 'Kazuyo Sejima', firm: 'SANAA', icon: '🏛️' },
+ { id: 'koo', name: 'Rem Koolhaas', firm: 'OMA', icon: '🏗️' },
+ { id: 'zha', name: 'Zaha Hadid', firm: 'ZHA', icon: '🌊' },
+ { id: 'fos', name: 'Norman Foster', firm: 'Foster + Partners', icon: '✈️' },
+ { id: 'geh', name: 'Frank Gehry', firm: 'Gehry Partners', icon: '🎸' },
+ { id: 'nou', name: 'Jean Nouvel', firm: 'Ateliers Jean Nouvel', icon: '🌆' },
+ { id: 'adj', name: 'David Adjaye', firm: 'Adjaye Associates', icon: '🏛️' },
+ { id: 'ban', name: 'Shigeru Ban', firm: 'Shigeru Ban Architects', icon: '📦' },
+ { id: 'fuj', name: 'Sou Fujimoto', firm: 'Sou Fujimoto Architects', icon: '🌿' },
+ { id: 'her', name: 'Herzog & de Meuron', firm: 'HdM', icon: '🏟️' },
+ { id: 'pia', name: 'Renzo Piano', firm: 'RPBW', icon: '🎹' },
+ { id: 'and', name: 'Tadao Ando', firm: 'Tadao Ando Architect', icon: '⛪' },
+ { id: 'lib', name: 'Daniel Libeskind', firm: 'Studio Libeskind', icon: '📐' },
+ { id: 'cal', name: 'Santiago Calatrava', firm: 'Calatrava', icon: '🌉' },
+ { id: 'zum', name: 'Peter Zumthor', firm: 'Zumthor', icon: '🏔️' },
+ { id: 'ito', name: 'Toyo Ito', firm: 'Toyo Ito & Associates', icon: '🌀' },
+ { id: 'kum', name: 'Kengo Kuma', firm: 'Kengo Kuma & Associates', icon: '🎋' },
+ { id: 'hea', name: 'Thomas Heatherwick', firm: 'Heatherwick Studio', icon: '🔮' },
+ { id: 'hol', name: 'Steven Holl', firm: 'Steven Holl Architects', icon: '💡' }
+ ];
+
+ // State
+ let ratings = {};
+ let battles = 0;
+ let wcWins = 0;
+ let archWins = 0;
+ let currentWC = null;
+ let currentArch = null;
+ let isVoting = false;
+
+ // Initialize ratings
+ function init() {
+ wcTeams.forEach(team => {
+ ratings[team.id] = {
+ rating: 1500,
+ wins: 0,
+ losses: 0,
+ name: team.name,
+ type: 'wc'
+ };
+ });
+ architects.forEach(arch => {
+ ratings[arch.id] = {
+ rating: 1500,
+ wins: 0,
+ losses: 0,
+ name: arch.name,
+ type: 'arch'
+ };
+ });
+ pickNewPair();
+ updateStats();
+ }
+
+ // Elo calculation
+ function calculateElo(winner, loser) {
+ const K = 32;
+ const expectedWinner = 1 / (1 + Math.pow(10, (ratings[loser].rating - ratings[winner].rating) / 400));
+ const expectedLoser = 1 / (1 + Math.pow(10, (ratings[winner].rating - ratings[loser].rating) / 400));
+
+ ratings[winner].rating += K * (1 - expectedWinner);
+ ratings[loser].rating += K * (0 - expectedLoser);
+ ratings[winner].wins++;
+ ratings[loser].losses++;
+ }
+
+ // Pick new pair
+ function pickNewPair() {
+ const wcIndex = Math.floor(Math.random() * wcTeams.length);
+ const archIndex = Math.floor(Math.random() * architects.length);
+
+ currentWC = wcTeams[wcIndex];
+ currentArch = architects[archIndex];
+
+ // Reset cards
+ document.getElementById('wcCard').classList.remove('winner', 'loser');
+ document.getElementById('archCard').classList.remove('winner', 'loser');
+ document.getElementById('wcResult').classList.remove('show');
+ document.getElementById('archResult').classList.remove('show');
+
+ // Update display
+ document.getElementById('wcIcon').textContent = currentWC.icon;
+ document.getElementById('wcName').textContent = currentWC.name;
+ document.getElementById('wcDetail').textContent = currentWC.year;
+ document.getElementById('wcRating').textContent = Math.round(ratings[currentWC.id].rating);
+
+ document.getElementById('archIcon').textContent = currentArch.icon;
+ document.getElementById('archName').textContent = currentArch.name;
+ document.getElementById('archDetail').textContent = currentArch.firm;
+ document.getElementById('archRating').textContent = Math.round(ratings[currentArch.id].rating);
+
+ isVoting = true;
+ }
+
+ // Handle vote
+ function vote(winner) {
+ if (!isVoting) return;
+ isVoting = false;
+
+ battles++;
+
+ const wcId = currentWC.id;
+ const archId = currentArch.id;
+
+ if (winner === 'wc') {
+ calculateElo(wcId, archId);
+ wcWins++;
+ document.getElementById('wcCard').classList.add('winner');
+ document.getElementById('archCard').classList.add('loser');
+ document.getElementById('wcResult').classList.add('show');
+ } else {
+ calculateElo(archId, wcId);
+ archWins++;
+ document.getElementById('archCard').classList.add('winner');
+ document.getElementById('wcCard').classList.add('loser');
+ document.getElementById('archResult').classList.add('show');
+ }
+
+ // Update displayed ratings
+ document.getElementById('wcRating').textContent = Math.round(ratings[wcId].rating);
+ document.getElementById('archRating').textContent = Math.round(ratings[archId].rating);
+
+ updateStats();
+ updateProgress();
+
+ // Auto advance after delay
+ setTimeout(() => {
+ pickNewPair();
+ }, 1500);
+ }
+
+ function updateStats() {
+ document.getElementById('battleCount').textContent = battles;
+ document.getElementById('wcWins').textContent = wcWins;
+ document.getElementById('archWins').textContent = archWins;
+ }
+
+ function updateProgress() {
+ const maxBattles = 100; // Arbitrary target for visual
+ const progress = Math.min((battles / maxBattles) * 100, 100);
+ document.getElementById('progressBar').style.width = progress + '%';
+ }
+
+ function toggleLeaderboard() {
+ const lb = document.getElementById('leaderboard');
+ lb.classList.toggle('active');
+
+ if (lb.classList.contains('active')) {
+ renderLeaderboard();
+ }
+ }
+
+ function renderLeaderboard() {
+ // Sort WC teams
+ const wcSorted = wcTeams.map(t => ({
+ ...t,
+ ...ratings[t.id]
+ })).sort((a, b) => b.rating - a.rating);
+
+ // Sort architects
+ const archSorted = architects.map(a => ({
+ ...a,
+ ...ratings[a.id]
+ })).sort((a, b) => b.rating - a.rating);
+
+ // Render WC
+ const wcHtml = wcSorted.map((item, idx) => `
+ <div class="leaderboard-item">
+ <span class="rank">${idx + 1}</span>
+ <span class="item-name">${item.icon} ${item.name}</span>
+ <span class="item-rating">${Math.round(item.rating)}</span>
+ </div>
+ `).join('');
+
+ // Render Architects
+ const archHtml = archSorted.map((item, idx) => `
+ <div class="leaderboard-item">
+ <span class="rank">${idx + 1}</span>
+ <span class="item-name">${item.icon} ${item.name}</span>
+ <span class="item-rating">${Math.round(item.rating)}</span>
+ </div>
+ `).join('');
+
+ document.getElementById('wcLeaderboard').innerHTML = wcHtml;
+ document.getElementById('archLeaderboard').innerHTML = archHtml;
+ }
+
+ // Keyboard shortcuts
+ document.addEventListener('keydown', (e) => {
+ if (e.key === 'ArrowLeft') vote('wc');
+ if (e.key === 'ArrowRight') vote('arch');
+ });
+
+ // Start
+ init();
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/f79cffc20d43/kimi.png b/data/artifacts/f79cffc20d43/kimi.png
new file mode 100644
index 0000000..e75c43e
Binary files /dev/null and b/data/artifacts/f79cffc20d43/kimi.png differ
diff --git a/data/artifacts/f79cffc20d43/qwen25-7b.html b/data/artifacts/f79cffc20d43/qwen25-7b.html
new file mode 100644
index 0000000..c554a4c
--- /dev/null
+++ b/data/artifacts/f79cffc20d43/qwen25-7b.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Hot or Not WC Battles</title>
+ <style>
+ body {
+ font-family: Arial, sans-serif;
+ text-align: center;
+ background-color: #f4f4f9;
+ }
+ .container {
+ margin-top: 50px;
+ }
+ .card {
+ border: 1px solid #ddd;
+ padding: 20px;
+ width: 300px;
+ margin-bottom: 20px;
+ background-color: white;
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
+ }
+ .card img {
+ max-width: 100%;
+ height: auto;
+ }
+ .result {
+ margin-top: 20px;
+ font-size: 1.2em;
+ }
+ </style>
+</head>
+<body>
+ <div class="container">
+ <h1>Hot or Not WC Battles</h1>
+ <p>Compare with last 20 new arrivals and internet trending for high-end architects.</p>
+
+ <div id="card-container" class="cards">
+ <!-- Card examples -->
+ <div class="card">
+ <img src="https://via.placeholder.com/300x200?text=Model+A" alt="Model A">
+ <div class="result">Vote: Not Hot</div>
+ </div>
+
+ <div class="card">
+ <img src="https://via.placeholder.com/300x200?text=Model+B" alt="Model B">
+ <div class="result">Vote: Hot</div>
+ </div>
+
+ <!-- Add more cards as needed -->
+ </div>
+ </div>
+
+ <script>
+ document.addEventListener('DOMContentLoaded', () => {
+ const cards = document.querySelectorAll('.card');
+ let hotCount = 0;
+ let notHotCount = 0;
+
+ cards.forEach(card => {
+ card.addEventListener('click', (event) => {
+ if (event.target.classList.contains('result')) {
+ event.target.textContent = 'Vote: Hot';
+ hotCount++;
+ } else {
+ event.target.textContent = 'Vote: Not Hot';
+ notHotCount++;
+ }
+ });
+ });
+
+ const resultDiv = document.createElement('div');
+ resultDiv.id = 'results';
+ resultDiv.innerHTML = `<p>Total Votes: ${hotCount} Hot, ${notHotCount} Not Hot</p>`;
+ cards[0].parentNode.insertBefore(resultDiv, cards[1]);
+ });
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/f79cffc20d43/qwen25-7b.png b/data/artifacts/f79cffc20d43/qwen25-7b.png
new file mode 100644
index 0000000..d71a947
Binary files /dev/null and b/data/artifacts/f79cffc20d43/qwen25-7b.png differ
diff --git a/data/artifacts/f79cffc20d43/qwen3-14b.html b/data/artifacts/f79cffc20d43/qwen3-14b.html
new file mode 100644
index 0000000..97244bc
--- /dev/null
+++ b/data/artifacts/f79cffc20d43/qwen3-14b.html
@@ -0,0 +1,186 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>Hot or Not WC Battles</title>
+ <style>
+ body {
+ margin: 0;
+ font-family: Arial, sans-serif;
+ background: #f4f4f4;
+ color: #333;
+ }
+ header {
+ background: #2c3e50;
+ color: #fff;
+ padding: 20px;
+ text-align: center;
+ }
+ .container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 20px;
+ }
+ .comparison {
+ display: flex;
+ justify-content: space-around;
+ width: 100%;
+ max-width: 800px;
+ margin-bottom: 20px;
+ }
+ .card {
+ background: #fff;
+ border-radius: 8px;
+ box-shadow: 0 2px 5px rgba(0,0,0,0.1);
+ width: 45%;
+ padding: 20px;
+ text-align: center;
+ transition: transform 0.2s;
+ }
+ .card:hover {
+ transform: scale(1.02);
+ }
+ .card img {
+ width: 100%;
+ border-radius: 50%;
+ margin-bottom: 15px;
+ }
+ .card h3 {
+ margin: 10px 0 5px;
+ font-size: 1.2em;
+ }
+ .stats {
+ font-size: 0.9em;
+ color: #555;
+ }
+ .buttons {
+ margin-top: 20px;
+ }
+ .buttons button {
+ padding: 10px 20px;
+ margin: 0 10px;
+ font-size: 1em;
+ border: none;
+ border-radius: 5px;
+ cursor: pointer;
+ }
+ .buttons .hot {
+ background: #e74c3c;
+ color: #fff;
+ }
+ .buttons .not {
+ background: #3498db;
+ color: #fff;
+ }
+ .results {
+ margin-top: 30px;
+ font-size: 1.2em;
+ text-align: center;
+ }
+ footer {
+ margin-top: 40px;
+ font-size: 0.9em;
+ color: #777;
+ text-align: center;
+ }
+ </style>
+</head>
+<body>
+ <header>
+ <h1>Hot or Not WC Battles</h1>
+ <p>Compare High-End Architectural Arrivals vs. Internet Trends</p>
+ </header>
+ <div class="container">
+ <div class="comparison" id="comparison">
+ <div class="card" id="card1">
+ <div class="image-placeholder" style="background: #3498db; color: #fff; padding: 50px 0; border-radius: 50%;"></div>
+ <h3 id="name1">Loading...</h3>
+ <div class="stats">
+ <p>Sustainability: <span id="sustain1">--</span></p>
+ <p>Innovation: <span id="innov1">--</span></p>
+ <p>Aesthetics: <span id="aesthetics1">--</span></p>
+ </div>
+ </div>
+ <div class="card" id="card2">
+ <div class="image-placeholder" style="background: #e74c3c; color: #fff; padding: 50px 0; border-radius: 50%;"></div>
+ <h3 id="name2">Loading...</h3>
+ <div class="stats">
+ <p>Sustainability: <span id="sustain2">--</span></p>
+ <p>Innovation: <span id="innov2">--</span></p>
+ <p>Aesthetics: <span id="aesthetics2">--</span></p>
+ </div>
+ </div>
+ </div>
+ <div class="buttons">
+ <button class="hot" onclick="vote('hot')">Hot</button>
+ <button class="not" onclick="vote('not')">Not</button>
+ </div>
+ <div class="results" id="results">Ready to vote?</div>
+ </div>
+ <footer>
+ <p>Mock data for demonstration. No network requests used.</p>
+ </footer>
+ <script>
+ const newArchitects = [
+ { name: "Skyline Tower", sustain: 85, innov: 92, aesthetics: 88 },
+ { name: "Oceanic Haven", sustain: 90, innov: 88, aesthetics: 95 },
+ { name: "EcoPulse", sustain: 95, innov: 80, aesthetics: 89 },
+ { name: "Glass Horizon", sustain: 82, innov: 95, aesthetics: 90 },
+ { name: "Cloud9 Residences", sustain: 88, innov: 87, aesthetics: 93 },
+ { name: "GreenSpire", sustain: 93, innov: 89, aesthetics: 86 },
+ { name: "Neon Nexus", sustain: 78, innov: 98, aesthetics: 91 },
+ { name: "Aero Dome", sustain: 84, innov: 94, aesthetics: 87 },
+ { name: "Canyon View", sustain: 89, innov: 85, aesthetics: 92 },
+ { name: "Solaria Complex", sustain: 91, innov: 83, aesthetics: 94 },
+ { name: "SkyBridge 2000", sustain: 87, innov: 90, aesthetics: 91 },
+ { name: "Marble Heights", sustain: 80, innov: 93, aesthetics: 96 },
+ { name: "Urban Pod", sustain: 86, innov: 88, aesthetics: 89 },
+ { name: "Fusion Tower", sustain: 92, innov: 86, aesthetics: 95 },
+ { name: "Nebula House", sustain: 83, innov: 97, aesthetics: 88 },
+ { name: "Eclipse Plaza", sustain: 89, innov: 84, aesthetics: 93 },
+ { name: "Luna Residence", sustain: 94, innov: 81, aesthetics: 92 },
+ { name: "Vortex Tower", sustain: 85, innov: 96, aesthetics: 87 },
+ { name: "Zenith Heights", sustain: 88, innov: 91, aesthetics: 94 },
+ { name: "TerraHaven", sustain: 93, innov: 82, aesthetics: 90 }
+ ];
+
+ const trendingArchitects = [
+ { name: "Pixel Peak", sustain: 91, innov: 95, aesthetics: 96 },
+ { name: "Aurora Spire", sustain: 89, innov: 94, aesthetics: 97 },
+ { name: "Quantum Nexus", sustain: 92, innov: 96, aesthetics: 95 },
+ { name: "Nova Dome", sustain: 90, innov: 93, aesthetics: 98 },
+ { name: "Eclipse Tower", sustain: 93, innov: 92, aesthetics: 94 }
+ ];
+
+ let currentPair = [null, null];
+ let votes = { hot: 0, not: 0 };
+
+ function getRandomEntry(arr) {
+ return arr[Math.floor(Math.random() * arr.length)];
+ }
+
+ function displayComparison() {
+ currentPair[0] = getRandomEntry(newArchitects);
+ currentPair[1] = getRandomEntry(trendingArchitects);
+ document.getElementById("name1").textContent = currentPair[0].name;
+ document.getElementById("sustain1").textContent = currentPair[0].sustain;
+ document.getElementById("innov1").textContent = currentPair[0].innov;
+ document.getElementById("aesthetics1").textContent = currentPair[0].aesthetics;
+ document.getElementById("name2").textContent = currentPair[1].name;
+ document.getElementById("sustain2").textContent = currentPair[1].sustain;
+ document.getElementById("innov2").textContent = currentPair[1].innov;
+ document.getElementById("aesthetics2").textContent = currentPair[1].aesthetics;
+ document.getElementById("results").textContent = "Ready to vote?";
+ }
+
+ function vote(choice) {
+ votes[choice]++;
+ document.getElementById("results").textContent = `You voted "${choice.toUpperCase()}"!`;
+ setTimeout(displayComparison, 1500);
+ }
+
+ displayComparison();
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/f79cffc20d43/qwen3-14b.png b/data/artifacts/f79cffc20d43/qwen3-14b.png
new file mode 100644
index 0000000..fb65bc9
Binary files /dev/null and b/data/artifacts/f79cffc20d43/qwen3-14b.png differ
diff --git a/data/challenges.json b/data/challenges.json
index fcf3d35..82b9bf6 100644
--- a/data/challenges.json
+++ b/data/challenges.json
@@ -105,13 +105,22 @@
"runs": [
{
"model": "qwen3-14b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": 0,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-23T14:14:17.673Z"
+ "seconds": 40,
+ "cost": 0,
+ "started_at": "2026-07-23T14:21:32.644Z",
+ "finished_at": "2026-07-23T14:22:12.263Z",
+ "queued_at": "2026-07-23T14:14:17.673Z",
+ "bytes": 5464,
+ "thumb": true,
+ "aiScore": 3.8,
+ "aiReason": "The image shows a 'GAME OVER' message but lacks the interactive elements and visual style of an actual playable HTML game like Tron.",
+ "aiScores": {
+ "qwen2.5vl:7b": 4,
+ "minicpm-v:latest": 3.5
+ },
+ "aiSpread": 0.5
},
{
"model": "gemma3-12b",
@@ -132,7 +141,14 @@
"started_at": "2026-07-23T05:32:19.764Z",
"bytes": 12191,
"finished_at": "2026-07-23T05:32:56.077Z",
- "thumb": true
+ "thumb": true,
+ "aiScore": 2.5,
+ "aiReason": "The image is blank and does not display any game content or visual elements.",
+ "aiScores": {
+ "qwen2.5vl:7b": 2,
+ "minicpm-v:latest": 3
+ },
+ "aiSpread": 1
},
{
"model": "qwen25-7b",
@@ -144,7 +160,14 @@
"resumes": 1,
"finished_at": "2026-07-23T14:05:39.250Z",
"bytes": 1282,
- "thumb": true
+ "thumb": true,
+ "aiScore": 3,
+ "aiReason": "The image is nearly black and there's only one small green pixel visible.",
+ "aiScores": {
+ "qwen2.5vl:7b": 2,
+ "minicpm-v:latest": 4
+ },
+ "aiSpread": 2
},
{
"model": "claude",
@@ -164,7 +187,14 @@
"started_at": "2026-07-23T05:29:23.128Z",
"bytes": 4559,
"finished_at": "2026-07-23T05:32:28.001Z",
- "thumb": true
+ "thumb": true,
+ "aiScore": 6.8,
+ "aiReason": "The game is functional and visually reminiscent of Tron, but lacks the complexity or polish expected in a polished HTML build-off.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 6.5
+ },
+ "aiSpread": 0.5
},
{
"model": "gpt",
@@ -175,7 +205,14 @@
"started_at": "2026-07-23T14:12:58.855Z",
"finished_at": "2026-07-23T14:13:27.235Z",
"bytes": 7809,
- "thumb": true
+ "thumb": true,
+ "aiScore": 6.3,
+ "aiReason": "The game is functional and visually appealing for the challenge.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 5.5
+ },
+ "aiSpread": 1.5
},
{
"model": "grok",
@@ -186,13 +223,21 @@
"started_at": "2026-07-23T05:29:23.131Z",
"bytes": 7691,
"finished_at": "2026-07-23T05:29:58.821Z",
- "thumb": true
+ "thumb": true,
+ "aiScore": 6.8,
+ "aiReason": "The game is simple and visually appealing but lacks the complexity of a full Tron experience.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 6.5
+ },
+ "aiSpread": 0.5
}
],
"voted_at": "2026-07-23T05:51:21.751Z",
"category": "Games",
- "aiPick": null,
- "judging": false
+ "aiPick": "kimi",
+ "judging": false,
+ "judged_at": "2026-07-23T14:29:55.355Z"
},
{
"id": "74df3b61e7ca",
@@ -203,13 +248,22 @@
"runs": [
{
"model": "qwen3-14b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": 0,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-23T14:14:17.689Z"
+ "seconds": 77,
+ "cost": 0,
+ "started_at": "2026-07-23T14:22:12.266Z",
+ "finished_at": "2026-07-23T14:23:28.920Z",
+ "queued_at": "2026-07-23T14:14:17.689Z",
+ "bytes": 3316,
+ "thumb": true,
+ "aiScore": 7.3,
+ "aiReason": "The visualizer has the retro sun and animated grid elements but lacks the play/stop controls.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 7.5
+ },
+ "aiSpread": 0.5
},
{
"model": "gemma3-12b",
@@ -221,13 +275,13 @@
"finished_at": "2026-07-23T05:42:37.973Z",
"bytes": 3678,
"thumb": true,
- "aiScore": 6.5,
- "aiReason": "The visualizer has the correct elements but lacks smooth animation and a more dynamic sun pulsation.",
+ "aiScore": 7,
+ "aiReason": "The visualizer has the retro sun and grid elements but lacks the pulsing effect to music.",
"aiScores": {
"qwen2.5vl:7b": 7,
- "minicpm-v:latest": 6
+ "minicpm-v:latest": 7
},
- "aiSpread": 1
+ "aiSpread": 0
},
{
"model": "hermes3-8b",
@@ -249,7 +303,14 @@
"finished_at": "2026-07-23T14:14:31.637Z",
"bytes": 2184,
"thumb": true,
- "queued_at": "2026-07-23T14:14:17.704Z"
+ "queued_at": "2026-07-23T14:14:17.704Z",
+ "aiScore": 7,
+ "aiReason": "The visualizer has a retro aesthetic and basic functionality but lacks the complexity of an animated perspective grid.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 7
+ },
+ "aiSpread": 0
},
{
"model": "claude",
@@ -271,7 +332,7 @@
"bytes": 7415,
"thumb": true,
"aiScore": 9,
- "aiReason": "The visualizer effectively fulfills the challenge by using WebAudio oscillators and features a retro sun over an animated perspective grid that pulses to generated music with play/stop controls.",
+ "aiReason": "The visualizer effectively fulfills the challenge by creating a retro sun over an animated perspective grid that pulses to generated music and includes play/stop controls.",
"aiScores": {
"qwen2.5vl:7b": 9,
"minicpm-v:latest": 9
@@ -289,7 +350,7 @@
"bytes": 16071,
"thumb": true,
"aiScore": 9,
- "aiReason": "The visualizer effectively fulfills the challenge by creating a retro sun over an animated perspective grid that pulses to generated music and includes play/stop controls.",
+ "aiReason": "The visualizer effectively fulfills the challenge by using WebAudio oscillators and creating a retro sun over an animated perspective grid that pulses to generated music with play/stop controls.",
"aiScores": {
"qwen2.5vl:7b": 9,
"minicpm-v:latest": 9
@@ -307,7 +368,7 @@
"finished_at": "2026-07-23T05:37:35.718Z",
"thumb": true,
"aiScore": 9.3,
- "aiReason": "The visualizer effectively fulfills the challenge by using WebAudio oscillators and a retro synthwave aesthetic. The sun pulses to music and there are play/stop controls.",
+ "aiReason": "The visualizer effectively fulfills the challenge by using WebAudio oscillators to create a retro sun over an animated perspective grid that pulses in sync with generated music. The play/stop controls",
"aiScores": {
"qwen2.5vl:7b": 9,
"minicpm-v:latest": 9.5
@@ -318,7 +379,8 @@
"voted_at": "2026-07-23T05:51:45.195Z",
"category": "Games",
"judging": false,
- "judged_at": null
+ "judged_at": "2026-07-23T14:29:55.356Z",
+ "aiPick": "grok"
},
{
"id": "93946ee6d736",
@@ -432,7 +494,14 @@
"started_at": "2026-07-23T06:27:20.329Z",
"finished_at": "2026-07-23T06:28:35.081Z",
"bytes": 5679,
- "thumb": true
+ "thumb": true,
+ "aiScore": 5.3,
+ "aiReason": "The document provides a clear executive summary and timeline of key developments in quantum computing. However, it lacks detailed comparisons and citations for each company's advancements.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 3.5
+ },
+ "aiSpread": 3.5
},
{
"model": "gemma3-12b",
@@ -444,17 +513,33 @@
"finished_at": "2026-07-23T14:06:56.639Z",
"resumes": 1,
"bytes": 12938,
- "thumb": true
+ "thumb": true,
+ "aiScore": 6.8,
+ "aiReason": "The document provides the required information but lacks a comparison table and ranking criteria, which are essential for evaluating AI models effectively.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 6.5
+ },
+ "aiSpread": 0.5
},
{
"model": "hermes3-8b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": 0,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-23T14:14:17.719Z"
+ "seconds": 10,
+ "cost": 0,
+ "started_at": "2026-07-23T14:23:28.921Z",
+ "finished_at": "2026-07-23T14:23:38.932Z",
+ "queued_at": "2026-07-23T14:14:17.719Z",
+ "bytes": 3135,
+ "thumb": true,
+ "aiScore": 6.8,
+ "aiReason": "The image provides a comparison of AI coding assistants but lacks the detailed research and analysis required for the benchmark exercise.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 6.5
+ },
+ "aiSpread": 0.5
},
{
"model": "qwen25-7b",
@@ -465,7 +550,14 @@
"started_at": "2026-07-23T06:24:33.565Z",
"finished_at": "2026-07-23T06:24:53.433Z",
"bytes": 2810,
- "thumb": true
+ "thumb": true,
+ "aiScore": 7.3,
+ "aiReason": "The document provides the required information but lacks citations and a detailed executive summary.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 7.5
+ },
+ "aiSpread": 0.5
},
{
"model": "claude",
@@ -486,7 +578,14 @@
"finished_at": "2026-07-23T14:09:14.206Z",
"resumes": 1,
"bytes": 45186,
- "thumb": true
+ "thumb": true,
+ "aiScore": 5.8,
+ "aiReason": "The screenshot shows a basic interface for benchmarking AI models in coding assistants but lacks detailed content and visual polish.",
+ "aiScores": {
+ "qwen2.5vl:7b": 5,
+ "minicpm-v:latest": 6.5
+ },
+ "aiSpread": 1.5
},
{
"model": "gpt",
@@ -497,7 +596,14 @@
"started_at": "2026-07-23T06:25:19.992Z",
"finished_at": "2026-07-23T06:26:04.183Z",
"bytes": 18310,
- "thumb": true
+ "thumb": true,
+ "aiScore": 6.8,
+ "aiReason": "The prompt is clear and comprehensive but lacks specific instructions for formatting or visual quality assessment.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 6.5
+ },
+ "aiSpread": 0.5
},
{
"model": "grok",
@@ -509,12 +615,20 @@
"finished_at": "2026-07-23T14:07:50.412Z",
"resumes": 1,
"bytes": 31207,
- "thumb": true
+ "thumb": true,
+ "aiScore": 6.8,
+ "aiReason": "The report provides a comprehensive overview of the AI coding assistant market but lacks visual appeal and is not formatted as markdown.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 6.5
+ },
+ "aiSpread": 0.5
}
],
"category": "Real Work",
- "aiPick": null,
- "judging": false
+ "aiPick": "qwen25-7b",
+ "judging": false,
+ "judged_at": "2026-07-23T14:30:02.643Z"
},
{
"id": "35303b0ef3b8",
@@ -525,23 +639,41 @@
"runs": [
{
"model": "qwen3-14b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": 0,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-23T14:14:17.733Z"
+ "seconds": 11,
+ "cost": 0,
+ "started_at": "2026-07-23T14:23:38.933Z",
+ "finished_at": "2026-07-23T14:23:50.128Z",
+ "queued_at": "2026-07-23T14:14:17.733Z",
+ "bytes": 234,
+ "thumb": true,
+ "aiScore": 5.5,
+ "aiReason": "The image is blank and does not contain any color information.",
+ "aiScores": {
+ "qwen2.5vl:7b": 5,
+ "minicpm-v:latest": 6
+ },
+ "aiSpread": 1
},
{
"model": "gemma3-12b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": 0,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-23T14:14:17.748Z"
+ "seconds": 6,
+ "cost": 0,
+ "started_at": "2026-07-23T14:23:50.129Z",
+ "finished_at": "2026-07-23T14:23:55.985Z",
+ "queued_at": "2026-07-23T14:14:17.748Z",
+ "bytes": 173,
+ "thumb": true,
+ "aiScore": 7.5,
+ "aiReason": "The image correctly responds to the challenge and is visually clear.",
+ "aiScores": {
+ "qwen2.5vl:7b": 10,
+ "minicpm-v:latest": 5
+ },
+ "aiSpread": 5
},
{
"model": "hermes3-8b",
@@ -564,7 +696,14 @@
"started_at": "2026-07-23T14:05:39.251Z",
"finished_at": "2026-07-23T14:05:40.370Z",
"bytes": 105,
- "thumb": true
+ "thumb": true,
+ "aiScore": 2.5,
+ "aiReason": "The image is blank and does not contain any color or text.",
+ "aiScores": {
+ "qwen2.5vl:7b": 0,
+ "minicpm-v:latest": 5
+ },
+ "aiSpread": 5
},
{
"model": "claude",
@@ -572,7 +711,7 @@
"error": "server restarted mid-run",
"seconds": 0,
"cost": null,
- "resumes": 2
+ "resumes": 3
},
{
"model": "kimi",
@@ -584,7 +723,14 @@
"started_at": "2026-07-23T14:09:14.209Z",
"finished_at": "2026-07-23T14:09:33.862Z",
"bytes": 533,
- "thumb": true
+ "thumb": true,
+ "aiScore": 7.5,
+ "aiReason": "The color is cerulean.",
+ "aiScores": {
+ "qwen2.5vl:7b": 9,
+ "minicpm-v:latest": 6
+ },
+ "aiSpread": 3
},
{
"model": "gpt",
@@ -596,7 +742,14 @@
"started_at": "2026-07-23T14:05:31.091Z",
"finished_at": "2026-07-23T14:05:34.130Z",
"bytes": 298,
- "thumb": true
+ "thumb": true,
+ "aiScore": 8,
+ "aiReason": "The image correctly responds to the challenge and is visually clean.",
+ "aiScores": {
+ "qwen2.5vl:7b": 9,
+ "minicpm-v:latest": 7
+ },
+ "aiSpread": 2
},
{
"model": "grok",
@@ -608,7 +761,14 @@
"started_at": "2026-07-23T14:07:50.414Z",
"finished_at": "2026-07-23T14:07:58.725Z",
"bytes": 301,
- "thumb": true
+ "thumb": true,
+ "aiScore": 9.5,
+ "aiReason": "The color is blue.",
+ "aiScores": {
+ "qwen2.5vl:7b": 10,
+ "minicpm-v:latest": 9
+ },
+ "aiSpread": 1
}
],
"category": "Custom",
@@ -730,7 +890,7 @@
"error": "server restarted mid-run",
"seconds": 0,
"cost": null,
- "resumes": 2
+ "resumes": 3
},
{
"model": "kimi",
@@ -992,13 +1152,15 @@
"runs": [
{
"model": "qwen3-14b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": 0,
- "cost": null,
- "started_at": null,
- "finished_at": null,
- "queued_at": "2026-07-23T14:14:17.764Z"
+ "seconds": 134,
+ "cost": 0,
+ "started_at": "2026-07-23T14:23:55.988Z",
+ "finished_at": "2026-07-23T14:26:09.957Z",
+ "queued_at": "2026-07-23T14:14:17.764Z",
+ "bytes": 1941,
+ "thumb": true
},
{
"model": "gemma3-12b",
@@ -1703,7 +1865,14 @@
"started_at": "2026-07-23T13:47:44.578Z",
"finished_at": "2026-07-23T13:50:01.322Z",
"bytes": 2597,
- "thumb": true
+ "thumb": true,
+ "aiScore": 5.3,
+ "aiReason": "The canvas is empty and there are no particles or text visible.",
+ "aiScores": {
+ "qwen2.5vl:7b": 4,
+ "minicpm-v:latest": 6.5
+ },
+ "aiSpread": 2.5
},
{
"model": "gemma3-12b",
@@ -1714,7 +1883,14 @@
"started_at": "2026-07-23T13:53:49.227Z",
"finished_at": "2026-07-23T13:54:23.651Z",
"bytes": 4019,
- "thumb": true
+ "thumb": true,
+ "aiScore": 7.3,
+ "aiReason": "The particle system is visible and functional but lacks the smoothness expected for a 60fps output.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 7.5
+ },
+ "aiSpread": 0.5
},
{
"model": "hermes3-8b",
@@ -1725,7 +1901,14 @@
"started_at": "2026-07-23T13:53:40.844Z",
"finished_at": "2026-07-23T13:53:49.226Z",
"bytes": 2922,
- "thumb": true
+ "thumb": true,
+ "aiScore": 6.8,
+ "aiReason": "The particle system is visible and functional but lacks the smoothness and detail expected for a polished result.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 6.5
+ },
+ "aiSpread": 0.5
},
{
"model": "qwen25-7b",
@@ -1736,18 +1919,34 @@
"started_at": "2026-07-23T13:48:49.967Z",
"finished_at": "2026-07-23T13:49:08.530Z",
"bytes": 2933,
- "thumb": true
+ "thumb": true,
+ "aiScore": 7,
+ "aiReason": "The particle system is visually appealing and fulfills the challenge requirements but lacks smooth physics-based motion.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 7
+ },
+ "aiSpread": 0
},
{
"model": "kimi",
- "status": "running",
+ "status": "done",
"error": null,
- "seconds": 0,
- "cost": null,
+ "seconds": 152,
+ "cost": 0.0182,
"started_at": "2026-07-23T14:17:42.444Z",
- "finished_at": null,
+ "finished_at": "2026-07-23T14:20:14.351Z",
"resumes": 1,
- "queued_at": "2026-07-23T14:14:17.779Z"
+ "queued_at": "2026-07-23T14:14:17.779Z",
+ "bytes": 4545,
+ "thumb": true,
+ "aiScore": 8,
+ "aiReason": "The particle system effectively forms the word \"ARENA\" and smoothly transitions to an explosion effect upon click.",
+ "aiScores": {
+ "qwen2.5vl:7b": 9,
+ "minicpm-v:latest": 7
+ },
+ "aiSpread": 2
},
{
"model": "gpt",
@@ -1758,7 +1957,14 @@
"started_at": "2026-07-23T13:53:43.749Z",
"finished_at": "2026-07-23T13:54:06.210Z",
"bytes": 7780,
- "thumb": true
+ "thumb": true,
+ "aiScore": 8.3,
+ "aiReason": "The particle system effectively forms the word \"ARENA\" and transitions smoothly into an explosion effect upon click.",
+ "aiScores": {
+ "qwen2.5vl:7b": 9,
+ "minicpm-v:latest": 7.5
+ },
+ "aiSpread": 1.5
},
{
"model": "grok",
@@ -1769,11 +1975,20 @@
"started_at": "2026-07-23T13:48:04.785Z",
"finished_at": "2026-07-23T13:48:30.707Z",
"bytes": 5051,
- "thumb": true
+ "thumb": true,
+ "aiScore": 7,
+ "aiReason": "The particle system is visually appealing and fulfills the challenge requirements. However, it lacks a smooth 60fps animation due to the static nature of the screenshot.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 7
+ },
+ "aiSpread": 0
}
],
"voted_at": "2026-07-23T13:50:02.948Z",
- "aiPick": null
+ "aiPick": "gpt",
+ "judging": false,
+ "judged_at": "2026-07-23T14:30:02.641Z"
},
{
"id": "825890cbb1ea",
@@ -1900,7 +2115,14 @@
"finished_at": "2026-07-23T14:13:36.671Z",
"resumes": 1,
"bytes": 8856,
- "thumb": true
+ "thumb": true,
+ "aiScore": 8.3,
+ "aiReason": "The HTML fulfills the challenge well and has an elegant visual quality.",
+ "aiScores": {
+ "qwen2.5vl:7b": 9,
+ "minicpm-v:latest": 7.5
+ },
+ "aiSpread": 1.5
},
{
"model": "gemma3-12b",
@@ -1913,8 +2135,15 @@
"resumes": 2,
"queued_at": "2026-07-23T14:14:04.543Z",
"bytes": 8815,
- "thumb": true
- },
+ "thumb": true,
+ "aiScore": 8.3,
+ "aiReason": "The HTML fulfills the challenge well and has an elegant visual quality.",
+ "aiScores": {
+ "qwen2.5vl:7b": 9,
+ "minicpm-v:latest": 7.5
+ },
+ "aiSpread": 1.5
+ },
{
"model": "hermes3-8b",
"status": "done",
@@ -1926,7 +2155,14 @@
"resumes": 2,
"queued_at": "2026-07-23T14:14:04.544Z",
"bytes": 7775,
- "thumb": true
+ "thumb": true,
+ "aiScore": 8.3,
+ "aiReason": "The HTML fulfills the challenge well and has clean, elegant visual quality.",
+ "aiScores": {
+ "qwen2.5vl:7b": 9,
+ "minicpm-v:latest": 7.5
+ },
+ "aiSpread": 1.5
},
{
"model": "qwen25-7b",
@@ -1937,7 +2173,14 @@
"started_at": "2026-07-23T13:54:56.138Z",
"finished_at": "2026-07-23T13:55:57.570Z",
"bytes": 6556,
- "thumb": true
+ "thumb": true,
+ "aiScore": 8.3,
+ "aiReason": "The table is well-structured and visually appealing, fulfilling the challenge requirements effectively.",
+ "aiScores": {
+ "qwen2.5vl:7b": 9,
+ "minicpm-v:latest": 7.5
+ },
+ "aiSpread": 1.5
},
{
"model": "hf-qwen-coder-32b",
@@ -1950,12 +2193,20 @@
"resumes": 2,
"queued_at": "2026-07-23T14:14:04.545Z",
"bytes": 7922,
- "thumb": true
+ "thumb": true,
+ "aiScore": 8.3,
+ "aiReason": "The HTML fulfills the challenge well and has clean, elegant visual quality.",
+ "aiScores": {
+ "qwen2.5vl:7b": 9,
+ "minicpm-v:latest": 7.5
+ },
+ "aiSpread": 1.5
}
],
"category": "Real Work",
- "aiPick": null,
- "judging": true
+ "aiPick": "qwen3-14b",
+ "judging": false,
+ "judged_at": "2026-07-23T14:29:15.827Z"
},
{
"id": "75ec2d6d47f7",
@@ -2103,40 +2354,58 @@
"prompt": "Build a single self-contained HTML file: three sorting algorithms (bubble, quicksort, merge) racing side by side as animated bar charts, each labeled, with a Start/Shuffle button. Color-code comparisons vs swaps. Pure canvas or divs. Output ONLY the HTML.",
"category": "Games",
"created_at": "2026-07-23T14:04:47.412Z",
- "winner": null,
+ "winner": "grok",
"runs": [
{
"model": "qwen3-14b",
- "status": "running",
- "error": null,
- "seconds": 0,
+ "status": "error",
+ "error": "no HTML document in model output (0 chars)",
+ "seconds": 139,
"cost": null,
"started_at": "2026-07-23T14:18:01.999Z",
- "finished_at": null,
+ "finished_at": "2026-07-23T14:20:20.697Z",
"resumes": 2,
"queued_at": "2026-07-23T14:14:04.546Z"
},
{
"model": "gemma3-12b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": 0,
- "cost": null,
- "started_at": null,
- "finished_at": null,
+ "seconds": 55,
+ "cost": 0,
+ "started_at": "2026-07-23T14:20:20.699Z",
+ "finished_at": "2026-07-23T14:21:16.017Z",
"resumes": 2,
- "queued_at": "2026-07-23T14:14:04.547Z"
+ "queued_at": "2026-07-23T14:14:04.547Z",
+ "bytes": 7004,
+ "thumb": true,
+ "aiScore": 6.3,
+ "aiReason": "The HTML file is functional but lacks visual elements and color coding for comparisons and swaps.",
+ "aiScores": {
+ "qwen2.5vl:7b": 6,
+ "minicpm-v:latest": 6.5
+ },
+ "aiSpread": 0.5
},
{
"model": "hermes3-8b",
- "status": "queued",
+ "status": "done",
"error": null,
- "seconds": 0,
- "cost": null,
- "started_at": null,
- "finished_at": null,
+ "seconds": 17,
+ "cost": 0,
+ "started_at": "2026-07-23T14:21:16.019Z",
+ "finished_at": "2026-07-23T14:21:32.642Z",
"resumes": 2,
- "queued_at": "2026-07-23T14:14:04.547Z"
+ "queued_at": "2026-07-23T14:14:04.547Z",
+ "bytes": 4338,
+ "thumb": true,
+ "aiScore": 6.5,
+ "aiReason": "The HTML file is functional but lacks visual elements and color coding for comparisons and swaps.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 6
+ },
+ "aiSpread": 1
},
{
"model": "qwen25-7b",
@@ -2147,7 +2416,14 @@
"started_at": "2026-07-23T14:04:47.426Z",
"finished_at": "2026-07-23T14:05:16.457Z",
"bytes": 4417,
- "thumb": true
+ "thumb": true,
+ "aiScore": 6.5,
+ "aiReason": "The HTML file is functional but lacks visual elements and animations.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 6
+ },
+ "aiSpread": 1
},
{
"model": "kimi",
@@ -2160,7 +2436,14 @@
"resumes": 2,
"queued_at": "2026-07-23T14:14:04.548Z",
"bytes": 11220,
- "thumb": true
+ "thumb": true,
+ "aiScore": 8.3,
+ "aiReason": "The HTML file fulfills the challenge but lacks color coding for comparisons and swaps.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 9.5
+ },
+ "aiSpread": 2.5
},
{
"model": "gpt",
@@ -2171,7 +2454,14 @@
"started_at": "2026-07-23T14:04:47.430Z",
"finished_at": "2026-07-23T14:05:14.887Z",
"bytes": 14238,
- "thumb": true
+ "thumb": true,
+ "aiScore": 8.3,
+ "aiReason": "The HTML fulfills the challenge but lacks visual polish and interactivity.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 9.5
+ },
+ "aiSpread": 2.5
},
{
"model": "grok",
@@ -2183,9 +2473,581 @@
"finished_at": "2026-07-23T14:10:12.357Z",
"resumes": 1,
"bytes": 10882,
- "thumb": true
+ "thumb": true,
+ "aiScore": 9.3,
+ "aiReason": "The HTML file successfully implements the sorting algorithms as animated bar charts side by side, with clear labels and color coding for comparisons vs swaps. The design is visually appealing and fulf",
+ "aiScores": {
+ "qwen2.5vl:7b": 9,
+ "minicpm-v:latest": 9.5
+ },
+ "aiSpread": 0.5
}
],
- "aiPick": null
+ "aiPick": "grok",
+ "judging": false,
+ "judged_at": "2026-07-23T14:29:55.352Z",
+ "voted_at": "2026-07-23T14:35:50.510Z"
+ },
+ {
+ "id": "58d3738d2b99",
+ "title": "Design Tools Debut",
+ "prompt": "Design a luxury landing page for a boutique wallpaper studio: hero with display typography, a 3-card collection grid with hover states, and tasteful entrance animation. Visual quality is the whole game.",
+ "category": "Games",
+ "designTools": true,
+ "created_at": "2026-07-23T14:30:45.886Z",
+ "winner": null,
+ "runs": [
+ {
+ "model": "hermes3-8b",
+ "status": "done",
+ "error": null,
+ "seconds": 31,
+ "cost": 0,
+ "started_at": "2026-07-23T14:30:45.891Z",
+ "finished_at": "2026-07-23T14:31:17.224Z",
+ "queued_at": "2026-07-23T14:30:45.887Z",
+ "toolCalls": [
+ "opendesign",
+ "hyperframes"
+ ],
+ "bytes": 2823,
+ "thumb": true,
+ "aiScore": 6.3,
+ "aiReason": "The design is simple and effective but lacks the entrance animation and a more detailed collection grid.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 5.5
+ },
+ "aiSpread": 1.5
+ },
+ {
+ "model": "gemma3-12b",
+ "status": "done",
+ "error": null,
+ "seconds": 85,
+ "cost": 0,
+ "started_at": "2026-07-23T14:31:17.226Z",
+ "finished_at": "2026-07-23T14:32:42.705Z",
+ "queued_at": "2026-07-23T14:30:45.888Z",
+ "bytes": 5209,
+ "thumb": true,
+ "aiScore": 6.8,
+ "aiReason": "The design is clear and meets the brief but lacks the entrance animation and a more dynamic grid layout.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 6.5
+ },
+ "aiSpread": 0.5
+ },
+ {
+ "model": "kimi",
+ "status": "done",
+ "error": null,
+ "seconds": 60,
+ "cost": 0.0093,
+ "started_at": "2026-07-23T14:30:45.902Z",
+ "finished_at": "2026-07-23T14:31:46.272Z",
+ "queued_at": "2026-07-23T14:30:45.889Z",
+ "toolCalls": [
+ "opendesign",
+ "opendesign",
+ "hyperframes",
+ "hyperframes"
+ ],
+ "bytes": 7865,
+ "thumb": true,
+ "aiScore": 8.3,
+ "aiReason": "The landing page effectively showcases the boutique wallpaper studio's mission and aesthetic through clean typography and a simple yet elegant design.",
+ "aiScores": {
+ "qwen2.5vl:7b": 9,
+ "minicpm-v:latest": 7.5
+ },
+ "aiSpread": 1.5
+ }
+ ],
+ "judging": false,
+ "aiPick": "kimi",
+ "judged_at": "2026-07-23T14:33:24.099Z"
+ },
+ {
+ "id": "6fb7d108c932",
+ "title": "Warp Starfield Tunnel",
+ "prompt": "Build a single self-contained HTML file: a procedurally generated warp-speed starfield tunnel. Mouse position steers the camera; scroll changes speed; stars streak with motion blur. 60fps canvas. Output ONLY the HTML.",
+ "category": "Games",
+ "designTools": false,
+ "created_at": "2026-07-23T14:35:50.563Z",
+ "winner": "claude-code",
+ "runs": [
+ {
+ "model": "qwen3-14b",
+ "status": "error",
+ "error": "no HTML document in model output (0 chars)",
+ "seconds": 138,
+ "cost": null,
+ "started_at": "2026-07-23T14:35:50.586Z",
+ "finished_at": "2026-07-23T14:38:08.862Z",
+ "queued_at": "2026-07-23T14:35:50.567Z"
+ },
+ {
+ "model": "gemma3-12b",
+ "status": "done",
+ "error": null,
+ "seconds": 46,
+ "cost": 0,
+ "started_at": "2026-07-23T14:38:08.865Z",
+ "finished_at": "2026-07-23T14:38:54.748Z",
+ "queued_at": "2026-07-23T14:35:50.570Z",
+ "bytes": 2907,
+ "thumb": true,
+ "aiScore": 6.8,
+ "aiReason": "The HTML file is functional but lacks visual quality and detail.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 6.5
+ },
+ "aiSpread": 0.5
+ },
+ {
+ "model": "hermes3-8b",
+ "status": "done",
+ "error": null,
+ "seconds": 36,
+ "cost": 0,
+ "started_at": "2026-07-23T14:38:54.751Z",
+ "finished_at": "2026-07-23T14:39:30.424Z",
+ "queued_at": "2026-07-23T14:35:50.573Z",
+ "bytes": 3684,
+ "thumb": true,
+ "aiScore": 7,
+ "aiReason": "The file is functional but lacks visual quality and detail.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 7
+ },
+ "aiSpread": 0
+ },
+ {
+ "model": "qwen25-7b",
+ "status": "done",
+ "error": null,
+ "seconds": 12,
+ "cost": 0,
+ "started_at": "2026-07-23T14:35:50.588Z",
+ "finished_at": "2026-07-23T14:36:02.257Z",
+ "queued_at": "2026-07-23T14:35:50.575Z",
+ "bytes": 1668,
+ "thumb": true,
+ "aiScore": 7.3,
+ "aiReason": "The image shows a starfield tunnel but lacks the scroll functionality and motion blur effect.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 7.5
+ },
+ "aiSpread": 0.5
+ },
+ {
+ "model": "claude-code",
+ "status": "done",
+ "error": null,
+ "seconds": 44,
+ "cost": 0,
+ "started_at": "2026-07-23T14:35:50.590Z",
+ "finished_at": "2026-07-23T14:36:34.808Z",
+ "queued_at": "2026-07-23T14:35:50.578Z",
+ "bytes": 7520,
+ "thumb": true,
+ "aiScore": 9.3,
+ "aiReason": "The HTML file successfully fulfills the challenge requirements and produces a visually appealing warp-speed starfield tunnel.",
+ "aiScores": {
+ "qwen2.5vl:7b": 9,
+ "minicpm-v:latest": 9.5
+ },
+ "aiSpread": 0.5
+ },
+ {
+ "model": "kimi",
+ "status": "done",
+ "error": null,
+ "seconds": 164,
+ "cost": 0.02,
+ "started_at": "2026-07-23T14:35:50.605Z",
+ "finished_at": "2026-07-23T14:38:35.026Z",
+ "queued_at": "2026-07-23T14:35:50.580Z",
+ "bytes": 2941,
+ "thumb": true,
+ "aiScore": 7,
+ "aiReason": "The image shows a starfield tunnel effect but lacks scroll functionality and motion blur on stars.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 7
+ },
+ "aiSpread": 0
+ },
+ {
+ "model": "gpt",
+ "status": "done",
+ "error": null,
+ "seconds": 40,
+ "cost": 0.0328,
+ "started_at": "2026-07-23T14:35:50.607Z",
+ "finished_at": "2026-07-23T14:36:30.903Z",
+ "queued_at": "2026-07-23T14:35:50.582Z",
+ "bytes": 7034,
+ "thumb": true,
+ "aiScore": 8.3,
+ "aiReason": "The model fulfills the challenge requirements but lacks some polish and visual variety in star colors.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 9.5
+ },
+ "aiSpread": 2.5
+ },
+ {
+ "model": "grok",
+ "status": "done",
+ "error": null,
+ "seconds": 21,
+ "cost": 0.0264,
+ "started_at": "2026-07-23T14:35:50.608Z",
+ "finished_at": "2026-07-23T14:36:11.803Z",
+ "queued_at": "2026-07-23T14:35:50.585Z",
+ "bytes": 4158,
+ "thumb": true,
+ "aiScore": 7,
+ "aiReason": "The image shows a starfield tunnel effect but lacks the scroll functionality and motion blur for stars.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 7
+ },
+ "aiSpread": 0
+ }
+ ],
+ "voted_at": "2026-07-23T14:43:22.334Z",
+ "judging": false,
+ "aiPick": "claude-code",
+ "judged_at": "2026-07-23T14:46:39.552Z"
+ },
+ {
+ "id": "f79cffc20d43",
+ "title": "Hot or not WC",
+ "prompt": "Hot or not WC battles with last 20 new arrivals and compare to internet trending for high end architects",
+ "category": "Custom",
+ "designTools": false,
+ "created_at": "2026-07-23T14:38:54.889Z",
+ "winner": null,
+ "runs": [
+ {
+ "model": "qwen3-14b",
+ "status": "done",
+ "error": null,
+ "seconds": 80,
+ "cost": 0,
+ "started_at": "2026-07-23T14:39:30.426Z",
+ "finished_at": "2026-07-23T14:40:50.327Z",
+ "queued_at": "2026-07-23T14:38:54.890Z",
+ "bytes": 7188,
+ "thumb": true,
+ "aiScore": 7,
+ "aiReason": "The interface is clear and functional but lacks visual appeal.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 7
+ },
+ "aiSpread": 0
+ },
+ {
+ "model": "gemma3-12b",
+ "status": "done",
+ "error": null,
+ "seconds": 58,
+ "cost": 0,
+ "started_at": "2026-07-23T14:40:50.328Z",
+ "finished_at": "2026-07-23T14:41:48.597Z",
+ "queued_at": "2026-07-23T14:38:54.891Z",
+ "bytes": 5775,
+ "thumb": true,
+ "aiScore": 7.3,
+ "aiReason": "The image is clear and relevant to the challenge but lacks interactivity or additional context.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 7.5
+ },
+ "aiSpread": 0.5
+ },
+ {
+ "model": "hermes3-8b",
+ "status": "done",
+ "error": null,
+ "seconds": 19,
+ "cost": 0,
+ "started_at": "2026-07-23T14:41:48.597Z",
+ "finished_at": "2026-07-23T14:42:07.664Z",
+ "queued_at": "2026-07-23T14:38:54.892Z",
+ "bytes": 1857,
+ "thumb": true,
+ "aiScore": 6.8,
+ "aiReason": "The image is visually appealing and relevant to the challenge but lacks interactivity.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 6.5
+ },
+ "aiSpread": 0.5
+ },
+ {
+ "model": "qwen25-7b",
+ "status": "done",
+ "error": null,
+ "seconds": 15,
+ "cost": 0,
+ "started_at": "2026-07-23T14:38:54.896Z",
+ "finished_at": "2026-07-23T14:39:09.697Z",
+ "queued_at": "2026-07-23T14:38:54.892Z",
+ "bytes": 2542,
+ "thumb": true,
+ "aiScore": 4,
+ "aiReason": "The content is relevant but lacks visual appeal and interactivity.",
+ "aiScores": {
+ "qwen2.5vl:7b": 4,
+ "minicpm-v:latest": 4
+ },
+ "aiSpread": 0
+ },
+ {
+ "model": "claude-code",
+ "status": "done",
+ "error": null,
+ "seconds": 174,
+ "cost": 0,
+ "started_at": "2026-07-23T14:38:54.897Z",
+ "finished_at": "2026-07-23T14:41:49.301Z",
+ "queued_at": "2026-07-23T14:38:54.893Z",
+ "bytes": 28934,
+ "thumb": true,
+ "aiScore": 4.5,
+ "aiReason": "The interface is functional but lacks visual appeal and engagement.",
+ "aiScores": {
+ "qwen2.5vl:7b": 5,
+ "minicpm-v:latest": 4
+ },
+ "aiSpread": 1
+ },
+ {
+ "model": "kimi",
+ "status": "done",
+ "error": null,
+ "seconds": 171,
+ "cost": 0.0213,
+ "started_at": "2026-07-23T14:38:54.900Z",
+ "finished_at": "2026-07-23T14:41:45.476Z",
+ "queued_at": "2026-07-23T14:38:54.894Z",
+ "bytes": 23152,
+ "thumb": true,
+ "aiScore": 7.8,
+ "aiReason": "The image effectively compares two models in a clear and visually appealing manner.",
+ "aiScores": {
+ "qwen2.5vl:7b": 9,
+ "minicpm-v:latest": 6.5
+ },
+ "aiSpread": 2.5
+ },
+ {
+ "model": "gpt",
+ "status": "done",
+ "error": null,
+ "seconds": 129,
+ "cost": 0.2135,
+ "started_at": "2026-07-23T14:38:54.901Z",
+ "finished_at": "2026-07-23T14:41:04.224Z",
+ "queued_at": "2026-07-23T14:38:54.895Z",
+ "bytes": 57597,
+ "thumb": true,
+ "aiScore": 8.3,
+ "aiReason": "The screenshot effectively displays the challenge's requirements and provides clear visual quality.",
+ "aiScores": {
+ "qwen2.5vl:7b": 9,
+ "minicpm-v:latest": 7.5
+ },
+ "aiSpread": 1.5
+ },
+ {
+ "model": "grok",
+ "status": "done",
+ "error": null,
+ "seconds": 115,
+ "cost": 0.1368,
+ "started_at": "2026-07-23T14:38:54.902Z",
+ "finished_at": "2026-07-23T14:40:50.071Z",
+ "queued_at": "2026-07-23T14:38:54.895Z",
+ "bytes": 26502,
+ "thumb": true,
+ "aiScore": 6.8,
+ "aiReason": "The image is visually engaging and relevant to the challenge but lacks detailed content for a full evaluation.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 6.5
+ },
+ "aiSpread": 0.5
+ }
+ ],
+ "judging": false,
+ "aiPick": "gpt",
+ "judged_at": "2026-07-23T14:46:47.221Z"
+ },
+ {
+ "id": "10c3c876aa67",
+ "title": "Living Fractal Tree",
+ "prompt": "Build a single self-contained HTML file: a recursive fractal tree that grows on load and sways in simulated wind, with seasonal leaf particles falling. A slider controls branch depth. Pure canvas + JS. Output ONLY the HTML.",
+ "category": "Custom",
+ "designTools": false,
+ "created_at": "2026-07-23T14:43:22.383Z",
+ "winner": null,
+ "runs": [
+ {
+ "model": "qwen3-14b",
+ "status": "error",
+ "error": "no HTML document in model output (0 chars)",
+ "seconds": 137,
+ "cost": null,
+ "started_at": "2026-07-23T14:43:28.368Z",
+ "finished_at": "2026-07-23T14:45:45.183Z",
+ "queued_at": "2026-07-23T14:43:22.385Z"
+ },
+ {
+ "model": "gemma3-12b",
+ "status": "done",
+ "error": null,
+ "seconds": 26,
+ "cost": 0,
+ "started_at": "2026-07-23T14:45:45.187Z",
+ "finished_at": "2026-07-23T14:46:11.613Z",
+ "queued_at": "2026-07-23T14:43:22.388Z",
+ "bytes": 3214,
+ "thumb": true,
+ "aiScore": 5.8,
+ "aiReason": "The image shows only the canvas and no visible tree or particles.",
+ "aiScores": {
+ "qwen2.5vl:7b": 5,
+ "minicpm-v:latest": 6.5
+ },
+ "aiSpread": 1.5
+ },
+ {
+ "model": "hermes3-8b",
+ "status": "done",
+ "error": null,
+ "seconds": 11,
+ "cost": 0,
+ "started_at": "2026-07-23T14:46:11.615Z",
+ "finished_at": "2026-07-23T14:46:22.780Z",
+ "queued_at": "2026-07-23T14:43:22.389Z",
+ "bytes": 3239,
+ "thumb": true,
+ "aiScore": 7.3,
+ "aiReason": "The HTML file is functional but lacks the visual quality and complexity expected for a fractal tree simulation.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 7.5
+ },
+ "aiSpread": 0.5
+ },
+ {
+ "model": "qwen25-7b",
+ "status": "done",
+ "error": null,
+ "seconds": 26,
+ "cost": 0,
+ "started_at": "2026-07-23T14:43:22.402Z",
+ "finished_at": "2026-07-23T14:43:48.177Z",
+ "queued_at": "2026-07-23T14:43:22.391Z",
+ "bytes": 3683,
+ "thumb": true,
+ "aiScore": 6.3,
+ "aiReason": "The image shows a basic slider control but lacks the recursive fractal tree and particle effects described in the challenge.",
+ "aiScores": {
+ "qwen2.5vl:7b": 6,
+ "minicpm-v:latest": 6.5
+ },
+ "aiSpread": 0.5
+ },
+ {
+ "model": "claude-code",
+ "status": "done",
+ "error": null,
+ "seconds": 69,
+ "cost": 0,
+ "started_at": "2026-07-23T14:43:22.404Z",
+ "finished_at": "2026-07-23T14:44:31.683Z",
+ "queued_at": "2026-07-23T14:43:22.393Z",
+ "bytes": 7986,
+ "thumb": true,
+ "aiScore": 6.8,
+ "aiReason": "The tree is recursive and grows as expected, but lacks wind simulation and seasonal leaf particles.",
+ "aiScores": {
+ "qwen2.5vl:7b": 6,
+ "minicpm-v:latest": 7.5
+ },
+ "aiSpread": 1.5
+ },
+ {
+ "model": "kimi",
+ "status": "done",
+ "error": null,
+ "seconds": 152,
+ "cost": 0.02,
+ "started_at": "2026-07-23T14:43:22.408Z",
+ "finished_at": "2026-07-23T14:45:54.524Z",
+ "queued_at": "2026-07-23T14:43:22.396Z",
+ "bytes": 7513,
+ "thumb": true,
+ "aiScore": 7.3,
+ "aiReason": "The tree is correctly rendered and the slider works as intended, but there's no visible wind effect or seasonal leaf particles.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 7.5
+ },
+ "aiSpread": 0.5
+ },
+ {
+ "model": "gpt",
+ "status": "done",
+ "error": null,
+ "seconds": 26,
+ "cost": 0.0398,
+ "started_at": "2026-07-23T14:43:22.414Z",
+ "finished_at": "2026-07-23T14:43:48.256Z",
+ "queued_at": "2026-07-23T14:43:22.398Z",
+ "bytes": 8416,
+ "thumb": true,
+ "aiScore": 7.3,
+ "aiReason": "The tree is recursive and seasonal effects are present, but the wind simulation lacks animation.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 7.5
+ },
+ "aiSpread": 0.5
+ },
+ {
+ "model": "grok",
+ "status": "done",
+ "error": null,
+ "seconds": 30,
+ "cost": 0.0392,
+ "started_at": "2026-07-23T14:43:22.418Z",
+ "finished_at": "2026-07-23T14:43:52.720Z",
+ "queued_at": "2026-07-23T14:43:22.400Z",
+ "bytes": 6157,
+ "thumb": true,
+ "aiScore": 6.8,
+ "aiReason": "The tree is recursive and grows, but it lacks swaying wind effect or seasonal leaf particles.",
+ "aiScores": {
+ "qwen2.5vl:7b": 7,
+ "minicpm-v:latest": 6.5
+ },
+ "aiSpread": 0.5
+ }
+ ],
+ "judging": false,
+ "aiPick": "hermes3-8b",
+ "judged_at": "2026-07-23T14:47:05.806Z"
}
]
\ No newline at end of file
diff --git a/data/costlog.jsonl b/data/costlog.jsonl
index ad9d08f..68c8116 100644
--- a/data/costlog.jsonl
+++ b/data/costlog.jsonl
@@ -45,3 +45,14 @@
{"ts":"2026-07-23T14:12:40.777Z","provider":"moonshot","model":"kimi-k2.5","task":"model-arena","input_tokens":120,"output_tokens":7558,"cost_usd":0.018967}
{"ts":"2026-07-23T14:13:27.232Z","provider":"openai","model":"gpt-5.1","task":"model-arena","input_tokens":88,"output_tokens":2610,"cost_usd":0.036694}
{"ts":"2026-07-23T14:17:42.438Z","provider":"moonshot","model":"kimi-k2.5","task":"model-arena","input_tokens":137,"output_tokens":11001,"cost_usd":0.027585}
+{"ts":"2026-07-23T14:20:14.344Z","provider":"moonshot","model":"kimi-k2.5","task":"model-arena","input_tokens":135,"output_tokens":7247,"cost_usd":0.018198}
+{"ts":"2026-07-23T14:31:46.267Z","provider":"moonshot","model":"kimi-k2.5","task":"model-arena-tools","input_tokens":3620,"output_tokens":2857,"cost_usd":0.009314}
+{"ts":"2026-07-23T14:36:11.799Z","provider":"xai","model":"grok-4.5","task":"model-arena","input_tokens":332,"output_tokens":1696,"cost_usd":0.026436}
+{"ts":"2026-07-23T14:36:30.901Z","provider":"openai","model":"gpt-5.1","task":"model-arena","input_tokens":127,"output_tokens":2325,"cost_usd":0.032772}
+{"ts":"2026-07-23T14:38:35.022Z","provider":"moonshot","model":"kimi-k2.5","task":"model-arena","input_tokens":127,"output_tokens":7978,"cost_usd":0.020021}
+{"ts":"2026-07-23T14:40:50.065Z","provider":"xai","model":"grok-4.5","task":"model-arena","input_tokens":306,"output_tokens":9056,"cost_usd":0.136758}
+{"ts":"2026-07-23T14:41:04.220Z","provider":"openai","model":"gpt-5.1","task":"model-arena","input_tokens":102,"output_tokens":15239,"cost_usd":0.213525}
+{"ts":"2026-07-23T14:41:45.465Z","provider":"moonshot","model":"kimi-k2.5","task":"model-arena","input_tokens":103,"output_tokens":8504,"cost_usd":0.021322}
+{"ts":"2026-07-23T14:43:48.255Z","provider":"openai","model":"gpt-5.1","task":"model-arena","input_tokens":127,"output_tokens":2827,"cost_usd":0.0398}
+{"ts":"2026-07-23T14:43:52.717Z","provider":"xai","model":"grok-4.5","task":"model-arena","input_tokens":331,"output_tokens":2549,"cost_usd":0.039228}
+{"ts":"2026-07-23T14:45:54.520Z","provider":"moonshot","model":"kimi-k2.5","task":"model-arena","input_tokens":128,"output_tokens":7985,"cost_usd":0.020039}
diff --git a/data/votes.jsonl b/data/votes.jsonl
index b437bf0..7385a3a 100644
--- a/data/votes.jsonl
+++ b/data/votes.jsonl
@@ -7,3 +7,6 @@
{"ts":"2026-07-23T13:35:47.844Z","challenge":"f2af82652fcd","title":"california real estate brokers","winner":"grok","field":["qwen3-14b","gemma3-12b","hermes3-8b","qwen25-7b","kimi","gpt","grok"]}
{"ts":"2026-07-23T13:50:02.948Z","challenge":"ca355985ca95","title":"Particle Text Reactor","winner":"qwen25-7b","field":["qwen3-14b","qwen25-7b","gpt","grok"]}
{"ts":"2026-07-23T14:04:47.358Z","challenge":"75ec2d6d47f7","title":"Gravity Slingshot Playground","winner":"gpt","field":["qwen3-14b","gemma3-12b","hermes3-8b","qwen25-7b","kimi","gpt","grok"]}
+{"ts":"2026-07-23T14:35:50.510Z","challenge":"e14b05b7754d","title":"Sorting Race Visualizer","winner":"grok","field":["gemma3-12b","hermes3-8b","qwen25-7b","kimi","gpt","grok"]}
+{"ts":"2026-07-23T14:37:06.356Z","challenge":"6fb7d108c932","title":"Warp Starfield Tunnel","winner":"gpt","field":["qwen25-7b","claude-code","gpt","grok"]}
+{"ts":"2026-07-23T14:43:22.334Z","challenge":"6fb7d108c932","title":"Warp Starfield Tunnel","winner":"claude-code","field":["gemma3-12b","hermes3-8b","qwen25-7b","claude-code","kimi","gpt","grok"]}
diff --git a/idea-run/harvest.md b/idea-run/harvest.md
index 0b6c55f..7242483 100644
--- a/idea-run/harvest.md
+++ b/idea-run/harvest.md
@@ -32,3 +32,22 @@ Contrarian RANKED:
**Best idea per model:** gpt=per-segment trail fade (alpha=t/len + tapered width) · grok=impulse collision j=-(1+e)*dvn/(1/ma+1/mb) + approaching-only guard + rgba-wipe ambient trails · kimi=central-mass singularity guard (dist<40 → elastic bounce vs divide-by-near-zero).
HIGHEST-LEVERAGE: Grok's impulse elastic-collision formula = the pass/fail gate (every model that nailed it worked; every one that hand-waved it broke).
COMPOSITE the contrarian proposed: Grok impulse+rotated-rect+DPR+sparks ⊕ GPT trail-fade+drag-slingshot ⊕ Kimi singularity-guard = beats all 7.
+
+## Cycle 3 — Sorting Race Visualizer (e14b05b7754d) · 6/7 (qwen3-14b errored again)
+Contrarian: **GROK WINS.** Its Promise.all + per-index color-array concurrency pattern (comparisons vs swaps color-coded per bar) cleanly ran all 3 algos side-by-side. GPT used step-generators (also correct, needs pivot color). Kimi (11KB) solid but had a merge-writeback reversal bug (lines 362-364).
+Best idea/model: grok=Promise.all + per-k color arrays for concurrent step-animation · gpt=generator/coroutine per algo (yield each comparison) · kimi=compact 3-algo impl (fix merge writeback).
+HIGHEST-LEVERAGE: Grok's Promise.all concurrency + per-index color state = the clean way to race N animated algorithms without blocking; swap setTimeout→one RAF loop.
+qwen3-14b: errored AGAIN (unreliable — stubbed cycle1, errored cycle3). Locals gemma/hermes/qwen25 completed but weaker.
+
+## Cycle 4 — Warp Starfield Tunnel (6fb7d108c932) · FIRST with Claude · 7/8 (qwen3-14b errored AGAIN)
+Contrarian RANKED:
+1. **claude-code (WINNER)** — full 3D projection + DPR + touch + scroll speed-bar + HUD + hue-shifted stars + smoothed steering. "Treated 'working' as the FLOOR, not the finish line."
+2. gpt — proper cylindrical tunnel spawn, perspective projection, scroll velocity decay, color variation. Math right, stopped at "works."
+3. grok — 900 stars, perspective z-depth, mouse steer, speed smoothing. No tunnel shaping, bare UX.
+4. kimi — 2000 stars, FOV/maxDepth projection, functional. No streaks, no steer feedback. Competent but flat.
+5. gemma3-12b — 500 stars flat 2D, a "camera angle" var that does nothing, no perspective.
+6. hermes3-8b — 300 stars falling straight down, no z-axis, no tunnel.
+7. qwen25-7b — moves via window.scrollY (not a thing), per-frame random hue = seizure flicker. Broken.
+
+**KEY FINDING:** Claude (free, Max-plan) WON its first battle by out-POLISHING GPT/Grok — they had correct math, Claude added DPR/touch/HUD/outlier-stars/smoothing. The others treat "it works" as done; Claude treats it as the floor.
+Best technique: kimi's rotation-matrix camera-steer (lines 76-88) is cleaner than the vanishing-point-offset the others (incl. Claude) used — the composite = Claude's polish + Kimi's rotation-matrix steer.
← afeb092 README: document the design-tools belt
·
back to Model Arena
·
auto-save: 2026-07-23T08:19:35 (2 files) — data/challenges.j bb586f8 →