Skip to content

Design system

The visual contract.

A design system is not a folder of pictures and not a style guide. It is an agreement between design and engineering about what the interface is made of — the same kind of artefact as an OpenAPI document, and subject to the same rules. It is settled once, away from any particular screen and before any particular feature, so that no screen has to settle it again. Story mapping and example mapping consume it; they do not produce it.

Three properties, and one of them is usually missing

Most design systems are explicit and agreed. The third property is where they fail: tokens copied by hand into CSS are a second implementation, and they drift exactly the way a hand-written API stub drifts — silently, while continuing to look correct.

  • 01

    Explicit

    Written down where both sides can point at it — a Figma library and a token file, not a habit and a screenshot.

  • 02

    Agreed

    Design and engineering both reviewed it, and both can propose a change to it. A contract one side can edit alone is a preference.

  • 03

    Enforced

    Something fails when it is breached: tokens generated rather than retyped, lint rules against raw values, contrast checked in the suite.

The foundations

Eight decisions taken once. Each one names what it forbids, because a contract that forbids nothing constrains nothing — and each one says what happens when it is breached. 3 of the eight are not enforced by anything yet, and are marked as such below.

  • Colour

    What may a surface, a text or a border be?

    Agreed
    Fixes
    A palette of raw values, and — the part that matters — the semantic roles laid over it: surface, surface-raised, ink, ink-muted, brand, danger, success, focus. Screens reference roles; only the theme references raw values.
    Forbids
    A hex code in a component. If a colour is worth using twice it is worth a role, and if it is used once it is probably a mistake.
    Enforced by
    A lint rule rejecting raw colour literals outside the token layer, plus a contrast check per role pairing in the accessibility suite.
  • Typography

    What sizes, weights and rhythms exist at all?

    Agreed
    Fixes
    A closed type scale with a line height and a tracking per step, and a role per step — display, title, body, caption, code. Two families, no more.
    Forbids
    An arbitrary font size. A one-off 17px heading is a fork of the scale, and it will be copied by the next screen that needs something "a bit bigger".
    Enforced by
    The scale ships as tokens; a lint rule rejects literal font sizes and line heights in component styles.
  • Spacing and layout

    How far apart is anything allowed to be?

    Agreed
    Fixes
    A 4px base with a named step per multiple, a container width per breakpoint, and the breakpoints themselves. Density is a token too, so a compact table is a setting rather than a rewrite.
    Forbids
    Off-scale margins. Most visual inconsistency between two screens built by two people is spacing, not colour.
    Enforced by
    Spacing tokens only in component styles, checked by the same lint rule as colour and type.
  • Interaction states

    What does every interactive thing do when touched?

    Agreed
    Fixes
    The full set each interactive component must answer for: rest, hover, focus-visible, active, disabled, loading, error, and — the ones most often forgotten — empty and read-only.
    Forbids
    Shipping a component with only its happy state designed. An undesigned state is not absent; it is designed badly by whoever implements it under deadline.
    Enforced by
    A story per state, so a missing state is a missing story and shows up as a gap in the library rather than as a bug in production.
  • Accessibility

    What is guaranteed for someone not using a mouse or a screen?

    Agreed
    Fixes
    Minimum contrast per role pairing, a visible focus ring that survives every theme, a target size floor, the heading and landmark structure of a page, and the reduced-motion behaviour of every animation.
    Forbids
    Removing an outline without replacing it, colour as the only carrier of meaning, and a control that a keyboard cannot reach.
    Enforced by
    An automated scan per story and per journey, failing the build — plus the manual keyboard pass that automation cannot do.
  • Motion

    How does the interface move, and when does it not?

    Drafting
    Fixes
    Durations, easings and a small set of named transitions — enter, exit, expand, attention — plus what each one is for.
    Forbids
    Motion that is not attached to a state change, and any animation that ignores `prefers-reduced-motion`.
    Enforced by
    Nothing yet.Agreed and written down, but no build fails when it is breached — so today it is a convention, not a contract.
  • Iconography

    What may a symbol look like, and what may it mean?

    Drafting
    Fixes
    One grid, one stroke weight, one optical size per context, and a name-to-meaning register so the same idea is never drawn two ways.
    Forbids
    An icon with no accessible name, and an icon-only button whose meaning is not also available as text.
    Enforced by
    Nothing yet.Agreed and written down, but no build fails when it is breached — so today it is a convention, not a contract.
  • Content and voice

    How does the product talk, especially when something has failed?

    Planned
    Fixes
    Sentence case, the second person, dates and numbers per locale, and the shape of an error message: what happened, why, and what to do next.
    Forbids
    An error the user cannot act on. "Something went wrong" is a shrug with a stack trace behind it.
    Enforced by
    Nothing yet.Agreed and written down, but no build fails when it is breached — so today it is a convention, not a contract.

Where it actually lives

The Figma library is the source; the published tokens are the same decisions in a form a build can consume. One direction of flow — a hand-edit downstream is a bug in the source, not a local fix. When a session finds something none of this covers, that is a change request against the contract, decided here rather than inside a story.