[§] /docs/rules
The rules
Twelve rules to decide once, write down and check before anything ships. Each one links to its detail page.
TL;DR
- Every value is a token. Every size is on a scale.
- It works at 390px, by keyboard, and with reduced motion on.
- Every state is designed. Every word says what it does.
- Read the twelve lines below. Open a page only when you need the detail.
The twelve rules
- Every value is a token. Pages hold no hex codes, pixel values or z-index numbers. Tokens and colour
- Name tokens by role, not by value.
--color-text-soft, never--grey-600. Tokens and colour - One accent, one meaning. Body text meets 4.5:1, large text 3:1. Tokens and colour
- Every size comes from a scale. Type, 4pt spacing, radius, shadow, z-index. Scales and type
- Type is chosen and set for reading. Body 16px or more, lines 65ch or fewer. Scales and type
- Mobile first, and 390px never scrolls sideways. Breakpoints and layout
- Every state is designed. Hover, focus-visible, disabled, loading, error, empty. Targets 44 × 44px. Components and states
- Motion uses four curves and four durations. UI changes stay under 400ms. Motion tokens
- Reduced motion gets a still, composed frame. Loops stop. Canvases pause off screen. Motion tokens
- Every image and video has a reserved box. AVIF first, real
sizes, a poster for video. Media - It meets WCAG 2.2 AA. Visible focus, keyboard access, labels,
lang. Accessibility - Words and speed are part of the design. Buttons say what they do. LCP 2.5 s, INP 200ms, CLS 0.1. Copy and Structure and performance
How to read MUST and SHOULD
The keywords follow RFC 2119, as the Vercel Web Interface Guidelines do.
- MUST means no exceptions without a written reason in the pull request.
- SHOULD means the default. Break it when you can say why in one sentence.
- SHOULD NOT means avoid it unless you can say why in one sentence.
Decisions flow one way
[01]
Primitive tokens
--v-ink: #f5f5f5
[02]
Semantic tokens
--accent: var(--v-ink)
[03]
Components
Button reads --accent
[04]
Patterns
form, card grid, empty state
[05]
Pages
compose patterns, set no values
The test is simple. If a page file contains a hex code, a pixel value or a z-index number, a
decision has leaked out of the token layer.
Hierarchy by contrast, not quantity
✕ everything shouts
✓ one big thing
One big thing per view. Size, weight, colour and space do the ranking. Boxes and borders are the last resort.
[ex] in the wild · 13
The ship checklist
Run this before anything goes live.
Layout and type
- MUST work at 390px wide with no horizontal scroll.
- MUST keep body text at 16px or more and lines at about 65ch or fewer.
- SHOULD use
tabular-numsfor numbers that change or line up. - SHOULD balance headings (
text-wrap: balance) and avoid single-word last lines.
Colour
- MUST meet 4.5:1 for body text and 3:1 for large text and UI boundaries.
- MUST design dark mode as its own palette, if you ship one.
Interaction
- MUST show a visible focus state on every interactive element.
- MUST give touch targets at least 44 × 44px.
- MUST keep hover-only information reachable by keyboard and touch.
- SHOULD give instant feedback: pressed states, optimistic UI, skeletons over spinners.
Motion
- MUST honour
prefers-reduced-motion: fade instead of move, stop loops. - MUST pause off-screen canvases and loops.
- SHOULD NOT animate layout properties (
width,top) whentransformwill do.
Completeness
- MUST design empty, loading and error states.
- MUST give every page a real
<title>, a description and an OG image. - SHOULD have a favicon that reads at 16px.
- MUST prove motion with frames about 1.5 s apart, not one screenshot. See how to verify.
Why it works
A rule turns a taste argument into a lookup. Reviews get shorter because the question changes from "does this look right?" to "is this the token?". New people and AI agents match the system on the first try, because the answer is written down.












