The predictable, reproducible 2026 workflow for migrating pixel-perfect designs from Figma into Pencil.dev — and then iterating inside Claude Code with a continuous visual-feedback loop that actually closes.
Select a frame in Figma → cmd+C. Open a .pen file in Cursor or Claude Code → cmd+V. Styles, auto-layout, and color variables come over pixel-perfect. Now you have a git-versioned canvas the agent can read and write. Ask Claude Code to generate React from the .pen. Run the dev server. A Playwright skill takes a screenshot of the rendered output, the agent reads the PNG via its vision capability, compares against the Figma reference, fixes specific numerical diffs, and iterates. Three to five rounds, total ~2 min, and the output matches the design with measured fidelity — not eyeballed.
getComputedStyle().fontSize and getBoundingClientRect() values from the rendered output, compare against the Figma spec, and feed numerical diffs to Claude Code: "heading is 28px, spec says 24px, change size from 7 to 6." Specific, numerical, unambiguous. The AI is the labor; Playwright is the quality gate; Figma is the source of truth.
The canonical pipeline is opinionated and CLI-runnable. Each stage is independently testable. Each stage has a verifiable output you can commit to git. No clipboard rituals required after stage 1 — once the .pen lives in the repo, every subsequent iteration is prompt-driven from Claude Code.
Select frames in Figma, paste into a .pen file opened in Cursor or VS Code. Auto-layout, padding, color/typography variables, components, and instances all preserve per Pencil's documented schema mapping.
$ touch src/designs/landing.pen
# Open in Cursor → Cmd-V
Figma Dev Mode MCP runs locally at http://127.0.0.1:3845/mcp. Tools: get_design_context, get_variable_defs, get_code_connect_map, get_image. The agent now sees Figma variables as real tokens, not eyeballed hex.
$ claude mcp add --transport http \
figma https://mcp.figma.com/mcp
Claude Code has the .pen in the repo and the Figma MCP at its disposal. Prompt: "Generate the landing page React component from landing.pen, use variables from Figma get_variable_defs, target shadcn/ui."
# in Claude Code
> read landing.pen and impl as
> Next.js + Tailwind + shadcn
Dev server up. Playwright captures three-viewport screenshots. Read screenshots/desktop.png in Claude Code — the agent sees what it built. Measure specific elements, compare to spec, patch. Repeat 3×.
$ npm run screenshot &&
claude < "Read screens/* and
compare to figma frame X"
reusable: true; instances import with ref. What doesn't: images. Pencil's docs explicitly warn that images don't paste from Figma — drag-drop them separately or use SVG. Complex vectors may lose path data on Figma's clipboard format — export problematic ones as raw SVG first.
Three MCP servers cover the entire loop: Figma (read-only source-of-truth), Pencil (read+write canvas), Playwright (visual feedback). Wire all three into Claude Code or Cursor and the inner loop has every primitive it needs.
Run these once, then they're available across all your repos:
~/.cursor/mcp.jsonPencil's Cursor extension auto-registers its MCP server when you install the extension — no manual entry needed. Verify in Settings → Tools & MCP.
The CLI, IDE extension, and desktop app all expose the same MCP surface. Memorize these — they're what gives Claude Code write access to the canvas (which Figma never will):
| Tool | Class | What it does |
|---|---|---|
batch_designwrite | write | Insert, update, delete, move, copy, replace nodes — the workhorse |
batch_getread | read | Search and read nodes by pattern or ID |
get_editor_stateread | read | Document metadata and structure |
snapshot_layoutread | read | Document structure with computed bounding boxes |
get_screenshotvisual | visual | Render a node to PNG — fuel for the visual loop |
get_variables / set_variablestokens | read+write | Read/update design tokens. The bridge to Tailwind config. |
find_empty_space_on_canvaslayout | read | Where to place new elements without overlap |
search_all_unique_propertiesutility | read | Recursive property search on a node tree |
replace_all_matching_propertiesutility | write | Recursive property replacement |
export_nodesexport | export | PNG / JPEG / WEBP / PDF export |
get_guidelinesstyle | style | Loads .pen guidelines + style refs |
claude CLI; credentials stored in ~/.claude/. Means: if your team uses Codex or Cursor's Anthropic-via-Cursor proxy primarily, you still need Claude Code installed for Pencil's canvas operations to work. For swarm.ing this is fine (your daily driver is Claude Code on Max plan). For mixed-CLI teams: budget for an extra Claude Code Pro seat per Pencil user.
Claude Code can read PNG files. That single capability is the entire visual feedback loop — the rest is plumbing. Three open-source skills (nukacha/claude-code-mock-starter, tonymfer/design-loop, leadgenjay test-improve) implement the same fundamental pattern with different orchestration. Pick one, don't reinvent it.
| Skill / Template | Repo | How it works | Best for |
|---|---|---|---|
| design-looptonymfer | tonymfer/design-loop |
Section-level screenshots via agent-browser. 5 anti-slop criteria scored 1–5 with weighting. Top-3 issues fixed per iteration, plateau detection after 3 stuck cycles. | Marketing pages, landing pages, anything with semantic section structure |
| claude-code-mock-starternukacha | nukacha/claude-code-mock-starter |
Vite + React template. Embedded Playwright MCP. Builder → critic → fixer agents. /discover → /spec → /tasks → /iterate with human gates only at first three. Tags every gap as [VISUAL] / [DATA] / [INTERACTION] / [STRUCTURAL]. |
Mock builds, proposal-grade work, client-facing prototypes |
| test-improveleadgenjay | leadgenjay.com/skills/test-improve |
4-phase: detect project → multi-viewport screenshot (1440/768/393) → audit against 6-category weighted checklist → fix → re-audit. Max 3 iterations. | Auditing existing pages, post-build polish, brand-compliance check |
| jimmc414 gistvisual development guide | gist.github.com/jimmc414/2416424a8e0fd6c0b5de948f28a00b13 |
The original pattern. Plain npm run screenshot → Read screenshots/desktop-*.png. No skill required, just a CLAUDE.md instruction. |
Greenfield projects where you want minimal harness overhead |
Four candidate paths from Figma to AI-iteration. The right path depends on whether Figma stays canonical or you migrate the source-of-truth. For swarm.ing's CLI-first workflow, Pencil is the answer. The others have their use cases.
| Path | Fidelity | Token sync | Code reuse | Source of truth | Best for |
|---|---|---|---|---|---|
Figma → Pencil .penrecommended |
High · Cmd-V preserves auto-layout, padding, variables, components | Native · Figma vars map to Pencil vars on paste | High · via Figma Code Connect or shadcn target | Drifts to .pen after import; Figma optional thereafter |
Agent-driven iteration with visual feedback loop · swarm.ing default |
| Figma → Paper.design | High · HTML/CSS-native; 24-tool MCP | Good · bidirectional but designer-led | Medium | Paper.design (after import) | GPU-shader-heavy brand work, motion design — niche |
| Figma → Magic Patterns | Medium · React-focused output | Low · no direct variable sync | High · React-structured handoff | Magic Patterns (after import) | Client-facing prototypes with versioning + SOC 2 / ISO posture |
| Figma stays canonicalMCP only | Absolute · Figma is single source | Native · get_variable_defs always reads live |
High · with Code Connect investment | Figma forever | Teams with dedicated designers, strict DS governance, big libraries |
.pen files commit alongside code. Design changes show up in PRs. Branch a feature, branch the design. No more "what version was this designed against?" (3) Real CLI: pencil --out --prompt --model means the entire design loop is scriptable. Cron a nightly design system audit. Pipe Figma exports through Pencil into Cloudflare Pages preview deploys. The boring infrastructure becomes possible.
Pixel-perfect doesn't mean pixel-diff. The trap most teams fall into is using Playwright's toHaveScreenshot() as the fidelity check — that catches code-to-code regression (did the UI change from yesterday?) but never catches code-to-design drift (does the baseline match the design at all?). For Figma-as-source fidelity, you need a measurement approach, not a comparison approach.
__name trap (will cost you an hour if you don't know)
If you write the measurement function as a TypeScript arrow function and pass it to page.evaluate(), tsx (TypeScript Execution) transforms your code and injects a __name helper that doesn't exist in the browser context. You get ReferenceError: __name is not defined from a script that looks correct. Pass a plain JavaScript string to page.evaluate(), or run via npx playwright test directly (which doesn't use tsx for the inner script). Documented in Vadim's March 2026 writeup.
Every one of these is a real failure mode documented in Pencil's troubleshooting guide, Figma's MCP setup docs, or 2026 published case studies. Read them once so you don't lose an afternoon to any of them.
Pencil's docs explicitly call this out as a known limitation. Image elements don't survive the clipboard. Vectors and text do.
FIX → Drag-drop images separately. Or import the entire Figma file viaFile → Import Image/SVG/Figma.... Or use SVG.
If Pencil doesn't have the font registered, your Fraunces hero text becomes Inter and you don't notice until you preview at full size.
FIX → Pre-install all design fonts via the OS, or specify web-font URLs in DESIGN.md and reference from Pencil tokens.If the designer used raw hex values (#FF0000) instead of Figma variables, get_variable_defs returns nothing.
Figma desktop must be running and Dev Mode MCP toggle must be on in Preferences. The local server only runs while Figma is open.
FIX →open -a "Figma"; Figma → Preferences → enable Dev Mode MCP Server. Verify at http://127.0.0.1:3845.
Pencil's .pen is JSON but the object tree restructures on changes, producing massive diffs even for small visual tweaks.
.pen files small (one component per file). Use git diff --stat not full diff in PR reviews. Pencil knows; text-diff readability is on their roadmap.
Figma's clipboard format doesn't always preserve complex path data on Cmd-V. Decorative SVGs may simplify or drop curves.
FIX → Export problematic SVGs from Figma first (Export → SVG), then drag-drop into Pencil. Or reference them externally via URL.
Selection-based prompting ("generate code from my current selection") only works with the desktop MCP. Remote requires a full URL with node-id.
FIX → Use desktop MCP for active design phases. Remote is for batch processing or when you can paste node URLs.Pencil's AI features require Claude Code installed and logged in. If you're a Codex-only or Gemini CLI shop, you'll need an extra Claude Code seat per Pencil user.
FIX → For swarm.ing this is moot (Claude Max already). For mixed teams, budget for it or use the headlesspencil --model flag to route via OpenRouter.
__name ReferenceError in Playwrighttsx injects a TypeScript helper that doesn't exist in browser context. Your page.evaluate() measurement script crashes.
page.evaluate(). Or run via npx playwright test directly (no tsx wrapper).
Without plateau detection, the agent will polish a screen forever, burning tokens on diminishing returns.
FIX → Usetonymfer/design-loop or test-improve which both cap at 3 iterations. Or set a hard budget in your CLAUDE.md instruction.
The hardest decision in this whole workflow isn't tool selection — it's where the canonical design lives after migration. Get this wrong and you'll have three out-of-sync sources, designers blaming engineers and vice versa. Five branches, pick one per project.
.pen into the repo, abandon Figma after migration..pen file is the design. Claude Code edits it directly via MCP. Visual loop closes inside the IDE. This is swarm.ing's default for Openclaw and CuriSphere..pen. Engineers iterate the .pen with agents. Updates flow back to Figma manually (or via Pencil → Figma export when Pencil adds it)./impeccable teach to seed DESIGN.md + PRODUCT.md. Prompt Claude Code to generate the .pen from text. Iterate in Pencil. Skip Figma until you need a real designer collaborator. This is the swarm.ing greenfield pattern..pen OR DESIGN.md as canonical. Generate everything else from it. Refuse "let's update both" — it never happens./teach). Canvas lives in .pen (commits to git). Code lives in your existing Cloudflare Pages repo. The visual feedback loop runs locally via Playwright. Only introduce Figma when you hire a designer who lives in it — then move to the Hybrid branch above.
Twenty primary sources current as of May 2026. Parallel.ai Pro processor synthesized the structural recommendations; Exa confirmed the specific commands, MCP tool names, and the Pencil docs verbatim. Vadim's blog and the Pencil docs do the heavy lifting on the fidelity gate. Verify before deploying to production.