[object Object]

← back to Model Arena

ALL-MUST-WORK: local models (qwen3-14b, hermes3-8b) use design PACK not the live tool loop — 8B/14B returned 0 chars through function-calling; API models keep the tool loop

f4b407f731bf4f96b4315bc560f293631efa68b1 · 2026-07-25 01:46:25 -0700 · Steve Abrams

Files touched

Diff

commit f4b407f731bf4f96b4315bc560f293631efa68b1
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sat Jul 25 01:46:25 2026 -0700

    ALL-MUST-WORK: local models (qwen3-14b, hermes3-8b) use design PACK not the live tool loop — 8B/14B returned 0 chars through function-calling; API models keep the tool loop
---
 data/artifacts/327c5eb5b964/qwen3-14b.html | 224 +++++++
 data/artifacts/327c5eb5b964/qwen3-14b.png  | Bin 0 -> 10935 bytes
 data/artifacts/5410cf08e245/gpt.html       | 993 +++++++++++++++++++++++++++++
 data/artifacts/5410cf08e245/gpt.png        | Bin 0 -> 128900 bytes
 data/challenges.json                       | 205 +++---
 data/costlog.jsonl                         |   1 +
 server.js                                  |   8 +-
 7 files changed, 1347 insertions(+), 84 deletions(-)

diff --git a/data/artifacts/327c5eb5b964/qwen3-14b.html b/data/artifacts/327c5eb5b964/qwen3-14b.html
new file mode 100644
index 0000000..49776ed
--- /dev/null
+++ b/data/artifacts/327c5eb5b964/qwen3-14b.html
@@ -0,0 +1,224 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="UTF-8">
+  <title>Neon Noir Drive</title>
+  <style>
+    html, body {
+      margin: 0;
+      padding: 0;
+      overflow: hidden;
+      background-color: #000;
+      font-family: 'Courier New', Courier, monospace;
+      color: #00ffcc;
+    }
+
+    canvas {
+      display: block;
+    }
+
+    #score {
+      position: absolute;
+      top: 10px;
+      left: 10px;
+      font-size: 24px;
+      text-shadow: 0 0 10px #00ffcc;
+      pointer-events: none;
+    }
+  </style>
+</head>
+<body>
+  <div id="score">Score: 0</div>
+  <canvas id="gameCanvas"></canvas>
+
+  <script>
+    const canvas = document.getElementById('gameCanvas');
+    const ctx = canvas.getContext('2d');
+    const scoreDisplay = document.getElementById('score');
+
+    canvas.width = window.innerWidth;
+    canvas.height = window.innerHeight;
+
+    let carX = canvas.width / 2 - 25;
+    let carY = canvas.height - 75;
+    let carSpeed = 5;
+    let carWidth = 50;
+    let carHeight = 50;
+
+    let roadY = 0;
+    let roadSpeed = 4;
+
+    let obstacles = [];
+    let buildings = [];
+    let score = 0;
+    let gameOver = false;
+
+    const carColor = '#00ffcc';
+
+    const keys = {};
+    window.addEventListener('keydown', e => keys[e.key] = true);
+    window.addEventListener('keyup', e => keys[e.key] = false);
+
+    function drawCar(x, y) {
+      ctx.fillStyle = carColor;
+      ctx.beginPath();
+      ctx.moveTo(x, y);
+      ctx.lineTo(x + 30, y + 15);
+      ctx.lineTo(x + 10, y + 30);
+      ctx.lineTo(x, y + 15);
+      ctx.closePath();
+      ctx.fill();
+    }
+
+    function drawBuilding(x, y, width, height, color) {
+      ctx.fillStyle = color;
+      ctx.fillRect(x, y, width, height);
+    }
+
+    function drawObstacle(x, y, width, height, color) {
+      ctx.fillStyle = color;
+      ctx.beginPath();
+      ctx.moveTo(x, y);
+      ctx.lineTo(x + width, y);
+      ctx.lineTo(x + width, y + height);
+      ctx.lineTo(x, y + height);
+      ctx.closePath();
+      ctx.fill();
+    }
+
+    function createObstacle() {
+      const width = 40 + Math.random() * 40;
+      const height = 40 + Math.random() * 40;
+      const x = Math.random() * (canvas.width - width - 50);
+      const y = -height;
+      const color = `hsl(${Math.random() * 360}, 100%, 60%)`;
+      obstacles.push({ x, y, width, height, color });
+    }
+
+    function createBuilding() {
+      const height = 100 + Math.random() * 150;
+      const width = 80 + Math.random() * 100;
+      const x = Math.random() * (canvas.width - width);
+      const y = -height;
+      const color = `hsl(${Math.random() * 360}, 80%, 50%)`;
+      buildings.push({ x, y, width, height, color });
+    }
+
+    function updateObstacles() {
+      for (let i = obstacles.length - 1; i >= 0; i--) {
+        obstacles[i].y += roadSpeed;
+        if (obstacles[i].y > canvas.height) {
+          obstacles.splice(i, 1);
+        }
+      }
+    }
+
+    function updateBuildings() {
+      for (let i = buildings.length - 1; i >= 0; i--) {
+        buildings[i].y += roadSpeed;
+        if (buildings[i].y > canvas.height) {
+          buildings.splice(i, 1);
+        }
+      }
+    }
+
+    function checkCollision(x1, y1, w1, h1, x2, y2, w2, h2) {
+      return !(
+        x1 + w1 < x2 ||
+        x1 > x2 + w2 ||
+        y1 + h1 < y2 ||
+        y1 > y2 + h2
+      );
+    }
+
+    function update() {
+      if (gameOver) return;
+
+      carX += (keys['ArrowRight'] ? carSpeed : 0) + (keys['ArrowLeft'] ? -carSpeed : 0);
+      carX = Math.max(0, Math.min(canvas.width - carWidth, carX));
+
+      if (keys['ArrowUp']) {
+        carY -= carSpeed;
+      } else if (keys['ArrowDown']) {
+        carY += carSpeed;
+      }
+
+      roadY += roadSpeed;
+
+      if (Math.random() < 0.01) createObstacle();
+      if (Math.random() < 0.02) createBuilding();
+
+      updateObstacles();
+      updateBuildings();
+
+      for (let obstacle of obstacles) {
+        if (checkCollision(carX, carY, carWidth, carHeight, obstacle.x, obstacle.y, obstacle.width, obstacle.height)) {
+          gameOver = true;
+        }
+      }
+
+      score++;
+      scoreDisplay.textContent = "Score: " + score;
+    }
+
+    function draw() {
+      ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+      // Road
+      ctx.fillStyle = '#000';
+      ctx.fillRect(0, 0, canvas.width, canvas.height);
+
+      // Road lines
+      ctx.strokeStyle = '#00ffcc';
+      ctx.lineWidth = 3;
+      ctx.setLineDash([20, 10]);
+      ctx.beginPath();
+      for (let i = 0; i < canvas.height; i += 20) {
+        ctx.moveTo(0, i + roadY);
+        ctx.lineTo(canvas.width, i + roadY);
+      }
+      ctx.stroke();
+      ctx.setLineDash([]);
+
+      // Buildings
+      for (let building of buildings) {
+        drawBuilding(building.x, building.y, building.width, building.height, building.color);
+      }
+
+      // Obstacles
+      for (let obstacle of obstacles) {
+        drawObstacle(obstacle.x, obstacle.y, obstacle.width, obstacle.height, obstacle.color);
+      }
+
+      // Car
+      drawCar(carX, carY);
+
+      // Game Over
+      if (gameOver) {
+        ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
+        ctx.fillRect(0, 0, canvas.width, canvas.height);
+        ctx.fillStyle = '#00ffcc';
+        ctx.font = '48px "Courier New", Courier, monospace';
+        ctx.textAlign = 'center';
+        ctx.fillText('Game Over', canvas.width / 2, canvas.height / 2);
+        ctx.font = '24px "Courier New", Courier, monospace';
+        ctx.fillText('Press R to restart', canvas.width / 2, canvas.height / 2 + 40);
+      }
+    }
+
+    function gameLoop() {
+      update();
+      draw();
+      requestAnimationFrame(gameLoop);
+    }
+
+    window.addEventListener('keydown', (e) => {
+      if (gameOver && e.key === 'r') {
+        location.reload();
+      }
+    });
+
+    gameLoop();
+  </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/327c5eb5b964/qwen3-14b.png b/data/artifacts/327c5eb5b964/qwen3-14b.png
new file mode 100644
index 0000000..f3e1191
Binary files /dev/null and b/data/artifacts/327c5eb5b964/qwen3-14b.png differ
diff --git a/data/artifacts/5410cf08e245/gpt.html b/data/artifacts/5410cf08e245/gpt.html
new file mode 100644
index 0000000..a81ad75
--- /dev/null
+++ b/data/artifacts/5410cf08e245/gpt.html
@@ -0,0 +1,993 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8" />
+<title>Designer Wallcoverings Memory</title>
+<style>
+:root {
+  --bg: #0d0d0f;
+  --surface: #17171c;
+  --surface-soft: #1f1f26;
+  --text: #f5f2ea;
+  --muted: #8a8578;
+  --accent: #c9a961;
+  --accent-soft: #7d6a45;
+
+  --radius-card: 10px;
+  --radius-soft: 18px;
+  --shadow-soft: 0 22px 60px rgba(0, 0, 0, 0.55);
+  --shadow-subtle: 0 12px 30px rgba(0, 0, 0, 0.45);
+  --border-hairline: 1px solid rgba(201,169,97,0.32);
+
+  --font-display: "Playfair Display", "Didot", "Bodoni MT", Georgia, serif;
+  --font-serif: "Playfair Display", "EB Garamond", "Cormorant Garamond", Georgia, serif;
+  --font-sans: "Avenir Next", "Century Gothic", "Segoe UI", system-ui, sans-serif;
+
+  --fs-caption: 12px;
+  --fs-body: 16px;
+  --fs-lead: 21px;
+  --fs-h3: 28px;
+  --fs-h2: 38px;
+  --fs-h1: 50px;
+
+  --easing-swift-out: cubic-bezier(.22,.9,.24,1);
+  --easing-hero: cubic-bezier(.22,1,.36,1);
+}
+
+*,
+*::before,
+*::after {
+  box-sizing: border-box;
+}
+
+html, body {
+  margin: 0;
+  padding: 0;
+  height: 100%;
+  background: radial-gradient(circle at top, #272733 0, #0d0d0f 55%);
+  color: var(--text);
+  font-family: var(--font-sans);
+}
+
+body {
+  display: flex;
+  flex-direction: column;
+}
+
+/* Top bar */
+.top-bar {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  height: 64px;
+  padding: 0 36px;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  backdrop-filter: blur(16px);
+  background: linear-gradient(to bottom, rgba(13,13,15,0.96), rgba(13,13,15,0.82));
+  border-bottom: 1px solid rgba(201,169,97,0.32);
+  z-index: 20;
+}
+
+.wordmark {
+  font-family: var(--font-serif);
+  font-size: 15px;
+  letter-spacing: 0.18em;
+  text-transform: uppercase;
+  color: var(--text);
+  white-space: nowrap;
+}
+
+.top-bar-meta {
+  display: flex;
+  gap: 18px;
+  font-size: 11px;
+  text-transform: uppercase;
+  letter-spacing: 0.14em;
+  color: var(--muted);
+}
+
+.top-bar-meta span {
+  padding: 4px 10px;
+  border-radius: 999px;
+  border: 1px solid rgba(138,133,120,0.6);
+}
+
+/* Layout */
+.main {
+  flex: 1;
+  padding: 96px 24px 32px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+.shell {
+  width: 100%;
+  max-width: 980px;
+  display: grid;
+  grid-template-columns: minmax(0, 3fr) minmax(260px, 1.6fr);
+  gap: 32px;
+  align-items: stretch;
+}
+
+@media (max-width: 900px) {
+  .shell {
+    grid-template-columns: minmax(0, 1fr);
+  }
+}
+
+/* Panel styles */
+.panel {
+  background: radial-gradient(circle at top left, rgba(201,169,97,0.16), transparent 55%), var(--surface);
+  border-radius: var(--radius-soft);
+  border: var(--border-hairline);
+  box-shadow: var(--shadow-soft);
+  padding: 22px 22px 24px;
+  position: relative;
+  overflow: hidden;
+}
+
+.panel::before {
+  content: "";
+  position: absolute;
+  inset: 0;
+  pointer-events: none;
+  background:
+    linear-gradient(120deg, rgba(255,255,255,0.08), transparent 22%, transparent 78%, rgba(255,255,255,0.02));
+  mix-blend-mode: soft-light;
+  opacity: 0.75;
+}
+
+/* Heading block */
+.panel-header {
+  position: relative;
+  display: flex;
+  justify-content: space-between;
+  align-items: baseline;
+  margin-bottom: 18px;
+  z-index: 1;
+}
+
+.panel-title {
+  font-family: var(--font-display);
+  font-size: 26px;
+  letter-spacing: 0.06em;
+  text-transform: uppercase;
+  margin: 0;
+}
+
+.panel-subtitle {
+  font-size: 12px;
+  letter-spacing: 0.16em;
+  text-transform: uppercase;
+  color: var(--muted);
+}
+
+/* Stats row */
+.stats {
+  position: relative;
+  display: flex;
+  gap: 18px;
+  align-items: center;
+  margin-bottom: 16px;
+  padding-bottom: 14px;
+  border-bottom: 1px solid rgba(138,133,120,0.35);
+  z-index: 1;
+}
+
+.stat-block {
+  display: flex;
+  flex-direction: column;
+  gap: 3px;
+}
+
+.stat-label {
+  font-size: 11px;
+  letter-spacing: 0.16em;
+  text-transform: uppercase;
+  color: var(--muted);
+}
+
+.stat-value {
+  font-family: var(--font-display);
+  font-size: 19px;
+}
+
+/* Control buttons */
+.controls {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 10px;
+  margin-left: auto;
+}
+
+.btn {
+  position: relative;
+  border-radius: 999px;
+  padding: 7px 16px 8px;
+  border: 1px solid rgba(201,169,97,0.6);
+  background: radial-gradient(circle at top, rgba(201,169,97,0.28), rgba(125,106,69,0.9));
+  color: #0b0b0d;
+  font-size: 11px;
+  font-weight: 600;
+  letter-spacing: 0.16em;
+  text-transform: uppercase;
+  cursor: pointer;
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  gap: 6px;
+  outline: none;
+  box-shadow: 0 10px 25px rgba(0,0,0,0.65);
+  transition:
+    background 160ms var(--easing-swift-out),
+    transform 160ms var(--easing-swift-out),
+    box-shadow 160ms var(--easing-swift-out),
+    border-color 160ms var(--easing-swift-out);
+}
+
+.btn span.bullet {
+  width: 4px;
+  height: 4px;
+  border-radius: 50%;
+  background: #0b0b0d;
+}
+
+.btn:hover {
+  transform: translateY(-1px);
+  box-shadow: 0 14px 30px rgba(0,0,0,0.75);
+  border-color: rgba(255,231,178,0.9);
+}
+
+.btn:active {
+  transform: translateY(0);
+  box-shadow: 0 8px 18px rgba(0,0,0,0.7);
+}
+
+/* Game grid */
+.grid {
+  position: relative;
+  z-index: 1;
+  display: grid;
+  grid-template-columns: repeat(4, minmax(0, 1fr));
+  gap: 14px;
+  margin-top: 4px;
+}
+
+@media (max-width: 900px) {
+  .grid {
+    gap: 10px;
+  }
+}
+
+/* Card */
+.card {
+  position: relative;
+  cursor: pointer;
+  perspective: 900px;
+  height: 0;
+  padding-bottom: 115%;
+}
+
+.card-inner {
+  position: absolute;
+  inset: 0;
+  transform-style: preserve-3d;
+  transition: transform 520ms var(--easing-swift-out);
+}
+
+.card.is-flipped .card-inner,
+.card.is-matched .card-inner {
+  transform: rotateY(180deg);
+}
+
+.card-face {
+  position: absolute;
+  inset: 0;
+  border-radius: var(--radius-card);
+  backface-visibility: hidden;
+  overflow: hidden;
+}
+
+/* Card back */
+.card-back {
+  background:
+    linear-gradient(135deg, rgba(201,169,97,0.22), transparent 40%, rgba(125,106,69,0.8)),
+    radial-gradient(circle at 10% 0, rgba(255,255,255,0.18), transparent 55%),
+    linear-gradient(135deg, #181821, #101015);
+  border: 1px solid rgba(201,169,97,0.5);
+  box-shadow: var(--shadow-subtle);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  position: relative;
+}
+
+.card-back::before {
+  content: "";
+  position: absolute;
+  inset: 10%;
+  border-radius: calc(var(--radius-card) - 2px);
+  border: 1px solid rgba(245,242,234,0.14);
+}
+
+/* Subtle monogram pattern on back */
+.card-back::after {
+  content: "DW";
+  font-family: var(--font-serif);
+  font-size: 17px;
+  letter-spacing: 0.28em;
+  text-transform: uppercase;
+  color: rgba(13,13,15,0.84);
+  text-shadow: 0 0 0 rgba(0,0,0,0.6);
+}
+
+/* Card front */
+.card-front {
+  transform: rotateY(180deg);
+  background: #101015;
+  border: 1px solid rgba(245,242,234,0.16);
+  box-shadow: var(--shadow-subtle);
+  display: flex;
+  flex-direction: column;
+}
+
+.card-front-header {
+  padding: 6px 10px 4px;
+  border-bottom: 1px solid rgba(138,133,120,0.5);
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  background: radial-gradient(circle at top, rgba(201,169,97,0.18), transparent 75%);
+}
+
+.card-front-name {
+  font-family: var(--font-serif);
+  font-size: 12px;
+  letter-spacing: 0.18em;
+  text-transform: uppercase;
+  color: var(--text);
+  white-space: nowrap;
+}
+
+.card-front-tag {
+  font-size: 10px;
+  text-transform: uppercase;
+  letter-spacing: 0.18em;
+  color: var(--muted);
+}
+
+/* Swatch area */
+.card-swatch {
+  position: relative;
+  flex: 1;
+  overflow: hidden;
+}
+
+/* Pattern definitions */
+.pattern {
+  position: absolute;
+  inset: 0;
+  background-size: 24px 24px;
+  opacity: 0.96;
+}
+
+/* Damask: baroque floral using gradients + masks */
+.pattern-damask {
+  background-image:
+    radial-gradient(circle at 0 0, rgba(245,242,234,0.24) 0, rgba(245,242,234,0.24) 16%, transparent 18%),
+    radial-gradient(circle at 100% 100%, rgba(245,242,234,0.2) 0, rgba(245,242,234,0.2) 14%, transparent 16%),
+    radial-gradient(circle at 50% 50%, rgba(245,242,234,0.12) 0, rgba(245,242,234,0.12) 32%, transparent 34%);
+  background-color: #17171f;
+}
+
+/* Toile: sketchy pastoral stripes */
+.pattern-toile {
+  background-image:
+    repeating-linear-gradient(135deg, rgba(245,242,234,0.26) 0, rgba(245,242,234,0.26) 1px, transparent 1px, transparent 6px),
+    repeating-linear-gradient(180deg, rgba(201,169,97,0.14) 0, rgba(201,169,97,0.14) 2px, transparent 2px, transparent 14px);
+  background-color: #161621;
+}
+
+/* Ikat: blurred diamonds */
+.pattern-ikat {
+  background-image:
+    radial-gradient(circle at 0 50%, rgba(201,169,97,0.85) 0, rgba(201,169,97,0.85) 32%, transparent 40%),
+    radial-gradient(circle at 50% 0, rgba(245,242,234,0.9) 0, rgba(245,242,234,0.9) 26%, transparent 34%),
+    radial-gradient(circle at 100% 50%, rgba(201,169,97,0.75) 0, rgba(201,169,97,0.75) 30%, transparent 40%),
+    radial-gradient(circle at 50% 100%, rgba(245,242,234,0.75) 0, rgba(245,242,234,0.75) 25%, transparent 38%);
+  background-size: 44px 44px;
+  background-color: #101018;
+  filter: blur(0.2px);
+}
+
+/* Chinoiserie: fine branches + blossoms */
+.pattern-chinoiserie {
+  background-image:
+    radial-gradient(circle at 10% 20%, rgba(245,242,234,0.7) 0, rgba(245,242,234,0.7) 2px, transparent 3px),
+    radial-gradient(circle at 40% 70%, rgba(245,242,234,0.6) 0, rgba(245,242,234,0.6) 2px, transparent 3px),
+    radial-gradient(circle at 80% 30%, rgba(245,242,234,0.6) 0, rgba(245,242,234,0.6) 2px, transparent 3px),
+    repeating-linear-gradient(120deg, rgba(125,106,69,0.7) 0, rgba(125,106,69,0.7) 1px, transparent 1px, transparent 9px);
+  background-color: #151521;
+}
+
+/* Trellis: lattice */
+.pattern-trellis {
+  background-image:
+    linear-gradient(45deg, transparent 0, transparent 47%, rgba(245,242,234,0.65) 47%, rgba(245,242,234,0.65) 53%, transparent 53%),
+    linear-gradient(-45deg, transparent 0, transparent 47%, rgba(245,242,234,0.65) 47%, rgba(245,242,234,0.65) 53%, transparent 53%);
+  background-size: 26px 26px;
+  background-color: #101018;
+}
+
+/* Fret: Greek key style maze */
+.pattern-fret {
+  background-image:
+    linear-gradient(90deg, rgba(201,169,97,0.85) 2px, transparent 2px 12px, rgba(201,169,97,0.5) 12px 14px, transparent 14px),
+    linear-gradient(180deg, rgba(201,169,97,0.85) 2px, transparent 2px 12px, rgba(201,169,97,0.5) 12px 14px, transparent 14px);
+  background-size: 16px 16px;
+  background-color: #15151f;
+}
+
+/* Botanical: leaves & stems */
+.pattern-botanical {
+  background-image:
+    radial-gradient(circle at 10% 30%, rgba(245,242,234,0.85) 0, rgba(245,242,234,0.85) 3px, transparent 4px),
+    radial-gradient(circle at 35% 60%, rgba(245,242,234,0.65) 0, rgba(245,242,234,0.65) 3px, transparent 4px),
+    radial-gradient(circle at 70% 20%, rgba(245,242,234,0.75) 0, rgba(245,242,234,0.75) 3px, transparent 4px),
+    radial-gradient(circle at 80% 80%, rgba(245,242,234,0.75) 0, rgba(245,242,234,0.75) 3px, transparent 4px),
+    repeating-linear-gradient(145deg, rgba(125,106,69,0.85) 0, rgba(125,106,69,0.85) 1px, transparent 1px, transparent 7px);
+  background-color: #141821;
+}
+
+/* Stripe: tailored hotel stripe */
+.pattern-stripe {
+  background-image:
+    repeating-linear-gradient(90deg,
+      rgba(245,242,234,0.92) 0,
+      rgba(245,242,234,0.92) 3px,
+      rgba(201,169,97,0.85) 3px,
+      rgba(201,169,97,0.85) 4px,
+      #14141f 4px,
+      #14141f 13px);
+  background-color: #14141f;
+}
+
+/* Card overlays */
+.card-swatch::after {
+  content: "";
+  position: absolute;
+  inset: 0;
+  background:
+    radial-gradient(circle at top, rgba(255,255,255,0.2), transparent 50%),
+    linear-gradient(to bottom, rgba(0,0,0,0.2), rgba(0,0,0,0.85));
+  mix-blend-mode: soft-light;
+  opacity: 0.7;
+}
+
+/* Win overlay */
+.win-overlay {
+  position: absolute;
+  inset: 0;
+  background: radial-gradient(circle at top, rgba(13,13,15,0.1), rgba(13,13,15,0.96));
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 5;
+  opacity: 0;
+  pointer-events: none;
+  transition: opacity 380ms var(--easing-hero);
+}
+
+.win-overlay.is-visible {
+  opacity: 1;
+  pointer-events: auto;
+}
+
+.win-dialog {
+  background: radial-gradient(circle at top left, rgba(201,169,97,0.18), transparent 65%), var(--surface-soft);
+  border-radius: 18px;
+  border: 1px solid rgba(201,169,97,0.6);
+  padding: 26px 26px 22px;
+  max-width: 340px;
+  text-align: left;
+  box-shadow: 0 26px 80px rgba(0,0,0,0.86);
+  animation: scaleIn 520ms var(--easing-hero) both;
+}
+
+.win-label {
+  font-size: 11px;
+  letter-spacing: 0.2em;
+  text-transform: uppercase;
+  color: var(--muted);
+  margin-bottom: 8px;
+}
+
+.win-title {
+  font-family: var(--font-display);
+  font-size: 24px;
+  margin: 0 0 8px;
+  letter-spacing: 0.08em;
+  text-transform: uppercase;
+}
+
+.win-body {
+  font-size: 13px;
+  line-height: 1.6;
+  color: var(--muted);
+  margin-bottom: 14px;
+}
+
+.win-metrics {
+  display: flex;
+  gap: 16px;
+  font-size: 12px;
+  margin-bottom: 16px;
+}
+
+.win-metrics span {
+  display: block;
+}
+
+.win-metrics .label {
+  text-transform: uppercase;
+  letter-spacing: 0.18em;
+  font-size: 10px;
+  color: rgba(138,133,120,0.9);
+}
+
+.win-metrics .value {
+  font-family: var(--font-display);
+  font-size: 17px;
+}
+
+/* Side legend */
+.legend {
+  position: relative;
+  z-index: 1;
+  display: flex;
+  flex-direction: column;
+  gap: 16px;
+}
+
+.legend-copy {
+  font-size: 13px;
+  line-height: 1.7;
+  color: var(--muted);
+  max-width: 40rem;
+}
+
+.legend-list {
+  margin: 0;
+  padding: 0;
+  list-style: none;
+  border-radius: 14px;
+  border: 1px solid rgba(201,169,97,0.4);
+  background: linear-gradient(145deg, rgba(23,23,28,0.92), rgba(12,12,15,0.98));
+  box-shadow: 0 14px 36px rgba(0,0,0,0.7);
+}
+
+.legend-item {
+  display: grid;
+  grid-template-columns: 40px minmax(0, 1.3fr) minmax(0, 2fr);
+  gap: 10px;
+  padding: 10px 12px;
+  align-items: center;
+  border-bottom: 1px solid rgba(60,60,70,0.8);
+}
+
+.legend-item:last-child {
+  border-bottom: none;
+}
+
+.legend-swatch {
+  width: 32px;
+  height: 32px;
+  border-radius: 8px;
+  overflow: hidden;
+  border: 1px solid rgba(201,169,97,0.6);
+  box-shadow: 0 10px 24px rgba(0,0,0,0.7);
+  position: relative;
+}
+
+.legend-swatch-inner {
+  position: absolute;
+  inset: 0;
+}
+
+.legend-name {
+  font-family: var(--font-serif);
+  font-size: 12px;
+  letter-spacing: 0.16em;
+  text-transform: uppercase;
+}
+
+.legend-desc {
+  font-size: 12px;
+  color: var(--muted);
+}
+
+/* Animation keyframes from HyperFrames */
+@keyframes fadeUp {
+  from {opacity:0; transform:translateY(28px);}
+  to {opacity:1; transform:none;}
+}
+@keyframes scaleIn {
+  from {opacity:0; transform:scale(.92);}
+  to {opacity:1; transform:none;}
+}
+@keyframes clipReveal {
+  from {clip-path:inset(0 100% 0 0);}
+  to {clip-path:inset(0);}
+}
+@keyframes blurIn {
+  from {opacity:0; filter:blur(12px);}
+  to {opacity:1; filter:blur(0);}
+}
+
+.panel.game-panel {
+  animation: fadeUp 0.7s var(--easing-hero) both;
+}
+.panel.info-panel {
+  animation: fadeUp 0.7s var(--easing-hero) both;
+  animation-delay: 90ms;
+}
+
+/* Accessibility states */
+.card.is-matched {
+  cursor: default;
+}
+.card.disabled {
+  pointer-events: none;
+}
+
+/* Focus outline */
+button:focus-visible,
+.card:focus-visible {
+  outline: 1px solid rgba(255,231,178,0.9);
+  outline-offset: 2px;
+}
+</style>
+</head>
+<body>
+<header class="top-bar">
+  <div class="wordmark">DESIGNER WALLCOVERINGS</div>
+  <div class="top-bar-meta">
+    <span>Pattern Memory Study</span>
+    <span>Muted Luxe Edition</span>
+  </div>
+</header>
+
+<main class="main">
+  <div class="shell">
+    <!-- Game Panel -->
+    <section class="panel game-panel" aria-label="Memory game">
+      <div class="panel-header">
+        <h1 class="panel-title">Pattern Pairing</h1>
+        <div class="panel-subtitle">Match each motif to its twin</div>
+      </div>
+
+      <div class="stats">
+        <div class="stat-block" aria-live="polite">
+          <span class="stat-label">Timer</span>
+          <span class="stat-value" id="time">00:00</span>
+        </div>
+        <div class="stat-block" aria-live="polite">
+          <span class="stat-label">Moves</span>
+          <span class="stat-value" id="moves">0</span>
+        </div>
+        <div class="controls">
+          <button class="btn" id="restartBtn" type="button">
+            <span class="bullet"></span>
+            Restart Layout
+          </button>
+        </div>
+      </div>
+
+      <div class="grid" id="grid" aria-label="Pattern cards"></div>
+
+      <!-- Win overlay -->
+      <div class="win-overlay" id="winOverlay" aria-hidden="true">
+        <div class="win-dialog">
+          <div class="win-label">Collection complete</div>
+          <h2 class="win-title">Wallcovering Suite Mastered</h2>
+          <p class="win-body">
+            You’ve paired each design motif with its perfect counterpart. Consider this your instant upgrade in
+            pattern literacy.
+          </p>
+          <div class="win-metrics">
+            <div>
+              <span class="label">Time</span>
+              <span class="value" id="winTime">00:00</span>
+            </div>
+            <div>
+              <span class="label">Moves</span>
+              <span class="value" id="winMoves">0</span>
+            </div>
+          </div>
+          <button class="btn" id="playAgainBtn" type="button">
+            <span class="bullet"></span>
+            Play Again
+          </button>
+        </div>
+      </div>
+    </section>
+
+    <!-- Info / Legend Panel -->
+    <aside class="panel info-panel" aria-label="Motif legend">
+      <div class="panel-header">
+        <h2 class="panel-title" style="font-size:22px; letter-spacing:0.14em;">Motif Lexicon</h2>
+        <div class="panel-subtitle">Study the signatures</div>
+      </div>
+      <p class="legend-copy">
+        Each pair reveals a distinct wallcovering language—from classical damask to tailored stripe.
+        Note the geometry, movement, and spacing; these are the cues designers read at a glance.
+      </p>
+      <ul class="legend-list">
+        <li class="legend-item">
+          <div class="legend-swatch"><div class="legend-swatch-inner pattern pattern-damask"></div></div>
+          <div class="legend-name">Damask</div>
+          <div class="legend-desc">Ornate, mirrored florals with regal symmetry and a heritage feel.</div>
+        </li>
+        <li class="legend-item">
+          <div class="legend-swatch"><div class="legend-swatch-inner pattern pattern-toile"></div></div>
+          <div class="legend-name">Toile</div>
+          <div class="legend-desc">Delicate scenic narratives in fine linework, often pastoral.</div>
+        </li>
+        <li class="legend-item">
+          <div class="legend-swatch"><div class="legend-swatch-inner pattern pattern-ikat"></div></div>
+          <div class="legend-name">Ikat</div>
+          <div class="legend-desc">Soft, feathered diamonds that suggest hand-dyed threads.</div>
+        </li>
+        <li class="legend-item">
+          <div class="legend-swatch"><div class="legend-swatch-inner pattern pattern-chinoiserie"></div></div>
+          <div class="legend-name">Chinoiserie</div>
+          <div class="legend-desc">Lyrical branches, blossoms, and pagodas—painterly and romantic.</div>
+        </li>
+        <li class="legend-item">
+          <div class="legend-swatch"><div class="legend-swatch-inner pattern pattern-trellis"></div></div>
+          <div class="legend-name">Trellis</div>
+          <div class="legend-desc">Lattice frameworks that feel architectural yet airy.</div>
+        </li>
+        <li class="legend-item">
+          <div class="legend-swatch"><div class="legend-swatch-inner pattern pattern-fret"></div></div>
+          <div class="legend-name">Fret</div>
+          <div class="legend-desc">Interlocking key motifs with strong neoclassical structure.</div>
+        </li>
+        <li class="legend-item">
+          <div class="legend-swatch"><div class="legend-swatch-inner pattern pattern-botanical"></div></div>
+          <div class="legend-name">Botanical</div>
+          <div class="legend-desc">Leafy repeats that bring a softened, organic cadence.</div>
+        </li>
+        <li class="legend-item">
+          <div class="legend-swatch"><div class="legend-swatch-inner pattern pattern-stripe"></div></div>
+          <div class="legend-name">Stripe</div>
+          <div class="legend-desc">Tailored bands that elongate walls and sharpen architecture.</div>
+        </li>
+      </ul>
+    </aside>
+  </div>
+</main>
+
+<script>
+(function() {
+  const motifs = [
+    { name: 'Damask', className: 'pattern-damask' },
+    { name: 'Toile', className: 'pattern-toile' },
+    { name: 'Ikat', className: 'pattern-ikat' },
+    { name: 'Chinoiserie', className: 'pattern-chinoiserie' },
+    { name: 'Trellis', className: 'pattern-trellis' },
+    { name: 'Fret', className: 'pattern-fret' },
+    { name: 'Botanical', className: 'pattern-botanical' },
+    { name: 'Stripe', className: 'pattern-stripe' }
+  ];
+
+  const gridEl = document.getElementById('grid');
+  const movesEl = document.getElementById('moves');
+  const timeEl = document.getElementById('time');
+  const restartBtn = document.getElementById('restartBtn');
+  const winOverlay = document.getElementById('winOverlay');
+  const playAgainBtn = document.getElementById('playAgainBtn');
+  const winTimeEl = document.getElementById('winTime');
+  const winMovesEl = document.getElementById('winMoves');
+
+  let firstCard = null;
+  let secondCard = null;
+  let lockBoard = false;
+  let moves = 0;
+  let matchesFound = 0;
+  let startTime = null;
+  let timerId = null;
+
+  function formatTime(msElapsed) {
+    const totalSec = Math.floor(msElapsed / 1000);
+    const m = String(Math.floor(totalSec / 60)).padStart(2, '0');
+    const s = String(totalSec % 60).padStart(2, '0');
+    return m + ':' + s;
+  }
+
+  function startTimer() {
+    if (timerId) return;
+    startTime = Date.now();
+    timerId = setInterval(() => {
+      const now = Date.now();
+      timeEl.textContent = formatTime(now - startTime);
+    }, 1000);
+  }
+
+  function stopTimer() {
+    if (timerId) {
+      clearInterval(timerId);
+      timerId = null;
+    }
+  }
+
+  function createCard(id, motif) {
+    const card = document.createElement('button');
+    card.type = 'button';
+    card.className = 'card';
+    card.setAttribute('data-id', id);
+    card.setAttribute('data-motif', motif.name);
+    card.setAttribute('aria-label', motif.name + ' motif card');
+    card.setAttribute('aria-pressed', 'false');
+
+    const inner = document.createElement('div');
+    inner.className = 'card-inner';
+
+    const back = document.createElement('div');
+    back.className = 'card-face card-back';
+
+    const front = document.createElement('div');
+    front.className = 'card-face card-front';
+
+    const header = document.createElement('div');
+    header.className = 'card-front-header';
+
+    const nameEl = document.createElement('div');
+    nameEl.className = 'card-front-name';
+    nameEl.textContent = motif.name;
+
+    const tagEl = document.createElement('div');
+    tagEl.className = 'card-front-tag';
+    tagEl.textContent = 'Design Motif';
+
+    header.appendChild(nameEl);
+    header.appendChild(tagEl);
+
+    const swatch = document.createElement('div');
+    swatch.className = 'card-swatch';
+
+    const pattern = document.createElement('div');
+    pattern.className = 'pattern ' + motif.className;
+    swatch.appendChild(pattern);
+
+    front.appendChild(header);
+    front.appendChild(swatch);
+
+    inner.appendChild(back);
+    inner.appendChild(front);
+    card.appendChild(inner);
+
+    card.addEventListener('click', () => handleCardClick(card));
+
+    return card;
+  }
+
+  function shuffle(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]];
+    }
+    return array;
+  }
+
+  function setupBoard() {
+    gridEl.innerHTML = '';
+    firstCard = null;
+    secondCard = null;
+    lockBoard = false;
+    moves = 0;
+    matchesFound = 0;
+    movesEl.textContent = '0';
+    timeEl.textContent = '00:00';
+    stopTimer();
+    startTime = null;
+
+    const deck = [];
+    let id = 0;
+    motifs.forEach(motif => {
+      deck.push(createCard(id++, motif));
+      deck.push(createCard(id++, motif));
+    });
+    shuffle(deck);
+
+    deck.forEach(card => gridEl.appendChild(card));
+  }
+
+  function handleCardClick(card) {
+    if (lockBoard || card.classList.contains('is-flipped') || card.classList.contains('is-matched')) return;
+
+    if (!startTime) {
+      startTimer();
+    }
+
+    card.classList.add('is-flipped');
+    card.setAttribute('aria-pressed', 'true');
+
+    if (!firstCard) {
+      firstCard = card;
+      return;
+    }
+
+    if (card === firstCard) return;
+
+    secondCard = card;
+    moves++;
+    movesEl.textContent = String(moves);
+    checkMatch();
+  }
+
+  function checkMatch() {
+    const isMatch = firstCard.getAttribute('data-motif') === secondCard.getAttribute('data-motif');
+    if (isMatch) {
+      handleMatch();
+    } else {
+      handleMismatch();
+    }
+  }
+
+  function handleMatch() {
+    firstCard.classList.add('is-matched');
+    secondCard.classList.add('is-matched');
+    firstCard.classList.add('disabled');
+    secondCard.classList.add('disabled');
+    matchesFound++;
+    resetTurn();
+
+    if (matchesFound === motifs.length) {
+      endGame();
+    }
+  }
+
+  function handleMismatch() {
+    lockBoard = true;
+    setTimeout(() => {
+      firstCard.classList.remove('is-flipped');
+      secondCard.classList.remove('is-flipped');
+      firstCard.setAttribute('aria-pressed', 'false');
+      secondCard.setAttribute('aria-pressed', 'false');
+      resetTurn();
+    }, 820);
+  }
+
+  function resetTurn() {
+    [firstCard, secondCard] = [null, null];
+    lockBoard = false;
+  }
+
+  function endGame() {
+    stopTimer();
+    const finalTime = startTime ? Date.now() - startTime : 0;
+    winTimeEl.textContent = formatTime(finalTime);
+    winMovesEl.textContent = String(moves);
+    winOverlay.classList.add('is-visible');
+    winOverlay.setAttribute('aria-hidden', 'false');
+  }
+
+  function restartGame() {
+    winOverlay.classList.remove('is-visible');
+    winOverlay.setAttribute('aria-hidden', 'true');
+    setupBoard();
+  }
+
+  restartBtn.addEventListener('click', restartGame);
+  playAgainBtn.addEventListener('click', restartGame);
+
+  setupBoard();
+})();
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/data/artifacts/5410cf08e245/gpt.png b/data/artifacts/5410cf08e245/gpt.png
new file mode 100644
index 0000000..3eab39f
Binary files /dev/null and b/data/artifacts/5410cf08e245/gpt.png differ
diff --git a/data/challenges.json b/data/challenges.json
index 46b4f38..ea81007 100644
--- a/data/challenges.json
+++ b/data/challenges.json
@@ -14606,7 +14606,7 @@
         "thumb": true
       }
     ],
-    "judging": true
+    "judging": false
   },
   {
     "id": "b72f0e9e751b",
@@ -14761,7 +14761,7 @@
         "thumb": true
       }
     ],
-    "judging": true
+    "judging": false
   },
   {
     "id": "d7f4f8ca5f8d",
@@ -14916,7 +14916,7 @@
         "thumb": true
       }
     ],
-    "judging": true,
+    "judging": false,
     "judged_at": null
   },
   {
@@ -15065,7 +15065,7 @@
         "thumb": true
       }
     ],
-    "judging": true
+    "judging": false
   },
   {
     "id": "172f180e3161",
@@ -15166,8 +15166,9 @@
         "thumb": true
       }
     ],
-    "judging": true,
-    "judged_at": null
+    "judging": false,
+    "judged_at": null,
+    "category": "Games"
   },
   {
     "id": "eda6b5e29387",
@@ -15261,7 +15262,8 @@
         "thumb": true
       }
     ],
-    "judging": true
+    "judging": false,
+    "category": "Custom"
   },
   {
     "id": "028885e12558",
@@ -15436,7 +15438,7 @@
         "thumb": true
       }
     ],
-    "judging": true,
+    "judging": false,
     "judged_at": null
   },
   {
@@ -15524,7 +15526,8 @@
         "thumb": true
       }
     ],
-    "judging": true
+    "judging": false,
+    "category": "Custom"
   },
   {
     "id": "6a3a34df3dc6",
@@ -15689,7 +15692,7 @@
         "thumb": true
       }
     ],
-    "judging": true
+    "judging": false
   },
   {
     "id": "689983752ba8",
@@ -15847,7 +15850,7 @@
         "thumb": true
       }
     ],
-    "judging": true,
+    "judging": false,
     "judged_at": null
   },
   {
@@ -15927,7 +15930,8 @@
         "thumb": true
       }
     ],
-    "judging": true
+    "judging": false,
+    "category": "Games"
   },
   {
     "id": "8443d9162963",
@@ -16007,8 +16011,9 @@
         "thumb": true
       }
     ],
-    "judging": true,
-    "judged_at": null
+    "judging": false,
+    "judged_at": null,
+    "category": "Games"
   },
   {
     "id": "6923e6180f0f",
@@ -16154,7 +16159,7 @@
         "thumb": true
       }
     ],
-    "judging": true
+    "judging": false
   },
   {
     "id": "b3721d9fe563",
@@ -16301,7 +16306,7 @@
         "thumb": true
       }
     ],
-    "judging": true
+    "judging": false
   },
   {
     "id": "71a0784e71c8",
@@ -16343,13 +16348,13 @@
       },
       {
         "model": "hermes3-8b",
-        "status": "error",
-        "error": "no HTML document in model output (0 chars)",
+        "status": "queued",
+        "error": null,
         "seconds": 17,
         "cost": null,
-        "started_at": "2026-07-25T08:42:15.481Z",
-        "finished_at": "2026-07-25T08:42:32.683Z",
-        "queued_at": "2026-07-25T08:25:23.397Z",
+        "started_at": null,
+        "finished_at": null,
+        "queued_at": "2026-07-25T08:46:25.711Z",
         "toolCalls": [
           "opendesign",
           "hyperframes",
@@ -16473,7 +16478,7 @@
         "thumb": true
       }
     ],
-    "judging": true,
+    "judging": false,
     "judged_at": null
   },
   {
@@ -16488,33 +16493,37 @@
     "runs": [
       {
         "model": "qwen3-14b",
-        "status": "running",
+        "status": "done",
         "error": null,
-        "seconds": null,
-        "cost": null,
+        "seconds": 56,
+        "cost": 0,
         "started_at": "2026-07-25T08:44:31.327Z",
-        "finished_at": null,
-        "queued_at": "2026-07-25T08:34:13.027Z"
+        "finished_at": "2026-07-25T08:45:27.478Z",
+        "queued_at": "2026-07-25T08:34:13.027Z",
+        "bytes": 5738,
+        "thumb": true
       },
       {
         "model": "gemma3-12b",
-        "status": "queued",
+        "status": "running",
         "error": null,
-        "seconds": null,
+        "seconds": 0,
         "cost": null,
-        "started_at": null,
+        "started_at": "2026-07-25T08:46:22.621Z",
         "finished_at": null,
-        "queued_at": "2026-07-25T08:34:13.034Z"
+        "queued_at": "2026-07-25T08:46:22.560Z",
+        "resumes": 1
       },
       {
         "model": "hermes3-8b",
         "status": "queued",
         "error": null,
-        "seconds": null,
+        "seconds": 0,
         "cost": null,
         "started_at": null,
         "finished_at": null,
-        "queued_at": "2026-07-25T08:34:13.041Z"
+        "queued_at": "2026-07-25T08:46:22.563Z",
+        "resumes": 1
       },
       {
         "model": "qwen25-7b",
@@ -16532,13 +16541,16 @@
         "model": "hf-qwen-coder-32b",
         "status": "queued",
         "error": null,
-        "seconds": null,
+        "seconds": 0,
         "cost": null,
         "started_at": null,
         "finished_at": null,
-        "queued_at": "2026-07-25T08:34:13.051Z"
+        "queued_at": "2026-07-25T08:46:22.566Z",
+        "resumes": 1
       }
-    ]
+    ],
+    "aiPick": null,
+    "category": "Games"
   },
   {
     "id": "6eb0315c9845",
@@ -16553,31 +16565,34 @@
         "model": "qwen3-14b",
         "status": "queued",
         "error": null,
-        "seconds": null,
+        "seconds": 0,
         "cost": null,
         "started_at": null,
         "finished_at": null,
-        "queued_at": "2026-07-25T08:35:55.343Z"
+        "queued_at": "2026-07-25T08:46:22.569Z",
+        "resumes": 1
       },
       {
         "model": "gemma3-12b",
         "status": "queued",
         "error": null,
-        "seconds": null,
+        "seconds": 0,
         "cost": null,
         "started_at": null,
         "finished_at": null,
-        "queued_at": "2026-07-25T08:35:55.352Z"
+        "queued_at": "2026-07-25T08:46:22.572Z",
+        "resumes": 1
       },
       {
         "model": "hermes3-8b",
         "status": "queued",
         "error": null,
-        "seconds": null,
+        "seconds": 0,
         "cost": null,
         "started_at": null,
         "finished_at": null,
-        "queued_at": "2026-07-25T08:35:55.359Z"
+        "queued_at": "2026-07-25T08:46:22.575Z",
+        "resumes": 1
       },
       {
         "model": "qwen25-7b",
@@ -16595,11 +16610,12 @@
         "model": "hf-qwen-coder-32b",
         "status": "queued",
         "error": null,
-        "seconds": null,
+        "seconds": 0,
         "cost": null,
         "started_at": null,
         "finished_at": null,
-        "queued_at": "2026-07-25T08:35:55.371Z"
+        "queued_at": "2026-07-25T08:46:22.578Z",
+        "resumes": 1
       },
       {
         "model": "claude-code",
@@ -16666,7 +16682,8 @@
         "bytes": 19690,
         "thumb": true
       }
-    ]
+    ],
+    "aiPick": null
   },
   {
     "id": "c135c54c4121",
@@ -16682,53 +16699,60 @@
         "model": "qwen3-14b",
         "status": "queued",
         "error": null,
-        "seconds": null,
+        "seconds": 0,
         "cost": null,
         "started_at": null,
         "finished_at": null,
-        "queued_at": "2026-07-25T08:45:15.872Z"
+        "queued_at": "2026-07-25T08:46:22.581Z",
+        "resumes": 1
       },
       {
         "model": "gemma3-12b",
         "status": "queued",
         "error": null,
-        "seconds": null,
+        "seconds": 0,
         "cost": null,
         "started_at": null,
         "finished_at": null,
-        "queued_at": "2026-07-25T08:45:15.878Z"
+        "queued_at": "2026-07-25T08:46:22.584Z",
+        "resumes": 1
       },
       {
         "model": "hermes3-8b",
         "status": "queued",
         "error": null,
-        "seconds": null,
+        "seconds": 0,
         "cost": null,
         "started_at": null,
         "finished_at": null,
-        "queued_at": "2026-07-25T08:45:15.884Z"
+        "queued_at": "2026-07-25T08:46:22.586Z",
+        "resumes": 1
       },
       {
         "model": "qwen25-7b",
         "status": "running",
         "error": null,
-        "seconds": null,
+        "seconds": 0,
         "cost": null,
-        "started_at": "2026-07-25T08:45:15.903Z",
+        "started_at": "2026-07-25T08:46:22.633Z",
         "finished_at": null,
-        "queued_at": "2026-07-25T08:45:15.891Z"
+        "queued_at": "2026-07-25T08:46:22.589Z",
+        "resumes": 1
       },
       {
         "model": "hf-qwen-coder-32b",
         "status": "queued",
         "error": null,
-        "seconds": null,
+        "seconds": 0,
         "cost": null,
         "started_at": null,
         "finished_at": null,
-        "queued_at": "2026-07-25T08:45:15.897Z"
+        "queued_at": "2026-07-25T08:46:22.592Z",
+        "resumes": 1
       }
-    ]
+    ],
+    "aiPick": null,
+    "category": "Games"
   },
   {
     "id": "5410cf08e245",
@@ -16743,92 +16767,109 @@
         "model": "qwen3-14b",
         "status": "queued",
         "error": null,
-        "seconds": null,
+        "seconds": 0,
         "cost": null,
         "started_at": null,
         "finished_at": null,
-        "queued_at": "2026-07-25T08:45:15.963Z"
+        "queued_at": "2026-07-25T08:46:22.596Z",
+        "resumes": 1
       },
       {
         "model": "gemma3-12b",
         "status": "queued",
         "error": null,
-        "seconds": null,
+        "seconds": 0,
         "cost": null,
         "started_at": null,
         "finished_at": null,
-        "queued_at": "2026-07-25T08:45:15.969Z"
+        "queued_at": "2026-07-25T08:46:22.599Z",
+        "resumes": 1
       },
       {
         "model": "hermes3-8b",
         "status": "queued",
         "error": null,
-        "seconds": null,
+        "seconds": 0,
         "cost": null,
         "started_at": null,
         "finished_at": null,
-        "queued_at": "2026-07-25T08:45:15.975Z"
+        "queued_at": "2026-07-25T08:46:22.602Z",
+        "resumes": 1
       },
       {
         "model": "qwen25-7b",
         "status": "queued",
         "error": null,
-        "seconds": null,
+        "seconds": 0,
         "cost": null,
         "started_at": null,
         "finished_at": null,
-        "queued_at": "2026-07-25T08:45:15.978Z"
+        "queued_at": "2026-07-25T08:46:22.605Z",
+        "resumes": 1
       },
       {
         "model": "hf-qwen-coder-32b",
         "status": "queued",
         "error": null,
-        "seconds": null,
+        "seconds": 0,
         "cost": null,
         "started_at": null,
         "finished_at": null,
-        "queued_at": "2026-07-25T08:45:15.981Z"
+        "queued_at": "2026-07-25T08:46:22.608Z",
+        "resumes": 1
       },
       {
         "model": "claude-code",
         "status": "running",
         "error": null,
-        "seconds": null,
+        "seconds": 0,
         "cost": null,
-        "started_at": "2026-07-25T08:45:15.997Z",
+        "started_at": "2026-07-25T08:46:22.637Z",
         "finished_at": null,
-        "queued_at": "2026-07-25T08:45:15.985Z"
+        "queued_at": "2026-07-25T08:46:22.611Z",
+        "resumes": 1
       },
       {
         "model": "kimi",
         "status": "running",
         "error": null,
-        "seconds": null,
+        "seconds": 0,
         "cost": null,
-        "started_at": "2026-07-25T08:45:16.001Z",
+        "started_at": "2026-07-25T08:46:22.643Z",
         "finished_at": null,
-        "queued_at": "2026-07-25T08:45:15.987Z"
+        "queued_at": "2026-07-25T08:46:22.614Z",
+        "resumes": 1
       },
       {
         "model": "gpt",
-        "status": "running",
+        "status": "done",
         "error": null,
-        "seconds": null,
-        "cost": null,
+        "seconds": 54,
+        "cost": 0.1186,
         "started_at": "2026-07-25T08:45:16.006Z",
-        "finished_at": null,
-        "queued_at": "2026-07-25T08:45:15.991Z"
+        "finished_at": "2026-07-25T08:46:10.120Z",
+        "queued_at": "2026-07-25T08:45:15.991Z",
+        "toolCalls": [
+          "opendesign",
+          "opendesign",
+          "hyperframes",
+          "hyperframes"
+        ],
+        "bytes": 26136,
+        "thumb": true
       },
       {
         "model": "grok",
         "status": "running",
         "error": null,
-        "seconds": null,
+        "seconds": 0,
         "cost": null,
-        "started_at": "2026-07-25T08:45:16.010Z",
+        "started_at": "2026-07-25T08:46:22.658Z",
         "finished_at": null,
-        "queued_at": "2026-07-25T08:45:15.994Z"
+        "queued_at": "2026-07-25T08:46:22.617Z",
+        "resumes": 1
       }
-    ]
+    ],
+    "aiPick": null
   }
 ]
\ No newline at end of file
diff --git a/data/costlog.jsonl b/data/costlog.jsonl
index ae7c15e..6539c24 100644
--- a/data/costlog.jsonl
+++ b/data/costlog.jsonl
@@ -234,3 +234,4 @@
 {"ts":"2026-07-25T08:36:36.723Z","provider":"openai","model":"gpt-5.1","task":"model-arena-tools","input_tokens":2727,"output_tokens":5819,"cost_usd":0.086238}
 {"ts":"2026-07-25T08:37:23.677Z","provider":"xai","model":"grok-4.5","task":"model-arena-tools","input_tokens":4922,"output_tokens":7428,"cost_usd":0.126186}
 {"ts":"2026-07-25T08:37:33.195Z","provider":"moonshot","model":"kimi-k2.5","task":"model-arena-tools","input_tokens":4905,"output_tokens":5077,"cost_usd":0.015636}
+{"ts":"2026-07-25T08:46:10.116Z","provider":"openai","model":"gpt-5.1","task":"model-arena-tools","input_tokens":2702,"output_tokens":8132,"cost_usd":0.118577}
diff --git a/server.js b/server.js
index f8f13f9..7500a4a 100644
--- a/server.js
+++ b/server.js
@@ -69,9 +69,13 @@ header h1{font-size:15px;margin:0;font-weight:600}header .by{color:#8a93a0;font-
 // Local ollama models are free and enabled by default. Metered models require
 // their env key AND explicit per-run selection in the UI (never pre-checked).
 const MODELS = [
-  { id: 'qwen3-14b',  label: 'Qwen3 14B',    kind: 'local', host: 'http://localhost:11434',      model: 'qwen3:14b',  estCost: 0, tools: true },
+  // small local models get the design PACK (material injected as text), not the live
+  // tool-calling loop — an 8B/14B is unreliable at function-calling and returned 0 chars
+  // through the tool loop (ALL-MUST-WORK fix, 2026-07-25). Live tool loop stays on the
+  // reliable API models (kimi/gpt/grok) + claude-code.
+  { id: 'qwen3-14b',  label: 'Qwen3 14B',    kind: 'local', host: 'http://localhost:11434',      model: 'qwen3:14b',  estCost: 0 },
   { id: 'gemma3-12b', label: 'Gemma3 12B',   kind: 'local', host: 'http://localhost:11434',      model: 'gemma3:12b', estCost: 0 },
-  { id: 'hermes3-8b', label: 'Hermes3 8B',   kind: 'local', host: 'http://localhost:11434',      model: 'hermes3:8b', estCost: 0, tools: true },
+  { id: 'hermes3-8b', label: 'Hermes3 8B',   kind: 'local', host: 'http://localhost:11434',      model: 'hermes3:8b', estCost: 0 },
   // was Mac1 (192.168.1.133) — that Ollama host wedges (model pinned in VRAM, generations hang);
   // repointed to Mac2-local qwen2.5 for reliable liveness. Set OLLAMA_MAC1=1 to use Mac1 again.
   { id: 'qwen25-7b',  label: 'Qwen2.5 (local)', kind: 'local', host: process.env.OLLAMA_MAC1 ? 'http://192.168.1.133:11434' : 'http://localhost:11434', model: process.env.OLLAMA_MAC1 ? 'qwen2.5:7b' : 'qwen2.5:latest', estCost: 0 },

← 5092bf1 night-loop: cycle 01:45 — judged=71a0784e71c8 · fired 1 →; F  ·  back to Model Arena  ·  Beauty loop: Cost Savings Ticker (referee 9.3 vs designer 3, adc0d82 →