How this was built

A design system where Figma, the code and the build agree, and a build that refuses to ship if they stop.

The first case study argues for one specification that designers, engineers and language models all build from. That project ended before it reached production, so this site is the smallest complete version of the same idea, running on something you can open.

The workflow

Claude Code, in VS Code
Where the work happens. The repo, the Figma file and the checks are driven from one place, so a change reaches the design file, the code and the tests without a handoff between them.
Figma Console MCP
A live connection into the Figma file. Tokens, components and the layout rules are read and written from the editor rather than exported by hand, which is what stops the file and the repo drifting.
GitHub Actions
Every push runs the checks below. If Figma and the code disagree, the build stops rather than the disagreement getting noticed later.
Storybook and Chromatic
Every component rendered inside a band and snapshotted in both themes, so a regression in either one fails the build.

What that adds up to

None of these numbers were typed in. They are computed when this page is built, from the files they describe.

Design tokens
141 primitives and 56 semantic tokens per theme, exported from Figma and checksum verified against it.
Text styles
25, emitted as CSS custom properties. Type steps between two of them at a breakpoint rather than clamping, so every size on screen exists in the design file.
Components
25 in code, 25 with a published contract. The ones with no Figma counterpart have their specs generated from their own TypeScript and stylesheets.
Stories
68, each snapshotted light and dark.
Layout rules
7 band adjacency rules, read from the Figma page rather than transcribed. Checksum 2143010685.
Checks
17 on every push, counted from the gate that runs them rather than from memory. The same gate runs on my machine before the push, so a green run here means the same thing as a green build there. Any one of them failing stops both.

What the build refuses to ship

Each of these exists because something got through without it.

  • Types. Nothing else in the repo reads TypeScript. Astro transpiles without checking and Storybook will happily render a story whose props no longer exist, which is how three stale props on Parallax survived the change that removed them.
  • Secrets. This repo is public, so a committed credential is harvested in minutes and the only cheap moment to catch one is before the push. It scans tracked files only, because the ignored ones legitimately hold the real token, and it never prints what it finds.
  • Tokens. Every alias resolves, and the export checksum matches the one Figma reproduces from inside the file. A renamed variable fails the build instead of silently rendering nothing.
  • Brand packs. A brand pack adds its own colours and repoints the same token names the components already use, which is what lets one build serve several brands without a component knowing that brands exist. Every value in a pack has to be an alias rather than a typed colour, both themes have to cover the same tokens, and the checksum has to match the one the brand Figma file produces, so the file and the repository cannot quietly disagree.
  • Components. Every value in every spec is a token reference. Zero literals, asserted rather than reviewed.
  • CSS. Every custom property resolves to a real token. A typo like fg-secondry is not a CSS error, because it renders as an inherited default and looks deliberate, so nothing else would catch it.
  • Fonts. Every typeface the design file names has to actually arrive: a face declaration behind it, a file on disk behind that, and nothing fetched from a third party. This exists because the check above it asked whether every font value was bound to the scale, and never whether the font turned up, so a twenty-three style type system rendered in whatever the reader’s operating system happens to use, for weeks, on a site whose whole argument is that the design file and the code agree. Binding is not arriving.
  • Contrast. Every pairing of text and background the pages actually use, measured for every brand in both themes against the WCAG AA thresholds. See-through colours are composited over whatever sits beneath them first, because a white at seventy per cent is a different colour on every band. Decorative pairs like rules and placeholder outlines are measured and printed rather than failed, since a threshold applied to something it was never meant for gets satisfied by changing a value that was already correct.
  • Contracts. Every component has a published contract somewhere. The number above says so, and until this check existed that number was right by coincidence rather than by measurement, because two ways of counting happened to cancel.
  • Provenance. Every image on the site has to say what it is, whether that is a real screenshot, a diagram, a piece of abstract artwork, or a reconstruction that imitates a real interface. Nothing here can check that the answer is honest, because a faked screen is a claim baked into a picture rather than into text, so what this enforces is narrower and still worth having: an image cannot ship until somebody has opened it and written down what they saw.
  • Gates. The checks that run on a push and the checks that run on this machine have to be the same checks. They were two separate lists for a while and they had already drifted apart, so a clean run here proved nothing about the build, which is the kind of gap that only ever announces itself long after the work has moved on.
  • The README. The numbers the repository’s front page states are checked against the repository. That page is markdown read on GitHub with no build step to substitute into, so unlike this one it cannot compute them; they are typed, and a program asks whether they are still true. It had twice been wrong about how many checks there are, which is a plausible enough sentence that nobody reading it noticed.
  • Generated files. Regenerating everything has to change nothing. If it does, someone hand-edited a file that is supposed to be measured, and a stale generated file is invisible in a diff because the change you would be looking for is the one that never got made.
  • Bands. The built pages are linted against the layout rules, and those rules are read from Figma rather than copied. Adding a rule there fails the build here until someone implements it.
  • Gaps. A missing fact renders on the page as a marker rather than hiding in a comment, so it cannot be quietly forgotten. This reads the built pages and fails if one would ship, which matters most when a new case study is being written and the holes are still being filled.
  • Deploy configuration. Vercel reads its own config file before it installs anything and before it builds, so a mistake in that one file fails the deployment without ever producing a build log, and every check above stays green while the site quietly keeps serving the build before it. That is how a comment written into it cost eight deployments and a day, found by asking the live site what it was serving rather than by looking at a badge. This reads it: the keys against the ones Vercel accepts, and any rewrite pointing at a path that also exists as a real file, because the file wins and the rule silently never runs.
  • The working record. CLAUDE.md is the long technical record sitting behind this page, and it states figures that it cannot compute for itself, among them four export checksums. Three of those had sat in it stale while the build was printing something else, each one reading as a perfectly ordinary sentence, so every figure is now read back from the script that prints it rather than trusted where it lies.

What it does not do

It does not check whether the design is any good. It checks that the design and the code are the same thing, which is a narrower claim and the only one worth automating. Taste is still done by looking.

It does not check that the result is usable either. axe-core runs clean across nine pages, two widths and two themes, and the site still shipped a menu that told screen readers it was modal while keyboard focus walked straight out of it, onto a button that was invisible and could not be clicked. No single element was wrong, so nothing automated could see it. A person tabbing through the sheet did.

It only sees what the design file sees. The carousel’s back arrow was a right-pointing chevron flipped in CSS, which looked right on screen and left the published contract naming the wrong icon, because a contract is measured from Figma and Figma could not see the flip. Every check passed. What fixed it was drawing the icon.

It stops at the token layer. The contrast check resolves every pairing out of the token files, which is the wrong question for a diagram painted in somebody else’s palette. The token-tiers figure resolves a brand’s values in CSS as you pick one, with no JavaScript in it at all, so the pair a reader sees exists nowhere but a browser with a theme applied and a selection made. Measured there it was failing in three places, including a label that passed in dark and sat at 3.67:1 in light. What found them was a second script that opens the page and reads the pixels.

The receipts