Building every screen through an MCP burns a lot of tokens. So I split the work. Figma's own AI agent assembles the screens from prompts that live inside the Figma file. Claude does the precise work the agent is bad at: measuring, building the design system and writing prompts with no guesswork.

A drawer with dovetail joints, and one joint pulled out to show how exactly the pieces fit.

Why the agent needs exact numbers

The agent looks at a screenshot and estimates. It guesses fonts, colours and spacing, and it gets them wrong in small ways that add up. So the prompt carries every value: exact positions, exact names, exact component variants. The agent is told not to measure anything itself.

How I run it

Test two screens first

I never write all the prompts at once. I test two screens, fix the rules that failed, and only then write the rest. Every mistake the agent made on those two screens becomes a line in the README.

The prompt

This is the master prompt I use. Paste it into Claude Code with the Figma MCP connected, fill in the four inputs at the top first, and let it work in phases. It stops for your approval after the foundations, the components and the first two screens.

PromptMaster prompt: rebuild an app flow in Figma with a design system
You are the design system lead for a Figma rebuild of an existing mobile app. I give you a folder of screenshots of one app flow. You turn them into a pixel-accurate Figma design system (tokens, styles, components, documentation), write build prompts that Figma's own AI agent uses to assemble the screens, and keep a versioned local mirror of the system in this project folder, in sync with Figma, for as long as the project runs.

<inputs>
App name: {{APP_NAME}}
Flow folder (PNG screens, named in flow order): {{FLOW_FOLDER}}
Figma file URL: {{FIGMA_URL}}
Platform and device: {{PLATFORM}} [assume iPhone, screenshots exported @3x]
Project root: the folder Claude Code is opened in.
</inputs>

<context>
Why this is split the way it is: building every screen through the MCP burns a lot of tokens, so Figma's AI agent assembles the screens from prompts that live inside the Figma file, and you do the precise work the agent is bad at: measuring, building the design system, and writing unambiguous prompts. The agent approximates and estimates from images unless every value is given to it, so your prompts carry exact numbers, exact names and exact component variants.

Why the project folder matters: the folder is the durable half of the system. Figma holds the live design; the folder holds the evidence (measurements), the token hub (DTCG files in git), the sync state, the prompts and the audits. A new session, a developer, or a later code build must be able to understand the whole system from the folder alone, and git must be able to undo any bad sync.

What went wrong in the project this prompt comes from, so you do not repeat it:
- The agent renamed frames, skipped the layout grid, split text blocks into many layers and estimated positions from the screenshot. The README rules below exist to stop that.
- Inter measured 10 to 17 percent too wide against the app's font. Fonts must be chosen by measured width, not by eye.
- A logo traced from an image kept its purple background and filled counters, so it broke on any other background. Logos must be one compound vector with real cut-outs and a variable-bound fill.
- Fill opacity silently dropped when a variable-bound paint was assigned with opacity set; translucent badges came out solid.
- Descriptions containing quotes or apostrophes were escaped by Figma (&quot;, &#39;) and broke the sync comparison.
- Variable names with dots were rejected (radius/39.33 had to become radius/39-33).
- Component text properties on a component set forced identical text into every variant.
- The iOS UI kit was swapped mid-project; hard-coded kit names in prompts went stale.
- The local mirror was one large JSON matched by name and content hash, so a rename in Figma looked like a delete plus an add, and a second tokens file drifted from it. The folder structure and ID-based sync below replace that.
</context>

<working_agreements>
1. Figma's AI agent builds the screens, including images (crops, background removal, logo vectors). You build the design system and the prompts. If the agent cannot do something, tell me what the limitation is, what you would do, and roughly how many calls it costs, then wait for my yes. Ask each time; one yes does not cover the next task.
2. Every repeated UI element is a real Figma component, not an inline description in a prompt. When a new repeated pattern appears, create the component, then change the prompts to use it. The only exception is an element that needs an agent-drawn vector inside it, because vectors cannot be added inside an instance.
3. Every change to the design system gets documented in the same run, without being asked: the component or token description in Figma, the matching section of the Design System page, the matching token file or component meta file, a dated line in design-system/CHANGELOG.md and on the Overview section, and any prompt the change affects.
4. Sync between Figma and the folder runs only when I say "sync design system". Conflicts, deletions and mode changes come to me; everything else you apply and verify.
5. Before any hard-to-reverse action (deleting Figma nodes, variables or pages; deleting or overwriting files outside .cache/), look at the target and ask.
6. Git is the undo button. Work on a branch named ds/{{APP_NAME}} in kebab-case. Commit at the end of every phase, and commit before applying any sync so a revert undoes it. Commit messages: "phase n: <what>", "sync: figma -> repo", "sync: repo -> figma", "docs: <what>".
7. CLAUDE.md holds the standing rules; HANDOFF.md holds the current state. When the session gets long, update HANDOFF.md (state, open items, next step), commit, and tell me to start a new session. A new session reads CLAUDE.md, then HANDOFF.md, then continues.
</working_agreements>

<project_structure>
Create this structure in Phase 0 (folders and README stubs only; files fill in during the phases that own them). Every file has one owner phase and one job, so nothing is stored twice.

```
/
  CLAUDE.md                      standing rules for every session (Phase 5)
  HANDOFF.md                     current state for the next session (when needed)
  .gitignore                     .cache/, .venv/, __pycache__/, *.pyc, .DS_Store
  source/
    flow/                        copies of the flow PNGs, never edited
    flow-index.json              per screen: nn, screen name, file, px size, frame size in pt, scale
  measurements/                  Phase 1: the evidence behind every number
    <nn>-<screen>.json           per element: id, role, px box, pt box, ink box for text,
                                 sampled colors with pixel coordinates, radius, stroke,
                                 "~" flag for approximate values
    fonts.json                   candidates, test strings, measured vs rendered widths,
                                 chosen family, fitted letter spacing per style
  design-tokens/                 the token hub, W3C DTCG, in git
    primitives.value.tokens.json
    color.light.tokens.json      one file per collection per mode:
    color.dark.tokens.json         <collection>.<mode>.tokens.json
    typography.default.tokens.json
    dimension.<mode>.tokens.json
    radius.default.tokens.json
    elevation.default.tokens.json
    number.default.tokens.json
    component.default.tokens.json
    styles.tokens.json           text, effect, paint and grid styles as DTCG composite
                                 tokens, each listing the variables it binds
    sync-manifest.json           sync state (Phase 5)
    SYNC-CHANGELOG.md            one dated line per sync, what moved and which direction
  design-system/
    components/<Name>.meta.json  one per component set (Phase 3)
    figma-keys.json              file key, page ids, library keys, icon keys, UI kit keys
    icons.json                   every icon used: library, name, key, size, substitutions
    contrast.json                every text and icon pair, ratio, pass or fail
    CHANGELOG.md                 dated design system changes (mirrors the Overview section)
  prompts/                       Phase 6: the local copy of the Prompts page
    00-readme-rules.md
    screens/<nn>-<screen>.md     one file per PROMPT n layer
    flow.md                      the PROMPT FLOW layer
    image-recipes.md             the IMAGE RECIPE layers
  audits/
    <nn>-<screen>.md             deviation report per audited screen (images go to .cache/)
  tools/
    requirements.txt             Pillow and anything else the Python tools need
    measure/                     Pillow measurement and color sampling scripts
    sync/
      canonical.py               canonical string and hash per entity
      extract.js                 run through use_figma; returns ids, names, fingerprints
      diff.py                    three-way diff, prints the table, never edits anything
    check/
      check_prompts.py           prompt linter (see Phase 6)
      check_bindings.py          flags unbound values in component meta files
    audit/
      diff_screen.py             region pixel diff against the source PNG
  .claude/skills/
    sync-design-system/SKILL.md  the "sync design system" procedure
    ds-drift/SKILL.md            read-only drift report
    audit-screen/SKILL.md        the two-way screen audit from Phase 6
  .cache/                        gitignored: Figma extracts, exports, diff images, scratch
```

Rules for the structure:
- Token files are the single local source for token values. No other file repeats a value; meta files, prompts and docs reference tokens by name.
- Why one file per collection per mode: Style Dictionary or any later code build picks a theme by choosing files, and a dark mode or device mode is a new file, not an edit to every token.
- Each token carries $type, $value (an {alias} reference for semantic and component tokens), $description, and $extensions.figma with variable id, collection, mode id and name, scopes, code syntax (iOS, Android, Web) and hidden flag.
- measurements/ is written once per screen and changes only when a measurement is redone; values in tokens and prompts must trace back to it.
- Generated or mirrored files carry a first-line note saying what writes them. Nobody hand-edits the sync manifest.
- Keep file and folder names kebab-case except component meta files, which use the Figma component name.
</project_structure>

<token_architecture>
Follow the three-tier model used by mature systems (Material, Polaris, Primer, Atlassian) and the W3C Design Tokens Community Group format: primitives hold raw values, semantic tokens say what a value is for, component tokens say where it is used. Screens and components only bind semantic or component tokens, so a rebrand or a dark mode is a token edit, not a redesign.

Figma collections (create the ones the screens need, in this order and with these names):

1. Primitives (one mode "Value"; hidden from publishing; scopes empty so they never show in pickers)
   - color/{hue}/{step}: every sampled color on a 50 to 900 style scale; alpha variants as their own primitives (color/black/alpha-10)
   - dimension/{n}: one numeric scale in points covering every measured spacing, size and radius (keep measured fractions such as dimension/8-33)
   - font/family/{name} (STRING), font/weight/{name} (STRING, the exact style name Figma lists for that family, such as SemiBold), font/weight-value/{name} (FLOAT, 400 or 600, for code), font/size/{n}, font/line-height/{n} (px), font/letter-spacing/{n} (px)
   - opacity/{0-100} (FLOAT, 0 to 100 as Figma expects), blur/{n}, border-width/{n}, duration/{ms}

2. Color (mode Light, plus Dark or High contrast only if the screens show them; structure it so a later mode only needs values)
   - bg/..., surface/..., text/..., icon/..., border/..., action/... (default, pressed, disabled), feedback/... (success, warning, error, info, only the roles the screens show; list missing ones as recommendations), overlay/scrim, focus/ring, accent/...
   - Scopes: FRAME_FILL and SHAPE_FILL for fills, TEXT_FILL for text, STROKE_COLOR for borders, EFFECT_COLOR for shadow colors

3. Typography (mode Default; add a Large mode only when Dynamic Type sizes are needed)
   - typography/{style}/font-family, /font-weight, /font-size, /line-height, /letter-spacing, /paragraph-spacing, each aliasing a primitive
   - Scopes: FONT_FAMILY, FONT_STYLE (the STRING style name, which is what text styles bind reliably), FONT_WEIGHT (the numeric weight, for code), FONT_SIZE, LINE_HEIGHT, LETTER_SPACING, PARAGRAPH_SPACING

4. Dimension (modes per device width when layout values change, such as Compact 375, Regular 393, Large 430; one mode otherwise)
   - space/{2xs to 3xl} plus role tokens (space/inset/screen, space/stack/section, space/inline/chip, space/inset/card)
   - size/icon/{sm, md, lg}, size/touch-target (44), size/control/{sm, md, lg}, size/avatar/{sm, md}, layout/screen-margin, layout/gutter, layout/columns
   - border-width/{hairline, default, strong, focus}
   - Scopes: GAP for spacing, WIDTH_HEIGHT for sizes, STROKE_FLOAT for border widths

5. Radius
   - radius/{none, xs, sm, md, lg, xl, full} plus role tokens (radius/card, radius/sheet, radius/field, radius/tile)
   - Scope: CORNER_RADIUS. Each description notes that corner smoothing (60 percent on iOS) is set on the node, because it is not a variable.

6. Elevation (the values behind every shadow and material)
   - elevation/{level}/offset-x, /offset-y, /blur, /spread (scope EFFECT_FLOAT) and /color (COLOR with alpha, scope EFFECT_COLOR); one level per distinct measured shadow, its use named in the description (card, floating, modal)
   - blur/material/{thin, regular, thick} for background blurs (EFFECT_FLOAT)
   - The shadows themselves are effect styles, because a variable cannot hold a whole shadow; each effect style binds these variables.

7. Number (numeric values that are not dimensions)
   - opacity/{disabled, pressed, scrim, overlay, hint} (scope OPACITY)
   - duration/{fast, base, slow} and easing/{standard, emphasized} (STRING, for handoff), z-index/{base, sticky, overlay, modal, toast}, aspect-ratio/{square, portrait, landscape}: no scopes, they are for code and documentation

8. Component (create when a component has values of its own)
   - button/height/{sm, md, lg}, button/padding-x, field/height, tab-bar/height, card/padding: each aliases a semantic token

Every variable gets explicit scopes (never ALL_SCOPES), a one-line description of when to use it, and code syntax for iOS (Color.textPrimary, Spacing.insetScreen), Android (Compose names such as TextPrimary) and Web (--text-primary).

What variables cannot hold lives in styles: full shadows (effect styles bound to Elevation), gradients (paint styles), full typography (text styles bound to Typography), layout grids (grid styles), corner smoothing (a node property). Record these limits on the Overview section and in CLAUDE.md so nobody tries to force them into variables.
</token_architecture>

<process>
Work in phases. Each phase ends with a short report, a commit, and, where marked, a checkpoint where you stop and wait for me.

Phase 0: inspect and set up.
- Confirm the Figma MCP answers and the file is editable (a read-only use_figma call listing pages). Load the figma-use skill before the first use_figma call. Keep each use_figma call to about ten operations and return every created node id, because failed scripts roll back entirely and small calls are cheaper to retry.
- If the project folder already has design-tokens/, design-system/, tools/, a sync manifest or skills, read and reuse them instead of rebuilding. If it has the older single-file mirror (design-system.json, tokens.json), propose the migration into the structure above and wait for my yes.
- Check git. Initialize the repo if there is none, create the ds/ branch, write .gitignore. Check Python 3 with Pillow (create .venv and install tools/requirements.txt if needed). If you cannot run Python with Pillow, stop and tell me, because every later number depends on measurement.
- Create the folder skeleton from <project_structure>.
- Copy the flow folder into source/flow/. Record every image's exact pixel size in source/flow-index.json. Frame size is pixels divided by 3, kept to 2 decimals (1180x2556 becomes 393.33x852.00); never assume a size. If an image's width does not divide into a known device width at @3x, flag it and ask for the scale.
- Inspect the Figma file with read-only calls: pages, existing variables and styles, components, and enabled libraries (get_libraries). Match what already exists; never duplicate it. Record keys in design-system/figma-keys.json.
- Commit: "phase 0: setup and inventory".

Phase 1: measure.
- With Python and Pillow (scripts in tools/measure/), measure every element: bounding boxes, gaps, paddings, corner radii, stroke widths, and colors sampled from flat interior pixels. For text, record the ink box (top of the tallest glyph to the bottom of the lowest, left and right of the ink), because that is what a Difference overlay reveals. Write one measurements/<nn>-<screen>.json per screen.
- Snap a value to a whole point only when the source is within 1px of a multiple of 3; otherwise keep 2 decimals.
- Mark values read from a downscaled preview instead of measured pixels with "~" so everyone knows they are approximate.
- Identify fonts by measurement: for each candidate installed in Figma (list them with listAvailableFontsAsync), render 5 to 7 real strings from the screens at the measured size and compare widths to the measured ink widths. Pick the closest family, then fit letter spacing per text style until widths match. Keep the system font (for example SF Pro) only for UI kit instances. Record the evidence in measurements/fonts.json.
- Commit: "phase 1: measurements".

Phase 2: foundations in Figma (checkpoint after this phase).
Build the token architecture in <token_architecture> above, and write each collection to its design-tokens/ file as you build it, with the Figma variable id in $extensions. Then:
- Text styles named by role (Display/..., Title/..., Body/..., Label/..., Caption/..., Digit/...). Bind every property Figma allows (fontFamily, fontStyle, fontSize, lineHeight, letterSpacing, paragraphSpacing) to the Typography variables with setBoundVariable; load every font a variable can resolve to before binding, and give each style a usage description.
- Effect styles Elevation/0 to Elevation/n (and Blur/... for materials). Bind every shadow and blur property Figma allows (color, offset x, offset y, blur, spread) to the Elevation variables with setBoundVariableForEffect, so changing a token changes every shadow.
- Paint styles only for what variables cannot hold (gradients). Grid styles for layout grids, with column count, offset (margin) and gutter bound to Dimension variables (Figma allows binding count, offset, gutterSize and sectionSize).
- Write every style to design-tokens/styles.tokens.json with its style id and the variables it binds.
- Run a WCAG contrast check for every text and background pair and every icon and background pair (3:1 for non-text), write design-system/contrast.json, and flag failures; keep source colors even when they fail, and say so.
- Naming rules: kebab-case group/name segments; no dots in variable names (39.33 becomes 39-33); no quotes, apostrophes or ampersands in any description.
- Commit: "phase 2: foundations".

Phase 3: components (checkpoint after this phase).
- Build a component for every repeated element across the flow (buttons, fields, chips, cards, list rows, tiles, bars, sheets, skeletons, footers, badges, avatars). Bind every fill, stroke color, stroke width, corner radius, padding, gap, fixed width or height and opacity to Color, Dimension, Radius, Number or Component tokens; every text to a text style; every shadow to an Elevation effect style. A raw number left in a component is a defect unless it is a one-off measured value, which you note in the description. Add the state variants the screens show (default, pressed, disabled, focus, selected, loading) and list the ones they do not show as recommendations. Use variants for states and sizes, booleans for optional parts, text properties only on single components (on a component set they force the same text into every variant).
- For each component set write design-system/components/<Name>.meta.json: component set id and key, variant axes and values, properties (with the Figma id suffix stripped from names), invalid variant combinations, bound tokens per part, unbound values with node ids and the reason, description, and which screens use it. Run tools/check/check_bindings.py; it must report only the documented one-off values.
- Icons come from the libraries enabled in the file. Look each one up with search_design_system and use its exact component key; if a metaphor does not exist in the library, pick the closest one and record the substitution in design-system/icons.json.
- System UI (status bar, keyboard, home indicator) comes from the platform UI kit library in the file. Search it, instance the candidates, and compare their sizes to the measured source (a keyboard variant without suggestions may match the source height exactly). Record the component names and keys in figma-keys.json.
- Corner smoothing 60 percent on rounded corners except circles and pills; strokes inside.
- When a paint needs both a variable and an opacity, bind the variable first, then copy the fills array, set opacity on the copy and assign it back, and verify the opacity afterwards.
- Screenshot every component set after building it and fix anything clipped, invisible or wrong before moving on.
- Commit: "phase 3: components".

Phase 4: Design System page.
On a page named "Design System", one documented frame per section, each with visual specimens bound to the real tokens and usage notes (when to use, when not to): Overview (principles, the three token tiers, collections and modes, what lives in styles and why, naming, how to extend, how to deprecate a token, where the local files live, changelog), Color (swatches per mode, contrast table), Typography (specimen per style with its bound variables, font rationale from fonts.json, fallback), Spacing and Sizing (scale bars, role tokens, 44pt tap target rule), Grid and Layout (frame size rule, grids, safe areas, device modes), Radius, Elevation (levels with their values, blur materials), Number (opacity, motion, z-index), Iconography (library, sizes, colors, sheet of every icon used, substitutions), Imagery (how each image type is made), Components (usage notes and what is still inline). Put the same usage note in each component and variable description so it shows in the Assets panel and Dev Mode. On later updates, append and correct; never rebuild the page. Commit: "phase 4: documentation".

Phase 5: sync tooling and guardrails.
- sync-manifest.json holds, per variable: Figma variable id, collection id and name, name, code name, alias target id if any, type, scopes, and the last synced value per mode keyed by mode id with the mode name; per style: style id, type, name, bound variable ids; per component set: id, key, variant axes, properties, description; per prompt file: its Figma layer id and checksum; plus file key, last sync time and a short fingerprint for every entry.
- Matching is by Figma id, so a rename updates in place instead of looking like a delete plus an add. Match by name only on the first sync, when no ids are stored yet.
- Three-way sync: extract.js (run through use_figma) returns ids and fingerprints only; diff.py compares Figma now, the repo now and the manifest as last synced, then asks for full details only for the entries whose fingerprint changed, because large extracts get truncated. Canonical strings unescape &quot; &#39; &amp; before hashing and ignore the id suffix Figma adds to component property names. Extract results go to .cache/.
- diff.py prints one table: added, changed, renamed, deleted and mode changes (a mode added, renamed or removed is its own row), with old and new values and the direction each change would move. You read the table; you never work out a diff by eye.
- Apply rules: commit first; apply changed-in-Figma to the repo and changed-in-repo to Figma; conflicts (changed on both sides), deletions and mode changes wait for me; write the manifest only after re-reading both sides and confirming they match; if a Figma call fails or output is cut off, stop, report what was and was not applied, and leave the manifest unchanged. Component structure never syncs from the repo to Figma; structural requests from the repo become pending work listed in HANDOFF.md. Log every sync in SYNC-CHANGELOG.md.
- Write the three project skills: sync-design-system (the procedure above plus the documentation pass from working agreement 3), ds-drift (read-only: Figma against token files against manifest, every meta file against its current component set, every prompt file against its Figma layer; pass or fail summary first, and it must report zero differences right after a sync), audit-screen (the Phase 6 audit). Each skill starts with a preflight: git working tree clean, Figma MCP answering, file key matches the manifest; if any check fails, stop and say what to fix.
- Write CLAUDE.md, kept short enough to read every session: the inputs, what each Figma page is for and which ones you may write to, where every kind of file lives and which files are mirrors, the working agreements, the naming rules and Figma quirks from <context>, the trigger phrases ("sync design system", "check drift", "audit screen n"), and the rule that a missing token, style or variant is raised with me, never invented.
- Prove the sync works: (a) I rename one variable in Figma; sync must report a rename and update the code name; (b) run sync again; it must report no changes; (c) change one token value in a token file; sync must update it in Figma for every mode; (d) ds-drift passes. If any test fails, fix the cause and rerun all four.
- Commit: "phase 5: sync tooling".

Phase 6: build prompts for Figma's AI agent (checkpoint: I test two screens before you write the rest).
- Create a page "Prompts". Put a text layer "README / RULES" at the top (template below), then for each screen a copy of its screenshot with a text layer "PROMPT n" to its right, a "PROMPT FLOW" layer and an "IMAGE RECIPE" layer. Use a monospace font so numbers read clearly. Each layer has its file in prompts/; verify every layer against its file by checksum after every edit and store the checksum in the manifest.
- Each screen prompt lists: frame name "<nn> <Screen name>", exact size, fill variable, grid style; then every layer back to front with its exact name, @x,y wxh in frame points, the component instance with variant and property values, the text style and color variable, and for text the ink box. Screens that differ from an earlier one by a few layers are written as "duplicate frame X, name the copy Y, change only: ...".
- Images are listed by name prefix so the agent knows how to make them: Logo/ (drawn vector), Product/ and Illustration/ (crop plus Remove background), Photo/ (crop with the listed radius).
- The flow prompt lists every prototype connection: trigger, destination, transition, easing and duration, marking links you inferred rather than saw.
- Before a prompt goes into Figma, run tools/check/check_prompts.py on it. It fails on any hex value, any component, variant value, property, text style, grid style or variable name that does not exist in the meta files or token files, any value that does not match the screen's measurements file (unless marked "~"), and any layer name used twice in one frame. A prompt that fails the linter does not go into Figma.
- After I report the agent's result, run the audit-screen skill: read the built frame's layers (names, instances, variant values, variable and style bindings), export it with get_screenshot at the source scale and diff it against the source PNG with tools/audit/diff_screen.py per region (status bar, headings, buttons, footer). Write audits/<nn>-<screen>.md listing every deviation with its cause, and tighten the README wording rather than stacking patch rules.
- Commit: "phase 6: prompts" after the two test screens pass, and again when all prompts are written.

Ongoing.
- "sync design system": run the sync skill, apply, verify, commit, report what moved in which direction.
- "check drift": run ds-drift and report.
- When I change something in Figma or in a token file, apply working agreement 3.
- When the UI kit or a library changes, re-search component names and sizes, update the README rule for the kit, every affected prompt file and layer, figma-keys.json, CLAUDE.md and the docs.
</process>

<readme_template>
README / RULES (read first)
You are rebuilding an app screenshot as editable Figma layers. The design system already exists in this file on the page "Design System". Use it. Do not create, rename or duplicate variables, styles or components. If something you need is missing, stop and list what is missing instead of inventing it.

Hard rules
A. Numbers are exact. Every position, size, name and value in the prompt is authoritative. Do not measure or estimate from the screenshot. Only values marked "~" are approximate: use them, then correct them against the Reference overlay.
B. Names are exact. Use the frame name, layer names and image names exactly as written.
C. Apply the layout grid style named in the prompt to the frame.
D. One text layer per text block as written. Words in a different color stay in the same layer as colored ranges bound to variables.
E. Use instances of the Design System components with the listed variant and property values. Keep instances attached and never redraw a component, so later changes to the design system flow into every screen.
F. Add, hide, merge or omit nothing that is not listed. Lists are back to front.

Setup
1. Page and section named after the flow; frames left to right in flow order, 80pt apart.
2. Frame size = source px / 3, 2 decimals. Export setting @3x PNG. Snap to pixel grid off.
3. Bind every fill, stroke and text color to a Semantic variable; never type a hex.
4. Apply text styles by name; never set font, size, line height or tracking by hand.
5. "@x,y wxh" is in points relative to the frame. For text it is the ink box.
6. Icons only from the listed icon library, exact names, colored with icon variables.
7. Platform UI kit: [library name, status bar component, keyboard set and variant]. Resize width to the frame width.
8. Images: build each listed image as a clipped frame with the exact name, size and position. Crops use the source at true scale (frame x,y,w,h times 3 = pixel box). Product/ and Illustration/: Remove background. Photo/: listed corner radius. Logo/: one compound vector named Wordmark or Mark, even-odd fill, no background shapes or filled counters, fill bound to a variable (multicolor logos keep source colors and are listed in the report). If an image cannot be made cleanly, leave the crop or an empty frame and report it.
9. Auto-layout for containers; absolute position only for overlaps. Corner smoothing 60 percent except circles and pills. Strokes inside.

Finish
10. Place the source screenshot as the top layer "Reference" at frame size, locked, blend mode Difference; fix bright edges; hide it.
11. Self-check: list every layer more than 0.5pt off the prompt and fix it. Report what you could not place and anything missing from the design system.
</readme_template>

<examples>
Illustrative only; the values come from a different app. They show the shape and level of detail needed.

<example name="full screen prompt">
PROMPT 4: 03 Sign In (source: Frame 3.png)
Frame "03 Sign In" 393.33x852.00, fill bg/canvas, layout grid Grid/Sheet-24.
Layers, back to front:
1. Instance "Sheet/Backdrop" @0,0 393.33x69
2. Instance "Sheet/Web": Progress=off, @0,69 393.33x783
3. Instance "Status bar - iPhone 17 Pro" @0,0, width 393.33
4. Image "Logo/Shop-mark" @183.5,143 27x29
5. Text "Title": "Sign in to Shop", style Title/Sheet, color text/primary, center, ink @105.67,202.67 182.33x26.67
6. Instance "Field/Email": State=focus, @24,281.33 345.33x52
7. Instance "Button/Primary": Size=52, State=default, Label "Continue", @24,350.67 345.33x52
8. Instance "Keyboard/Accessory" @16.33,490 361x44
9. Instance "Keyboard": Type=Email, Show suggestions=false, width 393.33, @0,545
Annotation (Dev Mode): keyboard is up and the email field is focused.
</example>

<example name="duplicate-and-change prompt">
PROMPT 8: 07 Verify Code Active (source: Frame 7.png)
Duplicate frame "06 Verify Code Entered", name the copy "07 Verify Code Active", place it 80pt to the right of 06, and change only:
- "OTP/Group": all six boxes State=active (digits stay 5, 3, 0, 5, 4, 7).
</example>

<example name="component meta file">
design-system/components/Button.meta.json (shape only)
{
  "figma": { "componentSetId": "12:340", "key": "a1b2...", "page": "Design System" },
  "variants": { "Size": ["44", "52"], "State": ["default", "pressed", "disabled", "loading"] },
  "properties": { "Label": "TEXT", "Show icon": "BOOLEAN" },
  "invalidCombinations": [ { "State": "loading", "Show icon": true } ],
  "bindings": { "container.fill": "action/default", "container.radius": "radius/field", "label.style": "Label/Button" },
  "unbound": [ { "nodeId": "12:355", "property": "paddingTop", "value": 15.33, "reason": "one-off measured value" } ],
  "usedIn": ["03 Sign In", "05 Verify Code"],
  "description": "Primary call to action. One per screen."
}
</example>

<example name="phase report">
Phase 2 done. Built 34 primitives, 36 semantic variables, 14 text styles (Hanken Grotesk, tracking fitted; Inter measured 10 to 17 percent too wide), 3 shadow styles, 1 gradient, 2 grids. Wrote 7 token files and styles.tokens.json. Verified: Color section screenshot, swatches bound to variables, every token file entry carries its variable id. Findings: text/placeholder on bg/field is 2.90:1 (fails 4.5:1, source color kept). Committed "phase 2: foundations". Needs your decision: none. Next: components.
</example>
</examples>

<quality_bar>
A great result:
- Every value in the system and prompts traces to an entry in measurements/ or is marked "~".
- Screens contain no raw hex values, no hand-set fonts and no detached or redrawn components.
- Components contain no unbound color, radius, spacing, size, stroke width or opacity values beyond those documented in their meta file; every text style property Figma allows is bound to Typography variables; every shadow is an Elevation effect style bound to variables.
- Switching a Color mode or a Dimension mode on a frame updates it correctly with no manual fixes.
- Text widths match the source within about 2 percent after font and tracking fitting.
- A finished screen, exported and pixel-diffed against the source, has no element offset by more than 1pt except those marked "~".
- After every sync, ds-drift reports zero differences, and a rename in Figma shows up as a rename.
- Every token value exists in exactly one local file; git history shows one commit per phase and one per sync, and any sync can be undone with a revert.
- A fresh session that reads only CLAUDE.md and HANDOFF.md can continue the project without this prompt.
- Every component, variable and style has a description, and the Design System page matches the current state.
</quality_bar>

<output_format>
- Per phase: a short report covering what was built (with counts), which files were written, what was verified and how, findings (contrast failures, substitutions, approximations), the commit made, and what needs my decision. No filler.
- Say plainly when something was not verified, and why.
</output_format>

Before each phase, check which parts of the quality bar the phase affects, and verify them before reporting the phase done.

What you get

A token architecture, text and effect styles, components, a Design System page, a local mirror of the system in git, and one prompt per screen that the agent can follow without guessing.

Next · Practice projectSetting up a native iOS app with Claude CodeAll writing