Use when an ask names one phase of design system work, such as "extract tokens from the app" or "add states and specs to our Button", or for an empty repo, such as "start a design system from scratch". A whole-app ask on a shipped app ("we need a design system") goes to design-system-boss when it is installed. Moving an app onto an existing system is migrate-design-system.
Real-world examples not captured yet
This skill shows a gallery of live HTML demos (CDN libraries welcome — GSAP, Three.js, etc.) rendered inline via srcdoc.
Skill markdown
# 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. 5. **Checks.** Copy `scripts/check-system.mjs` and `scripts/oklch.mjs` into the repo's `scripts/`, run `--init`, then `--init-allowlist` once. A rule counts only once it is seen failing: plant one violation in a scanned folder, run `--files <plant> --no-allowlist`, see exit 1 naming the rule, then delete the plant. The allowlist and ratchet only shrink. A ban ships with its check rule in the same change. Copy rules ship with their exemptions, element-scoped, for text that must stay verbatim (quotes, terms, version strings) and for payload strings that a machine or person pastes elsewhere (a prompt, an API example, a clipboard value), because rewriting them changes what someone else receives. Done when the check exits 0 on a clean clone, `--self-test` ends "all as expected", and every rule the run added was seen failing on its plant this session. 6. **Pilot.** Move the pilot flow with a codemod you read hunk by hunk. Capture after with the baseline's command, widths, themes and data, changing only `--kind after`, then `pixdiff.mjs` the two folders. An unexplained difference is a defect. …
More from arla6ka
- Component DocsWrites one component's documentation entry from its code, stories and real call sites, in a Geist-style page order. Use for "document the button", "write docs for Select", "what states does Toast have", usage rules for a component, or a new or changed component. Skip foundations, overview pages and multi-component patterns. Docs for a whole design system go to design-system-boss.
- Design System BossUse for vague whole-app design system asks on an app that already ships UI, like "our UI is a mess, fix it", "we need a design system", "we hardcode colors everywhere", "make the buttons consistent for an upstream PR", "document our whole design system" or "check the app before I ship". Triages the app, then runs the design.how skills in order. One named screen goes to ui-review, one component to component-docs, an empty repo to build-design-system.
- LimeLime design system rules for this project's UI. Use when building or changing any screen, component, form or style, when porting an existing screen onto Lime, or when checking UI against Lime.
- Migrate Design SystemUse when an app has to move onto a design system that already exists, such as "migrate the app to our design system", "move every screen onto the new components", a rollout, or an adoption audit. When design-system-boss is installed and nobody has checked the system's specs, the boss triages first, since a migration copies a weak system's gaps everywhere. Not for making the system.
- QuartzQuartz design system rules for this project's UI. Use when building or changing any screen, component, form or style, when porting an existing screen onto Quartz, or when checking UI against Quartz.
- Token MappingReports how hardcoded style values on a page, file or diff map onto a project's existing design tokens, purpose first, then value. Use for "are we using our tokens here", "which hardcoded colors map to which tokens", a token audit or planning a token migration. It never edits and never creates or renames tokens. Fixes and whole-app consistency go to design-system-boss.