figma-to-html-pixel-perfect 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +217 -0
- package/SKILL.md +1855 -0
- package/bin/install.js +42 -0
- package/package.json +23 -0
- package/references/accessibility-checklist.md +68 -0
- package/references/animation-guidelines.md +113 -0
- package/references/visual-review-checklist.md +121 -0
- package/scripts/figma_discover.py +218 -0
- package/scripts/figma_fonts.py +90 -0
- package/scripts/figma_icons.py +391 -0
- package/scripts/figma_lint.py +246 -0
- package/scripts/figma_pull.py +153 -0
- package/scripts/figma_report.py +1320 -0
- package/scripts/figma_spec.py +93 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 fieldqqq
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# figma-to-html-pixel-perfect
|
|
2
|
+
|
|
3
|
+
A Claude Code / Claude Agent skill that turns a Figma design into production HTML & CSS
|
|
4
|
+
with verified visual fidelity — and refuses to guess when it can't see the design.
|
|
5
|
+
|
|
6
|
+
It exists because the naive approach ("read the Figma JSON, write the CSS") reliably
|
|
7
|
+
produces a page whose section heights match to the pixel and whose design is completely
|
|
8
|
+
wrong. Every rule in `SKILL.md` is a guard against a failure that actually happened.
|
|
9
|
+
|
|
10
|
+
## What it does
|
|
11
|
+
|
|
12
|
+
- **Looks at the whole file first**: other design widths are other designs (build them, do
|
|
13
|
+
not guess them); an icon that ships in the file is never redrawn; hover variants named by
|
|
14
|
+
`interactions[]` are fetched, not invented.
|
|
15
|
+
- Pulls **exact values** from the Figma REST API (geometry, auto-layout, colour tokens,
|
|
16
|
+
real text, image refs) — not eyeballed from a screenshot.
|
|
17
|
+
- Pulls **one reference render per section**, and refuses to implement a section it
|
|
18
|
+
hasn't looked at.
|
|
19
|
+
- Builds **section by section**, verifying each one visually *and* numerically before
|
|
20
|
+
moving on.
|
|
21
|
+
- **Measures** font substitutions instead of guessing them.
|
|
22
|
+
- **Reproduces the motion the file already specifies** (`interactions[]`) as fidelity work,
|
|
23
|
+
and only asks approval for motion it would invent.
|
|
24
|
+
- Tells you up front which fonts the design needs and where to put them.
|
|
25
|
+
- Separates exact implementation from inferred behaviour from optional enhancement, and
|
|
26
|
+
asks before changing the design.
|
|
27
|
+
- Reports blocked sections as blocked, instead of shipping a geometry-only guess.
|
|
28
|
+
- Names, in the report, every breakpoint it did **not** build and every check it did **not** run.
|
|
29
|
+
- Audits in **both** directions: the design's nodes against the page, and the page's graphics
|
|
30
|
+
against the design. Anything you added that the design has no node for is listed.
|
|
31
|
+
- Checks *which* icon landed on a node, not merely that one did.
|
|
32
|
+
- **Builds from the numbers**, not from the picture: spacing comes from `itemSpacing`,
|
|
33
|
+
type from each TEXT node's `style`, copy verbatim from `characters`, icons from exported
|
|
34
|
+
vectors. A linter rejects any value — or any hand-drawn icon — the design never had.
|
|
35
|
+
- Ends with a **fidelity report** the user can open: every section, reference beside the
|
|
36
|
+
live page, cross-fade and difference-blend, height and content-extent checks, and a
|
|
37
|
+
per-text-node audit of position, size, weight and colour.
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
**npx (recommended)**
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx figma-to-html-pixel-perfect # personal: ~/.claude/skills (all projects)
|
|
45
|
+
npx figma-to-html-pixel-perfect --project # this project only: ./.claude/skills
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**One-liner without npm (pulls straight from GitHub)**
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npx tiged fieldqqq/figma-to-html-perfect-pixel \
|
|
52
|
+
~/.claude/skills/figma-to-html-pixel-perfect
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Personal skill (git — recommended if you want `git pull` updates)**
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
git clone https://github.com/fieldqqq/figma-to-html-perfect-pixel \
|
|
59
|
+
~/.claude/skills/figma-to-html-pixel-perfect
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Project skill**
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
git clone https://github.com/fieldqqq/figma-to-html-perfect-pixel \
|
|
66
|
+
.claude/skills/figma-to-html-pixel-perfect
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Restart the session; the skill is picked up automatically, or invoke it explicitly with
|
|
70
|
+
`/figma-to-html-pixel-perfect`.
|
|
71
|
+
|
|
72
|
+
## Requirements
|
|
73
|
+
|
|
74
|
+
- **Claude Code** (or any Claude agent runtime that reads `SKILL.md` skills)
|
|
75
|
+
- **Python 3.9+** — the scripts use only the standard library (no `pip install`)
|
|
76
|
+
- A modern browser for the fidelity report (it computes its numbers live, in-page)
|
|
77
|
+
- A **Figma personal access token** (below); a paid Figma seat is NOT required —
|
|
78
|
+
everything runs over the REST API. Note the REST API has **plan-based monthly quotas
|
|
79
|
+
on every endpoint** (even node JSON can 429 for hours) — the skill works cache-first,
|
|
80
|
+
so each node is fetched once and everything afterwards runs offline from `figma/nodes/`
|
|
81
|
+
|
|
82
|
+
## Setup (one-time)
|
|
83
|
+
|
|
84
|
+
1. **Figma token** — figma.com → Settings → Security → Personal access tokens,
|
|
85
|
+
scope `File content: Read`:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
echo 'YOUR_TOKEN' > ~/.figma_token && chmod 600 ~/.figma_token
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Never paste the token into the chat.
|
|
92
|
+
|
|
93
|
+
2. **Export permission** — the scripts preflight this. If you get
|
|
94
|
+
`403 File not exportable`, the file owner has disabled export/copy/share; only they
|
|
95
|
+
(or an editor) can re-enable it in the Share dialog.
|
|
96
|
+
|
|
97
|
+
3. **Font files** — on first run the skill reports, from *your* file, exactly which faces
|
|
98
|
+
the design renders and which of them are licensed. Drop those into `design/fonts/` and
|
|
99
|
+
they are used automatically. Free faces are loaded from a CDN and are never asked for.
|
|
100
|
+
Without the licensed files the skill measures a substitute and says so; the type will
|
|
101
|
+
not be exact.
|
|
102
|
+
|
|
103
|
+
See `SKILL.md` §0 for the full checklist.
|
|
104
|
+
|
|
105
|
+
## Usage
|
|
106
|
+
|
|
107
|
+
Give it a **node-specific** Figma URL:
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
implement this Figma as pixel-perfect HTML/CSS — Mode A (exact, no redesign)
|
|
111
|
+
URL: https://figma.com/design/<fileKey>/<fileName>?node-id=<nodeId>
|
|
112
|
+
|
|
113
|
+
- pull real values via the REST API; do not eyeball from screenshots
|
|
114
|
+
- download the real assets; no placeholders
|
|
115
|
+
- framework: plain HTML/CSS
|
|
116
|
+
- responsive: desktop + tablet + mobile
|
|
117
|
+
- verify each section against its render, then give me a difference log
|
|
118
|
+
- reproduce any motion the file specifies; propose anything it doesn't
|
|
119
|
+
- do not add shadows/sections that aren't in the design
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Modes: **A** = exact reproduction · **B** = exact + suggestions (approval required) ·
|
|
123
|
+
**C** = implement approved enhancements only.
|
|
124
|
+
|
|
125
|
+
## Scripts
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# FIRST: what is in this file that you are about to ignore?
|
|
129
|
+
# breakpoints · icon library · hover variants · how many screens
|
|
130
|
+
python3 scripts/figma_discover.py <fileKey> --nodes figma/nodes --json figma/discovery.json
|
|
131
|
+
|
|
132
|
+
# node JSON + one render per section (preflights access, fails loudly)
|
|
133
|
+
python3 scripts/figma_pull.py <fileKey> <nodeId>[,<nodeId>...] figma/
|
|
134
|
+
|
|
135
|
+
# accurate spec for one node: characters / textCase / fills / strokes / radii / layout
|
|
136
|
+
python3 scripts/figma_spec.py figma/nodes/<nodeId>.json 6
|
|
137
|
+
|
|
138
|
+
# which fonts the design really renders, split free vs licensed -> report this first
|
|
139
|
+
python3 scripts/figma_fonts.py figma/nodes/*.json
|
|
140
|
+
|
|
141
|
+
# every icon the page draws, extracted offline from the page SVG (no API, no quota)
|
|
142
|
+
python3 scripts/figma_icons.py --svg design/exports/page.svg --nodes figma/nodes
|
|
143
|
+
|
|
144
|
+
# build-stage guard: spacing / sizes / colours / <br> that exist nowhere in the design
|
|
145
|
+
python3 scripts/figma_lint.py --css css/styles.css --html index.html --nodes figma/nodes
|
|
146
|
+
|
|
147
|
+
# fidelity report: reference vs live page, difference blend, and audits of every
|
|
148
|
+
# text node, icon, image, box (fill/radius/stroke/shadow) and hover duration
|
|
149
|
+
python3 scripts/figma_report.py --page index.html --selectors selectors.json \
|
|
150
|
+
--breakpoints 1600,402 --assets-map assets-map.json --icons-dir design/exports/icons
|
|
151
|
+
|
|
152
|
+
# verify ONE section while you are still building it
|
|
153
|
+
python3 scripts/figma_report.py --only <section> --out /tmp/one.html
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
The two guards catch different things. `figma_lint.py` runs **before** you look: it fails on
|
|
157
|
+
any `gap`, `font-size` or colour that appears nowhere in the node JSON — invented spacing is
|
|
158
|
+
what later shows up as a hundred vertical offsets. `figma_report.py` runs **after**: it
|
|
159
|
+
compares every Figma TEXT node against the DOM for position, size, weight and colour.
|
|
160
|
+
|
|
161
|
+
> Matching section heights proves almost nothing. In one build every section matched on
|
|
162
|
+
> height and content extents while only **10 of 224 text nodes** — and **17 of 114 icons** —
|
|
163
|
+
> actually did. Geometry is a smoke test, not a verdict.
|
|
164
|
+
|
|
165
|
+
The report also audits, per section: every icon (the design's own asset, hand-drawn, or
|
|
166
|
+
missing — and *which* icon, via shape signatures), every image (real photo vs placeholder,
|
|
167
|
+
and *which* photo, via `--assets-map`), every non-text box (fill, radius, stroke, shadow),
|
|
168
|
+
and every hover transition duration vs the design's `interactions[]`. It states plainly
|
|
169
|
+
what it still does **not** check (hover *appearance*, z-order, viewports you didn't run it
|
|
170
|
+
at) so a green report is never mistaken for proof.
|
|
171
|
+
|
|
172
|
+
`figma_fonts.py` excludes hidden subtrees *and* nodes whose cumulative ancestor `opacity`
|
|
173
|
+
is 0, and reads per-character overrides — so it will not send you chasing a licensed font
|
|
174
|
+
the design never actually shows.
|
|
175
|
+
|
|
176
|
+
`figma_spec.py` marks image fills carrying an `imageTransform` (rotation/flip) as
|
|
177
|
+
`IMG(<ref>*)` — ignore that asterisk and your background will render upside-down.
|
|
178
|
+
|
|
179
|
+
## If the API rate-limits you
|
|
180
|
+
|
|
181
|
+
Renders (`GET /v1/images`) are the scarcest, but **every** endpoint — including
|
|
182
|
+
`/v1/files` node JSON — sits under a plan-based quota and can 429 with an hours-long
|
|
183
|
+
Retry-After. The skill is built for this: node JSON is pulled once and cached in
|
|
184
|
+
`figma/nodes/` (the puller skips anything already on disk), and all scripts read the
|
|
185
|
+
cache, never the API. If you hit 429 mid-acquisition, the error prints the Retry-After;
|
|
186
|
+
everything already cached keeps working. When it 429s, ask for a **PNG @2x export of the page frame** and slice it
|
|
187
|
+
locally using the section offsets from the JSON. If you use **SVG** as a visual
|
|
188
|
+
reference, you must enable **"Outline text"** on export — otherwise the SVG references a
|
|
189
|
+
font you don't have and the reference lies to you. Details in `SKILL.md` §6.5.2.
|
|
190
|
+
|
|
191
|
+
## Layout
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
figma-to-html-pixel-perfect/
|
|
195
|
+
├── SKILL.md # the skill itself
|
|
196
|
+
├── README.md
|
|
197
|
+
├── references/
|
|
198
|
+
│ ├── visual-review-checklist.md
|
|
199
|
+
│ ├── accessibility-checklist.md # WCAG 2.2 AA
|
|
200
|
+
│ └── animation-guidelines.md # motion in the file = required; motion you invent = approval
|
|
201
|
+
└── scripts/
|
|
202
|
+
├── figma_discover.py
|
|
203
|
+
├── figma_icons.py
|
|
204
|
+
├── figma_pull.py
|
|
205
|
+
├── figma_spec.py
|
|
206
|
+
├── figma_fonts.py
|
|
207
|
+
├── figma_lint.py
|
|
208
|
+
└── figma_report.py
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Core principle
|
|
212
|
+
|
|
213
|
+
The Figma design is the visual source of truth. Implement first, verify second,
|
|
214
|
+
recommend third, and change the design only after the user approves.
|
|
215
|
+
|
|
216
|
+
Never claim "100% identical" without comparison evidence. Matching section heights is
|
|
217
|
+
not that evidence.
|