From oh-my-design
Implements Figma designs: pulls the file, synthesizes the design system, builds frames pixel-faithfully with an iterative diff loop, matches responsive pairs, and ships a fidelity report.
How this skill is triggered — by the user, by Claude, or both
Slash command
/oh-my-design:figmaThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
When Figma exists, the design is already decided. The frame/concept/reference steps
When Figma exists, the design is already decided. The frame/concept/reference steps of the design loop are not needed — someone made those choices, and they are visible in the file. The job here is different: read what was designed, build it faithfully, systematize it so the implementation can be maintained, and tell the user honestly how close the build got.
Read protocol/reference-assembly.md under omd pack dir to preserve its boundary:
the Figma structural-bypass route is not a substitute reference assembly. Figma snapshot
frames and their attribution are the supplied design source, not LEGO fragments; do not
create candidate assemblies, a chat candidate table, a selection record, a clean-room
composite, or a reference-usage report for them. If the user separately asks for external
visual reference research, run that work through the normal chat-first LEGO protocol rather
than mixing raw external captures into the Figma route.
The slop linter still runs. If the original Figma design fires slop rules, report that to the user as information — never silently "fix" their design. The user hired a faithful implementation, not a corrected one.
omd doctor
Run omd doctor first, quietly. If any check fails, surface the failure in one
sentence and stop. A missing Playwright installation or an unwritable .omd/ will
break every subsequent step, and discovering that mid-loop is wasteful.
omd figma pull is the Figma API path, not interactive visual research. If a separate
user-directed external-region capture is needed, initialize browser-rs first; only an
observed initialization/capability failure permits headless, reduced-motion omd render
or omd probe as the deterministic Playwright fallback. Never open a reference board UI,
HTML, PNG, showcase, or omd-board for this route.
omd figma pull requires a Figma personal access token. This is the one allowed
user interaction in the skill. Check for it before pulling:
echo $FIGMA_TOKEN
If FIGMA_TOKEN is absent, tell the user exactly how to create one and where to set
it, then stop:
To use
oh-my-design:figma, you need a Figma personal access token.
- Open Figma → Account settings (your avatar, top-left) → Security tab.
- Under Personal access tokens, click Generate new token. Scopes: File content (read) is sufficient.
- Copy the token and set it in your shell:
To persist it, add that line toexport FIGMA_TOKEN=figd_...~/.zshrcor~/.bashrc.- Then re-run the skill.
Do not attempt to proceed without the token. Do not invent a workaround.
omd figma pull <figma-url>
This writes .omd/figma/snapshot.json — the normalized page → frame → node tree —
and prints a page/frame inventory so the implementer can see what they are building.
The snapshot includes a responsive section: frames grouped into breakpoint sets by
the name-suffix and structure-similarity heuristics. Read this section before
building. It is the answer to "which frames go together."
The pull also computes responsive pairs (F4). Read the responsive.breakpointSets
section to understand which frames are desktop/tablet/mobile variants of the same
screen. Unpaired frames are in responsive.unmatched — they will fall back to the
dual-viewport rule (build once, diff at the frame's own width; record that the
pairing was a fallback).
omd figma system
This reads the snapshot and writes two artifacts:
.omd/figma/design-system.md — color palette, type scale, spacing, radii,
shadows, and the component inventory as a human-readable table.:root CSS file with all tokens as custom properties, ready to paste into
the build's stylesheet.Build the design system before any frame. Components with variants become React components (when the project is React) or standalone CSS classes with modifier variants. Build each component set once; every frame that uses it is an instance, not a copy. A component that appears in three frames is implemented three times only if you did not read the inventory.
Record the component decisions:
omd decision "Button component: 3 variants (Size=sm/md, State=default/hover)" \
--why "component set from snapshot; variant props map directly to CSS modifiers"
For each frame in the inventory (name-matched responsive pairs count as one build target with multiple viewports):
① Build the frame — using the design system tokens from step 2, not hardcoded
values. Every color is a var(--color-*), every spacing is a var(--spacing-*),
every radius is a var(--radius-*).
② Diff
omd figma diff <frame-id> <rendered-page> --json
Read the cells array. Find the worst cells (highest mismatch). The cell
coordinates are in the reference image's pixel space — they tell you where the
divergence is, not just how much.
③ Fix — address the worst cells. Typical causes: wrong component size, wrong spacing token, missing border, wrong font weight. Fix the specific region the diff named; do not guess.
④ Re-diff — repeat until score ≥ 0.97 or the iteration ceiling is reached.
Ceiling: 4 iterations per frame. After 4, record the final score and move on. A frame that reaches the ceiling with score < 0.97 is not a failure of the loop — it is honest data. The fidelity report will show it.
Record each frame's final score:
omd decision "Hero frame: final score 0.983 (3 iterations)" \
--why "font rendering divergence on large display text; within antialiasing tolerance"
For each breakpoint set in responsive.breakpointSets:
For frames in responsive.unmatched (no Figma-side viewport partner):
omd decision "Contact page: no mobile variant in Figma — dual-viewport fallback applied" \
--why "responsive.unmatched; mobile layout interpolated from desktop, not diffed"
After all frames are built, run the slop linter on each page:
omd check <page> --category slop --json
If the slop linter fires on findings that trace back to the original Figma design (the indigo gradient that was in Figma, the three identical feature cards that were in the design), report them to the user as information, not corrections:
The original Figma design has these slop findings:
SLOP-GRADIENT(hero background),SLOP-TRIPLE-CARD(features section). The build implements the design as specified. If you want these addressed, update the Figma file and re-pull, or override them with a written reason.
Never silently "fix" the design. The user's Figma file is the source of truth.
If findings arise from the implementation (a gradient the build introduced that was not in the Figma file), fix them — those are build errors, not design choices.
Run the full check suite:
omd check <page> --json --viewport 1280x800
omd check <page> --json --viewport 375x812
Then deliver the working implementation plus a fidelity report table. The table is not a decoration — it is the honest record of how close the build got to the design.
Fidelity report format:
| Frame | Viewport | Score | Iterations | Notes |
|---|---|---|---|---|
| Hero | 1440px (desktop) | 0.983 | 3 | Font AA delta on display heading |
| Hero | 375px (mobile) | 0.978 | 2 | — |
| Features | 1440px | 0.997 | 1 | — |
| Contact | 1440px | 0.965 | 4 | Ceiling reached; map embed diff |
| Contact | 375px | — | — | Fallback: no Figma mobile frame |
Include the attribution map. The frame IDs are the sources. .omd/attribution.md
should record which Figma frame each token group was extracted from:
| Decision | Source | Reason |
|---|---|---|
| --color-bg: #ffffff | snapshot frame:1:2 (Hero) | dominant fill, luminance=1 |
| --type-scale-1: 48px | snapshot frame:1:2 (Hero) | display heading fontSize |
| Button component | component set "Button" | variant matrix from system step |
Everything lands in .omd/figma/ and .omd/attribution.md, committed with the repo.
When a Figma file is in the brief, the design decisions — concept, colour, type, layout — were made in Figma. The ultradesign loop's frame/concept/reference steps (steps 1–3) are not needed and should not run. Hand off here.
The discipline of the ultradesign loop that does carry over:
.omd/motion-spec.md; if not, the motion decision falls to the implementer and
must be recorded.$FIGMA_TOKEN is there.var(--color-*) from the
design system output.npx claudepluginhub 3x-haust/oh-my-design --plugin omdParses Figma links, extracts design specs, and generates UI code via Figma MCP. Useful for design-to-code translation and design token extraction.
Translates Figma designs into production-ready code with 1:1 visual fidelity. Use when implementing UI from Figma URLs, generating components, or matching Figma specs.
Translates Figma designs into production-ready code with pixel-perfect accuracy. Activates when user mentions implementing design, generating code, or provides Figma URLs.