Skip to content

Chapter 08

Build

Six steps, in the order a builder needs them. Two rules stand above all of it: values live once, and a surface closes on a render. A specification is not a deliverable.

Before the first line

This book is the reader facing half of the system. The builder facing half is the living style guide, which carries every component with its demo, its markup snippet and its rules table, generated from the component folders themselves.

Open the style guide

Adopt, never hand build

If a component exists in the library, use it. A hand written version of an existing component is a second copy of a rule, and second copies drift. If the thing you need does not exist, that is a component to add to the library, not a block to invent inside a surface.

Step 1. The tokens

One source of truth, two generated artefacts, and no third copy. The failure this prevents: a value declared once in a config and once again in a stylesheet, the two drift, and nobody notices until a client surface ships with last year's ink.

What to link

A surface links the emitted files, or vendors them whole with the generated banner intact, which is how the no mirror gate recognises them. It never re-declares a value, never pastes the root block by hand, and never redefines a house custom property.

  • 02_TOKENS/fonts.css, then 02_TOKENS/tokens.css. Fonts first, always.
  • The audit build is a different file. It emits ten fewer properties: the six signal colours and the display and poster steps with their leadings are absent, so a rule that says no signals on the audit becomes a token that does not exist.

The house names

Every house property is prefixed --u-. Colour is --u-color-group-name. Then --u-font-voice, --u-size-step, --u-leading-step, --u-tracking-step, --u-space-step, --u-measure-name, --u-line-name, --u-radius-none, --u-chrome-frame and --u-motion-name.

When the house does not have the value you need

Surface local tokens, and the four rules on them
Rule The test
The name carries the surface prefix Grep for a house prefixed declaration outside the generated files. Zero.
A local token is never a colour The no mirror gate exits non zero on any hex or colour function outside the token file.
It composes house tokens, or carries a value the house has no vocabulary for A grid gap, a bleed measure, an aspect ratio, a count. Written as an expression over house tokens where it can be.
A local value a second surface needs is promoted, not copied The promotion test, then the token file and a version bump.

A token invented before its surface is a guess, and a guess in the token file outranks a later measurement. When the audit needed a grid gap, a bleed measure and an aspect set, it named the three values it lacked and refused to invent them. That is the pattern.

The permitted literals, in full

Zero. One pixel, only through the hairline token. Layout percentages and 100 percent. Auto, currentColor, transparent. A unitless number where no token applies, meaning flex, grid, a z index of 0 or 1, an opacity of 1. Nothing else. No hex, no named colour, no pixel or rem size, no millisecond duration, no radius other than the none token, no shadow, no gradient other than the chrome frame as a border image.

Step 2. The grounds

Paper is the default and it is the body. The other three are wrappers, and each one decides which ink its children read.

A component reads the ink of the ground it sits on through four aliases the base stylesheet sets. So a component never asks which ground it is on, and the ground wrapper never has to know which components are inside it.

Step 3. The components

Five layers, composed in one direction. A surface is built from templates and organisms; it does not reach past them into atoms to rebuild something that already exists.

The library, by layer
Layer What is in it
Shared The reset, the body voice, the four ground aliases and three wrappers, the focus ring, the two measures, the stack, the skip link. Plus the flush device and the demo frame.
Atoms Type steps, link, button, action, the form controls and their label, hairline, chrome frame, swatch, tag, band, flood, number, the wordmark and the icon.
Molecules Form row, card, quote, figure, table, bar chart, method step, nav item, proof tile, price line, faq item, testimonial, footer column, explainer object, notice.
Organisms Nav, plate, section, statement, method index, proof row, pricing, faq, testimonials, call to action, form section, audit band, document frame, colophon, footer, signal pair.
Templates Landing page, document, audit opening, app shell, deck slide, social frame. Whole surfaces composed from the library and nothing else.

Stylesheet order, and it matters

  1. The font stylesheet.
  2. The token stylesheet.
  3. The shared base stylesheet, and the flush stylesheet where a flush block is set.
  4. The component stylesheets in composition order: atoms, then molecules, then organisms.
  5. The surface's own sheet, last, carrying layout and nothing that belongs in a component.

Naming, so a class says where it came from

A component is its own class, its parts are that class with a double underscore and a part name, its variants that class with a double hyphen and a variant name. States are never classes: they are the attributes and pseudo classes the browser already owns, meaning focus visible, disabled, pressed, expanded, current, or a data state attribute. Never a state that exists only on hover, because a phone has no hover.

Step 4. The copy

The copy is part of the build, not a thing that arrives afterwards. Three checks before a line goes on a page.

Step 5. The surface layer

A surface may narrow the house layer. It may never widen it and never contradict it.

A constraint discovered while building a surface is surface scoped by default. It is promoted to the house only by a deliberate decision, recorded with its reason and, if a value moves, a version bump of the token file. A constraint that appears in a surface file and also in the house layer is a defect, and the surface file wins for that surface only until the duplication is resolved.

The promotion test, yes or no: does the constraint hold on the landing page, the proposal, the app and a social frame, for the same reason? One no, and it stays where it is. See the surfaces chapter for the worked case.

Step 6. The gates

Every tool runs from 01_IDENTITY/. Exit 0 is the only pass. Exit 1 is a failure and exit 2 is a usage error, so a mistyped flag can never read as a pass.

The gates, in the order they are useful
Tool What it proves
measure-palette.mjs The 62 palette rules hold. Contrast, raw luminance, lightness, hue arc, colour vision deficiency distance, chroma. The colour maths lives once, here.
build-tokens.mjs --check The generated stylesheet and theme file match the token file. Run this after any token change, before anything else.
check-no-mirror.mjs No colour literal anywhere outside the token file. Generated files are exempt by their banner. A value printed as documentation says so per line.
check-paint.mjs Every declared value reaches a pixel at 320, 390, 768 and 1280, and every material the build emits is carried. This is the gate against a value that is declared and never seen.
check-coverage.mjs The first viewport carries 18 to 40 percent pigment, measured at 1280 by 900 and 390 by 844. Brand surfaces only. This is the loudness floor as a number.
check-flush.mjs Every flush line fills 96 to 100 percent of its measure by spacing alone.
check-surface.mjs The web guideline assertions, per page, plus the measured lane routed by the page's own surface attribute. It writes a report.
shoot.mjs Screenshots to read. Zero overflow, zero broken images. Taking them is not the gate. Reading them is.

A gate that passes on an empty set is not a pass

On 2026-08-20 the paint gate returned green against a deck that carried none of the material it was built to test. That is why it now has a material floor. Before trusting a green run, ask what the run actually looked at.

The ship checklist

One page. Eleven items. The gate tails and the report path go into the surface's record, because a pass is evidence only with its artefact.

  1. The page links the token and font stylesheets, declares its surface, carries a language attribute, one first level heading, one main landmark, a skip link, and a label on every control. Local tokens carry the surface prefix and are never colours.
  2. The palette gate and the token build check both exit 0.
  3. The no mirror gate exits 0 on the surface directory.
  4. The paint gate passes at 320, 390, 768 and 1280.
  5. The coverage gate passes, on a brand surface.
  6. The flush gate passes on every page with a flush block.
  7. The surface gate exits 0 and its report is saved with the record.
  8. The screenshots at 320, 390 and 1280 show zero overflow and zero broken images, and they were read rather than only taken.
  9. Counted on the render: floods two or fewer and never beside a signal; one signal field per viewport and none over a quarter of it; one action per viewport; the mark once per viewport in the right version for its ground; acid once; heat only as the audit band; nothing animated.
  10. The first viewport is 350 kilobytes or less, with zero requests off the page's own host, and every image is a sized cut.
  11. The copy passes step 4.

The floors underneath all of it

Accessibility

WCAG 2.2 at level AA. Every interactive element reaches the shared focus ring, which is two adjacent rings so the indicator carries its own edge on any ground. Targets at least 44 by 44 pixels. Forms labelled, landmarks present, headings in order, images with alternative text. Reflow at 320. Forced letter spacing must not lose content.

The ring is the one box shadow in the library, and it is a ring, not a shadow. Removing an outline is banned outright.

The tested widths

320, 390, 768 and 1280. The scales are clamps solved between 390 and 1280, so the breakpoints test the scale rather than stepping it. 320 is the reflow floor with a 280 pixel column. 768 is the composition seam where the house breakpoint queries switch.

A composition that changes at any other width is a defect. There is no breakpoint token, so a new query is recorded in its component's README.

Chapter 08 of the Unforged brand book. Written from 01_IDENTITY/06_COMPONENTS/CONTRACT.md, 01_BRAND-LAYER/layer-model.md v3 and 03_SURFACES/web-guidelines.md v3.