Home / Benchmark

Fifteen of our 28 design specs disagreed with the stylesheet

Every style here ships a DESIGN.md: the file you drop into a project so an agent knows the palette, the type stack and the radius values before it writes any interface code. It only works if the file is true. So we wrote a checker that reads the stylesheet and the spec and compares them token by token — names and values, not prose.

The first run disagreed with 15 of 28 specs. Not a matter of taste: 14 tokens were missing outright, and 8 carried a value that the stylesheet had already overridden somewhere further down. An agent following those files would have shipped the wrong header colour on eight styles, and nothing in the build would have complained.

28specs audited
15disagreed on the first run
8tokens with a stale value
36/176rules specific to one style

Three things the check caught

1. The cascade was invisible to the generator

Themes are not always defined in one place. Six of them get a second body.theme-* block near the end of the stylesheet, where the header colour was darkened because the original pairing could not be read — glassmorphism had white text on a mint gradient, 1.16:1. The generator looked up only the first block, so it wrote the old value into the spec. Both values look reasonable in isolation. Only a comparison catches it.

Every stale value found on the first run. Left: what the spec said. Right: what the browser actually applies.
Style Token Spec said Actually applied
illustration --header-text-color #ffffff #2b2118
glassmorphism --header-text-color #fff #06251f
natural-organic --header-bg #8b7e66 #6f6250
monochromatic --header-bg var(--mono-base) var(--mono-dark)
maximalism --header-text-color var(--max-c5) #000000
claymorphism --clay-text #7a6f5a #5b5140
claymorphism --header-text-color var(--clay-heading) #3f3728
abstract-geometric --header-text-color #fff var(--text-color)

2. Three quarters of the rules were the same sentence

A spec earns its place through the rules that only make sense for that style. Counting them: the 28 specs hold 176 Do / Don't items, and 36 of them are specific — the rest appear verbatim in more than half of the files. The 6 styles that were written with their own guidance account for every one of those 36; the other 22 carry a shared boilerplate set about not hard-coding hex values. Useful advice, but it is the same advice everywhere, so it cannot be the reason an agent gets one style right and another wrong.

3. Two tokens point at a variable that does not exist

--mono-font: var(--font-roboto-mono) appears in two themes, and --font-roboto-mono is declared nowhere in the stylesheet. The declaration is silently dropped, the code blocks fall back to the browser's default monospace — close enough to Roboto Mono that nobody noticed. This one is left open on the table below: fixing it changes how two live pages render, so it belongs in its own change rather than in a spec regeneration.

Every style, before and after

Coverage counts tokens whose name and value match what the browser applies. Rules is specific items over total Do / Don't items in that file.

Regenerated 2026-11-02. Baseline captured from the same commit the fix started on, so the two columns describe the same stylesheet.
Style Tokens Coverage Missing Stale Dangling Rules Status
skeuomorphism 37 97.3% → 100.0% 1 → 0 0 → 0 — 0/5 fixed
swiss-style 29 100.0% → 100.0% 0 → 0 0 → 0 — 0/5 ok
grunge 33 97.0% → 100.0% 1 → 0 0 → 0 — 0/5 fixed
modern-tech 32 100.0% → 100.0% 0 → 0 0 → 0 --mono-font → --font-roboto-mono 0/5 open
brutalism 31 100.0% → 100.0% 0 → 0 0 → 0 — 0/5 ok
retro-90s 32 93.8% → 100.0% 2 → 0 0 → 0 — 0/5 fixed
retro-y2k 29 100.0% → 100.0% 0 → 0 0 → 0 — 0/5 ok
retro-pixel 30 96.7% → 100.0% 1 → 0 0 → 0 — 0/5 fixed
illustration 31 93.5% → 100.0% 2 → 0 1 → 0 — 0/5 fixed
3d-interactive 32 100.0% → 100.0% 0 → 0 0 → 0 --mono-font → --font-roboto-mono 0/5 open
dark-mode 30 100.0% → 100.0% 0 → 0 0 → 0 — 0/5 ok
bold-typography 29 100.0% → 100.0% 0 → 0 0 → 0 — 0/5 ok
glassmorphism 29 100.0% → 100.0% 0 → 0 1 → 0 — 0/5 fixed
aurora-ui 33 97.0% → 100.0% 1 → 0 0 → 0 — 0/5 fixed
natural-organic 29 100.0% → 100.0% 0 → 0 1 → 0 — 0/5 fixed
monochromatic 38 100.0% → 100.0% 0 → 0 1 → 0 — 0/5 fixed
maximalism 36 100.0% → 100.0% 0 → 0 1 → 0 — 0/5 fixed
claymorphism 46 93.5% → 100.0% 3 → 0 2 → 0 — 0/5 fixed
abstract-geometric 35 94.3% → 100.0% 2 → 0 1 → 0 — 0/5 fixed
sustainable-green 34 100.0% → 100.0% 0 → 0 0 → 0 — 0/5 ok
art-deco 33 100.0% → 100.0% 0 → 0 0 → 0 — 0/5 ok
neomorphism 28 96.4% → 100.0% 1 → 0 0 → 0 — 0/5 fixed
bento-grid 19 100.0% → 100.0% 0 → 0 0 → 0 — 6/11 ok
liquid-glass 19 100.0% → 100.0% 0 → 0 0 → 0 — 6/11 ok
editorial 19 100.0% → 100.0% 0 → 0 0 → 0 — 6/11 ok
neo-brutalism 19 100.0% → 100.0% 0 → 0 0 → 0 — 6/11 ok
neo-swiss 19 100.0% → 100.0% 0 → 0 0 → 0 — 6/11 ok
acid-graphics 19 100.0% → 100.0% 0 → 0 0 → 0 — 6/11 ok

How it is measured

The checker parses the stylesheet by regular expression — no CSS parser, no headless browser, no new dependencies — and merges every body.theme-{id} block in source order, so the last declaration wins, as it does in the browser. It then reads every row of the form | <token> | <value> | out of the spec and compares the two sets in both directions: tokens the stylesheet has and the spec lacks, tokens the spec claims that do not exist, and tokens where both name the same property but disagree on the value.

Two derived numbers matter more than the raw counts. Coverage is matched tokens over applicable tokens — 100% means an agent has everything it needs to reproduce the style. Specific rules counts Do / Don't items that appear in fewer than half of the specs; a rule repeated 28 times constrains nothing, because every style already has it.

Every number on this page comes from spec-check.json; the pre-fix snapshot is spec-check.baseline.json. Both are regenerated, never edited by hand. To reproduce:

node scripts/bench-spec-check.mjs          # summary table
node scripts/bench-spec-check.mjs --json   # the data this page renders
node scripts/bench-spec-check.mjs --strict # exit 1 if any spec is out of sync

What this is not

This does not rank AI tools. It measures one thing: whether a design spec matches the stylesheet it claims to describe. The next step — handing these specs to v0, Lovable, Cursor and Claude Code and scoring what comes back — is a separate benchmark, and it needs artefacts those tools produce. When there are enough of them to be worth publishing, the numbers will appear here under the same rule: every figure traceable to a raw record, and no score invented for a tool that cannot export code.

Browse the specs →