Repository navigation
Releases
v0.3.0
- feat:
figma_verifychecks any running page. Passurl(and optionally
selector) to pixel-diff your own app against the Figma frame — any framework,
built by any tool — not only the HTML this server generates. - feat: images are written as files by default. Each distinct bitmap or vector
goes toassets/<hash>.<ext>once (and tonext/public/assets/for the Next.js
export), so a photo-heavy frame produces a ~60 KBgenerated.htmlinstead of a
20 MB one.inlineAssets: truerestores the single self-contained file. - feat: design tokens. Every conversion writes
tokens.json(W3C DTCG),
tokens.cssand a Tailwind v4tailwind.theme.css, collected from the colours,
fonts, font sizes, radii and spacing the frame actually uses. - feat: Tailwind output.
tailwind: trueemits the React / Next.js output as
Tailwind v4 classes (exact arbitrary values, theme tokens for colours and fonts)
and sets up Tailwind in the Next.js project. The HTML stays plain CSS for verify. - fix: fails fast instead of hanging on Figma rate limits.
figma_convertno
longer sleeps through multi-minute cooldowns: it tries once (whole-file download
capped byFIGMA_FILE_TIMEOUT_MS, default 90 s), then builds from any cached
copy of the frame and marks it STALE CACHE, or says when the limit lifts. - fix: clearer 401/403 errors: a dead token, a file the account cannot open and a
spent Figma cost budget are now told apart (via/v1/me). - fix: verify waits for webfonts before the screenshot. A small HTML file could be
captured before its Google Fonts had loaded. - fix: wrapped Auto Layout no longer pushes rows out of the frame. Figma keeps
two spacings for a wrapping row —itemSpacingbetween items and
counterAxisSpacingbetween wrapped rows — but CSSgapsets both. A
"space-between" footer with a 1,439 px item spacing wrapped its second row
1,439 px down and the frame clipped it. Wrapped layouts now emitcolumn-gap/
row-gapseparately (plusalign-contentfor SPACE_BETWEEN). On a real author
site this took verify from 148/162 elements with 9 over-clipped to 162/162. - fix: rotated elements are measured correctly. The element check compared a
rotated prop's unrotated design box with the browser's bounds of the turned
shape, so every rotated image counted as misplaced even when drawn exactly
right. Expected boxes are now rotated about their centre first. - fix: verify matches Figma's downscaled references. Figma exports a frame too
large for a 2x render at a smaller scale (a 1440x10490 frame came back at
1.49x). Verify now renders at the reference's actual scale instead of 2x, which
turned a meaningless 61% diff on such a frame into a real 9%. - chore: the optional refine loop defaults to
claude-opus-5-5at efforthigh,
with the server-side refusal fallback on (fallbacks: falseto disable). - chore: dependency updates (MCP SDK 1.32.2, Playwright 1.65, zod 4.6);
npm audit
clean. The Anthropic SDK moves to 1.6, which sends API version2026-10-21and
is Apache-2.0 licensed; the refine code needed no changes for it. After upgrading run
npx -y figma-codekit-mcp@latest --install-browseronce for the new Chromium.
v0.2.4
- Validate trusted npm publishing from GitHub Actions for the canonical package.
v0.2.3
- Rename the npm package and CLI to
figma-codekit-mcp. - Update install commands, setup checks and the local site branding.
- Align repository links and the MCP registry identifier with
figma-codekit-mcp.
v0.2.1 — --check and --install-browser, tag-triggered trusted publishing, MCP registry metadata
Setup can now be checked in one command, and the React and Next.js output
compiles when a frame uses components.
- feat:
--checktells you whether figma-mcp will work before an agent
tries. The server has nothing to say until an MCP host connects, so a fresh
install gave no way to tell a missing token from a broken browser.
npx -y @mehmoodqureshi/figma-mcp --checkreports the Node version, whether a
token was found and where (environment, or the.figma-tokenpath, never
the value), whether Figma accepts it (/v1/me), and whether the Chromium that
figma_verifyrenders in is on disk, then printsREADYor the fix for each
problem, exiting 0 or 1.--install-browserredoes a skipped or failed
Chromium download with the Playwright version this package pins. Both run
before the stdio transport starts, so stdout carries the report. - 28 new checks in
example/doctor-test.js, now part ofnpm test: every
/v1/meanswer (200, 401/403, 429, 5xx, offline, timeout), the report, and
the real binary in a scratch directory, including that the token value never
appears in the output. - fix: the React and Next.js output did not compile whenever a frame used a
bound component.generateReactemittedimport { Badge } from './components/Badge'for every Code Connect instance, and nothing anywhere
wrote that file — not the MCP server, notgenerateNext's file map. Two of the
three frames in the local cache hit it, sonpm run devdied on the first
import.generateComponentModules(ir)(src/codegen/react.js) now emits one
module per binding, and both callers write them. - fix: a bound instance rendered as a self-closing
<Badge />, so everything
Figma had inside it was dropped from the React tree. The HTML emitter keeps
that content (html.js,ROLES.COMPONENT) and React silently did not — the
two emitters disagreed about what the design contains, and since only the HTML
is ever rendered, nothing caught it. The instance's content is now passed to
the component as children, which is where it has to live: a binding is
instantiated many times per frame with different copy, so content held in the
module is content every instance shares. Building a real page with it in the
module rendered every nav link with the first one's label and lost 53 of 69
strings; as children, the page carries 63 and the render is pixel-identical to
the HTML. - feat:
figma_converttakesnext: trueand writes the runnable App Router
project to<dir>/next/.generateNexthas existed since 0.2.0 but was
reachable only throughsite/— the MCP server imported justgenerateHtml
andgenerateReact, so the one interface most people use could not emit a
Next.js project at all. - fix:
generateReactdropped the line breaks in multi-line copy. A break
arrives from Figma as "\n" inside a text run, and the HTML emitter turns it
into<br>(html.js,br()) while React interpolated it as raw whitespace.
These elements carrywhite-space:nowrapfrom cssgen, so a two-line headline
rendered as one long line overflowing its box, with the design's own breaks
gone. Found by building the generated project and diffing the running page
against the HTML: it accounted for the whole remaining 1.42% gap, which is now
0.00%.
v0.2.0
Verify now checks paint order and clipping
figma_verify gains a third signal alongside the pixel diff and the bounding-box IoU. Figma lists children back-to-front, so a node's pre-order index is its paint order; the render is probed with elementsFromPoint over a sample grid and the two orders compared wherever elements actually overlap.
This closes the blind spot the other two signals share by construction — elements present, in exactly the right box, stacked the wrong way round, or cut off by an ancestor's overflow where the design lets them overhang. Findings surface as WRONG STACKING / OVER-CLIPPED, and are reported even when the pixel diff has converged: a decorative overlay on the wrong side of a card shifts too few pixels to clear the threshold while being the first thing a person sees.
Two fixes make that signal trustworthy:
- Sampling scrolls the page and uses a square pitch, so findings no longer depend on viewport height. A 1440x10490 frame verified at a 900px viewport was previously sampled only across its first screen — 13 overlapping pairs instead of 502, and a clean bill of health for a frame with 24 stacking errors in it.
- Hit-testing briefly forces
pointer-events: auto, without which the probe skips exactly the decorative overlays the check exists to catch.
Next.js output
generateNext(ir, { assets }) emits a runnable App Router project — app/page.jsx, app/layout.jsx, app/globals.css, package.json, next.config.mjs. The component file is byte-for-byte generateReact's output, so the two can never drift apart in what they claim the design looks like; the rest is scaffolding. A canvas-fit design scales itself with hooks, so that variant alone is marked 'use client'.
Fixed: the React emitter produced no images
generateReact never received assets, so every image emitted src={""} and every vector emitted the "asset not exported" outline. The output was structurally correct and completely blank. It now takes the same assets map as the HTML emitter and follows the same rules: a cropped fill becomes a role="img" div carrying the background layer, everything else becomes an <img> with the data URI, and a missing export falls back to the same transparent placeholder.
A local web front end
npm run site opens a page for the same pipeline: a conversation that asks what to build — HTML, React or Next.js; exact or responsive — beside a pane carrying the generated app, its source files, the verify numbers and the pixel diff. It calls src/ directly rather than reimplementing anything, so it and the MCP server always agree. No build step, no new dependencies, excluded from the published package.
fontStylesheetUrls() was split out of html.js and exported so emitters that cannot use a <link> tag reach the same font list. generateHtml output is byte-identical across the change.