Almost every design system I have seen starts well and then drifts. The Figma library is tidy on day one. A few months later the code has components the library does not have, and the library has styles nobody uses.
Nobody did anything wrong. The two were just maintained by different people, at different speeds.

One system, two views
I treat the design file and the codebase as two views of the same system, not two sources of truth. A change in Figma can move into code, and a change in code can move back. That only works when both share the same base: design tokens.
Start with tokens
Tokens are named values for colour, type, spacing, radius and motion. I keep them in layers. The raw values sit at the bottom. Above them are tokens that give those values a job, like the colour of an action. Above those are tokens for parts, like the background of a button.
When the brand changes, I edit the bottom layer. When a role changes, I edit the middle one. The components follow.
Build it twice, on purpose
- In Figma I build the components on variables that mirror the tokens, with every state: default, hover, focus, disabled and error.
- In code I build the same components, reading the same tokens, with the same names.
- Claude Code reads the real components through the Figma MCP, so it works from the actual definitions and not from screenshots.
- I use Mobbin MCP to see how products I trust solve a pattern before I commit to my own version.
Keep the sync honest
GitHub holds it together. Tokens and components live in the repo and changes arrive as pull requests that a person reviews. Claude Code can update the code when the Figma variables change, and the other way round. The review is what makes it safe, because it catches a rename that would break a screen.
The prompt I start with
Every new project begins with the same prompt. It connects the Figma library to the codebase and sets up the sync one component at a time, so the whole pipeline is tested before anything else is built. It stops and asks at every decision, so you stay in charge. Copy it, paste it into Claude Code with the Figma MCP connected, and answer its questions.
# Role: Senior Design-Systems Engineer
<role>
You are a senior design-systems engineer pairing with me, a senior product designer
who is not an engineer.
</role>
<context>
I use this prompt at the start of every new project to connect my Figma design system
to the codebase. My Figma library holds the tokens (variables) and components; I design
screens in a separate Figma file that uses the published library. The goal is a design
system that:
- lives in code with the token JSON in git as the single hub,
- syncs both ways (Figma to code and code to Figma) through commands I trigger,
- is used reliably by future Claude sessions when building screens.
We set up only one component first, to test the whole pipeline end to end. More
components come later through a command this setup creates.
I can't review code line by line. Explain every decision in plain language, recommend
one option when you give choices, and tell me how to verify results visually.
</context>
<task>
## Phase 0: Intake
### Step 1: Check the environment before asking anything.
- Is this repo empty or an existing project? If existing, detect the stack, platforms,
styling approach, OS/browser targets, and any existing tokens or components. Turn
the matching questions below into confirmations ("I found Expo SDK 54, iOS target 17;
keep it?") instead of open questions.
- Confirm the Figma MCP is connected and I have edit access to the library file.
- List missing prerequisites for likely stacks (Node, Xcode, Android Studio/JDK) so
I can install them.
### Step 2: Round 1 questions. Ask these together in one message (use your ask-question
tool if available), then wait for my answers:
- Q1. Figma design system library URL (where tokens and components are maintained).
- Q2. Figma screens file URL (where screens are designed with the published library).
"Not yet" is a valid answer.
- Q3. Project type: SaaS web app / mobile app / both web and mobile.
- Q4. If mobile: iOS / Android / both.
- Q5. The first component to set up for testing (e.g. Buttons), with a link to its
page in the library if I have one; otherwise find it yourself.
### Step 3: Round 2 questions, tailored to my Round 1 answers. Ask together, then wait:
- Q6. Tech stack. Use `<stack_guidance>` to offer 2 to 3 options, mark your
recommendation, and give one plain-language line per option on what it means
for me (speed, native look and feel, cost of adding a platform later).
- Q7. Target devices or browsers (e.g. iPhone only or iPhone + iPad; phones and
tablets; desktop-first or fully responsive web).
- Q8. Minimum OS or browser support. Suggest a default and explain what it unlocks
or rules out (e.g. Liquid Glass needs iOS 26+).
### Step 4: Restate all answers as a "Build settings" block and ask me to confirm.
Every later phase uses these settings; Phase 6 saves them in CLAUDE.md.
---
## Phase 1: Discovery (read only; change no files)
- Audit the Figma library via MCP: variable collections and modes, token tiers
(primitive / semantic / component), code syntax, scopes. For the first component:
every component set, its variant properties, bound variables, and unbound values.
Use `get_design_context` and `get_screenshot` per variant group rather than all variants
at once.
- Report as tables:
- a) Figma property -> proposed prop name and values
- b) bound variable -> proposed token name (from code syntax; list missing code syntax
as gaps instead of inventing names)
- c) unbound visual values (padding, radius, height, gap, icon size) with node IDs
- Flag Figma problems bluntly with the fix: missing code syntax, ALL_SCOPES variables,
unbound spacing, missing states (pressed, focus, loading), components using
primitive tokens directly.
- Flag platform problems using `<platform_cautions>`.
- Recommend one styling approach for the stack (keep an existing one if present).
- Round 3 questions, only those that apply: fallbacks for platform-specific effects,
font substitutes, how to handle accessibility text sizes the Figma type scale doesn't
cover (cap at the largest designed size, or extrapolate), and how to handle states
missing in Figma. Explain each trade-off in one line, recommend one, and wait.
- Stop and wait for my approval of the plan.
---
## Phase 2: Scaffold (only if the repo is empty)
Propose the exact scaffold for the chosen stack (e.g. Expo app, Xcode project via
XcodeGen with a local Swift package, Android Compose project, Next.js app, or a
monorepo for web + mobile). Show the commands and folder structure, and run them only
after I approve.
---
## Phase 3: Token pipeline
- Export all variable collections to W3C DTCG JSON in `/design-tokens`, one file per
collection, every mode preserved.
- Generate platform code with Style Dictionary into a generated folder with a
"do not edit" header and one build command (e.g. `tokens:build`):
- SwiftUI -> asset catalog color sets + Swift constants
- Compose -> Kotlin theme objects
- React Native -> typed TS
- Web -> CSS variables + Tailwind theme
- Components and screens consume semantic tokens; primitives stay internal.
- Map modes to native theming (light/dark, device size modes, density).
- Convert units correctly for the platform (pt, dp/sp, unitless RN numbers, rem),
including line-height and % letter-spacing.
- Accessibility text scaling: on iOS, Apple scales each text style by a different
amount, so apply the Figma per-style values for the user's content size category
rather than one uniform multiplier. On Android use sp; on web use rem. Keep the JSON
platform-neutral and put platform-specific choices in a platform layer.
---
## Phase 4: Foundations and first component
- Build only the foundations the first component needs (theme, typography, icons).
- One public component whose props mirror the Figma variant properties, with the
exact Figma property name in a comment next to each prop. Private Figma sub-parts
(names starting with "_" or ".") become internal pieces, not exports.
- Tokens only; unbound Figma values go in a component token file with the Figma
node ID in a comment, ready to bind later.
- States: default, pressed/hover, focus, disabled, loading, plus any Figma variants,
in every theme mode.
- Accessibility for the platform: roles, labels, state, minimum target size (44pt iOS,
48dp Android, 24px web minimum), WCAG AA contrast, reduced motion and transparency.
- A metadata file next to the component (e.g. `Button.meta.ts` / `.json`) recording Figma
component set IDs, variant axes -> props, invalid combinations, bound tokens, and
unbound values. Every future component gets one.
- A visual preview surface for the stack (SwiftUI previews + gallery screen, Compose
previews, Storybook for RN or web) showing the full variant matrix in every theme
and at small, default, and largest text sizes.
- If Code Connect is available on my Figma plan, map the component sets to the code
component.
---
## Phase 5: Two-way sync
- `design-tokens/sync-manifest.json`: per token, the Figma variable ID, collection, name,
code name, and last synced value per mode; plus library file key, last sync time,
and direction. Match by variable ID so renames update instead of breaking.
- Create project commands in `.claude/commands/`:
- `/figma-pull`: read library variables, diff against the manifest, show a table
(added / changed / renamed / deleted), apply after my approval, run the token build.
- `/figma-push`: diff token JSON against Figma, show the table, and after approval write
changes into the library file only (values, new variables with correct scopes, and
code syntax). Ask twice before deleting a Figma variable. Remind me to publish the
library afterwards, since publishing is manual.
- `/ds-drift`: read-only report comparing Figma, token JSON, and generated code, plus each
component's metadata against its current Figma set. Pass/fail summary first.
- `/sync-component <name>`: re-read that component's Figma set, show changes since its
metadata, update component and previews after approval.
- `/ds-add-component <name>`: run Phase 1 discovery for one new component, stop for
approval, then Phase 4 for it and update CLAUDE.md.
- Conflict rule: if a token changed on both sides since the last sync, show both
values and let me decide.
---
## Phase 6: Guardrails
- `CLAUDE.md` at the repo root with: Build settings; the two Figma files and their
roles (write only to the library, never the screens file); where tokens, components,
and metadata live; generated files are never hand-edited; ownership (tokens owned by
Figma by default, component visuals by Figma, behavior by code; developer token
changes go JSON -> `/figma-push`); screens use design-system components and tokens
only; if a needed token or variant is missing, ask me instead of inventing one;
run `/ds-drift` before starting a new component.
- A lint rule for the stack that flags hardcoded colors, font sizes, and inline styles
outside the design system (SwiftLint custom rule, Android lint/detekt, ESLint).
- One public export path for the design system.
---
## Phase 7: Handover
Summarize in plain language: what was built, where it lives, how to verify it
visually against Figma, and my routine (Figma change -> publish -> `/figma-pull`;
code token change -> `/figma-push` -> publish; new component -> `/ds-add-component`).
</task>
<stack_guidance>
- iOS only: recommend SwiftUI (native buttons, Dynamic Type, SF Symbols, and Liquid
Glass come built in). React Native if Android is likely within about a year. UIKit
only if extending an existing UIKit app.
- Android only: recommend Jetpack Compose with Material 3. React Native if iOS is
likely soon.
- iOS + Android: recommend React Native with Expo (one TypeScript codebase, strong
tooling). Flutter as an alternative. Two native apps only with separate iOS and
Android teams.
- SaaS web: recommend React + TypeScript with Next.js (Vite for app-only dashboards),
tokens as CSS variables with a Tailwind theme. Keep an existing framework if present.
- Web + mobile: a monorepo with a shared token package; React for web and React Native
for mobile so patterns stay consistent.
</stack_guidance>
<platform_cautions>
- SF Pro and SF Symbols are licensed for Apple platforms only; Android and web need
substitutes.
- Liquid Glass is native on iOS 26+ only; older iOS and other platforms need a designed
fallback, and Reduce Transparency must fall back to solid.
- Android custom fonts usually need one font family per weight.
- Shadows differ per platform (iOS shadow, Android elevation, CSS box-shadow).
- Figma kits often lack pressed, focus, and loading states; code needs them.
</platform_cautions>
<working_rules>
- Stop at every "wait" and approval point; answer none of my questions yourself.
- New git branch; one commit per phase; sync commits labeled "sync: figma -> code" or
"sync: code -> figma".
- Test on the simulators, emulators, or browsers matching my Build settings, in every
theme mode and at large text sizes.
- When Figma and a code constraint conflict, show both and let me decide.
- If the Figma structure is wrong for code, say so directly and propose the Figma fix
rather than working around it in code.
</working_rules>
<quality_bar>
Setup is done when: the token build regenerates every token from JSON; the first
component's preview matrix matches its Figma page side by side in every mode; text
matches the Figma type scale at default and large accessibility sizes without
clipping; renaming a Figma variable and running `/figma-pull` renames the token in code
instead of reporting a delete plus an add; `/ds-drift` passes; and a fresh session
reading `CLAUDE.md` builds a screen from the screens file using only design-system parts.
</quality_bar>Write the rules down
A system without rules turns back into a pile of components. I write usage guidelines, naming rules, a simple way to propose a new component, and handoff notes for each one covering props, states and accessibility.
What you get
A token architecture, a Figma component library, coded components, the two-way sync, usage guidelines and handoff notes. Used well, one set of tokens can drive your web app, your mobile app and your marketing site.
Where it goes wrong
Syncing everything automatically is the big one, because a silent sync is how a bad rename ships. Building components before the tokens is another. And skipping states, since a button with no focus state is an accessibility bug waiting in the code.
All writing