| name | design-token-system |
| description | Architects a framework-agnostic design-token system with primitive/semantic/component tiers, theming and multi-brand/dark-mode alias contracts, and multi-platform export (CSS vars, Tailwind, JS/TS, iOS/Android) from one W3C-DTCG source via Style Dictionary. |
| when_to_use | Setting up or refactoring a token architecture, building a theme/multi-brand/dark-mode system, exporting one token source to web + native, or adopting Style Dictionary / the W3C Design Tokens format. Distinct from style-responsive-tailwind (consuming tokens in markup) and brainstorm-design (choosing the palette/visual direction). |
When to Use
Reach for this skill when the problem is the token architecture and export pipeline, not a single component's styling:
- "Set up design tokens / a theme system from scratch"
- "Add dark mode without forking every color"
- "Support multiple brands / white-label from one codebase"
- "Export the same tokens to CSS, Tailwind, and our iOS + Android apps"
- "Adopt Style Dictionary / the W3C Design Tokens (DTCG) format"
- "We have 300 hardcoded hex/px values — give us a governed token layer"
NOT this skill:
- Writing the markup/utility classes that consume tokens → style-responsive-tailwind
- Picking the actual palette, type pairing, or visual mood → brainstorm-design
- Translating one Figma frame into a component → implement-from-design
- Building the React component that renders from tokens → build-react-component
- Wiring a cross-platform app shell/build → scaffold-cross-platform-app
- Certifying contrast ratios meet WCAG → audit-accessibility-wcag (this skill structures color; it does not verify contrast)
Steps
-
Build exactly three tiers — never let a component read a primitive. This is the whole architecture; get it wrong and theming is impossible.
| Tier | Names mean | References | Example | Rule |
|---|
| Primitive (global/core) | nothing — raw scale | literal values only | blue.500 = #2563EB, space.4 = 16px | No semantics. Never themed. Never imported by components. |
| Semantic (alias) | role/intent | → primitives | color.bg.surface → gray.50, color.intent.danger → red.600 | The only layer that swaps per theme/brand. |
| Component (scoped) | one part | → semantics | button.primary.bg → color.intent.brand | Optional; add only when a component overrides a semantic. |
Default to 2 tiers (primitive + semantic); add component tokens only where a component genuinely diverges. Components and Tailwind/CSS consume semantic tokens only.
-
One source of truth in W3C DTCG JSON. Use the spec's $value / $type and {dot.path} references so any compliant tool (Style Dictionary v4+, Tokens Studio) can read it. No per-platform hand-edited files.
{ "color": { "blue": { "500": { "$type": "color", "$value": "#2563EB" }
Common Errors
- Components reading primitives (
button { color: blue.500 }). Dark mode and rebrand degrade to find-and-replace. Components must reference semantics only.
- Forking the palette per theme (
blue.500.dark). Palette count explodes and brands drift. Themes swap the semantic alias target; primitives are shared and immutable.
- Semantic tokens holding literal values instead of
{references}. The indirection is the entire point — a literal hex in a semantic token can't be retargeted by a theme.
outputReferences: false (the default) flattening CSS vars. The build bakes #2563EB into every rule, killing runtime theme switching. Set options: { outputReferences: true } so var(--color-intent-brand) chains survive.
- Duplicating tokens into
tailwind.config by hand. They desync within the first week. Import the Style Dictionary build output; never maintain two sources.
- No grid/scale — arbitrary
13px, 17px primitives. Defeats consistency. Primitives come from a 4px (or 8px) grid and a modular type ratio.
- Treating contrast as solved because colors are tokenized. Tokens organize color; they don't guarantee
bg.surface/text.primary meet 4.5:1. Run audit-accessibility-wcag on each theme.
- Component tokens for everything, including parts that never override a semantic. Pure bloat. Add a component token only where it diverges from the semantic.
- Per-platform manual edits to
build/ outputs. They're regenerated; your edit vanishes on the next build. Fix the source and rebuild.
- No versioning/changelog on the token package. A renamed semantic token silently breaks every consumer. Semver it; a rename is a breaking (major) change.
Verify
- Tier discipline:
grep app/component source — zero references to primitive names (blue.500, space.4) and zero raw hex/rgb(/bare px. Every match is a violation.
- Aliases resolve: every semantic
$value is a {reference}, not a literal; style-dictionary build reports 0 unresolved references and exits 0.
- One source, many outputs: a single
style-dictionary build produces CSS, Tailwind, TS, iOS, and Android artifacts from the same tokens/ tree (no hand-edited platform file).
- Theme swap is alias-only: diff
semantic/light.json vs semantic/dark.json — they differ only in reference targets; primitive/ is byte-identical across themes. Adding a brand touches no primitive.
- Runtime switch works: toggling
[data-theme="dark"] on the built CSS recolors the page with no CSS recompile (proves outputReferences chains survived).
- Lint gate is live: committing a raw
#fff or 12px in app code fails CI, not review.
- Native parity: the same semantic token (e.g.
color.intent.brand) yields the same color in build/css/vars.css, build/ios/Tokens.swift, and build/android/tokens.xml.
- Governance: naming matches
category.role.variant.state, the package carries a semver + CHANGELOG, and a token rename ships as a major bump.
Done = one W3C-DTCG source builds all platforms with zero unresolved references, components reference semantics only (lint-enforced in CI), themes/brands swap via alias targets over shared immutable primitives, and runtime theme switching recolors with no recompile.