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.
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, then02_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
| 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. |
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.
- Paper The default on the document root and on the body. Restate it with the paper ground wrapper only for a paper block sitting inside a flood.
- Flood The flood wrapper switches the whole ink set and the hairline. At most twice per surface, at most once in an audit, always with paper between two entries, never sharing an edge with a signal field.
- Raised Element backgrounds only: a zebra row, a quote figure, a notice, a span. Never the ground of a section, never stacked on itself. A hairline inside it takes the axis rule, because the paper hairline is invisible there.
- Trough A bar track and nothing else. No words sit on 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.
| 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
- The font stylesheet.
- The token stylesheet.
- The shared base stylesheet, and the flush stylesheet where a flush block is set.
- The component stylesheets in composition order: atoms, then molecules, then organisms.
- 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.
- English. Zero em dashes and zero en dashes. The slogan verbatim, hyphenated. Unforged in prose is sentence case.
- Every number carries its receipt, and the receipt is a row in the claims table. No invented numbers, no invented client names.
- The four voice tests from the voice chapter, run on the loudest sentence on the page and on the smallest label.
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.
| 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.
- 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.
- The palette gate and the token build check both exit 0.
- The no mirror gate exits 0 on the surface directory.
- The paint gate passes at 320, 390, 768 and 1280.
- The coverage gate passes, on a brand surface.
- The flush gate passes on every page with a flush block.
- The surface gate exits 0 and its report is saved with the record.
- The screenshots at 320, 390 and 1280 show zero overflow and zero broken images, and they were read rather than only taken.
- 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.
- The first viewport is 350 kilobytes or less, with zero requests off the page's own host, and every image is a sized cut.
- 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.