← 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
A demo/headtohead.mjsA demo/output/hermes3_8b.jsonA demo/output/hermes3_8b.raw.txtA demo/output/index.htmlA demo/output/qwen3_14b.jsonA demo/output/qwen3_14b.raw.txtA demo/render.mjs
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 →