[object Object]

← back to HERMES

demo: head-to-head Hermes-3-8B vs Qwen3:14b on Costa Brava brief

e96ccf98bedb0c29cda1fd291cb8c455f53b811e · 2026-05-10 13:45:42 -0700 · Steve Abrams

Files touched

Diff

commit e96ccf98bedb0c29cda1fd291cb8c455f53b811e
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sun May 10 13:45:42 2026 -0700

    demo: head-to-head Hermes-3-8B vs Qwen3:14b on Costa Brava brief
---
 demo/headtohead.mjs            | 132 ++++++++++++++++++++++++++
 demo/output/hermes3_8b.json    |  84 ++++++++++++++++
 demo/output/hermes3_8b.raw.txt |  50 ++++++++++
 demo/output/index.html         | 211 +++++++++++++++++++++++++++++++++++++++++
 demo/output/qwen3_14b.json     |  83 ++++++++++++++++
 demo/output/qwen3_14b.raw.txt  |  50 ++++++++++
 demo/render.mjs                |  96 +++++++++++++++++++
 7 files changed, 706 insertions(+)

diff --git a/demo/headtohead.mjs b/demo/headtohead.mjs
new file mode 100644
index 0000000..d7253e0
--- /dev/null
+++ b/demo/headtohead.mjs
@@ -0,0 +1,132 @@
+#!/usr/bin/env node
+// Head-to-head: Hermes-3-8B vs Qwen3:14b on a real DW task.
+// Prompt: 5 wallpaper concept briefs for a "Costa Brava" coastal-Spanish-luxury collection.
+// Strict JSON output → measure validity, latency, palette quality.
+
+import fs from 'node:fs';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
+const OUT = path.join(__dirname, 'output');
+fs.mkdirSync(OUT, { recursive: true });
+
+const HOST = process.env.OLLAMA_HOST || 'http://127.0.0.1:11434';
+
+const SYSTEM = `You are a senior wallpaper designer at Designer Wallcoverings.
+You speak in tight, editorial copy — the way a Vogue feature writes about an interior.
+You return STRICT JSON only. No prose, no markdown fences, no commentary.
+Schema:
+{
+  "collection": "string",
+  "concepts": [
+    {
+      "name": "string (2-3 words, evocative)",
+      "hero_hex": "#RRGGBB",
+      "palette": ["#RRGGBB", "#RRGGBB", "#RRGGBB"],
+      "motif": "string (one sentence)",
+      "room": "string (single room type)",
+      "tagline": "string (max 8 words)",
+      "tier": "Studio | Atelier | Bespoke"
+    }
+  ]
+}`;
+
+const USER = `Brief: Designer Wallcoverings is launching the COSTA BRAVA collection — coastal Spanish luxury, sun-bleached terracotta and Mediterranean blue, hand-block prints reinterpreted for 2026 interiors. Target client: hospitality + high-end residential.
+
+Generate exactly 5 distinct wallpaper concepts. Each must have a unique hero_hex and a palette that genuinely complements it. Names should evoke place, not be generic. Taglines must SELL — not describe.
+
+Return strict JSON only.`;
+
+async function callOllama(model, system, user) {
+  const t0 = Date.now();
+  const r = await fetch(`${HOST}/api/chat`, {
+    method: 'POST',
+    headers: { 'Content-Type': 'application/json' },
+    body: JSON.stringify({
+      model,
+      stream: false,
+      format: 'json',
+      options: { temperature: 0.7, num_ctx: 4096, num_predict: 1500 },
+      messages: [
+        { role: 'system', content: system },
+        { role: 'user', content: user },
+      ],
+    }),
+  });
+  const j = await r.json();
+  const ms = Date.now() - t0;
+  return {
+    model,
+    ms,
+    raw: j.message?.content ?? '',
+    eval_count: j.eval_count,
+    prompt_eval_count: j.prompt_eval_count,
+  };
+}
+
+function tryParse(raw) {
+  try { return { ok: true, data: JSON.parse(raw) }; }
+  catch (e) {
+    const m = raw.match(/\{[\s\S]*\}/);
+    if (m) { try { return { ok: true, data: JSON.parse(m[0]), salvaged: true }; } catch {} }
+    return { ok: false, error: e.message };
+  }
+}
+
+function validate(data) {
+  const issues = [];
+  if (!data?.concepts || !Array.isArray(data.concepts)) {
+    return { issues: ['no concepts array'], valid: 0, total: 0 };
+  }
+  const total = data.concepts.length;
+  let valid = 0;
+  for (const c of data.concepts) {
+    const ok =
+      typeof c.name === 'string' && c.name.trim().length > 0 &&
+      /^#[0-9a-fA-F]{6}$/.test(c.hero_hex || '') &&
+      Array.isArray(c.palette) && c.palette.length >= 3 &&
+      c.palette.every(h => /^#[0-9a-fA-F]{6}$/.test(h)) &&
+      typeof c.motif === 'string' &&
+      typeof c.tagline === 'string' &&
+      (c.tagline.split(/\s+/).filter(Boolean).length <= 8) &&
+      ['Studio', 'Atelier', 'Bespoke'].includes(c.tier);
+    if (ok) valid++; else issues.push(`bad concept: ${JSON.stringify(c).slice(0, 80)}…`);
+  }
+  return { issues, valid, total };
+}
+
+console.log('→ pinging both models in parallel…');
+const [hermes, qwen] = await Promise.all([
+  callOllama('hermes3:8b', SYSTEM, USER),
+  callOllama('qwen3:14b', SYSTEM, USER),
+]);
+
+for (const r of [hermes, qwen]) {
+  const slug = r.model.replace(/[^a-z0-9]+/gi, '_');
+  fs.writeFileSync(path.join(OUT, `${slug}.raw.txt`), r.raw);
+  const p = tryParse(r.raw);
+  const v = p.ok ? validate(p.data) : { issues: [p.error], valid: 0, total: 0 };
+  const summary = {
+    model: r.model,
+    latency_ms: r.ms,
+    tokens_out: r.eval_count,
+    tokens_in: r.prompt_eval_count,
+    parsed_ok: p.ok,
+    salvaged: !!p.salvaged,
+    valid_concepts: v.valid,
+    total_concepts: v.total,
+    issues: v.issues,
+    data: p.ok ? p.data : null,
+  };
+  fs.writeFileSync(path.join(OUT, `${slug}.json`), JSON.stringify(summary, null, 2));
+  console.log(`\n[${r.model}]  ${r.ms}ms  parsed=${p.ok}  valid=${v.valid}/${v.total}  tokens=${r.eval_count}`);
+  if (p.ok && p.data?.concepts) {
+    for (const c of p.data.concepts) {
+      console.log(`   ${c.hero_hex || '------'}  ${(c.name || '?').padEnd(22)}  ${c.tagline || ''}`);
+    }
+  }
+}
+
+console.log('\n✓ outputs written to demo/output/');
+console.log('  hermes3_8b.json     qwen3_14b.json');
diff --git a/demo/output/hermes3_8b.json b/demo/output/hermes3_8b.json
new file mode 100644
index 0000000..ba76775
--- /dev/null
+++ b/demo/output/hermes3_8b.json
@@ -0,0 +1,84 @@
+{
+  "model": "hermes3:8b",
+  "latency_ms": 134943,
+  "tokens_out": 570,
+  "tokens_in": 278,
+  "parsed_ok": true,
+  "salvaged": false,
+  "valid_concepts": 3,
+  "total_concepts": 5,
+  "issues": [
+    "bad concept: {\"name\":\"Terra del Sol\",\"hero_hex\":\"#FFA853\",\"palette\":[\"#8B4513\",\"#F5DEB3\",\"#CD…",
+    "bad concept: {\"name\":\"Mediterranean Tapestry\",\"hero_hex\":\"#8FBC8B\",\"palette\":[\"#FFFFE0\",\"#7CF…"
+  ],
+  "data": {
+    "collection": "COSTA BRAVA",
+    "concepts": [
+      {
+        "name": "Terra del Sol",
+        "hero_hex": "#FFA853",
+        "palette": [
+          "#8B4513",
+          "#F5DEB3",
+          "#CD853"
+        ],
+        "motif": "Sun-bleached terracotta and warm golden accents evoke the sun-soaked shores of Costa Brava.",
+        "room": "Living Room",
+        "tagline": "Surrender to the golden hues of Spain's Mediterranean paradise.",
+        "tier": "Atelier"
+      },
+      {
+        "name": "Blue Horizons",
+        "hero_hex": "#1E90FF",
+        "palette": [
+          "#ADD8E6",
+          "#90EE90",
+          "#F5DEB3"
+        ],
+        "motif": "Luminous blues and soft greens capture the tranquility of Costa Brava's coastal skies.",
+        "room": "Bedroom",
+        "tagline": "Escape to a haven of azure serenity.",
+        "tier": "Studio"
+      },
+      {
+        "name": "Mediterranean Tapestry",
+        "hero_hex": "#8FBC8B",
+        "palette": [
+          "#FFFFE0",
+          "#7CFC00",
+          "#32CD32"
+        ],
+        "motif": "Hand-blocked prints interweave vibrant flora and marina motifs in a celebration of Costa Brava's natural beauty.",
+        "room": "Dining Room",
+        "tagline": "Indulge in the lush tapestry of Spain's coastal jewel.",
+        "tier": "Atelier"
+      },
+      {
+        "name": "Cobblestone Charm",
+        "hero_hex": "#A0522D",
+        "palette": [
+          "#8B0000",
+          "#FFDB58",
+          "#F5DEB3"
+        ],
+        "motif": "Rich terracotta hues and warm accents mirror the charm of Costa Brava's quaint cobblestoned streets.",
+        "room": "Entryway",
+        "tagline": "Embrace the warmth of Spain's cobblestone havens.",
+        "tier": "Studio"
+      },
+      {
+        "name": "Sapphire Siesta",
+        "hero_hex": "#0F52BA",
+        "palette": [
+          "#ADD8E6",
+          "#B0E0E6",
+          "#87CEEB"
+        ],
+        "motif": "Deep sapphire blues and gentle pastels evoke the serene siestas of Costa Brava's shores.",
+        "room": "Bathroom",
+        "tagline": "Dive into the depths of Spain's coastal tranquility.",
+        "tier": "Atelier"
+      }
+    ]
+  }
+}
\ No newline at end of file
diff --git a/demo/output/hermes3_8b.raw.txt b/demo/output/hermes3_8b.raw.txt
new file mode 100644
index 0000000..c75fcb5
--- /dev/null
+++ b/demo/output/hermes3_8b.raw.txt
@@ -0,0 +1,50 @@
+{
+  "collection": "COSTA BRAVA",
+  "concepts": [
+    {
+      "name": "Terra del Sol",
+      "hero_hex": "#FFA853",
+      "palette": ["#8B4513", "#F5DEB3", "#CD853"],
+      "motif": "Sun-bleached terracotta and warm golden accents evoke the sun-soaked shores of Costa Brava.",
+      "room": "Living Room",
+      "tagline": "Surrender to the golden hues of Spain's Mediterranean paradise.",
+      "tier": "Atelier"
+    },
+    {
+      "name": "Blue Horizons",
+      "hero_hex": "#1E90FF",
+      "palette": ["#ADD8E6", "#90EE90", "#F5DEB3"],
+      "motif": "Luminous blues and soft greens capture the tranquility of Costa Brava's coastal skies.",
+      "room": "Bedroom",
+      "tagline": "Escape to a haven of azure serenity.",
+      "tier": "Studio"
+    },
+    {
+      "name": "Mediterranean Tapestry",
+      "hero_hex": "#8FBC8B",
+      "palette": ["#FFFFE0", "#7CFC00", "#32CD32"],
+      "motif": "Hand-blocked prints interweave vibrant flora and marina motifs in a celebration of Costa Brava's natural beauty.",
+      "room": "Dining Room",
+      "tagline": "Indulge in the lush tapestry of Spain's coastal jewel.",
+      "tier": "Atelier"
+    },
+    {
+      "name": "Cobblestone Charm",
+      "hero_hex": "#A0522D",
+      "palette": ["#8B0000", "#FFDB58", "#F5DEB3"],
+      "motif": "Rich terracotta hues and warm accents mirror the charm of Costa Brava's quaint cobblestoned streets.",
+      "room": "Entryway",
+      "tagline": "Embrace the warmth of Spain's cobblestone havens.",
+      "tier": "Studio"
+    },
+    {
+      "name": "Sapphire Siesta",
+      "hero_hex": "#0F52BA",
+      "palette": ["#ADD8E6", "#B0E0E6", "#87CEEB"],
+      "motif": "Deep sapphire blues and gentle pastels evoke the serene siestas of Costa Brava's shores.",
+      "room": "Bathroom",
+      "tagline": "Dive into the depths of Spain's coastal tranquility.",
+      "tier": "Atelier"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/demo/output/index.html b/demo/output/index.html
new file mode 100644
index 0000000..669f61e
--- /dev/null
+++ b/demo/output/index.html
@@ -0,0 +1,211 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<title>HERMES vs QWEN3 — Costa Brava brief</title>
+<style>
+  :root { --bg:#0e0e10; --panel:#15151a; --ink:#f5f0e8; --mute:#9b9591; --rule:#272528; --gold:#c9a96a; }
+  *{box-sizing:border-box}
+  body{margin:0;background:var(--bg);color:var(--ink);font:14px/1.5 -apple-system,'SF Pro Text',sans-serif;padding:32px}
+  h1{font:300 36px/1.1 'SF Pro Display',serif;letter-spacing:.02em;margin:0 0 4px}
+  h1 b{color:var(--gold);font-weight:500}
+  .lead{color:var(--mute);margin:0 0 28px;max-width:800px}
+  .lead code{background:#1c1c20;padding:2px 6px;border-radius:3px;color:var(--gold);font-size:12px}
+  .cols{display:grid;grid-template-columns:1fr 1fr;gap:24px}
+  .col{background:var(--panel);border:1px solid var(--rule);border-radius:6px;padding:20px}
+  .col-head{display:flex;justify-content:space-between;align-items:baseline;border-bottom:1px solid var(--rule);padding-bottom:14px;margin-bottom:18px;gap:12px;flex-wrap:wrap}
+  .col-head h2{margin:0;font:500 20px 'SF Pro Display',sans-serif;letter-spacing:.04em}
+  .stats{display:flex;gap:14px;font-size:11px;color:var(--mute);text-transform:uppercase;letter-spacing:.08em}
+  .stat b{color:var(--ink);font-weight:600;font-size:13px;letter-spacing:0;text-transform:none}
+  .stat.ok b{color:#7ad27a}
+  .stat.bad b{color:#e26d6d}
+  .grid{display:flex;flex-direction:column;gap:14px}
+  .concept{display:grid;grid-template-columns:160px 1fr;border:1px solid var(--rule);border-radius:4px;overflow:hidden}
+  .hero{position:relative;aspect-ratio:1;display:flex;flex-direction:column;justify-content:flex-end;padding:10px}
+  .palette{display:flex;gap:0;margin-bottom:auto;padding-top:6px}
+  .palette span{flex:1;height:18px;display:block;border:1px solid rgba(0,0,0,.15)}
+  .hex{font:600 11px/1 'SF Mono',monospace;letter-spacing:.05em;color:rgba(0,0,0,.65);background:rgba(255,255,255,.85);padding:3px 6px;border-radius:2px;align-self:flex-start}
+  .meta{padding:14px 16px;display:flex;flex-direction:column;gap:6px}
+  .meta h3{margin:0;font:500 16px 'SF Pro Display',sans-serif;letter-spacing:.02em}
+  .tier{display:inline-block;font:500 9px/1 'SF Pro Text';letter-spacing:.12em;text-transform:uppercase;color:var(--gold);border:1px solid var(--gold);padding:3px 6px;border-radius:2px;margin-left:6px;vertical-align:1px}
+  .tag{margin:2px 0 0;font-style:italic;color:var(--ink)}
+  .motif{margin:4px 0 0;color:var(--mute);font-size:13px}
+  .room{margin:2px 0 0;font-size:11px;color:var(--mute);text-transform:uppercase;letter-spacing:.08em}
+  .room span{color:var(--gold)}
+  footer{margin-top:28px;padding-top:18px;border-top:1px solid var(--rule);color:var(--mute);font-size:12px}
+</style>
+</head>
+<body>
+  <h1>Costa Brava — <b>HERMES vs QWEN3</b></h1>
+  <p class="lead">Same brief, same JSON schema, both models running locally on Mac2 Ollama. Strict-valid means the concept passed the entire schema gate (hex format, palette length, tagline ≤8 words, tier in {Studio, Atelier, Bespoke}). Run with <code>node demo/headtohead.mjs && node demo/render.mjs</code>.</p>
+  <div class="cols">
+    
+  <section class="col">
+    <header class="col-head">
+      <h2>Hermes-3-Llama-3.1-8B</h2>
+      <div class="stats">
+        <span class="stat"><b>134943</b>ms</span>
+        <span class="stat"><b>570</b> tok out</span>
+        <span class="stat"><b>3/5</b> strict-valid</span>
+        <span class="stat ok">JSON ✓</span>
+      </div>
+    </header>
+    <div class="grid">
+  <article class="concept" style="--hero:#FFA853">
+    <div class="hero" style="background:#FFA853">
+      <div class="palette">
+        <span style="background:#8B4513" title="#8B4513"></span><span style="background:#F5DEB3" title="#F5DEB3"></span><span style="background:#CD853" title="#CD853"></span>
+      </div>
+      <div class="hex">#FFA853</div>
+    </div>
+    <div class="meta">
+      <h3>Terra del Sol <span class="tier">Atelier</span></h3>
+      <p class="tag">"Surrender to the golden hues of Spain's Mediterranean paradise."</p>
+      <p class="motif">Sun-bleached terracotta and warm golden accents evoke the sun-soaked shores of Costa Brava.</p>
+      <p class="room"><span>Best for:</span> Living Room</p>
+    </div>
+  </article>
+  <article class="concept" style="--hero:#1E90FF">
+    <div class="hero" style="background:#1E90FF">
+      <div class="palette">
+        <span style="background:#ADD8E6" title="#ADD8E6"></span><span style="background:#90EE90" title="#90EE90"></span><span style="background:#F5DEB3" title="#F5DEB3"></span>
+      </div>
+      <div class="hex">#1E90FF</div>
+    </div>
+    <div class="meta">
+      <h3>Blue Horizons <span class="tier">Studio</span></h3>
+      <p class="tag">"Escape to a haven of azure serenity."</p>
+      <p class="motif">Luminous blues and soft greens capture the tranquility of Costa Brava's coastal skies.</p>
+      <p class="room"><span>Best for:</span> Bedroom</p>
+    </div>
+  </article>
+  <article class="concept" style="--hero:#8FBC8B">
+    <div class="hero" style="background:#8FBC8B">
+      <div class="palette">
+        <span style="background:#FFFFE0" title="#FFFFE0"></span><span style="background:#7CFC00" title="#7CFC00"></span><span style="background:#32CD32" title="#32CD32"></span>
+      </div>
+      <div class="hex">#8FBC8B</div>
+    </div>
+    <div class="meta">
+      <h3>Mediterranean Tapestry <span class="tier">Atelier</span></h3>
+      <p class="tag">"Indulge in the lush tapestry of Spain's coastal jewel."</p>
+      <p class="motif">Hand-blocked prints interweave vibrant flora and marina motifs in a celebration of Costa Brava's natural beauty.</p>
+      <p class="room"><span>Best for:</span> Dining Room</p>
+    </div>
+  </article>
+  <article class="concept" style="--hero:#A0522D">
+    <div class="hero" style="background:#A0522D">
+      <div class="palette">
+        <span style="background:#8B0000" title="#8B0000"></span><span style="background:#FFDB58" title="#FFDB58"></span><span style="background:#F5DEB3" title="#F5DEB3"></span>
+      </div>
+      <div class="hex">#A0522D</div>
+    </div>
+    <div class="meta">
+      <h3>Cobblestone Charm <span class="tier">Studio</span></h3>
+      <p class="tag">"Embrace the warmth of Spain's cobblestone havens."</p>
+      <p class="motif">Rich terracotta hues and warm accents mirror the charm of Costa Brava's quaint cobblestoned streets.</p>
+      <p class="room"><span>Best for:</span> Entryway</p>
+    </div>
+  </article>
+  <article class="concept" style="--hero:#0F52BA">
+    <div class="hero" style="background:#0F52BA">
+      <div class="palette">
+        <span style="background:#ADD8E6" title="#ADD8E6"></span><span style="background:#B0E0E6" title="#B0E0E6"></span><span style="background:#87CEEB" title="#87CEEB"></span>
+      </div>
+      <div class="hex">#0F52BA</div>
+    </div>
+    <div class="meta">
+      <h3>Sapphire Siesta <span class="tier">Atelier</span></h3>
+      <p class="tag">"Dive into the depths of Spain's coastal tranquility."</p>
+      <p class="motif">Deep sapphire blues and gentle pastels evoke the serene siestas of Costa Brava's shores.</p>
+      <p class="room"><span>Best for:</span> Bathroom</p>
+    </div>
+  </article></div>
+  </section>
+    
+  <section class="col">
+    <header class="col-head">
+      <h2>Qwen3:14b</h2>
+      <div class="stats">
+        <span class="stat"><b>141247</b>ms</span>
+        <span class="stat"><b>591</b> tok out</span>
+        <span class="stat"><b>4/5</b> strict-valid</span>
+        <span class="stat ok">JSON ✓</span>
+      </div>
+    </header>
+    <div class="grid">
+  <article class="concept" style="--hero:#D2B48C">
+    <div class="hero" style="background:#D2B48C">
+      <div class="palette">
+        <span style="background:#4A5568" title="#4A5568"></span><span style="background:#F8F9FA" title="#F8F9FA"></span><span style="background:#A06660" title="#A06660"></span>
+      </div>
+      <div class="hex">#D2B48C</div>
+    </div>
+    <div class="meta">
+      <h3>Cala Blanca <span class="tier">Atelier</span></h3>
+      <p class="tag">"Where the sea’s whisper meets the villa’s embrace."</p>
+      <p class="motif">Sun-bleached terracotta tiles fractured by wave-like ripples in cobalt blue.</p>
+      <p class="room"><span>Best for:</span> living room</p>
+    </div>
+  </article>
+  <article class="concept" style="--hero:#B87333">
+    <div class="hero" style="background:#B87333">
+      <div class="palette">
+        <span style="background:#E6E6FA" title="#E6E6FA"></span><span style="background:#D2B48C" title="#D2B48C"></span><span style="background:#8B4513" title="#8B4513"></span>
+      </div>
+      <div class="hex">#B87333</div>
+    </div>
+    <div class="meta">
+      <h3>Plaza del Sol <span class="tier">Bespoke</span></h3>
+      <p class="tag">"Feast where the Mediterranean pulses with life."</p>
+      <p class="motif">Hand-blocked ochre and saffron patterns mimic wrought-iron balconies over sun-drenched cobblestones.</p>
+      <p class="room"><span>Best for:</span> dining room</p>
+    </div>
+  </article>
+  <article class="concept" style="--hero:#5E919D">
+    <div class="hero" style="background:#5E919D">
+      <div class="palette">
+        <span style="background:#F5F5DC" title="#F5F5DC"></span><span style="background:#708090" title="#708090"></span><span style="background:#1E90FF" title="#1E90FF"></span>
+      </div>
+      <div class="hex">#5E919D</div>
+    </div>
+    <div class="meta">
+      <h3>Caminito Azul <span class="tier">Studio</span></h3>
+      <p class="tag">"Wake to the rhythm of the ocean’s breath."</p>
+      <p class="motif">Driftwood silhouettes float across a teal-and-sand palette, evoking coastal footpaths.</p>
+      <p class="room"><span>Best for:</span> bedroom</p>
+    </div>
+  </article>
+  <article class="concept" style="--hero:#C19A6B">
+    <div class="hero" style="background:#C19A6B">
+      <div class="palette">
+        <span style="background:#F0E68C" title="#F0E68C"></span><span style="background:#A0522D" title="#A0522D"></span><span style="background:#FFF8DC" title="#FFF8DC"></span>
+      </div>
+      <div class="hex">#C19A6B</div>
+    </div>
+    <div class="meta">
+      <h3>Villa de la Luz <span class="tier">Atelier</span></h3>
+      <p class="tag">"Step into a legend woven by centuries of light."</p>
+      <p class="motif">Lace-like motifs in amber and terracotta echo Andalusian lacework on sun-faded walls.</p>
+      <p class="room"><span>Best for:</span> entryway</p>
+    </div>
+  </article>
+  <article class="concept" style="--hero:#2F4F4F">
+    <div class="hero" style="background:#2F4F4F">
+      <div class="palette">
+        <span style="background:#87CEEB" title="#87CEEB"></span><span style="background:#F5DEB3" title="#F5DEB3"></span><span style="background:#FFFFFF" title="#FFFFFF"></span>
+      </div>
+      <div class="hex">#2F4F4F</div>
+    </div>
+    <div class="meta">
+      <h3>Acantus Cliffs <span class="tier">Bespoke</span></h3>
+      <p class="tag">"Bask in the luxury of a cliffside sanctuary."</p>
+      <p class="motif">Bold cobalt acanthus leaves climb a limestone background, reimagined as a cliffside fresco.</p>
+      <p class="room"><span>Best for:</span> bathroom</p>
+    </div>
+  </article></div>
+  </section>
+  </div>
+  <footer>Generated 2026-05-10T20:44:09.112Z · ~/Projects/HERMES/demo · prompt + raw outputs in demo/output/</footer>
+</body>
+</html>
\ No newline at end of file
diff --git a/demo/output/qwen3_14b.json b/demo/output/qwen3_14b.json
new file mode 100644
index 0000000..2acc77a
--- /dev/null
+++ b/demo/output/qwen3_14b.json
@@ -0,0 +1,83 @@
+{
+  "model": "qwen3:14b",
+  "latency_ms": 141247,
+  "tokens_out": 591,
+  "tokens_in": 704,
+  "parsed_ok": true,
+  "salvaged": false,
+  "valid_concepts": 4,
+  "total_concepts": 5,
+  "issues": [
+    "bad concept: {\"name\":\"Villa de la Luz\",\"hero_hex\":\"#C19A6B\",\"palette\":[\"#F0E68C\",\"#A0522D\",\"#…"
+  ],
+  "data": {
+    "collection": "COSTA BRAVA",
+    "concepts": [
+      {
+        "name": "Cala Blanca",
+        "hero_hex": "#D2B48C",
+        "palette": [
+          "#4A5568",
+          "#F8F9FA",
+          "#A06660"
+        ],
+        "motif": "Sun-bleached terracotta tiles fractured by wave-like ripples in cobalt blue.",
+        "room": "living room",
+        "tagline": "Where the sea’s whisper meets the villa’s embrace.",
+        "tier": "Atelier"
+      },
+      {
+        "name": "Plaza del Sol",
+        "hero_hex": "#B87333",
+        "palette": [
+          "#E6E6FA",
+          "#D2B48C",
+          "#8B4513"
+        ],
+        "motif": "Hand-blocked ochre and saffron patterns mimic wrought-iron balconies over sun-drenched cobblestones.",
+        "room": "dining room",
+        "tagline": "Feast where the Mediterranean pulses with life.",
+        "tier": "Bespoke"
+      },
+      {
+        "name": "Caminito Azul",
+        "hero_hex": "#5E919D",
+        "palette": [
+          "#F5F5DC",
+          "#708090",
+          "#1E90FF"
+        ],
+        "motif": "Driftwood silhouettes float across a teal-and-sand palette, evoking coastal footpaths.",
+        "room": "bedroom",
+        "tagline": "Wake to the rhythm of the ocean’s breath.",
+        "tier": "Studio"
+      },
+      {
+        "name": "Villa de la Luz",
+        "hero_hex": "#C19A6B",
+        "palette": [
+          "#F0E68C",
+          "#A0522D",
+          "#FFF8DC"
+        ],
+        "motif": "Lace-like motifs in amber and terracotta echo Andalusian lacework on sun-faded walls.",
+        "room": "entryway",
+        "tagline": "Step into a legend woven by centuries of light.",
+        "tier": "Atelier"
+      },
+      {
+        "name": "Acantus Cliffs",
+        "hero_hex": "#2F4F4F",
+        "palette": [
+          "#87CEEB",
+          "#F5DEB3",
+          "#FFFFFF"
+        ],
+        "motif": "Bold cobalt acanthus leaves climb a limestone background, reimagined as a cliffside fresco.",
+        "room": "bathroom",
+        "tagline": "Bask in the luxury of a cliffside sanctuary.",
+        "tier": "Bespoke"
+      }
+    ]
+  }
+}
\ No newline at end of file
diff --git a/demo/output/qwen3_14b.raw.txt b/demo/output/qwen3_14b.raw.txt
new file mode 100644
index 0000000..267ac1a
--- /dev/null
+++ b/demo/output/qwen3_14b.raw.txt
@@ -0,0 +1,50 @@
+{
+  "collection": "COSTA BRAVA",
+  "concepts": [
+    {
+      "name": "Cala Blanca",
+      "hero_hex": "#D2B48C",
+      "palette": ["#4A5568", "#F8F9FA", "#A06660"],
+      "motif": "Sun-bleached terracotta tiles fractured by wave-like ripples in cobalt blue.",
+      "room": "living room",
+      "tagline": "Where the sea’s whisper meets the villa’s embrace.",
+      "tier": "Atelier"
+    },
+    {
+      "name": "Plaza del Sol",
+      "hero_hex": "#B87333",
+      "palette": ["#E6E6FA", "#D2B48C", "#8B4513"],
+      "motif": "Hand-blocked ochre and saffron patterns mimic wrought-iron balconies over sun-drenched cobblestones.",
+      "room": "dining room",
+      "tagline": "Feast where the Mediterranean pulses with life.",
+      "tier": "Bespoke"
+    },
+    {
+      "name": "Caminito Azul",
+      "hero_hex": "#5E919D",
+      "palette": ["#F5F5DC", "#708090", "#1E90FF"],
+      "motif": "Driftwood silhouettes float across a teal-and-sand palette, evoking coastal footpaths.",
+      "room": "bedroom",
+      "tagline": "Wake to the rhythm of the ocean’s breath.",
+      "tier": "Studio"
+    },
+    {
+      "name": "Villa de la Luz",
+      "hero_hex": "#C19A6B",
+      "palette": ["#F0E68C", "#A0522D", "#FFF8DC"],
+      "motif": "Lace-like motifs in amber and terracotta echo Andalusian lacework on sun-faded walls.",
+      "room": "entryway",
+      "tagline": "Step into a legend woven by centuries of light.",
+      "tier": "Atelier"
+    },
+    {
+      "name": "Acantus Cliffs",
+      "hero_hex": "#2F4F4F",
+      "palette": ["#87CEEB", "#F5DEB3", "#FFFFFF"],
+      "motif": "Bold cobalt acanthus leaves climb a limestone background, reimagined as a cliffside fresco.",
+      "room": "bathroom",
+      "tagline": "Bask in the luxury of a cliffside sanctuary.",
+      "tier": "Bespoke"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/demo/render.mjs b/demo/render.mjs
new file mode 100644
index 0000000..9c26bfc
--- /dev/null
+++ b/demo/render.mjs
@@ -0,0 +1,96 @@
+#!/usr/bin/env node
+// Render a side-by-side HTML page from headtohead output JSON.
+import fs from 'node:fs';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
+const OUT = path.join(__dirname, 'output');
+
+const hermes = JSON.parse(fs.readFileSync(path.join(OUT, 'hermes3_8b.json'), 'utf8'));
+const qwen   = JSON.parse(fs.readFileSync(path.join(OUT, 'qwen3_14b.json'), 'utf8'));
+
+const card = (c) => `
+  <article class="concept" style="--hero:${c.hero_hex || '#888'}">
+    <div class="hero" style="background:${c.hero_hex || '#888'}">
+      <div class="palette">
+        ${(c.palette || []).map(h => `<span style="background:${h}" title="${h}"></span>`).join('')}
+      </div>
+      <div class="hex">${c.hero_hex || '—'}</div>
+    </div>
+    <div class="meta">
+      <h3>${c.name || '—'} <span class="tier">${c.tier || ''}</span></h3>
+      <p class="tag">"${c.tagline || ''}"</p>
+      <p class="motif">${c.motif || ''}</p>
+      <p class="room"><span>Best for:</span> ${c.room || ''}</p>
+    </div>
+  </article>`;
+
+const column = (label, run) => {
+  const concepts = run.data?.concepts || [];
+  return `
+  <section class="col">
+    <header class="col-head">
+      <h2>${label}</h2>
+      <div class="stats">
+        <span class="stat"><b>${run.latency_ms}</b>ms</span>
+        <span class="stat"><b>${run.tokens_out ?? '—'}</b> tok out</span>
+        <span class="stat"><b>${run.valid_concepts}/${run.total_concepts}</b> strict-valid</span>
+        <span class="stat ${run.parsed_ok ? 'ok' : 'bad'}">${run.parsed_ok ? 'JSON ✓' : 'JSON ✗'}</span>
+      </div>
+    </header>
+    <div class="grid">${concepts.map(card).join('')}</div>
+  </section>`;
+};
+
+const html = `<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<title>HERMES vs QWEN3 — Costa Brava brief</title>
+<style>
+  :root { --bg:#0e0e10; --panel:#15151a; --ink:#f5f0e8; --mute:#9b9591; --rule:#272528; --gold:#c9a96a; }
+  *{box-sizing:border-box}
+  body{margin:0;background:var(--bg);color:var(--ink);font:14px/1.5 -apple-system,'SF Pro Text',sans-serif;padding:32px}
+  h1{font:300 36px/1.1 'SF Pro Display',serif;letter-spacing:.02em;margin:0 0 4px}
+  h1 b{color:var(--gold);font-weight:500}
+  .lead{color:var(--mute);margin:0 0 28px;max-width:800px}
+  .lead code{background:#1c1c20;padding:2px 6px;border-radius:3px;color:var(--gold);font-size:12px}
+  .cols{display:grid;grid-template-columns:1fr 1fr;gap:24px}
+  .col{background:var(--panel);border:1px solid var(--rule);border-radius:6px;padding:20px}
+  .col-head{display:flex;justify-content:space-between;align-items:baseline;border-bottom:1px solid var(--rule);padding-bottom:14px;margin-bottom:18px;gap:12px;flex-wrap:wrap}
+  .col-head h2{margin:0;font:500 20px 'SF Pro Display',sans-serif;letter-spacing:.04em}
+  .stats{display:flex;gap:14px;font-size:11px;color:var(--mute);text-transform:uppercase;letter-spacing:.08em}
+  .stat b{color:var(--ink);font-weight:600;font-size:13px;letter-spacing:0;text-transform:none}
+  .stat.ok b{color:#7ad27a}
+  .stat.bad b{color:#e26d6d}
+  .grid{display:flex;flex-direction:column;gap:14px}
+  .concept{display:grid;grid-template-columns:160px 1fr;border:1px solid var(--rule);border-radius:4px;overflow:hidden}
+  .hero{position:relative;aspect-ratio:1;display:flex;flex-direction:column;justify-content:flex-end;padding:10px}
+  .palette{display:flex;gap:0;margin-bottom:auto;padding-top:6px}
+  .palette span{flex:1;height:18px;display:block;border:1px solid rgba(0,0,0,.15)}
+  .hex{font:600 11px/1 'SF Mono',monospace;letter-spacing:.05em;color:rgba(0,0,0,.65);background:rgba(255,255,255,.85);padding:3px 6px;border-radius:2px;align-self:flex-start}
+  .meta{padding:14px 16px;display:flex;flex-direction:column;gap:6px}
+  .meta h3{margin:0;font:500 16px 'SF Pro Display',sans-serif;letter-spacing:.02em}
+  .tier{display:inline-block;font:500 9px/1 'SF Pro Text';letter-spacing:.12em;text-transform:uppercase;color:var(--gold);border:1px solid var(--gold);padding:3px 6px;border-radius:2px;margin-left:6px;vertical-align:1px}
+  .tag{margin:2px 0 0;font-style:italic;color:var(--ink)}
+  .motif{margin:4px 0 0;color:var(--mute);font-size:13px}
+  .room{margin:2px 0 0;font-size:11px;color:var(--mute);text-transform:uppercase;letter-spacing:.08em}
+  .room span{color:var(--gold)}
+  footer{margin-top:28px;padding-top:18px;border-top:1px solid var(--rule);color:var(--mute);font-size:12px}
+</style>
+</head>
+<body>
+  <h1>Costa Brava — <b>HERMES vs QWEN3</b></h1>
+  <p class="lead">Same brief, same JSON schema, both models running locally on Mac2 Ollama. Strict-valid means the concept passed the entire schema gate (hex format, palette length, tagline ≤8 words, tier in {Studio, Atelier, Bespoke}). Run with <code>node demo/headtohead.mjs && node demo/render.mjs</code>.</p>
+  <div class="cols">
+    ${column('Hermes-3-Llama-3.1-8B', hermes)}
+    ${column('Qwen3:14b', qwen)}
+  </div>
+  <footer>Generated ${new Date().toISOString()} · ~/Projects/HERMES/demo · prompt + raw outputs in demo/output/</footer>
+</body>
+</html>`;
+
+const outPath = path.join(OUT, 'index.html');
+fs.writeFileSync(outPath, html);
+console.log(`✓ wrote ${outPath}`);

← 9e5e8cd initial scaffold: HERMES project for Hermes-3-Llama-3.1-8B v  ·  back to HERMES  ·  snapshot: 2 file(s) changed, +2 new 5b1199f →