build-design-system

Installation
SKILL.md

Build a design system

Vocabulary is in references/glossary.md, defaults for bans and widths in references/taste.md. The app's own look is the source. Invent no colour, font, shadow, gradient or motion value it does not already have, unless the person chose a design source and confirmed a sample.

Scripts are in this skill's scripts/. Run them from the repo root with node, and read --help first. scripts/capture.mjs takes the screenshots behind scripts/capture-guard.mjs, which blocks every write, and scripts/pixdiff.mjs compares them. Capture and pixdiff need Playwright and a Chromium, which scripts/find-chromium.mjs finds or explains how to install.

Steps

  1. Frame. Read AGENTS.md or CLAUDE.md, the manifest and the route tree. Write the complaint in the person's words, the first visible change that answers it, and the pilot flow (the one the complaint names, else the flow with the most component families and a form with an error state). Add .design-system/ to .git/info/exclude so no note, capture or scratch file is ever committed. Use the branch the person named as the run branch, or cut one and write the branch you started on to .design-system/start-branch, which land.mjs refuses. Offer references/taste.md once with its bans unselected and save the accepted copy to .design-system/taste.md. Ask nothing else. Take the default, record it as default (unanswered) and go on. Done when the complaint, pilot, branch and accepted taste file are written down.

  2. Inventory and baselines. List every surface, its states and whether it writes data. Count raw values in occurrences (#fff, text-gray-500, p-[13px]) with scripts/check-system.mjs --no-allowlist --no-self-test --json, and group components into families. Capture every surface in every state at the narrowest and widest supported width (390 and 1280 by default), one fresh navigation per width, before any edit. With the app running (port 3000 here), list each surface as a surface<TAB>route<TAB>states row in .design-system/surfaces.tsv and every write the app sends as METHOD URL in .design-system/writes.txt, copied from its network log, then run node <this skill>/scripts/capture.mjs --base http://localhost:3000 --kind before --out .design-system/captures --surfaces .design-system/surfaces.tsv --writes .design-system/writes.txt. It refuses to start without --writes (or --no-backend for an app that sends no writes), proves each write blocked before the browser opens, saves each capture's accessibility tree and exits 1 on any capture it missed. Delete what nothing uses, in its own commit. Done when each surface has a baseline or a stated not captured reason.

  3. Tokens. Cluster raw values by role, name them by purpose and pair each surface with its foreground (references/tokens.md). Run token-mapping until every raw value maps to a role, a merge or a listed exception. Merges inside tolerance are decisions. Past tolerance, open one gate per cluster whose default is the merge. Make every identical-value swap on every route. Done when token-mapping reports zero gaps outside the exception list and pixdiff.mjs at tolerance 0 reports 0% for every surface a swap touched.

  4. Components. Build the most-used family end to end first (references/components.md). The text primitive and the small-text primitive ship in wave 1 beside Button. Document each with component-docs. Show the family to the person before fan-out, because a core bug found after screens consume the system costs a sweep (a disabled field still drawn red, a Combobox 2 px taller than Input, panel actions that do not wrap, a file drop that fails in silence). Done when every canonical component has a registry row and a doc, and its disabled, required, error and long-text states are captured in the showcase and shown to the person.

Installs
355
GitHub Stars
176
First Seen
Sep 28, 2026