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 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.