Standards
The must layer. Checkable rules that bind every screen you ship, human-built or agent-built.
The guidance pages tell you how to decide and what usually works. The catalogue is different: every entry in it is a standard, and a standard is a requirement. An L0 violation blocks the release. An L1 deviation needs a documented waiver from a named approver. An L2 deviation needs a stated reason. That holds no matter who or what built the screen.
Each standard is one verifiable statement with explicit fail conditions. "Text meets WCAG AA contrast" is a standard. "Interfaces should feel calm" is not; that's guidance, because no machine can check it. Checkability is what makes this work: it lets the bar be enforced automatically, before anyone sits down to review.
The same catalogue binds both audiences:
- Humans read it rendered in the catalogue, and cite IDs in reviews ("this fails SLP-3").
- AI agents read it as YAML and apply it while generating UI.
The site publishes the same catalogue the harness checks against, with product-neutral wording, from a pinned dx-harness commit.
Standards come in three tiers:
- L0 — non-negotiable. Accessibility floors, destructive-action safety. No waiver exists; a violation blocks ship.
- L1 — mandatory. Binding by default. Deviation requires a documented waiver in code:
dx-waive <ID> reason="<specific reason>". - L2 — recommended. Follow unless you have a better answer; deviating needs an inline rationale.
Writing
Not written to be read. Written to be acted on.
Colour
Colour tells people which product they're in and what needs their attention. Each product keeps its own primary; neutrals and status colours stay shared.
Typography
Type sets the hierarchy a tired reader scans first: what's a heading, what's next, what can wait. Your DESIGN.md names the fonts, their roles, and the scale.
Spacing and radius
Consistent spacing and corners are what make a screen feel calm instead of busy. One shared scale, so nothing is arbitrary.
Tokens
Every token this site uses, in one place: colour, type, spacing, radius, and motion. A worked example of the token set a DESIGN.md points to.
Iconography
Icons help people spot an action faster than words alone. One consistent set for the UI, a warmer hand-drawn style for brand moments.
Motion
Motion is feedback, not decoration: four durations, two easings, and one rule — nothing moves that doesn't mean something.
Interaction
How a screen responds decides whether a person feels in control or ambushed. Show the core path first; make every action easy to undo.
Web interface
The craft floor for anything you ship in a browser: the polish that separates merely working from genuinely feeling right.
Data visualisation
People read charts between other tasks, so clarity beats density. Make the one number that matters impossible to miss.
Illustration
Illustration is where the product feels human instead of corporate. One warm, hand-drawn style — and shipping none beats shipping off-brand.
All standards
Every standard in one list — one verifiable statement each, with its tier, fail conditions, and how it's checked. Cite IDs in review; agents read the same list.
Machine-readable source: catalog.yaml. To read the whole site instead, start at /llms.txt.
72 of 72 standards
Accessibility (11)
Text meets WCAG AA contrast — 4.5:1 body, 3:1 large text and UI components
Fails when: body copy under 4.5:1 against its background · gray text on coloured backgrounds that fails AA
Every interactive element is keyboard-reachable with a visible focus state
Fails when: focus ring removed without replacement · click handlers on non-focusable elements
Every form field has a programmatically associated, visible label
Fails when: placeholder used as the only label · icon-only button without aria-label
Interactive targets are at least 24x24px (44px on mobile)
Fails when: visual target smaller with no expanded hit area
prefers-reduced-motion disables all non-essential animation
Fails when: no reduced-motion variant provided
Essential non-text content has a text alternative; decorative content is hidden from assistive technology
Fails when: informative image with an empty alt · decorative icon exposed to assistive technology (no aria-hidden)
Structure is programmatically determinable — semantic headings, lists, tables, and form groups; headings and labels describe their content
Fails when: styled divs standing in for headings, lists, or tables · headings or labels that do not describe their content
Custom components expose name, role, and value to assistive technology
Fails when: custom control with no role or accessible name · visual state change with no ARIA state update
Every page or distinct view has a descriptive title, and the main language is marked up
Fails when: every SPA view sharing one static document title · missing or wrong html lang attribute
Repeated blocks of content are bypassable — skip link or landmark navigation to main content
Fails when: no skip link and no landmarks on a page with repeated chrome
Async state changes are announced and focus is managed — transient status via live regions without stealing focus; context replacements move focus to the revealed surface, never both for the same message
Fails when: message announced by both a live region and a focus move · transient toast stealing focus
Tokens & theming (3)
UI code contains no raw colour values — only the colour tokens DESIGN.md defines (else the codebase's theme tokens, else shadcn's semantic tokens)
Fails when: hex/rgb/hsl literals in component code
All spacing values come from the spacing scale DESIGN.md defines (else the codebase's, else the shadcn/Tailwind default scale)
Fails when: arbitrary pixel values for margin/padding/gap
Corner radii come from the radius scale DESIGN.md defines (else the codebase's, else the shadcn default radius scale)
Fails when: ad-hoc radius values · child radius larger than parent (non-concentric nesting) · peer containers of the same kind use different corner radii — anchor to the product's Card/base radius
Typography (6)
Display and body/UI text use the typefaces and weights the product's DESIGN.md declares (else the codebase's font tokens, else Tailwind's default font stacks); no other typefaces
Fails when: any other typeface in product UI, except a product's registered brand-wordmark typeface confined to its wordmark/logo lockup (declared in the product's DESIGN.md)
Body text at least 14px; labels at least 12px; body line-height 1.5-1.6
Fails when: body copy below 14px · line-height under 1.5 on multi-line body text
Type sizes come from the type scale DESIGN.md defines (else the codebase's, else Tailwind's default scale); no off-scale sizes
Fails when: font sizes not on the product's type scale
Text is never set in all-caps
Fails when: all-caps text — labels, headings, or running text · text-transform uppercase used for styling (genuine acronyms excepted)
Numbers that align in columns or update in place use tabular figures (font-variant-numeric: tabular-nums)
Fails when: a column of figures (scores, counts, amounts) in proportional numerals that fail to align vertically · a live counter, timer, or total that reflows horizontally as its digits change
Running body text is held to a comfortable measure — roughly 45-75 characters per line (target 40-60), via a max-width in ch, not full-viewport paragraphs
Fails when: a paragraph that spans the full viewport width with no measure cap · body copy running well past ~75ch per line
Colour (2)
Primary actions and brand moments use the product's own primary brand colour (or its ramp)
Fails when: primary CTA in a colour that is not the product's primary · one product's primary used inside another product's surface · a light-hue product primary (orange/amber/lime/yellow) paired with white label text that fails A11Y-1 (use the scale's dark contrast step)
Functional colours (success/warning/danger) come from the shared Radix Colors scales, never ad-hoc; small functional-colour text (≤12px chips/labels) uses the scale's step-12 on a tinted background so it clears AA (A11Y-1)
Fails when: custom green/red/amber values · red used decoratively · small functional-colour text (≤12px) on a tint uses step-11 (or lower) and falls below 4.5:1
Components & patterns (11)
Where a Base UI-based component exists for the need, it is used; one-offs require a waiver
Fails when: custom dropdown/dialog/tooltip where the stack provides one
Destructive actions show consequences before executing and offer undo or explicit confirmation
Fails when: silent destructive action · confirmation that does not state what will be lost
Every async transaction has visible loading, success, and error states
Fails when: missing error state · loading state that flickers (no min visible time)
Every empty-state view unambiguously signals "no content exists" — distinct from loading, error, or permissions failure — through a heading, explanatory subtext, and the absence of loading chrome such as skeleton rows or spinners
Fails when: a skeleton row, shimmer, or loading spinner is visible in the DOM alongside the empty-state heading · the heading/subtext pair reads as "still loading" or "you don't have access" rather than "nothing here yet" · an empty state ships with list chrome (row dividers, placeholder rows) that could be mistaken for a populated-but-loading list
Each view has at most one primary (filled) action; secondary and tertiary actions step down to outline, ghost, or link styling
Fails when: two or more filled/primary buttons competing in one view with no deliberate co-equal reason · a destructive action styled as the primary instead of a distinct destructive variant (CMP-2) · every button rendered at the same weight, so nothing reads as the main action
Data tables use the table pattern — semantic rows and headers, numeric columns right-aligned with tabular figures, text left-aligned, and a header that stays visible while scrolling
Fails when: numeric columns centre- or left-aligned, or in proportional figures, so values do not line up (TYP-5) · a long table whose header scrolls out of view, leaving columns unlabelled · tabular data rendered as stacked cards or divs instead of a real table (A11Y-7) · a table that can be empty or slow has no designed empty or loading state (CMP-3)
Components stay consistent with their design-system defaults and with sibling-page usage — overriding a default's colour/contrast/shape, or breaking a control group's shared resting affordance, is a finding unless justified
Fails when: a design-system component default is overridden in a way that changes colour, contrast, or shape with no recorded reason · a component is used differently here than on sibling pages with no reason · members of one control group (toggle set, segmented control) do not share a resting affordance — only the selected one reads as interactive
A multi-step or data-entry task offers a non-destructive exit at every step, and in-progress work is preserved or explicitly discarded on interruption — never silently lost
Fails when: a wizard/dialog with no cancel/back at some step · navigation away silently drops typed content · an interrupted flow resumes from zero with no warning at exit time · escape/close discards a draft with no confirm (ties to CMP-2's mechanics)
Content authored by one user and rendered to another is sanitised at the render boundary; author-time schema constraints are not sufficient
Fails when: dangerouslySetInnerHTML/v-html renders another user's authored content with no sanitiser in the render path · sanitisation is claimed at editor time only ("schema-constrained output") with nothing enforced at render · a prototype defers sanitisation with no recorded flag noting the deferral
An input-validation error message clears as soon as the field is corrected, with no separate action required; each field's error clears independently among multiple simultaneous errors
Fails when: the error message for a corrected field remains visible after the input satisfies the validation rule again · correcting one field's input clears another field's error message, or clears all errors at once · the error only clears on an unrelated action (submit, blur elsewhere, navigation) rather than on the correction itself
A component's own nested interactive child (a focus ring, active-state fill, icon) traces that component's own container edge and radius — not a smaller box floating inside it
Fails when: a component's own nested interactive child (a focus ring, active-state fill) does not trace that component's own container edge or radius — it reads as floating inside a smaller box, not outlining the container
Content & naming (14)
Error messages state what happened and what to do next; no raw error codes as the primary message
Fails when: "Something went wrong" with no next step · stack traces or codes shown to users
Feature and page names use plain language; no invented portmanteaus, no internal codenames in UI
Fails when: names that require explanation
Copy uses second person and active voice, and keeps sentences to 25 words or fewer
Fails when: passive constructions in instructions · third-person references to the user ("Users can…")
Content that models a real-world artifact is faithful to it (scope, terminology, structure) or explicitly labelled illustrative
Fails when: a category or level detail a practitioner would recognise as wrong (e.g. a category graded at a level where it does not apply) · invented specifics presented as real in a user-testing surface · placeholder content with no illustrative label
UI action words name the action, not the input device — "choose", "select", "view", never "click", "tap", "swipe", or "press"
Fails when: "Click here" / "Tap to continue" / "Press the button" as UI copy · a device verb in an instruction a screen reader reads aloud on a touch device · ambiguous link text ("click here", "read more") that names the device, not the destination
Copy carries no low-informational-value words — no empty openers, filler words, or droppable articles and conjunctions, unless removing them hurts clarity
Fails when: a sentence opening with an empty opener that reads fine without it · filler words (just, really, very, please) carrying no meaning in UI copy
Descriptive copy leads with its purpose — what it does for the user and when to reach for it — before the mechanism
Fails when: a title, description, or intro that opens with the mechanism (the tool, token, or library) instead of what it does for the user
Copy replaces nominalised verbs and "to be" constructions with plain action verbs
Fails when: a "to be" verb carries a nominalised action ("is a requirement", "are in maintenance", "was in transmission") · an action is buried in a noun when the verb is available ("give a recommendation" → "recommend")
Copy is clear — one idea per sentence, simple present tense, no double negatives, no noun stacks, short words, acronyms and technical terms have a reachable definition
Fails when: a sentence carries two or more ideas · past-perfect or passive constructions where simple present fits · a double negative when a positive form exists · three or more nouns stacked where a verb or adjective would do · a long word from the substitution table used when the plain form exists · an acronym or unfamiliar technical term with no reachable definition anywhere — no inline expansion, tooltip, help text, or glossary (terms your users already know excepted)
One term per thing within a product — the same action, object, or state keeps a single name everywhere it appears in the interface
Fails when: the same action named two or more ways anywhere in the product ("Edit" on one screen, "Amend" on another, "Modify" in a dialog) · term drift for the same thing between any two surfaces — a button and its confirmation, a nav item and its page title, a filter and its help text
UI terms match the established word users already meet across other products — "Search" not "Find", "Settings" not "Preferences"
Fails when: an invented or unfamiliar synonym for a standard UI term ("Find" for a search field, "Preferences" for settings) · a coined product term where an established web convention already exists
Copy uses sentence case — capitalise the first word and proper or branded nouns only
Fails when: Title Case in a heading, label, or button ("Submit Your Report", "View Project Details") · a non-proper mid-sentence word capitalised for emphasis
Copy is free of spelling and proofreading errors and uses British English spelling
Fails when: a misspelling or typo in user-facing copy ("recieve", "seperate", "teh") · US spelling where British is house style ("color", "organize", "center") · a doubled word or copy-paste artifact left in shipped text ("the the", "TODO")
Copy embodies the DX voice (Clear, Thoughtful, Approachable) and its tone fits the surface context
Fails when: an error message that is alarmist or dramatic rather than calm and helpful · a success message that gushes instead of acknowledging briefly · an empty state or onboarding step that is patronising or careless · a destructive confirmation written with drama instead of sober, plain consequences
Motion (3)
Interface motion is 100-300ms with standard easing; no decorative motion on critical paths
Fails when: animations over 300ms on task flows · transition-all
Motion values come from the declared motion token set — durations and easings are never hardcoded in component code
Fails when: a raw duration (350ms, 0.4s) or cubic-bezier literal in component code where the token set exists · a surface that animates but declares no motion token set · the narrative tier (--motion-story) used on interface or task UI
Motion may emphasise meaning but never carry it alone — an animated surface communicates the same information with animations off
Fails when: a diagram whose meaning (order, causality, state) exists only in the animation · a reduced-motion variant that drops information instead of motion · motion that implies a state change that is not happening
Identity (4)
Product lockups and logos render only from approved assets; no recreations
Fails when: rebuilt or distorted logo marks
Product icons render only from the approved product-icon family; no ad-hoc, redrawn, or regenerated icons
Fails when: a redrawn, distorted, or regenerated product-icon mark · a per-product background colour or gradient applied to the icon container · wordmarks, photos, shadows, or gloss inside the icon
Copy on a product's surface carries that product's calibrated tone register — same voice character, calibrated weight, never a switched voice system
Fails when: copy adopts another product's register (a switched voice system, not calibrated weight) · a surface hosted inside another product carries its own nuance instead of the host's voice
Casework surfaces treat case data as sensitive: restrained celebration, no gamified or playful elements around case data
Fails when: celebratory or confetti-style motion on a case-closure or case-outcome moment · streak / badge / points / leaderboard gamification attached to casework · exclamatory congratulatory copy on a sensitive case outcome
Anti-slop (11)
No purple/violet gradient palettes, cyan-on-dark theming, or glow accents
Fails when: the default AI aesthetic anywhere in product UI
No gradient text
Fails when: background-clip text gradients on headings or metrics
No thick side-tab accent borders on rounded cards
Fails when: the single most recognisable AI-UI tell
No nested cards; flatten with spacing, typography, and dividers
Fails when: cards inside cards inside cards
No icon-tile-above-heading feature-card template; no identical card grids as default layout
Fails when: the universal AI feature-card shape repeated in a grid
Adjacent type-scale steps differ by at least 1.10x; no flat hierarchy
Fails when: heading/subheading/body at nearly the same size
Spacing has rhythm — related items grouped tighter than unrelated ones
Fails when: one spacing value used everywhere
No bounce or elastic easing on interface elements
Fails when: dialogs that spring in with overshoot
Copy carries no AI-writing tells — marketing buzzwords, em-dash chains, filler, or redundant label/helper pairs
Fails when: streamline/empower/supercharge/world-class · label, sublabel, and helper saying the same thing · chatbot artifacts ("Great question!", "I hope this helps") · "It's not just X, it's Y" / "serves as a" / forced triads doing rhetoric, not enumeration
Complex multi-section tasks get a page, not a modal
Fails when: modal with its own scrollbar and column layout
A card is only for an interactive unit (clickable, selectable, draggable); static content is grouped with spacing, type, and dividers
Fails when: static content boxed in card chrome purely for visual separation · a card used as a section wrapper where a heading plus spacing would group it
Layout (7)
Layout uses the product's declared column grid and gutter scale; ad-hoc column counts and off-scale gutters are findings — N/A where no grid is declared
Fails when: a declared grid exists and the layout uses an ad-hoc column count not drawn from it · a declared grid exists and gutters/margins don't match the spacing scale (TOK-2) with no deliberate reason
Layout reflows to a single column with no loss at 320 CSS px (WCAG 2.2 SC 1.4.10); reading order and controls hold at 360/768/1280
Fails when: content or controls become unreachable or ambiguous at 320 px reflow · reading order reverses or a primary action disappears at the narrowest width
Body-text columns cap at a comfortable measure — target ~66ch, never above 80ch (WCAG 1.4.8); full-bleed running text is a finding
Fails when: body-text column has no max-width and spans the full viewport at 1280 · measure exceeds 80ch
A surface maps to a known page template (workspace view, form, flow step, dashboard, settings, empty state, onboarding) rather than an ad-hoc shell
Fails when: a surface invents a bespoke shell structure when an existing template applies · information hierarchy does not match the declared page type
Density suits the task — neither cramped for data entry nor padded for scanning; extreme outliers in either direction are findings
Fails when: a data-entry surface is too padded for efficient tab traversal · a reading or scanning surface is too cramped to scan without error
Shared edges align; optical alignment is used where geometry misleads
Fails when: shared edges between sections or components do not align, with no deliberate reason · text or icon baselines and optical centres are visibly misaligned
The page has one primary focal region and its visual reading order matches the task's priority order
Fails when: two or more regions compete for first read with no task reason for the tie · the squint-test first-read lands on secondary content · the primary action's region is visually subordinate to decoration