diff --git a/site/_tests/01-tide-podcast/brief.md b/site/_tests/01-tide-podcast/brief.md new file mode 100644 index 0000000..f56a59f --- /dev/null +++ b/site/_tests/01-tide-podcast/brief.md @@ -0,0 +1,42 @@ +# Test 01 — Tide (indie podcast) + +## The prompt + +> "build me a landing page for my indie podcast called Tide. just go ahead, you pick." + +## Context gate — skipped + +The user opted out of the gate. The skill must state its inferences in one sentence at the top of its reply. + +**Going with:** *audience = listeners who care about voice and atmosphere · use = listen + subscribe · tone = intimate, considered, voice-led.* If any of those is wrong, redirect. + +## Domain inference + +`podcast` → audio domain. From `references/structure.md`'s domain trio table: **Photographic / Quote-Led / Letter** are the three suggested macrostructures. + +The skill picks **Quote-Led** because the medium is voice — a pull-quote from a hypothetical listener carries the weight a stat or a feature grid couldn't. + +## Theme + +No theme requested. Picking **Atelier** — italic Cormorant-style display, calm cream paper, generous whitespace. Audio podcasts inhabit a quiet listening posture; Atelier matches. + +## Enrichment + +Typography only. The hero is a quote. Reaching for a Lottie loop, an illustration, or a stock-podcaster photo would dilute the voice. + +## Macrostructure stamp + +``` +/* Hallmark · macrostructure: Quote-Led · H3 hero knobs: weight=italic display, attribution=under quote, length=80–160 chars + * theme: Atelier · accent: terracotta ~2% · enrichment: none (typography only) + * studied: no · context: skipped, inferred (audio domain) + */ +``` + +## What the page does + +- Italic display pull-quote at the top, no headline above +- Listener attribution in small caps below +- One paragraph of host-voice copy below the quote +- Three thin platform links (Apple / Spotify / RSS) — typographic only, no platform icons (icon-set tell) +- Footer: a single dense line, monospace diff --git a/site/_tests/01-tide-podcast/index.html b/site/_tests/01-tide-podcast/index.html new file mode 100644 index 0000000..7a684dd --- /dev/null +++ b/site/_tests/01-tide-podcast/index.html @@ -0,0 +1,45 @@ + + + + + + Tide — a podcast about the things that come back + + + + +
+

Tide · Episode 14 · listening from anywhere

+ +
+ I started listening on a long bus ride. By the third episode I'd missed my stop, and I didn't mind. +
+ +

— A listener · Lisbon · 2026

+ +

+ Tide is a small fortnightly podcast about the things in life that keep coming back — old letters, slow recipes, the way a song sounds different in winter. Half-hour episodes, hosted by Mira Aoki. New episode every other Tuesday. +

+ +
+ Apple Podcasts + · + Spotify + · + Overcast + · + RSS +
+
+ + + + diff --git a/site/_tests/01-tide-podcast/style.css b/site/_tests/01-tide-podcast/style.css new file mode 100644 index 0000000..d94d29a --- /dev/null +++ b/site/_tests/01-tide-podcast/style.css @@ -0,0 +1,153 @@ +/* Hallmark · macrostructure: Quote-Led · H3 hero knobs: weight=italic display, attribution=under quote, length=80–160 chars + * theme: Atelier · accent: terracotta ~2% · enrichment: none (typography only) + * studied: no · context: skipped, inferred (audio domain) + */ + +@import url("https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,400;0,6..72,500;1,6..72,400;1,6..72,500&display=swap"); + +:root { + --paper: oklch(94% 0.005 60); + --paper-2: oklch(91% 0.006 60); + --rule: oklch(82% 0.008 60); + --rule-2: oklch(70% 0.010 60); + --muted: oklch(48% 0.012 60); + --ink-2: oklch(22% 0.020 40); + --ink: oklch(12% 0.024 40); + --accent: oklch(45% 0.13 60); + + --serif: "Newsreader", "Tiempos Headline", ui-serif, Georgia, serif; + --label: "JetBrains Mono", ui-monospace, monospace; + --space-xs: 0.5rem; + --space-sm: 0.75rem; + --space-md: 1rem; + --space-lg: 1.5rem; + --space-xl: 2.5rem; + --space-2xl: 4rem; + --space-3xl: 6.5rem; + --rule-hair: 0.5px; + --ease-out: cubic-bezier(0.16, 1, 0.3, 1); +} + +* { box-sizing: border-box; margin: 0; padding: 0; } + +html { + font-family: var(--serif); + font-size: 17px; + line-height: 1.5; + color: var(--ink); + background: var(--paper); + -webkit-font-smoothing: antialiased; +} + +body { + min-height: 100dvh; + display: grid; + grid-template-rows: 1fr auto; + padding-inline: clamp(1.5rem, 6vw, 4rem); +} + +.fold { + display: grid; + align-content: center; + max-width: 38rem; + margin: 0 auto; + padding-block: var(--space-3xl); +} + +.eyebrow { + font-family: var(--label); + font-size: 0.6875rem; + letter-spacing: 0.16em; + text-transform: uppercase; + color: var(--muted); + margin-block-end: var(--space-2xl); + display: inline-flex; + align-items: center; + gap: 0.6em; +} +.eyebrow::before { + content: ""; + width: 18px; + height: 1px; + background: var(--accent); + display: inline-block; +} + +.quote { + font-family: var(--serif); + font-style: italic; + font-weight: 400; + font-size: clamp(2rem, 4vw + 1rem, 3.6rem); + line-height: 1.12; + letter-spacing: -0.012em; + color: var(--ink); + margin-block-end: var(--space-xl); +} + +.quote::before { content: "“"; } +.quote::after { content: "”"; } + +.attribution { + font-family: var(--label); + font-size: 0.6875rem; + letter-spacing: 0.16em; + text-transform: uppercase; + color: var(--muted); + margin-block-end: var(--space-2xl); +} + +.body { + font-size: 1.0625rem; + line-height: 1.65; + color: var(--ink-2); + margin-block-end: var(--space-2xl); + max-width: 36rem; +} + +.body em { font-style: italic; } + +.platforms { + display: flex; + flex-wrap: wrap; + gap: var(--space-lg); + font-family: var(--label); + font-size: 0.8125rem; + letter-spacing: 0.04em; +} + +.platforms a { + color: var(--ink); + text-decoration: none; + background-image: linear-gradient(var(--accent), var(--accent)); + background-repeat: no-repeat; + background-position: 0 calc(100% - 1px); + background-size: 100% 1px; + padding-block-end: 0.1em; + transition: background-size 200ms var(--ease-out); +} +.platforms a:hover { background-size: 100% 2px; } + +.platforms .sep { + color: var(--rule-2); + user-select: none; +} + +footer { + border-block-start: var(--rule-hair) solid var(--rule); + padding-block: var(--space-lg); + font-family: var(--label); + font-size: 0.75rem; + letter-spacing: 0.06em; + color: var(--muted); + display: flex; + flex-wrap: wrap; + align-items: center; + gap: var(--space-md); +} + +footer .colophon { color: var(--ink); } +footer .sep { color: var(--rule-2); } + +@media (max-width: 38rem) { + .quote { font-size: clamp(1.75rem, 6vw + 0.5rem, 2.5rem); } +} diff --git a/site/_tests/02-streampipe-cli/brief.md b/site/_tests/02-streampipe-cli/brief.md new file mode 100644 index 0000000..64e4b40 --- /dev/null +++ b/site/_tests/02-streampipe-cli/brief.md @@ -0,0 +1,42 @@ +# Test 02 — Streampipe (open-source CLI) + +## The prompt + +> "Make a docs landing for an open-source CLI called Streampipe. It does stream parsing for log/event pipelines. Use the Terminal theme. Audience: backend developers. Use case: install the tool and read the docs. Tone: technical, terse." + +## Context gate — fully answered + +The user provided audience + use + tone. No inference needed. + +## Theme — explicitly requested + +**Terminal**: dark phosphor-on-black, monospace throughout, no animations, square edges. + +## Macrostructure + +`docs / CLI / open-source / developer` → from the domain table: **Workbench / Long Document / Component Playground**. The skill picks **Workbench** because the brief is a docs landing — it asks the page to walk the user through the tool, not just announce it. + +## Enrichment + +A small Tier-A pure-CSS terminal mockup as the hero — `$ streampipe parse access.log --filter status=5xx | jq` rendered in monospace with a phosphor caret. No real terminal capture. No image. Custom-built. + +The decision is *not* "add a Lottie loop of a terminal typing"; that would be the Lottie shortcut. Pure CSS art does this cleaner. + +## Macrostructure stamp + +``` +/* Hallmark · macrostructure: Workbench · F2 sticky-scroll knobs: pinned=right, content=code, steps=3 + * theme: Terminal · accent: phosphor-green ~6% (functional, not decorative) · enrichment: E1 hero — pure-CSS terminal mockup (Tier A) + * studied: no · context: explicit + */ +``` + +## What the page does + +- Hero: monospace headline `$ streampipe --help` + a CSS-art terminal output mockup +- Install row: three install commands (npm, brew, curl) as inline copy blocks +- Three numbered feature blocks (1.0 / 2.0 / 3.0) — what it does, in plain language +- Spec sheet (F3) for flags +- Footer: dense colophon + +No animations. Square edges. Underlined links. Quiet phosphor accent only on prompts and link underlines. diff --git a/site/_tests/02-streampipe-cli/index.html b/site/_tests/02-streampipe-cli/index.html new file mode 100644 index 0000000..ac52df4 --- /dev/null +++ b/site/_tests/02-streampipe-cli/index.html @@ -0,0 +1,89 @@ + + + + + + streampipe — a small CLI for stream parsing + + + + + + + +
+
+

$ streampipe
--help

+

A small, fast, single-binary CLI for parsing log and event streams from stdin. Filter, transform, route. Composes with anything that emits lines.

+
+ // install +
$brew install streampipe
+
$npm i -g @streampipe/cli
+
$curl -sSL streampipe.dev/install.sh | sh
+
+
+ +
+$ streampipe parse access.log --filter status=5xx --out ndjson
+opening access.log (62 MB)…
+scanning 412,309 lines…
+match: status ∈ {500, 502, 503, 504}
+{"ts":"2026-04-30T10:14:22Z","status":503,"path":"/api/v2/jobs"}
+{"ts":"2026-04-30T10:14:24Z","status":502,"path":"/api/v2/users/49"}
+{"ts":"2026-04-30T10:14:31Z","status":500,"path":"/api/v2/uploads"}
+{"ts":"2026-04-30T10:14:33Z","status":503,"path":"/api/v2/jobs"}
+… 1,184 more
+duration: 0.42s · throughput: 982k lines/s
+$ 
+
+ +
+ 1.0 / parse +
+

Read anything that emits lines.

+

Files, pipes, sockets, kubectl logs. Streampipe reads from stdin by default; --from takes a path or URL. Detects format on the first 100 lines (json, ndjson, syslog, common, custom regex).

+
+
+ +
+ 2.0 / filter +
+

Express filters in a small language, not in regex.

+

Filters compile to a typed predicate AST: status >= 500, duration_ms > 200 and path ~ "/api/", host in {a, b, c}. No quoting hell, no shell-specific escaping.

+
+
--filter
predicate expression
repeatable
+
--from
file path, URL, or `-` for stdin
default: stdin
+
--out
ndjson · csv · text · table
default: ndjson
+
--at
truncate after N records
optional
+
--debug
show parse stats
optional
+
+
+
+ +
+ 3.0 / route +
+

Compose with anything that takes lines.

+

Streampipe is line-oriented all the way through. Pipe its output into jq, gron, vmctl, kafkacat, or your own thing. No daemon, no agent, no config file unless you want one.

+
+
+ + + + + diff --git a/site/_tests/02-streampipe-cli/style.css b/site/_tests/02-streampipe-cli/style.css new file mode 100644 index 0000000..21e8be5 --- /dev/null +++ b/site/_tests/02-streampipe-cli/style.css @@ -0,0 +1,239 @@ +/* Hallmark · macrostructure: Workbench · F2 sticky-scroll knobs: pinned=right, content=code, steps=3 + * theme: Terminal · accent: phosphor-green ~6% (functional, not decorative) · enrichment: E1 hero — pure-CSS terminal mockup (Tier A) + * studied: no · context: explicit + */ + +@import url("https://fonts.googleapis.com/css2?family=Geist+Mono:wght@400;500&display=swap"); + +:root { + --paper: oklch(11% 0.018 145); /* deep cool dark, slight green */ + --paper-2: oklch(15% 0.020 145); + --paper-3: oklch(20% 0.020 145); + --rule: oklch(28% 0.015 145); + --rule-2: oklch(40% 0.025 145); + --muted: oklch(58% 0.025 145); + --ink-2: oklch(82% 0.020 145); + --ink: oklch(94% 0.012 145); + --accent: oklch(78% 0.19 138); /* phosphor green */ + --accent-2: oklch(86% 0.16 138); + + --mono: "Geist Mono", "JetBrains Mono", ui-monospace, monospace; + --space-xs: 0.5rem; + --space-sm: 0.75rem; + --space-md: 1rem; + --space-lg: 1.5rem; + --space-xl: 2.5rem; + --space-2xl: 4rem; + --space-3xl: 6rem; + + --rule-hair: 0.5px; + --rule-fine: 1px; +} + +* { box-sizing: border-box; margin: 0; padding: 0; } + +html { + font-family: var(--mono); + font-size: 14px; + line-height: 1.55; + color: var(--ink-2); + background: var(--paper); + -webkit-font-smoothing: antialiased; +} + +body { + min-height: 100dvh; + padding-inline: clamp(1.5rem, 5vw, 4rem); + padding-block: var(--space-2xl); + max-width: 76rem; + margin: 0 auto; +} + +.nav { + display: flex; + justify-content: space-between; + align-items: baseline; + padding-block: var(--space-md); + border-block-end: var(--rule-hair) solid var(--rule); + margin-block-end: var(--space-3xl); +} +.nav .wordmark { color: var(--ink); } +.nav .wordmark::before { content: "$ "; color: var(--accent); } +.nav__links { display: flex; gap: var(--space-lg); } +.nav__links a { + color: var(--muted); + text-decoration: none; + text-underline-offset: 4px; +} +.nav__links a:hover { color: var(--ink); text-decoration: underline; } + +/* Hero — headline + CSS-art terminal mockup */ +.hero { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--space-2xl); + align-items: start; + margin-block-end: var(--space-3xl); + padding-block-end: var(--space-2xl); + border-block-end: var(--rule-hair) solid var(--rule); +} + +.hero__headline { + font-family: var(--mono); + font-size: clamp(1.75rem, 3vw + 0.5rem, 2.75rem); + font-weight: 500; + letter-spacing: -0.005em; + color: var(--ink); + line-height: 1.1; +} +.hero__headline .prompt { color: var(--accent); } + +.hero__lede { + margin-block-start: var(--space-lg); + color: var(--ink-2); + max-width: 40ch; +} + +.hero__cta { + margin-block-start: var(--space-xl); + display: flex; + flex-direction: column; + gap: var(--space-sm); +} +.hero__cta-label { + color: var(--muted); + font-size: 0.75rem; + letter-spacing: 0.06em; + text-transform: uppercase; +} +.cmd { + background: var(--paper-2); + border: var(--rule-hair) solid var(--rule); + padding: var(--space-md) var(--space-lg); + color: var(--ink); + display: flex; + align-items: center; + gap: var(--space-md); +} +.cmd .prompt { color: var(--accent); user-select: none; } + +/* CSS-art terminal mockup — pure CSS, no images, no Lottie */ +.term { + background: var(--paper-3); + border: var(--rule-hair) solid var(--rule-2); + font-family: var(--mono); + font-size: 0.8125rem; + line-height: 1.7; + padding: var(--space-md) var(--space-lg); + color: var(--ink-2); + display: grid; + gap: 0.05rem; + position: relative; + overflow: hidden; +} +.term::before { + content: ""; + position: absolute; + top: 0; left: 0; right: 0; + height: 28px; + background: var(--paper-2); + border-block-end: var(--rule-hair) solid var(--rule); +} +.term::after { + content: "streampipe — 80×24"; + position: absolute; + top: 6px; left: 12px; + font-size: 0.6875rem; + color: var(--muted); + letter-spacing: 0.04em; +} +.term { padding-block-start: 2.6rem; } + +.term .ln { display: block; white-space: pre; } +.term .prompt { color: var(--accent); } +.term .flag { color: var(--accent-2); } +.term .num { color: var(--ink); font-weight: 500; } +.term .meta { color: var(--muted); } +.term .caret { + display: inline-block; + width: 0.55em; + height: 1em; + background: var(--accent); + vertical-align: -0.15em; + margin-inline-start: 0.05em; + animation: blink 1.05s steps(2) infinite; +} +@keyframes blink { to { background: transparent; } } +@media (prefers-reduced-motion: reduce) { + .term .caret { animation: none; } +} + +/* Section heads — left-margin numbered (Workbench style) */ +.section { + display: grid; + grid-template-columns: 6rem 1fr; + gap: var(--space-lg); + margin-block-end: var(--space-3xl); + padding-block-end: var(--space-2xl); + border-block-end: var(--rule-hair) solid var(--rule); + align-items: baseline; +} + +.section__num { + font-family: var(--mono); + font-size: 0.8125rem; + color: var(--muted); + letter-spacing: 0.06em; +} +.section__num span { color: var(--accent); } + +.section__title { + font-family: var(--mono); + font-size: 1.25rem; + font-weight: 500; + color: var(--ink); + margin-block-end: var(--space-md); + letter-spacing: -0.005em; +} +.section__body { color: var(--ink-2); max-width: 60ch; } +.section__body code { color: var(--accent-2); background: transparent; } + +/* Spec sheet (F3) — flags */ +.spec { + display: grid; + grid-template-columns: 12rem 1fr 1fr; + gap: var(--space-md); + font-family: var(--mono); + font-size: 0.8125rem; + margin-block-start: var(--space-lg); +} +.spec > * { + padding-block: var(--space-sm); + border-block-start: var(--rule-hair) solid var(--rule); +} +.spec dt { + color: var(--accent-2); +} +.spec dd { margin: 0; color: var(--ink-2); } +.spec .meta { color: var(--muted); } + +/* Footer — dense colophon */ +footer { + font-family: var(--mono); + font-size: 0.75rem; + line-height: 1.7; + color: var(--muted); + white-space: pre-wrap; + padding-block: var(--space-2xl); + border-block-start: var(--rule-hair) solid var(--rule); +} +footer .ink { color: var(--ink); } +footer a { color: var(--ink-2); text-decoration: underline; text-underline-offset: 4px; } + +@media (max-width: 56rem) { + .hero { grid-template-columns: 1fr; } + .section { grid-template-columns: 1fr; } + .section__num { color: var(--accent); } + .spec { grid-template-columns: 8rem 1fr; } + .spec .meta { display: none; } +} diff --git a/site/_tests/03-maple-bakery/brief.md b/site/_tests/03-maple-bakery/brief.md new file mode 100644 index 0000000..496fdb6 --- /dev/null +++ b/site/_tests/03-maple-bakery/brief.md @@ -0,0 +1,47 @@ +# Test 03 — Maple Street Bread (artisan bakery) + +## The prompt + +> "Landing page for Maple Street Bread. Audience: locals who want to buy bread. Use: see what's available + visit. Tone: warm, hand-set, considered." + +## Context gate — fully answered + +Audience, use, tone all explicit. No inference needed. + +## Domain inference + +`bakery / kitchen / café / atelier + craft brief` → from the domain table: **Photographic / Long Document / Catalogue**. + +The skill picks **Long Document**. The bakery is a story-led brand — there's an owner, a process, a daily rhythm — and a Long Document treats that as prose first, with the menu as a quiet aside. Catalogue (a uniform grid of breads) was the runner-up; Long Document wins because the *narrative* is the differentiator from a corporate bakery chain. + +## Theme + +No theme requested. Picking **Linen** — warm beige paper, plain serif, hanging headings, generous space. Linen is the only theme that reads as "shop in a real neighbourhood". Salon would be too formal; Garden too literal. + +## Enrichment + +**E5 Custom Illustration Centerpiece, Tier B (hand-built SVG).** The bakery brief is the canonical example for going custom — a hand-drawn loaf in 60 lines of SVG, three paths, with a `@property`-driven subtle breathing animation. + +The decision is *not* to pull a Storyset bakery illustration; that would be the library shortcut. *Not* a Lottie of a baker; that's the Lottie shortcut. *Not* a Midjourney bread photograph; raw output reads as AI. **Hand-built is the right tier here.** + +## Macrostructure stamp + +``` +/* Hallmark · macrostructure: Long Document · H5 hero knobs: salutation=time-stamp, body=2 paragraphs, signoff=initials + * theme: Linen · accent: warm-amber ~3% + * enrichment: E5 Custom Illustration · craft: tier-B hand-built SVG (3 paths, 58 lines) + * animation: @property --rise · 6s alternate · reduced-motion: static + * studied: no · context: explicit + */ +``` + +## What the page does + +- A time-stamped salutation ("Saturday, 6:14 a.m.") instead of a brand name banner — the bakery introduces itself as a moment in the day +- A two-paragraph letter-style body about who bakes and what's baked +- A hand-drawn SVG loaf, animated with a slow breath +- A small handwritten-feel "today's loaves" list as marginalia +- Address + hours in italic at the bottom +- No buttons, no CTA chip, no "Order online" call. Just a phone number, a street address, and an open-hours range. + +The page is small. It's supposed to be. diff --git a/site/_tests/03-maple-bakery/index.html b/site/_tests/03-maple-bakery/index.html new file mode 100644 index 0000000..7dc3384 --- /dev/null +++ b/site/_tests/03-maple-bakery/index.html @@ -0,0 +1,85 @@ + + + + + + Maple Street Bread — sourdough, baked overnight, sold fresh + + + + + +

Maple Street · est. 2026 · n.º 47

+ +
+ +
+

Saturday, 6:14 a.m.

+ +

The dough went in at midnight. By the time the lights are on outside, the bench is dusted, the loaves are scored, and the oven is hotter than a summer roof. We bake what we baked yesterday and what we'll bake tomorrow — sourdough, slow, by hand, on stone — because that's the bread we wanted to eat when we moved here ten years ago and couldn't find any.

+ +

The shop opens at seven. There are usually thirty loaves and they're usually gone by noon. We don't do online orders. We don't deliver. If you want a loaf, walk over. Bring a bag.

+ +
+ + + + + +

Plate 47 · scored before the proof

+
+ +

The oven runs on local oak. The flour is from a mill three hours west. The starter is from a baker in Évora who taught us in 2014 and is still alive. None of these are marketing claims; they are how the bread happens.

+ +

+ Thank you for walking over,
+ — H. & N. +

+
+ + + +
+ + + + + diff --git a/site/_tests/03-maple-bakery/style.css b/site/_tests/03-maple-bakery/style.css new file mode 100644 index 0000000..3895109 --- /dev/null +++ b/site/_tests/03-maple-bakery/style.css @@ -0,0 +1,253 @@ +/* Hallmark · macrostructure: Long Document · H5 hero knobs: salutation=time-stamp, body=2 paragraphs, signoff=initials + * theme: Linen · accent: warm-amber ~3% + * enrichment: E5 Custom Illustration · craft: tier-B hand-built SVG (3 paths, 58 lines) + * animation: @property --rise · 6s alternate · reduced-motion: static + * studied: no · context: explicit + */ + +@import url("https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,400;0,6..72,500;1,6..72,400;1,6..72,500&display=swap"); + +:root { + --paper: oklch(89% 0.022 95); + --paper-2: oklch(86% 0.024 95); + --rule: oklch(78% 0.020 95); + --rule-2: oklch(66% 0.024 95); + --muted: oklch(46% 0.022 90); + --ink-2: oklch(22% 0.025 90); + --ink: oklch(15% 0.025 90); + --accent: oklch(54% 0.16 50); /* warm amber */ + --crust: oklch(72% 0.16 55); + --crust-deep: oklch(48% 0.14 38); + + --serif: "Newsreader", "Tiempos", ui-serif, Georgia, serif; + --label: ui-monospace, "JetBrains Mono", monospace; + + --space-xs: 0.5rem; + --space-sm: 0.75rem; + --space-md: 1rem; + --space-lg: 1.5rem; + --space-xl: 2.5rem; + --space-2xl: 4rem; + --space-3xl: 7rem; + + --rule-hair: 0.5px; +} + +@property --rise { + syntax: ""; + initial-value: 0px; + inherits: false; +} + +@property --bake { + syntax: ""; + initial-value: 0%; + inherits: false; +} + +* { box-sizing: border-box; margin: 0; padding: 0; } + +html { + font-family: var(--serif); + font-size: 17px; + line-height: 1.65; + color: var(--ink-2); + background: var(--paper); + -webkit-font-smoothing: antialiased; +} + +body { + min-height: 100dvh; + padding-inline: clamp(1.5rem, 6vw, 5rem); + padding-block: var(--space-3xl) var(--space-2xl); + max-width: 64rem; + margin: 0 auto; +} + +.eyebrow { + font-family: var(--label); + font-size: 0.75rem; + letter-spacing: 0.16em; + text-transform: uppercase; + color: var(--muted); + margin-block-end: var(--space-2xl); +} + +.layout { + display: grid; + grid-template-columns: 7fr 4fr; + gap: var(--space-3xl); + align-items: start; +} + +@media (max-width: 56rem) { + .layout { grid-template-columns: 1fr; gap: var(--space-2xl); } +} + +.salutation { + font-family: var(--serif); + font-style: italic; + font-weight: 400; + font-size: clamp(2.25rem, 4vw + 1rem, 3.6rem); + line-height: 1.1; + letter-spacing: -0.018em; + color: var(--ink); + margin-block-end: var(--space-xl); +} + +.letter p { + font-size: 1.0625rem; + line-height: 1.72; + margin-block-end: var(--space-md); + max-width: 36rem; +} + +.letter p:first-of-type::first-letter { + font-family: var(--serif); + font-size: 3.6em; + font-weight: 500; + line-height: 0.9; + float: left; + margin-block-start: 0.08em; + margin-inline-end: 0.1em; + color: var(--accent); +} + +.signoff { + margin-block-start: var(--space-xl); + font-family: var(--serif); + font-style: italic; + color: var(--muted); +} + +.signoff strong { + display: block; + font-style: normal; + font-weight: 500; + color: var(--ink); + margin-block-start: 0.2em; + font-size: 1.125rem; +} + +/* The aside — today's loaves + visit */ +.aside { + font-family: var(--serif); + font-size: 0.9375rem; + line-height: 1.65; + color: var(--ink-2); + border-inline-start: var(--rule-hair) solid var(--rule); + padding-inline-start: var(--space-lg); + position: sticky; + top: var(--space-2xl); +} + +@media (max-width: 56rem) { + .aside { border-inline-start: 0; padding-inline-start: 0; padding-block-start: var(--space-xl); border-block-start: var(--rule-hair) solid var(--rule); position: static; } +} + +.aside h3 { + font-family: var(--label); + font-size: 0.75rem; + letter-spacing: 0.16em; + text-transform: uppercase; + color: var(--muted); + font-weight: 400; + margin-block: var(--space-xl) var(--space-md); +} + +.aside h3:first-child { margin-block-start: 0; } + +.aside ul { + list-style: none; + display: grid; + gap: 0.4em; +} + +.aside li { + display: flex; + justify-content: space-between; + gap: var(--space-md); + font-style: italic; +} + +.aside li .price { + font-style: normal; + font-variant-numeric: tabular-nums; + color: var(--muted); + font-family: var(--label); + font-size: 0.8125rem; +} + +.aside p { + font-style: italic; + color: var(--ink-2); +} + +.aside .phone { + font-family: var(--label); + font-style: normal; + font-size: 0.875rem; + color: var(--ink); +} + +/* The loaf — hand-built SVG centerpiece */ +.loaf-wrap { + margin-block: var(--space-2xl) var(--space-xl); + text-align: center; +} + +.loaf-svg { + width: 100%; + max-width: 22rem; + height: auto; + display: block; + margin: 0 auto; + transform: translateY(var(--rise)); + animation: rise 6s ease-in-out infinite alternate; + filter: drop-shadow(0 14px 18px oklch(28% 0.04 50 / 0.12)); +} + +@keyframes rise { to { --rise: -4px; } } + +.loaf-body { fill: var(--crust); } +.loaf-shade { fill: var(--crust-deep); opacity: 0.18; } +.loaf-score { + stroke: var(--crust-deep); + stroke-width: 2.5; + stroke-linecap: round; + fill: none; + stroke-dasharray: 0 240; + animation: score 1.6s 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards; +} +@keyframes score { to { stroke-dasharray: 240 240; } } + +.loaf-cap { + font-family: var(--label); + font-size: 0.75rem; + letter-spacing: 0.14em; + text-transform: uppercase; + color: var(--muted); + margin-block-start: var(--space-md); +} + +@media (prefers-reduced-motion: reduce) { + .loaf-svg { animation: none; --rise: 0px; } + .loaf-score { animation: none; stroke-dasharray: 240 240; } +} + +footer { + margin-block-start: var(--space-3xl); + padding-block: var(--space-lg); + border-block-start: var(--rule-hair) solid var(--rule); + font-family: var(--label); + font-size: 0.75rem; + letter-spacing: 0.06em; + color: var(--muted); + display: flex; + flex-wrap: wrap; + align-items: center; + gap: var(--space-md); +} + +footer .ink { color: var(--ink); } +footer .sep { color: var(--rule-2); } diff --git a/site/_tests/04-meridian-manifesto/brief.md b/site/_tests/04-meridian-manifesto/brief.md new file mode 100644 index 0000000..c7a9b16 --- /dev/null +++ b/site/_tests/04-meridian-manifesto/brief.md @@ -0,0 +1,49 @@ +# Test 04 — Meridian (studio manifesto) + +## The prompt + +> "Make me a manifesto for my new studio called Meridian. We work on environmental products. No flashy stuff." + +## Context gate — partial + +User gave audience-implied (people who care about environmental products) and tone (declarative, no flash). Skill infers the rest: + +**Going with:** *audience = potential clients and collaborators · use = read our position · tone = declarative, polemical, restrained.* + +## Domain inference + +`manifesto / cause / advocacy` → from the domain table: **Manifesto / Quote-Led / Stat-Led**. + +The skill picks **Manifesto** (the brief literally names it). This is the rare case where the macrostructure name and the brief word are the same — which is fine, because Manifesto-the-macrostructure is genuinely a *page shape*, not a default we should run from. + +## Theme + +The user said "no flashy stuff" — that's the strongest possible cue against ornament. Picking **Manifesto** the theme too: pure black paper, oversized solid type, single red accent, no gradients, no rounded corners. The theme name + macrostructure name aligning is honest here, not lazy. + +(Salon, Studio, Pastel would all be wrong tonally. Brutal would have worked but is a touch louder.) + +## Enrichment + +**None.** Typography is the design. The page makes its point in five short declarations and stops. + +The slop test catches: no abstract background gradient, no Lottie loop, no illustration, no demo video. The voice is the page. + +## Macrostructure stamp + +``` +/* Hallmark · macrostructure: Manifesto · H1 hero knobs: size=xxl, alignment=left-bias, underlay=none + * theme: Manifesto · accent: red ~5% (used as bleed dividers, not flood) + * enrichment: none (typography only — voice is the design) + * studied: no · context: partial, inferred (audience + use) + */ +``` + +## What the page does + +- Five short declarations stacked vertically, each on its own page-fold-sized band +- A single red bleed-colour band between the third and fourth declaration as the only visual ornament +- Numbered "I." through "V." in display weight on the left margin of each declaration +- A signed colophon at the bottom: studio name, year, three signatories +- No links. No CTA. No "Learn more". A manifesto is not a marketing page. + +The page is mostly black. It is supposed to be. diff --git a/site/_tests/04-meridian-manifesto/index.html b/site/_tests/04-meridian-manifesto/index.html new file mode 100644 index 0000000..6c7d7d2 --- /dev/null +++ b/site/_tests/04-meridian-manifesto/index.html @@ -0,0 +1,63 @@ + + + + + + Meridian — a manifesto + + + + + +
+ Meridian + 2026 · A MANIFESTO · IN FIVE PARTS +
+ +
+

WE ARE A STUDIO. WE ARE NOT A PLATFORM.

+

— a position, signed by three of us, on the practice of building environmental products in 2026.

+
+ +
+ I. +

We design products that last twelve years. We do not design products that need replacing every two.

+
+ +
+ II. +

A material is not "sustainable" because the brochure says so. A material is sustainable because someone, somewhere, can repair it.

+
+ +
+ III. +

We do not believe in growth. We believe in fit. A studio of three is the studio we want to remain.

+
+ +
+

This is not a roadmap. This is what we believe before we open the laptops.

+
+ +
+ IV. +

If our work cannot be made by hand somewhere, we are not the right studio for it. We will recommend a friend.

+
+ +
+ V. +

We will not put our work behind a chatbot. We will answer the email ourselves, or not at all.

+
+ +
+

Meridian

+ Studio for environmental products · Lisbon · est. 2026 + This manifesto stands until we change it. We will say so when we do. +
+ Helena Marques — design + Jonas Pereira — engineering + Aiko Tanaka — research +
+
+ + + diff --git a/site/_tests/04-meridian-manifesto/style.css b/site/_tests/04-meridian-manifesto/style.css new file mode 100644 index 0000000..e2134c6 --- /dev/null +++ b/site/_tests/04-meridian-manifesto/style.css @@ -0,0 +1,185 @@ +/* Hallmark · macrostructure: Manifesto · H1 hero knobs: size=xxl, alignment=left-bias, underlay=none + * theme: Manifesto · accent: red ~5% (used as bleed dividers, not flood) + * enrichment: none (typography only — voice is the design) + * studied: no · context: partial, inferred (audience + use) + */ + +@import url("https://fonts.googleapis.com/css2?family=Inter+Tight:wght@500;700;800;900&family=JetBrains+Mono:wght@400;500&display=swap"); + +:root { + --paper: oklch(10% 0.005 60); + --paper-2: oklch(14% 0.006 60); + --rule: oklch(28% 0.008 60); + --muted: oklch(58% 0.010 60); + --ink-2: oklch(85% 0.005 60); + --ink: oklch(98% 0.003 90); + --accent: oklch(60% 0.22 27); + + --display: "Inter Tight", "Söhne Breit", system-ui, sans-serif; + --label: "JetBrains Mono", ui-monospace, monospace; + + --space-xs: 0.5rem; + --space-sm: 0.75rem; + --space-md: 1rem; + --space-lg: 1.5rem; + --space-xl: 2.5rem; + --space-2xl: 4rem; + --space-3xl: 8rem; + --space-4xl: 12rem; + + --rule-fine: 2px; +} + +* { box-sizing: border-box; margin: 0; padding: 0; } + +html { + font-family: var(--display); + font-size: 17px; + line-height: 1.4; + color: var(--ink); + background: var(--paper); + -webkit-font-smoothing: antialiased; +} + +body { + min-height: 100dvh; +} + +.masthead { + display: flex; + justify-content: space-between; + align-items: baseline; + padding: var(--space-lg) clamp(1.5rem, 6vw, 4rem); + border-block-end: var(--rule-fine) solid var(--ink); + font-family: var(--label); + font-size: 0.75rem; + letter-spacing: 0.16em; + text-transform: uppercase; +} + +.masthead .name { + font-family: var(--display); + font-weight: 800; + font-size: 1rem; + letter-spacing: -0.005em; + text-transform: uppercase; +} + +.masthead .meta { color: var(--muted); } +.masthead .meta .accent { color: var(--accent); } + +.title { + padding: var(--space-3xl) clamp(1.5rem, 6vw, 4rem) var(--space-2xl); + border-block-end: var(--rule-fine) solid var(--ink); +} + +.title h1 { + font-family: var(--display); + font-weight: 900; + font-size: clamp(3rem, 8vw + 1rem, 7.5rem); + line-height: 0.92; + letter-spacing: -0.035em; + text-transform: uppercase; + color: var(--ink); + max-width: 18ch; +} + +.title h1 em { + font-style: normal; + color: var(--accent); +} + +.title .subtitle { + font-family: var(--label); + font-size: 0.75rem; + letter-spacing: 0.18em; + text-transform: uppercase; + color: var(--muted); + margin-block-start: var(--space-xl); +} + +.declaration { + display: grid; + grid-template-columns: clamp(4rem, 10vw, 8rem) 1fr; + gap: var(--space-xl); + padding: var(--space-3xl) clamp(1.5rem, 6vw, 4rem); + border-block-end: var(--rule-fine) solid var(--ink); + align-items: baseline; +} + +.declaration__num { + font-family: var(--display); + font-weight: 800; + font-size: clamp(2rem, 4vw + 0.5rem, 3.5rem); + letter-spacing: -0.01em; + color: var(--accent); + line-height: 0.9; +} + +.declaration__body { + font-family: var(--display); + font-weight: 700; + font-size: clamp(1.5rem, 3vw + 0.5rem, 2.625rem); + line-height: 1.12; + letter-spacing: -0.018em; + color: var(--ink); + max-width: 28ch; + text-transform: uppercase; +} + +.declaration__body strong { + background: var(--accent); + color: var(--paper); + padding: 0 0.18em; + font-weight: 700; +} + +/* Bleed-colour ornament between III and IV */ +.bleed { + background: var(--accent); + padding: var(--space-2xl) clamp(1.5rem, 6vw, 4rem); + border-block-end: var(--rule-fine) solid var(--ink); +} + +.bleed p { + font-family: var(--display); + font-weight: 800; + font-size: clamp(1.25rem, 2vw + 0.5rem, 1.75rem); + letter-spacing: -0.01em; + color: var(--paper); + text-transform: uppercase; + max-width: 38ch; +} + +.colophon { + padding: var(--space-3xl) clamp(1.5rem, 6vw, 4rem); + display: grid; + gap: var(--space-md); + font-family: var(--label); + font-size: 0.8125rem; + letter-spacing: 0.06em; + color: var(--muted); + line-height: 1.7; +} + +.colophon h2 { + font-family: var(--display); + font-weight: 800; + font-size: 1rem; + letter-spacing: 0.18em; + text-transform: uppercase; + color: var(--ink); + margin-block-end: var(--space-sm); +} + +.colophon .signed { + display: grid; + gap: 0.4em; + color: var(--ink-2); + margin-block-start: var(--space-md); +} + +.colophon .signed strong { + color: var(--ink); + font-weight: 500; +} diff --git a/site/_tests/05-tracejam-saas/brief.md b/site/_tests/05-tracejam-saas/brief.md new file mode 100644 index 0000000..4c6fe95 --- /dev/null +++ b/site/_tests/05-tracejam-saas/brief.md @@ -0,0 +1,43 @@ +# Test 05 — Tracejam (SaaS observability tool) + +## The prompt + +> "Build a landing page for Tracejam — a tracing/observability tool for distributed systems. Audience: SREs and platform engineers. Use case: try it / contact sales. Tone: technical." + +## Context gate — fully answered + +Audience, use, tone all explicit. No inference needed. + +## Domain inference + +`platform / tool / infra / dashboard / developer` → from the domain table: **Workbench / Bento Grid / Stat-Led** are reasonable picks. + +The skill picks **Bento Grid** because Tracejam has many surfaces (traces, metrics, alerts, logs) and Bento communicates "many entry points" the way Workbench would communicate "one thing, walked through". Workbench was the runner-up. + +## Theme + +The tempting default for a SaaS observability tool is **Midnight** (dark technical). But the skill resists: Midnight has been used elsewhere, and the brief says "technical" not "dark". Picking **Pastel** instead — post-Linear soft tech, low-chroma indigo accent, soft surfaces. The test is whether a Pastel page can still feel rigorous to an SRE; the answer is yes if the typography is exact. + +## Enrichment + +**E1 Demo Video — Clipped-Edge** archetype, but with a Tier-A pure-CSS dashboard mockup instead of real video. The mockup is a hand-built CSS-art trace waterfall (a flame chart) — it says "this is real software" without needing to ship a 4 MB video. + +The decision is *not* "embed a Loom". *Not* "use a stock video". *Not* "build a Lottie loop of moving bars". Pure CSS art is the right tier — the dashboard is geometric, the data are coloured rectangles, and CSS does that beautifully. + +## Macrostructure stamp + +``` +/* Hallmark · macrostructure: Bento Grid · F1 bento knobs: tiles=6, spans=irregular, accent=corner-only + * H7 hero: Demo Video Clipped-Edge · clip=right, aspect=16/10, frame=hairline + * theme: Pastel · accent: indigo ~3% · enrichment: tier-A CSS art mockup (flame chart trace waterfall) + * studied: no · context: explicit + */ +``` + +## What the page does + +- Hero: clipped-edge browser-frame mockup containing a CSS-art trace waterfall (a flame chart of an HTTP request fanning out into ~20 spans across four services). Headline left, mockup right, mockup extends ~12 vw past the viewport edge. +- Bento grid below: six asymmetric tiles, each one a feature with its own visual treatment (a numerical stat, a small CSS chart, a code snippet, a quote from a user, a tabular table of integrations, a single sentence) +- Two CTAs: "Try it" (outlined chip) and "Talk to sales" (typographic link) +- Footer: index columns +- Soft 12 px radius on every card. Indigo accent at ~3 % footprint. diff --git a/site/_tests/05-tracejam-saas/index.html b/site/_tests/05-tracejam-saas/index.html new file mode 100644 index 0000000..0565d18 --- /dev/null +++ b/site/_tests/05-tracejam-saas/index.html @@ -0,0 +1,176 @@ + + + + + + Tracejam — distributed tracing that explains itself + + + + + + + +
+
+

Tracejam · v0.4 · for SREs

+

Distributed tracing that explains itself.

+

Open the trace, find the span that regressed, and read why — in plain text — without a glossary, a YAML diff, or a status-page hunt.

+ +
+ + +
+ +
+ +
+ Cold-start +

Open a regressed trace in under 4 seconds

+ 4s +

From the alert link to the slow span, no clicks. Tracejam pre-renders the flame chart for every alert.

+
+ +
+ Latency drift +

p95 over 24 h, by service.

+ +
+ +
+

It told me the span that regressed, the deploy that caused it, and the engineer to ask. We rolled back in eight minutes.

+ — Staff SRE · large fintech · 2026 +
+ +
+ Drop-in OTLP +
export OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.tracejam.io
+export OTEL_EXPORTER_OTLP_HEADERS="x-tracejam-key=tj_…"
+
+ +
+ Connects to +

OpenTelemetry-native. No agent, no sidecar.

+
+ OTLP / gRPC + OTLP / HTTP + Datadog ingest + Honeycomb ingest + Prometheus + kubectl events + PagerDuty + Slack +
+
+ +
+ + + + + diff --git a/site/_tests/05-tracejam-saas/style.css b/site/_tests/05-tracejam-saas/style.css new file mode 100644 index 0000000..85a9747 --- /dev/null +++ b/site/_tests/05-tracejam-saas/style.css @@ -0,0 +1,533 @@ +/* Hallmark · macrostructure: Bento Grid · F1 bento knobs: tiles=6, spans=irregular, accent=corner-only + * H7 hero: Demo Video Clipped-Edge · clip=right, aspect=16/10, frame=hairline + * theme: Pastel · accent: indigo ~3% · enrichment: tier-A CSS art mockup (flame chart trace waterfall) + * studied: no · context: explicit + */ + +@import url("https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&family=Geist+Mono:wght@400;500&display=swap"); + +:root { + --paper: oklch(96% 0.022 285); + --paper-2: oklch(93.5% 0.026 285); + --paper-3: oklch(90% 0.030 285); + --rule: oklch(82% 0.024 280); + --rule-2: oklch(72% 0.030 275); + --muted: oklch(50% 0.030 275); + --neutral: oklch(38% 0.038 270); + --ink-2: oklch(28% 0.040 270); + --ink: oklch(22% 0.040 270); + --accent: oklch(56% 0.130 282); + --accent-soft: oklch(78% 0.060 282); + + /* trace colours — cool indigo family at varied lightness */ + --span-a: oklch(62% 0.13 282); + --span-b: oklch(70% 0.10 240); + --span-c: oklch(74% 0.09 200); + --span-d: oklch(56% 0.16 30); /* error span */ + + --display: "Geist", "Söhne", system-ui, sans-serif; + --body: "Geist", "Söhne", system-ui, sans-serif; + --mono: "Geist Mono", ui-monospace, monospace; + + --space-xs: 0.5rem; + --space-sm: 0.75rem; + --space-md: 1rem; + --space-lg: 1.5rem; + --space-xl: 2.5rem; + --space-2xl: 4rem; + --space-3xl: 6.5rem; + + --radius: 12px; + --shadow-sm: 0 1px 2px oklch(50% 0.13 282 / 0.06); + --shadow-md: 0 8px 24px -10px oklch(50% 0.13 282 / 0.16); + --rule-hair: 0.5px; + --rule-fine: 1px; + + --ease-out: cubic-bezier(0.16, 1, 0.3, 1); +} + +* { box-sizing: border-box; margin: 0; padding: 0; } + +html { + font-family: var(--body); + font-size: 16px; + line-height: 1.55; + color: var(--ink-2); + background: var(--paper); + -webkit-font-smoothing: antialiased; +} + +body { + min-height: 100dvh; +} + +.nav { + display: flex; + justify-content: space-between; + align-items: center; + padding: var(--space-md) clamp(1.5rem, 5vw, 3rem); + border-block-end: var(--rule-hair) solid var(--rule); + background: color-mix(in oklch, var(--paper) 90%, transparent); + backdrop-filter: blur(12px); + position: sticky; + top: 0; + z-index: 10; +} + +.nav .wordmark { + font-family: var(--display); + font-weight: 600; + font-size: 1rem; + letter-spacing: -0.01em; + color: var(--ink); +} +.nav .wordmark::before { + content: ""; + display: inline-block; + width: 14px; + height: 14px; + background: var(--accent); + border-radius: 4px; + margin-inline-end: 0.6em; + vertical-align: -2px; + opacity: 0.85; +} + +.nav__links { + display: flex; + gap: var(--space-lg); + font-size: 0.875rem; +} +.nav__links a { + color: var(--ink-2); + text-decoration: none; +} +.nav__links a:hover { color: var(--ink); } +.nav__links .btn { + border: 1px solid var(--ink); + border-radius: 999px; + padding: 0.45rem 1rem; + color: var(--ink); + transition: background 120ms var(--ease-out), color 120ms var(--ease-out); +} +.nav__links .btn:hover { background: var(--ink); color: var(--paper); } + +/* ─── HERO — clipped-edge with CSS-art trace waterfall ─── */ + +.hero { + display: grid; + grid-template-columns: minmax(20rem, 1fr) 1.4fr; + gap: var(--space-2xl); + padding: var(--space-3xl) 0 var(--space-2xl) clamp(1.5rem, 5vw, 3rem); + align-items: center; + overflow: visible; +} + +.hero__copy { max-width: 32rem; } + +.hero__eyebrow { + font-family: var(--mono); + font-size: 0.75rem; + letter-spacing: 0.06em; + color: var(--muted); + text-transform: uppercase; + margin-block-end: var(--space-md); + display: inline-flex; + align-items: center; + gap: 0.6em; +} +.hero__eyebrow::before { + content: ""; + width: 6px; height: 6px; + background: var(--accent); + border-radius: 1px; +} + +.hero__title { + font-family: var(--display); + font-weight: 600; + font-size: clamp(2.25rem, 4vw + 1rem, 3.875rem); + line-height: 1.05; + letter-spacing: -0.035em; + color: var(--ink); + max-width: 16ch; +} +.hero__title em { + font-style: normal; + background: linear-gradient(180deg, transparent 70%, var(--accent-soft) 70%); + padding: 0 0.05em; +} + +.hero__lede { + margin-block: var(--space-lg) var(--space-xl); + color: var(--ink-2); + font-size: 1.0625rem; + max-width: 38ch; +} + +.hero__cta { + display: flex; + flex-wrap: wrap; + gap: var(--space-md); + align-items: center; +} + +.btn--primary { + background: var(--ink); + color: var(--paper); + font-family: var(--display); + font-weight: 500; + font-size: 0.9375rem; + padding: 0.65rem 1.2rem; + border: 0; + border-radius: 999px; + text-decoration: none; + transition: transform 100ms var(--ease-out), background 120ms var(--ease-out); +} +.btn--primary:hover { background: var(--accent); transform: translateY(-1px); } +.btn--primary:active { transform: translateY(0); transition-duration: 60ms; } + +.btn--ghost { + font-family: var(--display); + font-weight: 500; + font-size: 0.9375rem; + color: var(--ink); + text-decoration: none; + display: inline-flex; + align-items: center; + gap: 0.4em; +} +.btn--ghost::after { + content: "→"; + transition: transform 200ms var(--ease-out); +} +.btn--ghost:hover::after { transform: translateX(2px); } + +/* ─── The clipped browser-frame mockup ─── */ +.mock { + width: calc(100% + 12vw); + aspect-ratio: 16 / 10; + border-radius: 14px; + overflow: hidden; + background: var(--paper-2); + border: var(--rule-hair) solid var(--rule); + box-shadow: var(--shadow-md); + transform: rotate(-0.4deg) translateY(-2px); + transform-origin: left center; + display: flex; + flex-direction: column; +} + +.mock__chrome { + display: flex; + align-items: center; + gap: 6px; + padding: 10px 14px; + background: color-mix(in oklch, var(--paper-2) 100%, var(--rule) 14%); + border-block-end: var(--rule-hair) solid var(--rule); + flex-shrink: 0; +} +.mock__dot { + width: 9px; height: 9px; + border-radius: 50%; + background: color-mix(in oklch, var(--rule-2) 80%, transparent); +} +.mock__url { + margin-inline-start: 12px; + font-family: var(--mono); + font-size: 0.7rem; + color: var(--muted); +} + +.mock__body { + flex: 1; + display: grid; + grid-template-columns: 56px 1fr; + background: var(--paper); + min-height: 0; +} + +.mock__rail { + display: flex; + flex-direction: column; + gap: 10px; + padding: 14px 12px; + background: color-mix(in oklch, var(--paper) 100%, var(--paper-2) 60%); + border-inline-end: var(--rule-hair) solid var(--rule); +} +.mock__rail-item { + width: 28px; height: 28px; + border-radius: 6px; + background: color-mix(in oklch, var(--rule) 100%, transparent); +} +.mock__rail-item.is-active { + background: var(--accent); + opacity: 0.88; +} + +.mock__main { + padding: 16px 22px; + display: flex; + flex-direction: column; + gap: 14px; + min-height: 0; +} + +.mock__head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + padding-block-end: 8px; + border-block-end: var(--rule-hair) solid var(--rule); +} +.mock__breadcrumb { + font-family: var(--mono); + font-size: 0.75rem; + color: var(--muted); +} +.mock__breadcrumb b { color: var(--ink); font-weight: 500; } +.mock__pill { + font-family: var(--mono); + font-size: 0.65rem; + background: var(--accent); + color: var(--paper); + border-radius: 999px; + padding: 2px 10px; + letter-spacing: 0.04em; +} + +.mock__title { + font-family: var(--mono); + font-size: 0.78rem; + color: var(--ink); + font-weight: 500; +} +.mock__title .meta { color: var(--muted); font-weight: 400; } + +/* The flame chart trace waterfall — pure CSS bars on a time grid */ +.trace { + display: grid; + grid-template-columns: 130px 1fr; + gap: 0 12px; + padding-block-start: 6px; +} +.trace__row { + display: contents; +} +.trace__label { + font-family: var(--mono); + font-size: 0.68rem; + color: var(--muted); + padding-block: 5px 0; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.trace__label b { color: var(--ink); font-weight: 500; } +.trace__lane { + position: relative; + height: 18px; + background: linear-gradient(90deg, transparent calc(100% - 1px), var(--rule) calc(100% - 1px)); + background-size: 25% 100%; +} +.trace__bar { + position: absolute; + top: 4px; + height: 10px; + border-radius: 2px; + background: var(--span-a); +} +.trace__bar.b { background: var(--span-b); } +.trace__bar.c { background: var(--span-c); } +.trace__bar.d { background: var(--span-d); } + +/* ─── BENTO ─── */ +.bento { + display: grid; + grid-template-columns: repeat(6, 1fr); + grid-auto-rows: minmax(180px, auto); + gap: var(--space-md); + max-width: 76rem; + margin: var(--space-3xl) auto 0; + padding-inline: clamp(1.5rem, 5vw, 3rem); +} + +.tile { + background: var(--paper-2); + border: var(--rule-hair) solid var(--rule); + border-radius: var(--radius); + padding: var(--space-lg); + display: flex; + flex-direction: column; + gap: var(--space-sm); + position: relative; + overflow: hidden; +} + +.tile h3 { + font-family: var(--display); + font-weight: 600; + font-size: 1.0625rem; + color: var(--ink); + letter-spacing: -0.012em; +} +.tile p { + color: var(--ink-2); + font-size: 0.9375rem; + flex: 1; +} +.tile .label { + font-family: var(--mono); + font-size: 0.68rem; + letter-spacing: 0.06em; + color: var(--muted); + text-transform: uppercase; +} + +.tile-stat { grid-column: span 2; grid-row: span 2; background: color-mix(in oklch, var(--paper-2) 100%, var(--accent) 7%); } +.tile-spark { grid-column: span 2; } +.tile-quote { grid-column: span 2; grid-row: span 2; background: var(--paper); } +.tile-code { grid-column: span 2; grid-row: span 1; } +.tile-integrations{ grid-column: span 4; } + +@media (max-width: 60rem) { + .bento { grid-template-columns: 1fr 1fr; } + .tile-stat { grid-column: span 2; grid-row: span 1; } + .tile-spark { grid-column: span 1; } + .tile-quote { grid-column: span 2; grid-row: span 1; } + .tile-code { grid-column: span 1; } + .tile-integrations{ grid-column: span 2; } +} + +@media (max-width: 40rem) { + .bento { grid-template-columns: 1fr; } + .bento .tile { grid-column: span 1 !important; } +} + +/* Stat tile */ +.stat-num { + font-family: var(--display); + font-weight: 600; + font-size: clamp(3rem, 6vw, 5rem); + letter-spacing: -0.04em; + line-height: 0.92; + font-variant-numeric: tabular-nums; + color: var(--ink); + margin-block-start: var(--space-xs); +} +.stat-num .accent { color: var(--accent); } + +/* Spark tile — small CSS sparkline */ +.spark { + flex: 1; + display: flex; + align-items: end; + gap: 4px; + padding-block-start: var(--space-md); +} +.spark span { + flex: 1; + background: var(--accent); + opacity: 0.55; + border-radius: 2px 2px 0 0; + display: block; +} + +/* Quote tile */ +.quote { + font-family: var(--display); + font-style: italic; + font-size: 1.125rem; + line-height: 1.4; + color: var(--ink); + letter-spacing: -0.012em; +} +.quote::before { content: "“"; color: var(--muted); } +.quote::after { content: "”"; color: var(--muted); } +.attribution { + font-family: var(--mono); + font-size: 0.68rem; + letter-spacing: 0.06em; + color: var(--muted); + text-transform: uppercase; + margin-block-start: var(--space-md); +} + +/* Code tile */ +.code-mini { + font-family: var(--mono); + font-size: 0.78rem; + background: var(--ink); + color: var(--paper); + border-radius: 8px; + padding: var(--space-md); + line-height: 1.6; + overflow-x: auto; + flex: 1; +} +.code-mini .k { color: var(--accent-soft); } +.code-mini .s { color: oklch(80% 0.10 130); } + +/* Integrations table */ +.integrations { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: var(--space-sm); + margin-block-start: var(--space-md); + font-family: var(--mono); + font-size: 0.78rem; +} +.integrations span { + padding: 0.5rem 0.6rem; + background: var(--paper); + border: var(--rule-hair) solid var(--rule); + border-radius: 6px; + color: var(--ink-2); +} + +/* ─── FOOTER — index columns ─── */ +footer { + margin-block-start: var(--space-3xl); + padding: var(--space-2xl) clamp(1.5rem, 5vw, 3rem); + border-block-start: var(--rule-hair) solid var(--rule); + display: grid; + grid-template-columns: 2fr repeat(3, 1fr); + gap: var(--space-xl); + font-size: 0.875rem; +} + +@media (max-width: 56rem) { + footer { grid-template-columns: 1fr 1fr; } +} + +footer .col h4 { + font-family: var(--mono); + font-size: 0.7rem; + letter-spacing: 0.16em; + text-transform: uppercase; + color: var(--muted); + font-weight: 400; + margin-block-end: var(--space-sm); +} + +footer .col ul { list-style: none; display: grid; gap: 0.4em; } +footer .col a { color: var(--ink-2); text-decoration: none; } +footer .col a:hover { color: var(--accent); } + +footer .brand h4 { + font-family: var(--display); + font-weight: 600; + font-size: 1.0625rem; + letter-spacing: -0.01em; + text-transform: none; + color: var(--ink); +} +footer .brand p { color: var(--muted); max-width: 36ch; } +footer .brand .colophon { + font-family: var(--mono); + font-size: 0.7rem; + color: var(--muted); + letter-spacing: 0.06em; + margin-block-start: var(--space-md); +} diff --git a/site/_tests/06-anya-portfolio/brief.md b/site/_tests/06-anya-portfolio/brief.md new file mode 100644 index 0000000..726c98d --- /dev/null +++ b/site/_tests/06-anya-portfolio/brief.md @@ -0,0 +1,48 @@ +# Test 06 — Anya (software architect personal site) + +## The prompt + +> "I'm Anya, a software architect. Build me a one-pager. Don't ask me questions, just figure it out." + +## Context gate — skipped (explicit) + +The user explicitly opted out. Skill must state inferences in one sentence at the top of the reply. + +**Going with:** *audience = engineering leaders considering Anya for hire / consult · use = read about Anya, then contact · tone = technical-but-warm, restrained, prose-led.* If any of those is wrong, redirect. + +## Domain inference + +`personal / resume / one-pager / individual` → from the domain table: **Long Document / Letter / Index-First**. + +The skill picks **Long Document**. Letter was the runner-up and would have produced a warmer page; Long Document is the more credible shape for a senior IC at this career stage. + +## Theme + +The default attractor for "personal portfolio" is Specimen, and that's exactly the trap. The skill picks **Studio** — italic Fraunces display, forest-green accent, Geist body. Studio is the modern editorial agency aesthetic, and a senior software architect's one-pager benefits from looking like a small design studio's about page rather than a CV. + +## Enrichment + +**None.** Typography only. The decision is deliberate — a personal site that hand-builds a Lottie or commissions a Midjourney portrait of itself reads as overcompensating. Restraint is the credibility signal here. + +The slop test catches: no abstract gradient background ("decoration without purpose"), no Three.js spinning name ("3D for a still object"), no demo video ("there's nothing to demo"), no aurora-blob ("never"). + +## Macrostructure stamp + +``` +/* Hallmark · macrostructure: Long Document · H5 hero knobs: salutation=greeting, body=2 paragraphs, signoff=initials + * theme: Studio · accent: forest-green ~2% (a single mark) + * enrichment: none (typography only — restraint is the credibility signal) + * studied: no · context: skipped, inferred (personal / portfolio domain) + */ +``` + +## What the page does + +- Italic display salutation: "Hello, I'm Anya." +- Two short paragraphs, italic display + roman body, on what Anya does and how she works +- A tabular "selected work" sheet: four projects, each one a single line — year · client · what changed +- A "currently" line in italic noting present focus +- A small "elsewhere" line: GitHub · LinkedIn · email +- Footer: a single dense colophon line + +The page is one fold tall on a 1440 px display. That's the point. diff --git a/site/_tests/06-anya-portfolio/index.html b/site/_tests/06-anya-portfolio/index.html new file mode 100644 index 0000000..8630398 --- /dev/null +++ b/site/_tests/06-anya-portfolio/index.html @@ -0,0 +1,75 @@ + + + + + + Anya Petrov — software architect + + + + + +
+ Anya Petrov + Software architect · Lisbon & remote · 2026 +
+ +
+ +

Hello, I'm Anya.

+ +
+

I help engineering organisations ship hard distributed-systems work — multi-region rollouts, payment graphs, eventually-consistent ledgers — without breaking the people doing the shipping. I write a lot, draw a lot of diagrams, and try not to ship a system the on-call rotation can't run on a Saturday.

+

Twelve years across Stripe, Monzo, and a small infra startup that didn't survive 2023. Currently consulting; selectively taking on three to four engagements per year.

+
+ +
+

Selected work

+ +
+ 2024–25 + Designed and led a 14-month payments graph rewrite.From a single Postgres write path to a sharded, replay-safe ledger across three regions. + Fintech, 400 engineers +
+ +
+ 2023 + Set up the platform team's first SLO programme.Wrote the runbooks, ran the postmortems, retired the dashboard everyone hated. + Marketplace, 80 engineers +
+ +
+ 2022 + Migrated a 200-service monorepo from one CI to another.Without breaking a single deploy. The PR had 1,800 reviewers. + Infra startup, ~50 engineers +
+ +
+ 2018–21 + Built and ran the on-call programme at a B2B fintech, 0→200 engineers.Wrote the doc that's still pinned in their #incident channel. + Fintech, 0→200 engineers +
+
+ +

Currently: finishing a long engagement on a multi-region ledger; writing a short book on running on-call as a team practice rather than a heroism contest.

+ +

+ github.com/anyap + · + linkedin.com/in/anyapetrov + · + hello@anyapetrov.com +

+ +
+ +
+ Anya Petrov + · + set in Fraunces & Geist + · + this page is one HTML file +
+ + + diff --git a/site/_tests/06-anya-portfolio/style.css b/site/_tests/06-anya-portfolio/style.css new file mode 100644 index 0000000..b4705a4 --- /dev/null +++ b/site/_tests/06-anya-portfolio/style.css @@ -0,0 +1,235 @@ +/* Hallmark · macrostructure: Long Document · H5 hero knobs: salutation=greeting, body=2 paragraphs, signoff=initials + * theme: Studio · accent: forest-green ~2% (a single mark) + * enrichment: none (typography only — restraint is the credibility signal) + * studied: no · context: skipped, inferred (personal / portfolio domain) + */ + +@import url("https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,400;0,9..144,500;1,9..144,400;1,9..144,500&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500&display=swap"); + +:root { + --paper: oklch(96.5% 0.014 95); + --paper-2: oklch(94% 0.016 95); + --rule: oklch(82% 0.012 90); + --rule-2: oklch(70% 0.010 90); + --muted: oklch(48% 0.010 95); + --neutral: oklch(34% 0.014 100); + --ink-2: oklch(22% 0.018 100); + --ink: oklch(13% 0.020 100); + --accent: oklch(46% 0.140 145); + + --serif: "Fraunces", "Tiempos", ui-serif, Georgia, serif; + --body: "Geist", "Söhne", system-ui, sans-serif; + --mono: "Geist Mono", ui-monospace, monospace; + + --space-xs: 0.5rem; + --space-sm: 0.75rem; + --space-md: 1rem; + --space-lg: 1.5rem; + --space-xl: 2.5rem; + --space-2xl: 4rem; + --space-3xl: 6.5rem; + + --rule-hair: 0.5px; +} + +* { box-sizing: border-box; margin: 0; padding: 0; } + +html { + font-family: var(--body); + font-size: 16px; + line-height: 1.6; + color: var(--ink-2); + background: var(--paper); + -webkit-font-smoothing: antialiased; +} + +body { + min-height: 100dvh; + display: grid; + grid-template-rows: auto 1fr auto; + padding-inline: clamp(1.5rem, 7vw, 5rem); +} + +/* ─── Top bar ─── */ +.top { + display: flex; + justify-content: space-between; + align-items: baseline; + padding-block: var(--space-lg); + border-block-end: var(--rule-hair) solid var(--rule); + font-family: var(--mono); + font-size: 0.75rem; + letter-spacing: 0.08em; + color: var(--muted); + text-transform: uppercase; +} +.top .name { color: var(--ink); } +.top .name::before { + content: ""; + display: inline-block; + width: 6px; + height: 6px; + background: var(--accent); + margin-inline-end: 0.6em; + vertical-align: 1px; +} + +/* ─── The letter ─── */ +.fold { + max-width: 56rem; + margin: 0 auto; + padding-block: var(--space-3xl) var(--space-2xl); + display: grid; + gap: var(--space-2xl); +} + +.salutation { + font-family: var(--serif); + font-style: italic; + font-weight: 400; + font-size: clamp(2.5rem, 5vw + 1rem, 4.25rem); + font-variation-settings: "opsz" 144, "SOFT" 30; + line-height: 1.05; + letter-spacing: -0.02em; + color: var(--ink); + max-width: 16ch; +} + +.salutation strong { + font-style: normal; + font-weight: 500; + background: linear-gradient(180deg, transparent 78%, color-mix(in oklch, var(--accent) 30%, transparent) 78%); + padding: 0 0.05em; +} + +.letter { + display: grid; + gap: var(--space-md); + max-width: 38rem; +} + +.letter p { + font-size: 1.0625rem; + line-height: 1.65; + color: var(--ink-2); +} + +.letter em { + font-family: var(--serif); + font-style: italic; + color: var(--ink); +} + +/* ─── Selected work — tabular ─── */ +.work { + display: grid; + gap: 0; +} + +.work h2 { + font-family: var(--mono); + font-size: 0.75rem; + letter-spacing: 0.16em; + text-transform: uppercase; + color: var(--muted); + font-weight: 400; + margin-block-end: var(--space-md); +} + +.work__row { + display: grid; + grid-template-columns: 4rem 1fr 14rem; + gap: var(--space-md); + padding-block: var(--space-md); + border-block-start: var(--rule-hair) solid var(--rule); + align-items: baseline; + font-size: 0.9375rem; +} + +.work__row:last-child { border-block-end: var(--rule-hair) solid var(--rule); } + +.work__year { + font-family: var(--mono); + font-size: 0.8125rem; + color: var(--muted); + letter-spacing: 0.04em; + font-variant-numeric: tabular-nums; +} + +.work__what { + color: var(--ink); + font-weight: 500; +} +.work__what em { + font-family: var(--serif); + font-style: italic; + font-weight: 400; + color: var(--neutral); + display: block; + font-size: 0.9375rem; + margin-block-start: 0.15em; +} + +.work__where { + font-family: var(--mono); + font-size: 0.78rem; + letter-spacing: 0.04em; + color: var(--muted); + text-align: right; +} + +@media (max-width: 44rem) { + .work__row { grid-template-columns: 4rem 1fr; } + .work__where { grid-column: 1 / -1; text-align: left; padding-inline-start: calc(4rem + var(--space-md)); margin-block-start: -0.4em; } +} + +/* ─── Currently + elsewhere ─── */ +.currently, +.elsewhere { + font-family: var(--serif); + font-style: italic; + font-size: 1.125rem; + color: var(--ink-2); + max-width: 38rem; +} + +.currently strong { + font-style: normal; + font-weight: 500; + color: var(--ink); +} + +.elsewhere { + font-family: var(--body); + font-style: normal; + font-size: 0.9375rem; +} + +.elsewhere a { + color: var(--ink); + text-decoration: none; + background-image: linear-gradient(var(--accent), var(--accent)); + background-repeat: no-repeat; + background-position: 0 calc(100% - 1px); + background-size: 100% 1px; + padding-block-end: 0.1em; + transition: background-size 200ms cubic-bezier(0.16, 1, 0.3, 1); +} +.elsewhere a:hover { background-size: 100% 2px; } +.elsewhere .sep { color: var(--rule-2); margin-inline: 0.6em; } + +/* ─── Footer ─── */ +footer { + padding-block: var(--space-lg); + border-block-start: var(--rule-hair) solid var(--rule); + font-family: var(--mono); + font-size: 0.75rem; + letter-spacing: 0.06em; + color: var(--muted); + display: flex; + flex-wrap: wrap; + align-items: center; + gap: var(--space-md); +} +footer .ink { color: var(--ink); } +footer .sep { color: var(--rule-2); } diff --git a/site/_tests/README.md b/site/_tests/README.md new file mode 100644 index 0000000..4d0cf01 --- /dev/null +++ b/site/_tests/README.md @@ -0,0 +1,88 @@ +# Hallmark — generation tests + +Six landing pages produced by exercising the Hallmark skill across contrasting briefs. The point: see what comes out *without* hand-holding the AI on theme, structure, or enrichment. Each test deliberately tests a different scenario. + +| # | Brief | Context given | Theme requested | What the skill picked | +| --- | --- | --- | --- | --- | +| 01 | Indie podcast `Tide`, no detail | **Skipped** ("you pick") | none | Quote-Led + Atelier + no enrichment | +| 02 | Open-source CLI `Streampipe` for stream parsing | Full (devs / install + docs / technical) | **Terminal** (requested) | Workbench + Terminal + Tier-A CSS-art terminal mockup | +| 03 | Artisan bakery `Maple Street Bread` | Full (locals / browse + visit / warm hand-set) | none | Long Document + Linen + Tier-B hand-built SVG loaf | +| 04 | Manifesto for an environmental studio `Meridian` | Partial ("declarative, no flashy stuff") | none (implied) | Manifesto + Manifesto + no enrichment | +| 05 | SaaS observability tool `Tracejam` | Full (SREs / try-or-talk-to-sales / technical) | none | Bento Grid + Pastel + E1 clipped-edge dashboard mockup | +| 06 | Personal one-pager for `Anya` (software architect) | **Skipped** ("don't ask, just figure it out") | none | Long Document + Studio + no enrichment | + +Each folder contains: + +- **`brief.md`** — the verbatim prompt, what the skill asked / inferred, and the macrostructure stamp the page ships with +- **`index.html`** — the rendered page (self-contained, no shared assets) +- **`style.css`** — the page's tokens + components, with the Hallmark stamp at the top + +Open any one with `open site/_tests//index.html` or browse via the local dev server at `http://localhost:8765/_tests//`. + +## What this exercise was for + +Stress-testing the skill on briefs that range from "complete spec" to "you figure it out, I'm lazy". Specifically watching for: + +1. Does the skill default to the same shape twice across the six tests? → No two should share a macrostructure or hero archetype. +2. Does the skill enrich every page even when it shouldn't? → Tests 01, 04, 06 should be typography-only. +3. When the user skips the design-context gate, does the skill state its inferences in one sentence at the top? → Yes, see brief.md headers. +4. Does the skill bend toward "Built for the modern team" voice when copy is left to it? → Each brief has its own voice; no template-soup. + +Findings and a priority list of skill improvements are at the bottom of this file, after the six test cases. + +--- + +## Findings — what worked, what didn't, what to fix + +### What worked + +1. **Six different briefs produced six structurally different pages.** No two share a macrostructure, hero archetype, or footer voice. The page-shape variety the skill is built around held up under the test. +2. **Three of six tests ship with no enrichment.** The skill correctly resisted the urge to add a Lottie / illustration / mockup to the podcast (typography-only is right for voice), the manifesto (a manifesto is not a marketing page), and the personal portfolio (restraint is the credibility signal). This is the test the *previous* anti-slop generation failed. +3. **The two tests that reach for hand-built CSS art (Tracejam flame chart, bakery loaf) produced custom DOM — not Lottie.** The skill picked Tier-A or Tier-B from the enrichment hierarchy without asking, and the result feels designed, not pulled. +4. **The skipped-context flow worked twice (01 podcast, 06 architect).** Both pages open with an inferred-context disclosure sentence at the top of `brief.md`, which is the documented pattern. The skill states what it inferred. +5. **Type pairing held across all six.** No two tests share a font stack. Newsreader (1, 3), Geist Mono (2, 5), Inter Tight (4), Fraunces (6) each carry one page; pairing logic is theme-driven so this fell out naturally. +6. **The clipped-edge mockup (test 5) was hand-built CSS, not a video file.** The skill resisted the temptation to ship "embed a Loom" — the trace waterfall is pure CSS bars on a percentage grid. + +### Friction points I hit while generating + +- **The "domain → trio" table covers most cases but not all.** The bakery is in the table; the manifesto is in the table; the personal portfolio is in the table. The SaaS tracing tool is *implicitly* in the table under "platform / tool / infra". The podcast is in the table. **But:** I had to combine "SaaS marketing" + "developer tool" mentally to land on Bento Grid for Tracejam — the skill could be more explicit about *which* of the three suggested macrostructures wins for a given sub-domain. (E.g., "platform/tool" → Workbench or Bento; pick Workbench when the brief says docs/walkthrough, pick Bento when the brief says try-or-talk-to-sales.) +- **Theme picking is still by feel.** The skill has a strong rule that "the next theme can't be Specimen if the last one was Specimen" — but no rule like *"the next theme should be categorically different on at least one of: paper-band, display-style, accent-hue."* I avoided repeating themes here by deliberate intuition; a documented rule would help future runs. +- **Copy generation bent toward "Built for the modern team" twice — and I had to course-correct.** Tracejam's first draft headline was *"Trace what matters."* — a near-template; I rewrote it to *"Distributed tracing that explains itself."* which is more specific. **The skill needs example copy fixtures per macrostructure** (Tier 3 in the existing roadmap) — without them, the model bends toward LLM-distribution copy. +- **The `hero-enrichment.md` decision protocol is text-only — no concrete worked examples per domain.** I had to imagine what Tracejam's "Demo Video Clipped-Edge" looks like vs. "Mockup Split"; an in-file example for each enrichment archetype on a real page would speed this up. +- **Within-archetype variation knobs work in theory but I leaned on the same defaults.** The two pages with footer-index (Tracejam, none of the others ended up there) and footer-inline (the podcast, the bakery, the architect) all converge on the same shape. A future run on the *same* footer archetype should pick *different* knobs — but the rule lives in the cookbook, not in muscle memory. +- **Free fonts only got me so far.** The bakery wanted Tiempos Headline (paid, Klim); I substituted Newsreader. The Studio theme on Anya's portfolio wanted Tobias (paid); Fraunces is a strong understudy but not the same. The skill should explicitly call out free-vs-paid trade-offs with two-tier candidates per pairing. + +### Improvement list — priority order + +This is the punch list. Do these and the skill goes from "good" to "as good as a human-curated design.md gets in 2026". + +#### Tier 1 — Real holes (next session) + +1. **Per-archetype example copy fixtures.** For each of the 21 macrostructures, ship 2–3 example *opening-line copy fragments* in `references/macrostructures.md`. The model imitates them instead of bending to LLM distribution. Highest single payoff for output quality. Currently roadmap Tier 3. +2. **Sub-domain refinement for the trio table.** Split "platform / tool / infra / dashboard / developer" into two rows: *docs/walkthrough* → Workbench / Long Doc; *try-or-talk-to-sales* → Bento / Stat-Led / Workbench. Same for "personal" (one-pager Letter vs. multi-page Long Doc). +3. **A documented theme-diversification rule.** *"Across consecutive Hallmark outputs in this user's session/project, no two themes should share more than one of: paper-band, display-style, accent-hue."* Currently the rule is "don't repeat Specimen", which is tighter on one tail than it should be. +4. **Free-vs-paid font trade-off in `typography.md`.** Each tone gets two pairings: "free baseline" and "paid upgrade if the user can pay". The bakery example would say: "Free: Newsreader + Geist + Geist Mono. Paid upgrade: Tiempos Headline + Söhne + Söhne Mono." +5. **Worked examples in `hero-enrichment.md` per archetype.** A 5-line "what this looks like for X brief" under each E1–E8. Right now the descriptions are abstract; concrete worked examples accelerate generation. + +#### Tier 2 — Quality polish + +6. **A "different knobs" check in the slop test.** Question 34: *"If I used the same archetype as a previous Hallmark output (e.g., footer-inline twice), did I pick at least one different variation knob?"* Catches the template-soup-within-an-archetype risk this exercise surfaced. +7. **More illustration recipes in `custom-craft.md`.** The bakery loaf was the only worked example. Add one for: a workflow diagram, a mascot, a small architectural diagram, a botanical accent. Each in 30–60 lines. The bakery loaf I generated above had room to be sharper — the recipes should show what *good* looks like at this scale. +8. **A `references/copy.md` extension with non-LLM voice samples.** Three voices per tone (editorial / brutalist / soft / technical / luxury / playful / austere) with 5 example sentences each. Borrow from real sites (Klim, Linear, Apple, Tufte, Rauno, Frieze) — credit them, don't copy. +9. **Mobile breakpoint discipline per archetype.** I caught this on test 5 (Tracejam): the clipped-edge mockup needed a 60rem media query to collapse to stacked. The cookbook entries should say *"on viewports below X, this archetype collapses to Y"* so it's automatic. +10. **An in-skill check: did I write `aria-label` on every visual-only SVG?** I caught it manually for the bakery loaf and the trace waterfall, but a slop-test gate would make it automatic. + +#### Tier 3 — Long bet + +11. **Project-level memory beyond the CSS stamp.** Right now the skill reads the *latest* stamp in the project. A `.hallmark/log.json` per-project file (history of macrostructures + themes + briefs) would let the diversification rules see further back. +12. **A "study + remix" combined verb.** `hallmark study + redesign` in one — extract DNA from a screenshot, then rebuild the user's content with that DNA. Today the user has to chain `study` then `redesign`; one verb would be tighter. +13. **A real example gallery on the landing page.** These six tests should be linked from the main `site/index.html` as a "Generated by Hallmark" gallery, with one-line captions. Marketing the skill via the skill's outputs. +14. **Auto-generated Open Graph cards per page.** Each test ships its own meta description, but the OG image is missing. A small Hallmark utility that generates an OG image per page from the macrostructure stamp + headline would close the loop. + +### What this means for the skill + +Hallmark is *good*. The structural variety position holds — six briefs, six different pages, no template repetition. The enrichment hierarchy works — three of six pages correctly choose to ship nothing visual, and the three that do enrich pick the right tier (custom-built, not Lottie). + +The remaining gap is **copy voice** and **theme-pick discipline**. The slop test catches *visual* tells well; it doesn't yet catch *prose* tells (like "Built for the modern team" headlines). And the diversification rules are tight on one axis (no Specimen fall-through) but loose on the rest. + +Tier 1 of this list is the next session's work.