# Figma To Code

> Use when implementing a Figma design at pixel fidelity, auditing design-vs-code parity, or migrating many screens or a second breakpoint — and whenever a size, colour, radius or spacing value is about to be read off a screenshot, scaled from another breakpoint, or inferred from a sibling frame.

- Skill: `shivams07/figma-to-code` (Agent Skill, multi-file: 6 files)
- Install (CLI): `npx skillmds@latest add shivams07/figma-to-code`
- Raw SKILL.md: https://api.skillmd.com/api/skills/shivams07/figma-to-code/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Design & Media
- Author: shivams07 (https://skillmd.com/u/shivams07)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/shivams07/figma-to-code

---


# Measuring Figma Designs

## Overview

A Figma file is **source data containing defects**, not a specification. Screenshots show you what a
frame *looks like*; they cannot show you hidden nodes, tofu codepoints, stacked duplicates, impossible
padding, or a blur that is actually a copy of a photograph. Those only appear in the CSS.

**Core principle: measure every value, infer none, and record every place you deliberately don't match the file.**

The output is two documents: a **CSS spec** (the authority for how it looks) and a **deviations register**
(every place the file is defective and what ships instead). Without the second document, "pixel-perfect"
silently means "faithfully reproduced the bugs".

## When to Use

- Implementing a Figma screen where fidelity matters
- Auditing whether shipped code matches the design
- Migrating a flow, a role, or a whole app from a redesign
- Adding a second breakpoint from a different Figma file or page
- Any time you catch yourself about to write a number you did not measure

**Not for:** one screen you'll eyeball, or design work where the Figma file is a sketch rather than a spec.

## The Iron Rules

Each of these exists because violating it produced a wrong answer that survived until something else
contradicted it.

1. **Screenshots establish composition. Never values.** Use them to learn what a screen *is* and what it
   *does*. Never to read a size, colour, spacing, radius, or a background mechanism.
2. **Every value comes from `get_design_context`.** `get_metadata` is allowed for two things only:
   positions and box sizes of nodes that are **neither rotated nor flipped**, and **`hidden` flags**. A text
   node's height is its layout box, not its font size.

   ⚠️ **Flipped is not the same as rotated, and it is easy to miss.** For a node inside a `-scale-y-100` or
   `-scale-x-100` wrapper, `get_metadata` reports the **pre-flip origin** — which can place an element
   outside its own parent. Measured instances: a fade read at `y 603` when it actually sits at `496–603`,
   and progress segments read at `y 4` inside a `4px`-tall frame. A position that is impossible (below its
   container, outside the frame, at the far edge of a box it should fill) is the tell. Take flipped and
   rotated nodes from `get_design_context`.
3. **Never infer a state from its sibling.** "It obviously only differs in the footer" was wrong by four
   values and a whole anchoring change. Pull every state.
4. **Never derive one breakpoint's value by scaling another's.** Measured ratios on a single frame spanned
   1.00–1.73. Some components are byte-identical across breakpoints; others aren't. Measure; never compute.
5. **Establish rules from at least two frames per family before generalising.** Rules derived from one
   frame will be wrong for the rest — canvas colour, chrome, shell structure and header construction all
   varied by family in a file that looked uniform.
6. **Absence from the spec means "not yet measured", never "nothing to specify".** State coverage as two
   numbers: frames *viewed* and frames *measured*.
7. **Record retractions in place.** When a measurement overturns something you wrote, strike it, say what
   was wrong, and say *why it was wrong* — usually "because it came from a screenshot".
8. **1:1 by default; every departure justified in the register.** Reproducing a defect faithfully is not
   fidelity. Deciding silently not to is not either.

## Workflow

```dot
digraph figma_measure {
    "Check access + statefulness" [shape=box];
    "Inventory: frames + composition" [shape=box];
    "Measure 2+ frames YOURSELF" [shape=box];
    "Write rules (§0)" [shape=box];
    "More than ~8 frames left?" [shape=diamond];
    "Fan out: 1 part file per agent" [shape=box];
    "Measure serially into spec" [shape=box];
    "Editorial merge + reconcile" [shape=box];
    "Decisions gate" [shape=doublecircle];

    "Check access + statefulness" -> "Inventory: frames + composition";
    "Inventory: frames + composition" -> "Measure 2+ frames YOURSELF";
    "Measure 2+ frames YOURSELF" -> "Write rules (§0)";
    "Write rules (§0)" -> "More than ~8 frames left?";
    "More than ~8 frames left?" -> "Fan out: 1 part file per agent" [label="yes"];
    "More than ~8 frames left?" -> "Measure serially into spec" [label="no"];
    "Fan out: 1 part file per agent" -> "Editorial merge + reconcile";
    "Measure serially into spec" -> "Editorial merge + reconcile";
    "Editorial merge + reconcile" -> "Decisions gate";
}
```

### Phase 0 — Access and statefulness

The desktop Figma MCP reads **whichever document is the active tab**. Nodes from any other file return
"No node could be found". Confirm reachability with one cheap call before planning anything, and tell the
user not to switch tabs while agents are running.

A remote/API connector takes a file key explicitly and ignores tabs, but may require **editor** access.
If it 403s, the desktop app is your only route — say so early rather than discovering it mid-fan-out.

### Phase 1 — Inventory

`get_metadata` on the section to list frames (id, name, size). Then screenshot each frame **to learn
composition only**. Record a frame-by-frame audit table: node id, what the screen actually is, evidence
level. Expect frame *names* to lie — duplicate numbers, missing numbers, two frames sharing a name.
**Address frames by node id forever after.**

### Phase 2 — Measure two or more frames yourself, then write the rules

Do not delegate this. Pull `get_design_context` on the most structurally distinct frames and derive a
`§0` rules section covering:

- **Device/browser chrome to subtract** — mock status bars and browser bars are not app UI, and the
  offset they imply applies to every subsequent value
- **Canvas fill**, read from the frame — *not* from a bound variable, which may report something else
- **Whether a token layer exists.** Run `get_variable_defs`. Mostly-literals is normal; a handful of
  real tokens among literals is a signal worth chasing
- **Shell structure** — rails, headers, gutters, content column; and whether "screens" are pages, modals,
  or dialogs. Verify per family (Rule 5)
- **Type scale**, with actual ratios if a second breakpoint exists
- Which rules from a previous breakpoint's spec carry over and which explicitly do not

### Phase 3 — Fan out

One agent per 2–4 frames. Each brief must contain:

- The rules file to read first, and the house table style to match
- Its exact node ids, with a "stop and report if unreachable, do not guess" instruction
- **The specific measured values from comparable frames** to compare against — not "match mobile"
- The defect taxonomy to hunt (see `defect-taxonomy.md`)
- **The product decisions that kill UI**, so nobody specifies dead elements
- One output file **per agent** — never a shared file, or edits collide

**Deliberately give one shared-component claim to two agents who cannot see each other's work.** This is
the single highest-value trick in the workflow: independent agreement is evidence, and independent
disagreement finds real errors that a single pass asserts away.

Use `agent-brief-template.md` as the starting point.

### Phase 4 — Editorial merge

A separate agent with fresh context, no Figma calls. Renumber sections contiguously, merge all deviation
candidates into **one** register with duplicates collapsed into single rows citing every affected frame,
and produce:

- **A reconciliation section** — every cross-agent disagreement, both readings, and a verdict or an
  explicit "needs a human call". Hunt for unflagged ones too.
- **A cross-breakpoint section** if applicable — what is *proven* shared at ratio 1.0 and what genuinely
  diverges, each with its evidence.
- **A blockers section** — everything needing a human decision.
- **An asset inventory** — url → element → frames, flagging hashes shared across files.

Preserve every ⚠️ trap call-out and every retraction verbatim. Losing them re-opens settled questions.

### Phase 5 — Decisions gate

**Do not write an implementation plan yet.** Surface the decisions that no amount of measuring resolves:
contradictions between frames, values that fail accessibility, controls with no states, copy written for
the wrong role, screens the flow requires that nobody designed. Get rulings, then plan.

## Quick Reference

| Need | Tool | Notes |
|---|---|---|
| Any size/colour/type/radius/spacing | `get_design_context` | the only source of values |
| Position or box of an unrotated node | `get_metadata` | rotated nodes report a different envelope |
| **Hidden nodes** | `get_metadata` `hidden` flags | invisible to `get_design_context` |
| Token layer | `get_variable_defs` | may return `{}`; may disagree with the frame |
| What a screen *is* | `get_screenshot` | composition only, never values |
| Assets | urls in `get_design_context` | `curl` them; never re-trace an icon that exists |

## Common Mistakes

| Mistake | Consequence |
|---|---|
| Reading a background off a screenshot | A blurred copy of a photo becomes "a second canvas colour" — mechanism inverted |
| Generalising rules from one frame | Canvas, rail and header rules wrong for two of three shells |
| Inferring a sibling state | Four wrong values and a missed anchoring change |
| Trusting a bound variable over the frame fill | Every screen 12 units too dark |
| Transcribing padding on a fixed-size box | 105px of content specified inside a 79px box |
| Transcribing every radius | Four radii for one control that all render identically |
| Taking a text node's height as its font size | 39px box read as a 39px font when the font is 32px |
| Counting nodes to count UI | Ten rectangles for nine tiles; ~90 nodes rendering zero pixels |
| Normalising an odd value early | A deliberate second blue dismissed as a leftover |
| Measuring everything before ruling on scope | Sub-pixel work on rows a product decision had already deleted |

## Red Flags — stop

- About to write a number you did not measure
- About to say "it's the same as X" without pulling X
- About to scale a value between breakpoints
- About to write a rule from a single frame
- About to "clean up" an odd value without recording it
- A frame's header is not where the other frames' headers are — **find the wrapper**, don't correct the number
- A value looks arbitrary — **look for a hidden sibling** before transcribing it

## Files

- `defect-taxonomy.md` — the ~20 defect classes, how to detect each, what to ship instead
- `agent-brief-template.md` — fan-out brief template

