@pedroab0/skills 1.2.0 → 1.3.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/bin/cli.js +38 -8
- package/figma-extractor/README.md +2 -1
- package/figma-extractor/REFERENCE.md +111 -0
- package/figma-extractor/SKILL.md +45 -169
- package/figma-extractor/scripts/fetch_figma.js +1 -0
- package/figma-node-builder/SKILL.md +82 -93
- package/figma-to-code/README.md +2 -1
- package/figma-to-code/REFERENCE.md +110 -0
- package/figma-to-code/SKILL.md +50 -181
- package/figma-to-code/scripts/fetch_figma.js +1 -0
- package/package.json +2 -2
package/bin/cli.js
CHANGED
|
@@ -72,9 +72,37 @@ ${style.bold('Examples:')}
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
// -----------------------------------------------------------------------------
|
|
75
|
-
// Skill Discovery
|
|
75
|
+
// Frontmatter & Skill Discovery
|
|
76
76
|
// -----------------------------------------------------------------------------
|
|
77
77
|
|
|
78
|
+
function parseFrontmatterField(content, field) {
|
|
79
|
+
const fm = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
80
|
+
if (!fm) return '';
|
|
81
|
+
const lines = fm[1].split(/\r?\n/);
|
|
82
|
+
const line = lines.find((l) => l.startsWith(`${field}:`));
|
|
83
|
+
if (!line) return '';
|
|
84
|
+
const raw = line.slice(field.length + 1).trim();
|
|
85
|
+
if (raw.startsWith("'") && raw.endsWith("'")) {
|
|
86
|
+
return raw.slice(1, -1).replace(/''/g, "'");
|
|
87
|
+
}
|
|
88
|
+
if (raw.startsWith('"') && raw.endsWith('"')) {
|
|
89
|
+
try {
|
|
90
|
+
return JSON.parse(raw);
|
|
91
|
+
} catch (_) {
|
|
92
|
+
return raw.slice(1, -1);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return raw;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function rewriteRelativeLinksForCursor(body, skill) {
|
|
99
|
+
return body.replace(/\]\((?!https?:|#|\/)([^)\s#]+\.md)(#[^)]*)?\)/g, (m, rel, hash = '') => {
|
|
100
|
+
return fs.existsSync(path.join(skill.path, rel))
|
|
101
|
+
? `](../skills/${skill.name}/${rel}${hash || ''})`
|
|
102
|
+
: m;
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
78
106
|
function getAvailableSkills() {
|
|
79
107
|
const skills = [];
|
|
80
108
|
try {
|
|
@@ -87,10 +115,7 @@ function getAvailableSkills() {
|
|
|
87
115
|
let description = '';
|
|
88
116
|
try {
|
|
89
117
|
const content = fs.readFileSync(skillMdPath, 'utf8');
|
|
90
|
-
|
|
91
|
-
if (match) {
|
|
92
|
-
description = match[1].trim();
|
|
93
|
-
}
|
|
118
|
+
description = parseFrontmatterField(content, 'description');
|
|
94
119
|
} catch (_) {}
|
|
95
120
|
skills.push({
|
|
96
121
|
name: entry.name,
|
|
@@ -543,11 +568,14 @@ function installSkill(skill, destDir, useSymlink = false, isCursor = false) {
|
|
|
543
568
|
fs.cpSync(skill.path, cursorSkillsDir, { recursive: true, filter: copyFilter });
|
|
544
569
|
|
|
545
570
|
const rawSkillMd = fs.readFileSync(path.join(skill.path, 'SKILL.md'), 'utf8');
|
|
546
|
-
const skillBody =
|
|
571
|
+
const skillBody = rewriteRelativeLinksForCursor(
|
|
572
|
+
rawSkillMd.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n*/, ''),
|
|
573
|
+
skill,
|
|
574
|
+
);
|
|
547
575
|
const ruleFile = path.join(destDir, `${skill.name}.mdc`);
|
|
548
576
|
const ruleContent = `---
|
|
549
|
-
description: ${skill.description}
|
|
550
|
-
|
|
577
|
+
description: ${JSON.stringify(skill.description)}
|
|
578
|
+
alwaysApply: false
|
|
551
579
|
---
|
|
552
580
|
|
|
553
581
|
${skillBody}`;
|
|
@@ -880,6 +908,8 @@ if (require.main === module) {
|
|
|
880
908
|
|
|
881
909
|
module.exports = {
|
|
882
910
|
selectPrompt,
|
|
911
|
+
parseFrontmatterField,
|
|
912
|
+
rewriteRelativeLinksForCursor,
|
|
883
913
|
getAvailableSkills,
|
|
884
914
|
getAgentConfigs,
|
|
885
915
|
checkFigmaToken,
|
|
@@ -129,6 +129,7 @@ node figma-extractor/scripts/fetch_figma.js "<FigmaURL>" --tokens --spec tokens
|
|
|
129
129
|
| `--spec <name>` | | **Atomic SDD mode**: Saves `./.specs/<name>.json` (add `-i` to also download preview PNG). |
|
|
130
130
|
| `--image`, `--download-image` | `-i` | Download and save rendered preview image from Figma (Tier 1 call; optional). |
|
|
131
131
|
| `--image-path <path>` | `-o <path>` | Custom destination path for saved preview image (e.g., `./.specs/card.png`). |
|
|
132
|
+
| `--force`, `--fresh` | `-f` | Ignore existing local spec/preview and re-fetch freshly from Figma. |
|
|
132
133
|
| `--tokens`, `--variables` | | Export only the file's design token dictionary (colors, spacing, radii). |
|
|
133
134
|
| `--shallow-instances` | | Collapse internal layers of component instances into clean props. |
|
|
134
135
|
| `--include-tokens` | | Bundle complete design tokens dictionary alongside the node tree. |
|
|
@@ -137,7 +138,7 @@ node figma-extractor/scripts/fetch_figma.js "<FigmaURL>" --tokens --spec tokens
|
|
|
137
138
|
| `--raw` | | Return full unpruned Figma API response without filtering. |
|
|
138
139
|
| `--depth <number>` | | Limit node tree traversal depth (e.g., `--depth 2` for top-level layout only). |
|
|
139
140
|
| `--scale <1\|2\|3\|4>` | | Multiplier for rendered image resolution (default: `2`). |
|
|
140
|
-
| `--format <png\|svg\|jpg>` | | Image format for downloaded preview (default: `png`). |
|
|
141
|
+
| `--format <png\|svg\|jpg\|pdf>` | | Image format for downloaded preview (default: `png`). |
|
|
141
142
|
| `--no-variables` | | Skip querying local variables to speed up extraction. |
|
|
142
143
|
| `--help` | `-h` | Display command usage and available flags. |
|
|
143
144
|
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Figma Extractor Reference
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- Token setup
|
|
6
|
+
- Corporate proxy and SSL
|
|
7
|
+
- CLI flags
|
|
8
|
+
- Output spec schema
|
|
9
|
+
- Rate-limit gate internals
|
|
10
|
+
|
|
11
|
+
## Token setup
|
|
12
|
+
|
|
13
|
+
A Figma Personal Access Token (or OAuth token) is required. The user creates one in **Figma Settings → Personal Access Tokens**. The script reads `FIGMA_ACCESS_TOKEN` (or `FIGMA_TOKEN`) from the environment, from `.env` / `.env.local` in the working directory, from `~/.env`, and from shell profiles.
|
|
14
|
+
|
|
15
|
+
| Platform | Command for the user |
|
|
16
|
+
| :--- | :--- |
|
|
17
|
+
| macOS / Linux | `export FIGMA_ACCESS_TOKEN="figd_your_token_here"` in `~/.zshrc` or `~/.bashrc` |
|
|
18
|
+
| Windows (PowerShell) | `[Environment]::SetEnvironmentVariable("FIGMA_ACCESS_TOKEN", "figd_your_token_here", "User")` |
|
|
19
|
+
| Any (workspace) | `FIGMA_ACCESS_TOKEN=figd_your_token_here` in `.env` |
|
|
20
|
+
|
|
21
|
+
## Corporate proxy and SSL
|
|
22
|
+
|
|
23
|
+
Behind a corporate proxy with self-signed certificates, the script fails with `FIGMA_SSL_CERTIFICATE_ERROR`. The user can disable certificate verification for Figma requests:
|
|
24
|
+
|
|
25
|
+
```env
|
|
26
|
+
FIGMA_IGNORE_SSL=true
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## CLI flags
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
node "<skill-dir>/scripts/fetch_figma.js" <FigmaURL> [options]
|
|
33
|
+
node "<skill-dir>/scripts/fetch_figma.js" <fileKey> [nodeId] [options]
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
| Flag | Shorthand | Description |
|
|
37
|
+
| :--- | :--- | :--- |
|
|
38
|
+
| `--spec <name>` | | Save `./.specs/<name>.json` (and `<name>.png` with `-i`). Reuses an existing spec with 0 API calls. |
|
|
39
|
+
| `--image`, `--download-image` | `-i` | Download the rendered preview image (+1 Tier 1 call). |
|
|
40
|
+
| `--image-path <path>`, `--output <path>` | `-o <path>` | Destination path for the preview image (implies `--image`). |
|
|
41
|
+
| `--force`, `--fresh` | `-f` | Ignore the existing local spec/preview and re-fetch from Figma. |
|
|
42
|
+
| `--tokens`, `--variables` | | Output only the design token dictionary (colors, spacing, radii). |
|
|
43
|
+
| `--shallow-instances` | | Collapse internal layers of component instances into props. |
|
|
44
|
+
| `--include-tokens` | | Include the full design token dictionary alongside the node tree. |
|
|
45
|
+
| `--include-ids` | | Keep internal Figma node IDs on each node. |
|
|
46
|
+
| `--pretty` | | Pretty-print JSON with 2-space indentation (default is compact). |
|
|
47
|
+
| `--raw` | | Return the full, unpruned Figma API response. Large; avoid unless debugging. |
|
|
48
|
+
| `--depth <number>` | | Limit node tree traversal depth (e.g. `--depth 2` for an overview). |
|
|
49
|
+
| `--scale <1\|2\|3\|4>` | | Preview render scale (default: `2`). |
|
|
50
|
+
| `--format <png\|svg\|jpg\|pdf>` | | Preview image format (default: `png`). |
|
|
51
|
+
| `--no-variables` | | Skip querying `/variables/local`. |
|
|
52
|
+
| `--help` | `-h` | Show the help message. |
|
|
53
|
+
|
|
54
|
+
## Output spec schema
|
|
55
|
+
|
|
56
|
+
Each node keeps only properties that differ from Figma defaults. Hidden layers are dropped. Pure vector groups collapse into a single `VECTOR` node with `isSvg: true`.
|
|
57
|
+
|
|
58
|
+
| Field | Meaning |
|
|
59
|
+
| :--- | :--- |
|
|
60
|
+
| `name`, `type` | Layer name and node type (`FRAME`, `INSTANCE`, `TEXT`, `VECTOR`, ...). |
|
|
61
|
+
| `bounds` | `{ width, height }` render dimensions. |
|
|
62
|
+
| `layoutMode`, `layoutWrap`, `primaryAxisAlignItems`, `counterAxisAlignItems` | Auto-layout direction and alignment. |
|
|
63
|
+
| `layoutGrow`, `layoutAlign`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight` | Child sizing constraints. |
|
|
64
|
+
| `padding` / `paddingToken`, `itemSpacing` / `itemSpacingToken` | Spacing values and bound tokens. |
|
|
65
|
+
| `cornerRadius` / `cornerRadiusToken`, `cornerRadii` | Uniform or per-corner radius. |
|
|
66
|
+
| `fills`, `strokes`, `effects`, `opacity` | Paints (hex `color` + optional `token`), borders, shadows/blurs. |
|
|
67
|
+
| `characters`, `typography` | Text content and `fontFamily`, `fontSize`, `fontWeight`, `lineHeightPx`, `letterSpacing`, `textAlignHorizontal`, `textAlignVertical`. |
|
|
68
|
+
| `component`, `props` | Master component `name`/`variant` and normalized instance props. |
|
|
69
|
+
| `children` | Child nodes. |
|
|
70
|
+
| `image` | Present when `-i` was used: preview `path`, or `error`. |
|
|
71
|
+
|
|
72
|
+
### Resolved design tokens
|
|
73
|
+
|
|
74
|
+
When a layer is bound to Figma variables, the semantic token name is attached next to the computed fallback value:
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"name": "Card Container",
|
|
79
|
+
"type": "FRAME",
|
|
80
|
+
"layoutMode": "VERTICAL",
|
|
81
|
+
"padding": { "top": 16, "right": 16, "bottom": 16, "left": 16 },
|
|
82
|
+
"paddingToken": "spacing/md",
|
|
83
|
+
"itemSpacing": 12,
|
|
84
|
+
"itemSpacingToken": "spacing/sm",
|
|
85
|
+
"cornerRadius": 8,
|
|
86
|
+
"cornerRadiusToken": "radii/lg",
|
|
87
|
+
"fills": [{ "type": "SOLID", "color": "#1877F2", "token": "colors/brand/primary" }]
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Normalized component instances
|
|
92
|
+
|
|
93
|
+
Figma property hashes (`Label#12:3`) become clean props linked to the master component:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"name": "Submit Button",
|
|
98
|
+
"type": "INSTANCE",
|
|
99
|
+
"component": { "name": "Button", "variant": "Variant=Primary, Size=Large" },
|
|
100
|
+
"props": { "variant": "Primary", "size": "Large", "hasIcon": true, "label": "Confirm Order" },
|
|
101
|
+
"bounds": { "width": 140, "height": 44 }
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Rate-limit gate internals
|
|
106
|
+
|
|
107
|
+
The script protects the file quota automatically. No agent action is needed beyond the Zero-Hammer rules in `SKILL.md`.
|
|
108
|
+
|
|
109
|
+
- **Sliding window**: at most 5 requests per minute per file key (Figma throttles at roughly 10/min).
|
|
110
|
+
- **Pacing**: at least 2.5 s between consecutive requests.
|
|
111
|
+
- **Circuit breaker**: after an HTTP 429, the lockout end time is stored in `~/.figma_ratelimit.json`. Later calls to that file key fail immediately with `FIGMA_CIRCUIT_BREAKER_ACTIVE` and send no network traffic, so the lockout is not extended.
|
package/figma-extractor/SKILL.md
CHANGED
|
@@ -1,201 +1,77 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: figma-extractor
|
|
3
|
-
description: '
|
|
3
|
+
description: 'Extracts Figma frames and components into compact JSON spec files (.specs/*.json) with resolved design tokens, normalized component instance props, and optional preview images, using the Figma REST API. Use when the user shares a figma.com link and wants to inspect, extract, document, or plan a design before implementation, or asks to sync Figma variables and design tokens. Produces specification artifacts only and never edits application code. For immediate one-shot code generation from a Figma link, use figma-to-code instead.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Figma Extractor
|
|
6
|
+
# Figma Extractor (SDD Spec Ingest)
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Writes Figma designs to `.specs/<name>.json` (and optionally `.specs/<name>.png`) so a later implementation step can build from a fixed specification. A **spec** is the pruned Figma node tree with resolved tokens and component props.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Requires Node.js >= 16.7. The scripts have zero dependencies (no `npm install`).
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
## Operational Boundary: Spec Ingestion Only
|
|
15
|
-
|
|
16
|
-
* **Specification Artifacts Only**: This skill strictly outputs machine-readable design specifications (`.specs/<name>.json`) and visual references (`.specs/<name>.png`).
|
|
17
|
-
* **Zero Application Code Changes**: Do **NOT** create, edit, or modify application source code (`.tsx`, `.vue`, `.html`, `.css`, etc.) while executing this skill.
|
|
18
|
-
* **Hand-off to Implementation**: Once specifications are generated in `./.specs/`, present a summary of the extracted tokens, components, and layout bounds. The implementation phase is handled separately by the developer or a downstream builder skill (such as `figma-node-builder`).
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
## Strict Guardrails: No Browser Scraping / Automation
|
|
23
|
-
|
|
24
|
-
> [!CAUTION]
|
|
25
|
-
> **NEVER use browser tools (Playwright, Puppeteer, Chrome DevTools, `browser_navigate`, `read_browser_page`) on Figma URLs.**
|
|
26
|
-
>
|
|
27
|
-
> 1. **Figma Canvas is WebGL/Wasm**: Figma renders design canvas elements inside an HTML5 `<canvas>` via WebAssembly. There are NO inspectable HTML DOM elements for frames, layers, texts, or styles. Browser automation cannot extract Figma nodes or properties.
|
|
28
|
-
> 2. **Never search for local browser binaries**: Do not search OS application directories (e.g., `/Applications`, `Program Files`, `/usr/bin`) or run browser automation scripts.
|
|
29
|
-
> 3. **API Errors Are Final**: If `fetch_figma.js` returns an API error (e.g., 401 Unauthorized, 403 Forbidden, or 429 Rate Limited), **report the error directly to the user**. Guide them to check their `FIGMA_ACCESS_TOKEN`, permissions, or wait out rate limits. Do NOT attempt browser scraping fallbacks.
|
|
30
|
-
|
|
31
|
-
---
|
|
12
|
+
## Boundaries
|
|
32
13
|
|
|
33
|
-
|
|
14
|
+
- Output only `.specs/` artifacts. **Never create or edit application code** (`.tsx`, `.vue`, `.html`, `.css`, ...) while using this skill.
|
|
15
|
+
- **Never open Figma URLs with browser tools** (Playwright, Puppeteer, Chrome DevTools). The Figma canvas is WebGL, so there is no DOM to read. Do not search for local browser binaries.
|
|
16
|
+
- **API errors are final**: report them to the user. Never fall back to scraping.
|
|
34
17
|
|
|
35
|
-
|
|
36
|
-
* **Max 5 requests per minute** per file key (sliding window limit).
|
|
37
|
-
* **2.5s inter-request pacing** between consecutive requests.
|
|
38
|
-
* **Persistent Circuit Breaker**: If Figma returns HTTP 429, the script records the lockout time locally in `.figma_ratelimit.json` inside the user's home directory. All future calls to that file key are **immediately blocked with zero network traffic**, preventing Figma from extending the lockout penalty.
|
|
18
|
+
## Workflow
|
|
39
19
|
|
|
40
|
-
|
|
41
|
-
1. **Single-Shot Execution**: Run `fetch_figma.js` **once** per target frame or component.
|
|
42
|
-
2. **Never Retry on Failure**: If `fetch_figma.js` returns an error, **DO NOT retry in a loop**. Report the error directly to the user.
|
|
43
|
-
3. **Handling `FIGMA_CIRCUIT_BREAKER_ACTIVE`**: If the circuit breaker trips, inform the user that the file key is on cooldown, and suggest duplicating the file in Figma Drafts (Right-click $\rightarrow$ **Duplicate**) to get a fresh URL.
|
|
20
|
+
Copy this checklist and track your progress:
|
|
44
21
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
Configure it using either:
|
|
52
|
-
1. **Environment Variable**:
|
|
53
|
-
- **macOS / Linux**: `export FIGMA_ACCESS_TOKEN="figd_your_token_here"` (or `FIGMA_TOKEN`)
|
|
54
|
-
- **Windows (PowerShell)**: `[Environment]::SetEnvironmentVariable("FIGMA_ACCESS_TOKEN", "figd_your_token_here", "User")` or `$env:FIGMA_ACCESS_TOKEN="figd_your_token_here"` in `$PROFILE`
|
|
55
|
-
2. **Workspace `.env` File**:
|
|
56
|
-
```env
|
|
57
|
-
FIGMA_ACCESS_TOKEN=figd_your_token_here
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
### Corporate Proxy & SSL Certificates
|
|
61
|
-
If you are behind a corporate proxy or firewall with self-signed SSL certificates, enable SSL verification bypass:
|
|
62
|
-
```env
|
|
63
|
-
FIGMA_IGNORE_SSL=true
|
|
22
|
+
```
|
|
23
|
+
Extraction Progress:
|
|
24
|
+
- [ ] 1. Run the extraction (once)
|
|
25
|
+
- [ ] 2. Verify the result
|
|
26
|
+
- [ ] 3. Hand off a summary
|
|
64
27
|
```
|
|
65
28
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
## Tier 1 Quota Conservation: AST-Only by Default
|
|
69
|
-
|
|
70
|
-
> [!IMPORTANT]
|
|
71
|
-
> **Figma Starter plans enforce a strict limit of 20 Tier 1 requests/month.**
|
|
72
|
-
> Both `GET /v1/files/:key/nodes` and `GET /v1/images/:key` count as Tier 1 endpoints.
|
|
73
|
-
>
|
|
74
|
-
> 1. **Default to AST-only extraction**: Running `--spec <name>` without `-i` consumes **only 1 Tier 1 call**. The JSON AST contains 100% of layout rules (flexbox, padding, gap), dimensions, hex colors, corner radii, and text content needed for code generation.
|
|
75
|
-
> 2. **DO NOT pass `-i` / `--image` by default**: Only add `-i` if the user explicitly requests downloading a visual preview screenshot.
|
|
76
|
-
> 3. **Reuse existing specs**: If `.specs/<name>.json` exists, reuse it with **0 API calls**.
|
|
77
|
-
|
|
78
|
-
---
|
|
79
|
-
|
|
80
|
-
## Agent Execution Instructions
|
|
81
|
-
|
|
82
|
-
To extract a Figma frame or component as a specification artifact, run `fetch_figma.js` from this skill's `scripts/` directory:
|
|
29
|
+
**1. Run the extraction** (1 Tier 1 API call):
|
|
83
30
|
|
|
84
31
|
```bash
|
|
85
|
-
# Recommended: Atomic extraction (writes ./.specs/<name>.json - 1 Tier 1 call)
|
|
86
32
|
node "<skill-dir>/scripts/fetch_figma.js" "<FigmaURL>" --spec <name>
|
|
87
|
-
|
|
88
|
-
# Optional: With companion preview image (writes .json and .png - 2 Tier 1 calls)
|
|
89
|
-
node "<skill-dir>/scripts/fetch_figma.js" "<FigmaURL>" --spec <name> -i
|
|
90
33
|
```
|
|
91
34
|
|
|
92
|
-
|
|
93
|
-
Substitute `<skill-dir>` with the directory where this skill is installed — **never guess another agent's folder** (always keep double quotes around the script path for Windows/macOS/Linux compatibility):
|
|
94
|
-
- **Standard Skills (`SKILL.md`)**: `<skill-dir>` is the exact parent directory of this `SKILL.md` file.
|
|
95
|
-
- **Cursor Rule (`.cursor/rules/figma-extractor.mdc`)**: `<skill-dir>` is the sibling `.cursor/skills/figma-extractor` directory (replace `rules/figma-extractor.mdc` with `skills/figma-extractor`).
|
|
35
|
+
If `.specs/<name>.json` already exists, the script reuses it with 0 API calls. Pass `--force` only when the user explicitly asks to refresh the spec.
|
|
96
36
|
|
|
97
|
-
|
|
37
|
+
**2. Verify the result**
|
|
98
38
|
|
|
99
|
-
|
|
39
|
+
- Success: stdout shows `✔ Saved Figma specification` or `✔ Reusing local Figma specification`.
|
|
40
|
+
- Failure: stderr contains a JSON error payload. Follow [Errors](#errors). Do not retry.
|
|
100
41
|
|
|
101
|
-
|
|
42
|
+
**3. Hand off**: report the spec path and size, the root frame, the main component instances, and the design tokens found. Implementation is handled separately by the developer or by the `figma-node-builder` skill.
|
|
102
43
|
|
|
103
|
-
|
|
44
|
+
## Common variants
|
|
104
45
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
46
|
+
| Need | Command suffix |
|
|
47
|
+
| :--- | :--- |
|
|
48
|
+
| Preview PNG (only if the user asks; +1 Tier 1 call) | `--spec <name> -i` |
|
|
49
|
+
| Design tokens dictionary only | `--tokens --spec tokens` |
|
|
50
|
+
| Collapse instance internals into props | `--spec <name> --shallow-instances` |
|
|
51
|
+
| Top-level overview of a large frame | `--spec <name> --depth 2` |
|
|
108
52
|
|
|
109
|
-
|
|
110
|
-
node "<skill-dir>/scripts/fetch_figma.js" "https://www.figma.com/design/:fileKey/:name?node-id=4023-474" --spec card -i
|
|
53
|
+
All CLI flags, the output spec schema, token setup per OS, and proxy options: see [REFERENCE.md](REFERENCE.md) (located at `<skill-dir>/REFERENCE.md`).
|
|
111
54
|
|
|
112
|
-
|
|
113
|
-
node "<skill-dir>/scripts/fetch_figma.js" "https://www.figma.com/design/:fileKey/:name?node-id=4023-474" --spec card --shallow-instances
|
|
114
|
-
```
|
|
55
|
+
## Resolving `<skill-dir>`
|
|
115
56
|
|
|
116
|
-
|
|
57
|
+
Substitute `<skill-dir>` with the directory where this skill is installed. Never guess another agent's folder, and keep the double quotes around the script path (Windows/macOS/Linux):
|
|
117
58
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
node "<skill-dir>/scripts/fetch_figma.js" "https://www.figma.com/design/:fileKey/:name" --tokens --spec tokens
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
### 3. CLI Flags Reference
|
|
124
|
-
|
|
125
|
-
| Flag | Shorthand | Description |
|
|
126
|
-
| :--- | :--- | :--- |
|
|
127
|
-
| `--spec <name>` | | **Atomic SDD mode**: Saves `./.specs/<name>.json` (add `-i` to also download preview PNG). |
|
|
128
|
-
| `--image`, `--download-image` | `-i` | Download and save rendered preview image from Figma (Tier 1 call; optional). |
|
|
129
|
-
| `--image-path <path>` | `-o <path>` | Destination path for saved preview image (e.g. `./.specs/preview.png`). |
|
|
130
|
-
| `--tokens`, `--variables` | | Output only the design token dictionary (colors, spacing, radii). |
|
|
131
|
-
| `--shallow-instances` | | Collapse internal sub-layers of component instances into clean props. |
|
|
132
|
-
| `--pretty` | | Pretty-print JSON with 2-space indentation (default is compact single-line JSON). |
|
|
133
|
-
| `--include-tokens` | | Include full design tokens dictionary alongside node AST. |
|
|
134
|
-
| `--include-ids` | | Retain internal Figma node IDs on each node in the tree. |
|
|
135
|
-
| `--raw` | | Return full, unpruned raw Figma API AST. |
|
|
136
|
-
| `--depth <number>` | | Limit node tree traversal depth (e.g. `--depth 2` for top-level overview). |
|
|
137
|
-
| `--scale <1\|2\|3\|4>` | | Render resolution multiplier for preview images (default: `2`). |
|
|
138
|
-
| `--format <png\|svg\|jpg>` | | Rendered image file format (default: `png`). |
|
|
139
|
-
| `--no-variables` | | Skip querying `/variables/local`. |
|
|
140
|
-
| `--help` | `-h` | Show help message. |
|
|
141
|
-
|
|
142
|
-
---
|
|
59
|
+
- **Standard skills (`SKILL.md`)**: the parent directory of this `SKILL.md` file.
|
|
60
|
+
- **Cursor rule (`.cursor/rules/figma-extractor.mdc`)**: the sibling `.cursor/skills/figma-extractor` directory.
|
|
143
61
|
|
|
144
|
-
##
|
|
145
|
-
|
|
146
|
-
### 1. Resolved Design Tokens
|
|
147
|
-
When a layer uses Figma variables (design tokens), the extractor attaches semantic token names alongside computed fallback values:
|
|
148
|
-
|
|
149
|
-
```json
|
|
150
|
-
{
|
|
151
|
-
"name": "Card Container",
|
|
152
|
-
"type": "FRAME",
|
|
153
|
-
"layoutMode": "VERTICAL",
|
|
154
|
-
"padding": { "top": 16, "right": 16, "bottom": 16, "left": 16 },
|
|
155
|
-
"paddingToken": "spacing/md",
|
|
156
|
-
"itemSpacing": 12,
|
|
157
|
-
"itemSpacingToken": "spacing/sm",
|
|
158
|
-
"cornerRadius": 8,
|
|
159
|
-
"cornerRadiusToken": "radii/lg",
|
|
160
|
-
"fills": [
|
|
161
|
-
{
|
|
162
|
-
"type": "SOLID",
|
|
163
|
-
"color": "#1877F2",
|
|
164
|
-
"token": "colors/brand/primary"
|
|
165
|
-
}
|
|
166
|
-
]
|
|
167
|
-
}
|
|
168
|
-
```
|
|
62
|
+
## Quota rules (Zero-Hammer Protocol)
|
|
169
63
|
|
|
170
|
-
|
|
171
|
-
When an `INSTANCE` node is present, internal property hashes are converted into clean JavaScript props and linked to the master component name:
|
|
172
|
-
|
|
173
|
-
```json
|
|
174
|
-
{
|
|
175
|
-
"name": "Submit Button",
|
|
176
|
-
"type": "INSTANCE",
|
|
177
|
-
"component": {
|
|
178
|
-
"name": "Button",
|
|
179
|
-
"variant": "Variant=Primary, Size=Large"
|
|
180
|
-
},
|
|
181
|
-
"props": {
|
|
182
|
-
"variant": "Primary",
|
|
183
|
-
"size": "Large",
|
|
184
|
-
"hasIcon": true,
|
|
185
|
-
"label": "Confirm Order"
|
|
186
|
-
},
|
|
187
|
-
"bounds": { "width": 140, "height": 44 }
|
|
188
|
-
}
|
|
189
|
-
```
|
|
64
|
+
The script enforces a local rate gate and a persistent circuit breaker, but the agent must also follow these rules:
|
|
190
65
|
|
|
191
|
-
|
|
66
|
+
1. Run `fetch_figma.js` **once** per target frame or component. **Never retry in a loop.**
|
|
67
|
+
2. **Do not pass `-i`** unless the user explicitly requests a preview image. The JSON spec already contains layout, dimensions, colors, radii, typography, and text.
|
|
68
|
+
3. Figma Starter plans and View seats have very small monthly Tier 1 quotas, so every call matters. Prefer reusing existing specs.
|
|
192
69
|
|
|
193
|
-
##
|
|
70
|
+
## Errors
|
|
194
71
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
- Figma REST API has per-minute and monthly rate limits on Starter plans. If quota is exhausted or circuit breaker trips, inform the user they can export the specification directly via the companion **Figma Node JSON Extractor** desktop plugin (available on [Figma Community](https://www.figma.com/community/plugin/1691244420692136789/figma-node-json-extractor)) into `./.specs/<name>.json`.
|
|
72
|
+
| Error code | Action |
|
|
73
|
+
| :--- | :--- |
|
|
74
|
+
| `FIGMA_ACCESS_TOKEN is not set` / `FIGMA_TOKEN_EXPIRED_OR_INVALID` | Tell the user the token is missing, invalid, or expired. They create one in **Figma Settings → Personal Access Tokens** and set `FIGMA_ACCESS_TOKEN` (setup per OS in REFERENCE.md). |
|
|
75
|
+
| Node not found | Report that the `node-id` does not exist in the file. |
|
|
76
|
+
| `FIGMA_SSL_CERTIFICATE_ERROR` | Corporate proxy or self-signed certificate: suggest `FIGMA_IGNORE_SSL=true` in `.env`. |
|
|
77
|
+
| `FIGMA_RATE_LIMIT_EXCEEDED` / `FIGMA_CIRCUIT_BREAKER_ACTIVE` | Report the cooldown. Suggest duplicating the file in Figma Drafts (Right-click → **Duplicate**) for a fresh URL, or exporting the selection with the companion [Figma Node JSON Extractor](https://www.figma.com/community/plugin/1691244420692136789/figma-node-json-extractor) plugin into `.specs/<name>.json`. |
|
|
@@ -1402,6 +1402,7 @@ Options:
|
|
|
1402
1402
|
--spec <name> Atomically save ./.specs/<name>.json (add -i to also download preview PNG)
|
|
1403
1403
|
--image, -i Download rendered preview image from Figma (Tier 1 call)
|
|
1404
1404
|
--image-path, -o <path> Target path for saved preview image (implies --image)
|
|
1405
|
+
--force, -f Ignore existing local spec/preview and re-fetch from Figma
|
|
1405
1406
|
--tokens, --variables Export only the design token dictionary (colors, spacing, radii)
|
|
1406
1407
|
--shallow-instances Collapse internal layers of component instances into props
|
|
1407
1408
|
--include-tokens Include complete tokens dictionary in node output
|
|
@@ -1,112 +1,101 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: figma-node-builder
|
|
3
|
-
description: '
|
|
3
|
+
description: 'Builds production-ready UI components from previously extracted Figma spec files (.specs/*.json) and optional preview images (.specs/*.png), reusing the host project components, design tokens, and icon library. Works offline with no Figma API calls. Use when the user asks to implement, build, or code a component or screen from an existing .specs file, or approves implementation after a figma-extractor run.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Figma Node Builder
|
|
6
|
+
# Figma Node Builder (SDD Implementation Layer)
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Builds UI code from an extracted **spec** (`.specs/<name>.json`, the pruned Figma node tree with resolved tokens and component props) and its optional preview image (`.specs/<name>.png`). Works entirely offline: no Figma API calls or tokens.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Requires Node.js >= 16.7 for the inspector script (zero dependencies, no `npm install`).
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
## Workflow
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Copy this checklist and track your progress:
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
```
|
|
17
|
+
Implementation Progress:
|
|
18
|
+
- [ ] Phase 1: Discover the host project (stack, UI primitives, tokens, icons)
|
|
19
|
+
- [ ] Phase 2: Inspect the spec and map it to the codebase
|
|
20
|
+
- [ ] Phase 3: Build the component following the build rules
|
|
21
|
+
- [ ] Phase 4: Validate and fix
|
|
22
|
+
```
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
### Phase 1: Discover the host project
|
|
25
|
+
|
|
26
|
+
Before writing code, ground the implementation in the existing project:
|
|
27
|
+
|
|
28
|
+
1. **Framework and styling**: check `package.json` for React, Vue, Svelte, Angular, Next.js, Tailwind CSS, styled-components, or plain CSS.
|
|
29
|
+
2. **UI primitives**: inspect `components/ui/`, `src/components/`, or design system libraries (shadcn/ui, Radix, MUI) for reusable components (`Button`, `Input`, `Card`, `Badge`).
|
|
30
|
+
3. **Design tokens**: inspect `tailwind.config.*`, `theme.css`, or `globals.css` for color, spacing, and radius scales.
|
|
31
|
+
4. **Icons**: check `package.json` for icon packages (`lucide-react`, `@heroicons/react`, `phosphor-react`) and local icon folders (`components/icons/`, `src/assets/`, `public/`).
|
|
32
|
+
|
|
33
|
+
### Phase 2: Inspect the spec and map it to the codebase
|
|
22
34
|
|
|
23
|
-
|
|
35
|
+
Run the inspector instead of reading the raw JSON into context (resolve `<skill-dir>` as described below):
|
|
24
36
|
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
A["Phase 1: Codebase Discovery<br/>(Framework & Existing Primitives)"] --> B["Phase 2: Gap Analysis<br/>(Match Tokens & Props)"]
|
|
28
|
-
B --> C["Phase 3: Grounded Synthesis<br/>(No Hallucinated CSS)"]
|
|
29
|
-
C --> D["Phase 4: Visual Verification<br/>(Check vs .specs/*.png)"]
|
|
37
|
+
```bash
|
|
38
|
+
node "<skill-dir>/scripts/inspect_spec.js" .specs/<name>.json --markdown
|
|
30
39
|
```
|
|
31
40
|
|
|
32
|
-
|
|
33
|
-
Before writing any code, inspect the host project to ground your implementation:
|
|
34
|
-
1. **Framework & Styling**: Check `package.json` for React, Vue, Svelte, Next.js, Tailwind CSS, styled-components, or plain CSS.
|
|
35
|
-
2. **Existing UI Primitives**: Inspect `components/ui/`, `src/components/`, or design system libraries (e.g., shadcn/ui, Radix, MUI) to identify reusable components (`Button`, `Input`, `Card`, `Badge`).
|
|
36
|
-
3. **Design Token System**: Inspect `tailwind.config.js`, `theme.css`, or `globals.css` to see how colors and spacing scales are configured.
|
|
37
|
-
4. **Icons & Assets Discovery**: Check `package.json` for installed icon packages (e.g. `lucide-react`, `@heroicons/react`, `phosphor-react`) and check if local icon folders exist (`components/icons/`, `src/assets/`, `public/`).
|
|
38
|
-
|
|
39
|
-
### Phase 2: Gap Analysis & Token Mapping
|
|
40
|
-
Analyze the input JSON spec (`.specs/<name>.json`).
|
|
41
|
-
|
|
42
|
-
> **Tip**: Instead of reading the entire raw JSON AST into your context window, run the companion **Spec Inspector CLI** from this skill's directory (`<skill-dir>` is the folder containing this `SKILL.md` file; if loaded from `.cursor/rules/figma-node-builder.mdc`, use `.cursor/skills/figma-node-builder`):
|
|
43
|
-
> ```bash
|
|
44
|
-
> # Compact terminal summary (always quote the script path for Windows/macOS/Linux compatibility):
|
|
45
|
-
> node "<skill-dir>/scripts/inspect_spec.js" .specs/<name>.json
|
|
46
|
-
>
|
|
47
|
-
> # Output Markdown directly for your implementation plan:
|
|
48
|
-
> node "<skill-dir>/scripts/inspect_spec.js" .specs/<name>.json --markdown
|
|
49
|
-
> ```
|
|
50
|
-
|
|
51
|
-
* **Component Instances**: For each node with `type: "INSTANCE"`, match `component.name` against existing codebase components. Extract its `props` (e.g., `{ variant: "outline", size: "lg", hasIcon: true }`).
|
|
52
|
-
* **Design Tokens**: For every `token` property (e.g., `colors/brand/primary`, `spacing/md`, `radii/lg`), map to the project's CSS variables (`var(--color-brand-primary)`) or Tailwind classes (`bg-brand-primary`, `p-4`, `rounded-lg`).
|
|
53
|
-
* **Gaps**: Identify any sub-components that do not exist yet in the codebase and plan to scaffold them.
|
|
54
|
-
|
|
55
|
-
### Phase 3: Grounded Code Synthesis
|
|
56
|
-
Generate component code strictly adhering to the node specification and adapting syntax to the host project's detected stack (e.g., React, Vue, Svelte, Angular, or HTML/CSS):
|
|
57
|
-
|
|
58
|
-
1. **Reusing Existing Components (Anti-Div Soup Rule)**:
|
|
59
|
-
- When an `INSTANCE` node matches an existing component, **import and render it directly** (example in JSX — adapt to your framework):
|
|
60
|
-
```tsx
|
|
61
|
-
// Correct:
|
|
62
|
-
<Button variant="primary" size="large" hasIcon>Confirm Order</Button>
|
|
63
|
-
|
|
64
|
-
// Forbidden (do not rebuild existing primitives from raw divs):
|
|
65
|
-
<div className="flex bg-blue-500 rounded p-2 text-white">Confirm Order</div>
|
|
66
|
-
```
|
|
67
|
-
2. **Layout & Flexbox Translation**:
|
|
68
|
-
- `layoutMode: "HORIZONTAL"` $\rightarrow$ Flex row (`display: flex; flex-direction: row;` or `flex flex-row`).
|
|
69
|
-
- `layoutMode: "VERTICAL"` $\rightarrow$ Flex column (`display: flex; flex-direction: column;` or `flex flex-col`).
|
|
70
|
-
- `itemSpacing` $\rightarrow$ CSS `gap` (map to `itemSpacingToken` if available).
|
|
71
|
-
- `padding` $\rightarrow$ CSS `padding` (map to `paddingToken` if available).
|
|
72
|
-
- `primaryAxisAlignItems` / `counterAxisAlignItems` $\rightarrow$ `justify-*` and `items-*`.
|
|
73
|
-
3. **Typography & Colors**:
|
|
74
|
-
- Never guess hex colors. If `token` is present, use the semantic token. If not, use the fallback `color` hex string.
|
|
75
|
-
- Map font sizes, font weights, and line heights to existing design tokens or typography classes.
|
|
76
|
-
4. **Icon & Vector Resolution Hierarchy**:
|
|
77
|
-
When encountering a `VECTOR` node or icon instance:
|
|
78
|
-
- **Normalize Node Name**: Strip common prefixes (`icon/`, `ic_`, `ico-`) and clean the name (e.g., `icon/search` $\rightarrow$ `search` / `Search`).
|
|
79
|
-
- **Step 1 (Targeted Local Assets/Components)**: Look for matching files in `components/icons/`, `src/assets/`, or `public/` (e.g., `<SearchIcon />`, `/icons/search.svg`). Avoid recursive searches outside these targeted paths.
|
|
80
|
-
- **Step 2 (Installed Icon Library)**: If not found locally, import from the icon library detected in `package.json` (e.g., `import { Search } from 'lucide-react'`).
|
|
81
|
-
- **Step 3 (Semantic Fallback - Never Hallucinate Raw Béziers)**: If not found, render an accessible placeholder (`<span className="w-4 h-4 inline-flex items-center justify-center text-muted-foreground" aria-hidden="true" />`) with a `TODO: Missing icon 'search'` comment. Never hallucinate raw SVG `<path d="...">` coordinates.
|
|
82
|
-
5. **Image Layer Handling (`fills: [{ type: "IMAGE" }]`)**:
|
|
83
|
-
- Focus exclusively on applying the exact styling from the Figma spec: dimensions (`width`, `height`), border radius (`rounded-*`), and scale mode (`scaleMode: "FILL"` $\rightarrow$ `object-cover`, `"FIT"` $\rightarrow$ `object-contain`).
|
|
84
|
-
- Do **NOT** attempt to resolve, fetch, or hallucinate image files or external URLs (never invent Unsplash or third-party links).
|
|
85
|
-
- Render a standard `<img>` tag with `src=""` and a concise `TODO` comment specifying the target image:
|
|
86
|
-
```tsx
|
|
87
|
-
{/* TODO: Add image source for 'User Avatar' (48x48) */}
|
|
88
|
-
<img src="" alt="User Avatar" className="w-12 h-12 rounded-full object-cover" />
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
### Phase 4: Visual Cross-Check & Verification
|
|
92
|
-
* **Optional Companion Image**: If the companion preview image (`.specs/<name>.png`) exists, inspect it to cross-check visual styling and icons.
|
|
93
|
-
* **AST-Only Synthesis**: If `.specs/<name>.png` was omitted (to conserve Tier 1 API calls), rely strictly on the exact metrics, flexbox rules, hex colors, and font styles in `.specs/<name>.json`.
|
|
94
|
-
* If a dev server or browser preview is active, verify that the rendered DOM matches the specification.
|
|
41
|
+
Use `--json` instead of `--markdown` for a structured summary (or `--help` / `-h` for CLI options). Then:
|
|
95
42
|
|
|
96
|
-
|
|
43
|
+
- **Component instances**: match each `INSTANCE` `component.name` against existing codebase components and note its `props`.
|
|
44
|
+
- **Design tokens**: map each `token` (`colors/brand/primary`, `spacing/md`, `radii/lg`) to the project CSS variables or Tailwind classes.
|
|
45
|
+
- **Gaps**: list sub-components and tokens that do not exist yet and must be created.
|
|
46
|
+
|
|
47
|
+
Read specific parts of the raw spec only when the inspector summary is not enough.
|
|
48
|
+
|
|
49
|
+
### Phase 3: Build the component
|
|
50
|
+
|
|
51
|
+
Follow the [Build rules](#build-rules), adapting syntax to the stack detected in Phase 1.
|
|
52
|
+
|
|
53
|
+
### Phase 4: Validate and fix
|
|
54
|
+
|
|
55
|
+
1. Run the project's existing checks: `typecheck` or `lint` scripts from `package.json`, or `npx tsc --noEmit` when TypeScript is already installed. Never install new dependencies to do this.
|
|
56
|
+
2. If checks fail in the files you created or changed, fix them and run the checks again. Repeat until they pass.
|
|
57
|
+
3. Report pre-existing failures in other files instead of fixing them.
|
|
58
|
+
4. If `.specs/<name>.png` exists, compare it visually with the result. If it does not exist, rely strictly on the metrics in the spec.
|
|
59
|
+
|
|
60
|
+
## Build rules
|
|
97
61
|
|
|
98
|
-
|
|
62
|
+
1. **Reuse existing components (no div soup)**: when an `INSTANCE` matches an existing component, import and render it with the spec props. Never rebuild existing primitives from raw elements.
|
|
63
|
+
```tsx
|
|
64
|
+
// Correct
|
|
65
|
+
<Button variant="primary" size="large" hasIcon>Confirm Order</Button>
|
|
66
|
+
// Forbidden
|
|
67
|
+
<div className="flex bg-blue-500 rounded p-2 text-white">Confirm Order</div>
|
|
68
|
+
```
|
|
69
|
+
2. **Layout**: `layoutMode: "HORIZONTAL"` → flex row; `"VERTICAL"` → flex column; `itemSpacing` → `gap`; `padding` → padding; `primaryAxisAlignItems` / `counterAxisAlignItems` → `justify-*` / `items-*`. Prefer the matching `*Token` when present.
|
|
70
|
+
3. **Colors and typography**: never guess values. Use the semantic `token` when present, otherwise the exact hex `color`. Map font size, weight, and line height to existing typography tokens or classes.
|
|
71
|
+
4. **Icons and vectors** (`VECTOR` nodes, `isSvg: true`, or icon instances): normalize the name by stripping `icon/`, `ic_`, `ico-` (`icon/search` → `search`), then resolve in order:
|
|
72
|
+
1. Local assets or components in `components/icons/`, `src/assets/`, or `public/` only (no repo-wide searches).
|
|
73
|
+
2. The icon library installed in `package.json` (e.g. `import { Search } from 'lucide-react'`).
|
|
74
|
+
3. An accessible placeholder with a `TODO: Missing icon 'search'` comment. Never invent raw SVG `<path d="...">` coordinates.
|
|
75
|
+
5. **Image fills** (`fills: [{ type: "IMAGE" }]`): apply only the spec styling (size, radius, `scaleMode: "FILL"` → `object-cover`, `"FIT"` → `object-contain`). Never fetch or invent image URLs:
|
|
76
|
+
```tsx
|
|
77
|
+
{/* TODO: Add image source for 'User Avatar' (48x48) */}
|
|
78
|
+
<img src="" alt="User Avatar" className="w-12 h-12 rounded-full object-cover" />
|
|
79
|
+
```
|
|
99
80
|
|
|
100
|
-
|
|
81
|
+
## Spec field reference
|
|
101
82
|
|
|
102
|
-
| Field | Meaning | Code
|
|
83
|
+
| Field | Meaning | Code mapping |
|
|
103
84
|
| :--- | :--- | :--- |
|
|
104
|
-
| `type` |
|
|
105
|
-
| `layoutMode` |
|
|
106
|
-
| `itemSpacing` / `itemSpacingToken` | Gap between
|
|
107
|
-
| `padding` / `paddingToken` |
|
|
108
|
-
| `cornerRadius` / `cornerRadiusToken` | Border radius | `rounded-*`
|
|
109
|
-
| `component.name` | Master component
|
|
110
|
-
| `props` | Normalized
|
|
111
|
-
| `bounds` |
|
|
112
|
-
| `fills` |
|
|
85
|
+
| `type` | `FRAME`, `INSTANCE`, `TEXT`, `VECTOR` | Container, component import, typography tag, or icon (rule 4). |
|
|
86
|
+
| `layoutMode` | `HORIZONTAL` / `VERTICAL` auto-layout | `flex flex-row` / `flex flex-col`. |
|
|
87
|
+
| `itemSpacing` / `itemSpacingToken` | Gap between children | `gap-*` or `gap: Xpx`. |
|
|
88
|
+
| `padding` / `paddingToken` | `{ top, right, bottom, left }` | `p-*`, `px-*`, `py-*` or `padding`. |
|
|
89
|
+
| `cornerRadius` / `cornerRadiusToken` | Border radius | `rounded-*` or `border-radius`. |
|
|
90
|
+
| `component.name` | Master component of an `INSTANCE` | Import name (`import { Button } from '@/components/ui/button'`). |
|
|
91
|
+
| `props` | Normalized variant and boolean props | Component props (`<Component {...props} />`). |
|
|
92
|
+
| `bounds` | `{ width, height }` | Sizing (`w-*`, `h-*`, `max-w-*`). |
|
|
93
|
+
| `fills` | `SOLID`, `IMAGE`, gradients | Background, gradient, or `<img>` (rule 5). |
|
|
94
|
+
| `characters` / `typography` | Text content and font metrics | Text node with mapped typography classes. |
|
|
95
|
+
|
|
96
|
+
## Resolving `<skill-dir>`
|
|
97
|
+
|
|
98
|
+
Substitute `<skill-dir>` with the directory where this skill is installed, keeping the double quotes around the script path (Windows/macOS/Linux):
|
|
99
|
+
|
|
100
|
+
- **Standard skills (`SKILL.md`)**: the parent directory of this `SKILL.md` file.
|
|
101
|
+
- **Cursor rule (`.cursor/rules/figma-node-builder.mdc`)**: the sibling `.cursor/skills/figma-node-builder` directory.
|
package/figma-to-code/README.md
CHANGED
|
@@ -130,6 +130,7 @@ node figma-to-code/scripts/fetch_figma.js "<FigmaURL>" -i --shallow-instances
|
|
|
130
130
|
| :--- | :--- | :--- |
|
|
131
131
|
| `--image`, `--download-image` | `-i` | Download and save rendered preview image from Figma (Tier 1 call; optional). |
|
|
132
132
|
| `--image-path <path>` | `-o <path>` | Custom destination path for saved preview image (e.g., `./.specs/card.png`). |
|
|
133
|
+
| `--force`, `--fresh` | `-f` | Ignore existing local preview image and re-fetch freshly from Figma. |
|
|
133
134
|
| `--tokens`, `--variables` | | Export only the file's design token dictionary (colors, spacing, radii). |
|
|
134
135
|
| `--shallow-instances` | | Collapse internal layers of component instances into clean props. |
|
|
135
136
|
| `--include-tokens` | | Bundle complete design tokens dictionary alongside the node tree. |
|
|
@@ -138,7 +139,7 @@ node figma-to-code/scripts/fetch_figma.js "<FigmaURL>" -i --shallow-instances
|
|
|
138
139
|
| `--raw` | | Return full unpruned Figma API response without filtering. |
|
|
139
140
|
| `--depth <number>` | | Limit node tree traversal depth (e.g., `--depth 2` for top-level layout only). |
|
|
140
141
|
| `--scale <1\|2\|3\|4>` | | Multiplier for rendered image resolution (default: `2`). |
|
|
141
|
-
| `--format <png\|svg\|jpg>` | | Image format for downloaded preview (default: `png`). |
|
|
142
|
+
| `--format <png\|svg\|jpg\|pdf>` | | Image format for downloaded preview (default: `png`). |
|
|
142
143
|
| `--no-variables` | | Skip querying local variables to speed up extraction. |
|
|
143
144
|
| `--help` | `-h` | Display command usage and available flags. |
|
|
144
145
|
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Figma To Code Reference
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- Token setup
|
|
6
|
+
- Corporate proxy and SSL
|
|
7
|
+
- CLI flags
|
|
8
|
+
- Output spec schema
|
|
9
|
+
- Rate-limit gate internals
|
|
10
|
+
|
|
11
|
+
## Token setup
|
|
12
|
+
|
|
13
|
+
A Figma Personal Access Token (or OAuth token) is required. The user creates one in **Figma Settings → Personal Access Tokens**. The script reads `FIGMA_ACCESS_TOKEN` (or `FIGMA_TOKEN`) from the environment, from `.env` / `.env.local` in the working directory, from `~/.env`, and from shell profiles.
|
|
14
|
+
|
|
15
|
+
| Platform | Command for the user |
|
|
16
|
+
| :--- | :--- |
|
|
17
|
+
| macOS / Linux | `export FIGMA_ACCESS_TOKEN="figd_your_token_here"` in `~/.zshrc` or `~/.bashrc` |
|
|
18
|
+
| Windows (PowerShell) | `[Environment]::SetEnvironmentVariable("FIGMA_ACCESS_TOKEN", "figd_your_token_here", "User")` |
|
|
19
|
+
| Any (workspace) | `FIGMA_ACCESS_TOKEN=figd_your_token_here` in `.env` |
|
|
20
|
+
|
|
21
|
+
## Corporate proxy and SSL
|
|
22
|
+
|
|
23
|
+
Behind a corporate proxy with self-signed certificates, the script fails with `FIGMA_SSL_CERTIFICATE_ERROR`. The user can disable certificate verification for Figma requests:
|
|
24
|
+
|
|
25
|
+
```env
|
|
26
|
+
FIGMA_IGNORE_SSL=true
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## CLI flags
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
node "<skill-dir>/scripts/fetch_figma.js" <FigmaURL> [options]
|
|
33
|
+
node "<skill-dir>/scripts/fetch_figma.js" <fileKey> [nodeId] [options]
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
| Flag | Shorthand | Description |
|
|
37
|
+
| :--- | :--- | :--- |
|
|
38
|
+
| `--image`, `--download-image` | `-i` | Download the rendered preview image (+1 Tier 1 call). |
|
|
39
|
+
| `--image-path <path>`, `--output <path>` | `-o <path>` | Destination path for the preview image (implies `--image`). |
|
|
40
|
+
| `--force`, `--fresh` | `-f` | Ignore an existing local preview image and re-fetch it from Figma. |
|
|
41
|
+
| `--tokens`, `--variables` | | Output only the design token dictionary (colors, spacing, radii). |
|
|
42
|
+
| `--shallow-instances` | | Collapse internal layers of component instances into props. |
|
|
43
|
+
| `--include-tokens` | | Include the full design token dictionary alongside the node tree. |
|
|
44
|
+
| `--include-ids` | | Keep internal Figma node IDs on each node. |
|
|
45
|
+
| `--pretty` | | Pretty-print JSON with 2-space indentation (default is compact). |
|
|
46
|
+
| `--raw` | | Return the full, unpruned Figma API response. Large; avoid unless debugging. |
|
|
47
|
+
| `--depth <number>` | | Limit node tree traversal depth (e.g. `--depth 2` for an overview). |
|
|
48
|
+
| `--scale <1\|2\|3\|4>` | | Preview render scale (default: `2`). |
|
|
49
|
+
| `--format <png\|svg\|jpg\|pdf>` | | Preview image format (default: `png`). |
|
|
50
|
+
| `--no-variables` | | Skip querying `/variables/local`. |
|
|
51
|
+
| `--help` | `-h` | Show the help message. |
|
|
52
|
+
|
|
53
|
+
## Output spec schema
|
|
54
|
+
|
|
55
|
+
Each node keeps only properties that differ from Figma defaults. Hidden layers are dropped. Pure vector groups collapse into a single `VECTOR` node with `isSvg: true`.
|
|
56
|
+
|
|
57
|
+
| Field | Meaning |
|
|
58
|
+
| :--- | :--- |
|
|
59
|
+
| `name`, `type` | Layer name and node type (`FRAME`, `INSTANCE`, `TEXT`, `VECTOR`, ...). |
|
|
60
|
+
| `bounds` | `{ width, height }` render dimensions. |
|
|
61
|
+
| `layoutMode`, `layoutWrap`, `primaryAxisAlignItems`, `counterAxisAlignItems` | Auto-layout direction and alignment. |
|
|
62
|
+
| `layoutGrow`, `layoutAlign`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight` | Child sizing constraints. |
|
|
63
|
+
| `padding` / `paddingToken`, `itemSpacing` / `itemSpacingToken` | Spacing values and bound tokens. |
|
|
64
|
+
| `cornerRadius` / `cornerRadiusToken`, `cornerRadii` | Uniform or per-corner radius. |
|
|
65
|
+
| `fills`, `strokes`, `effects`, `opacity` | Paints (hex `color` + optional `token`), borders, shadows/blurs. |
|
|
66
|
+
| `characters`, `typography` | Text content and `fontFamily`, `fontSize`, `fontWeight`, `lineHeightPx`, `letterSpacing`, `textAlignHorizontal`, `textAlignVertical`. |
|
|
67
|
+
| `component`, `props` | Master component `name`/`variant` and normalized instance props. |
|
|
68
|
+
| `children` | Child nodes. |
|
|
69
|
+
| `image` | Present when `-i` was used: preview `path`, or `error`. |
|
|
70
|
+
|
|
71
|
+
### Resolved design tokens
|
|
72
|
+
|
|
73
|
+
When a layer is bound to Figma variables, the semantic token name is attached next to the computed fallback value:
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"name": "Card Container",
|
|
78
|
+
"type": "FRAME",
|
|
79
|
+
"layoutMode": "VERTICAL",
|
|
80
|
+
"padding": { "top": 16, "right": 16, "bottom": 16, "left": 16 },
|
|
81
|
+
"paddingToken": "spacing/md",
|
|
82
|
+
"itemSpacing": 12,
|
|
83
|
+
"itemSpacingToken": "spacing/sm",
|
|
84
|
+
"cornerRadius": 8,
|
|
85
|
+
"cornerRadiusToken": "radii/lg",
|
|
86
|
+
"fills": [{ "type": "SOLID", "color": "#1877F2", "token": "colors/brand/primary" }]
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Normalized component instances
|
|
91
|
+
|
|
92
|
+
Figma property hashes (`Label#12:3`) become clean props linked to the master component:
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"name": "Submit Button",
|
|
97
|
+
"type": "INSTANCE",
|
|
98
|
+
"component": { "name": "Button", "variant": "Variant=Primary, Size=Large" },
|
|
99
|
+
"props": { "variant": "Primary", "size": "Large", "hasIcon": true, "label": "Confirm Order" },
|
|
100
|
+
"bounds": { "width": 140, "height": 44 }
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Rate-limit gate internals
|
|
105
|
+
|
|
106
|
+
The script protects the file quota automatically. No agent action is needed beyond the Zero-Hammer rules in `SKILL.md`.
|
|
107
|
+
|
|
108
|
+
- **Sliding window**: at most 5 requests per minute per file key (Figma throttles at roughly 10/min).
|
|
109
|
+
- **Pacing**: at least 2.5 s between consecutive requests.
|
|
110
|
+
- **Circuit breaker**: after an HTTP 429, the lockout end time is stored in `~/.figma_ratelimit.json`. Later calls to that file key fail immediately with `FIGMA_CIRCUIT_BREAKER_ACTIVE` and send no network traffic, so the lockout is not extended.
|
package/figma-to-code/SKILL.md
CHANGED
|
@@ -1,213 +1,82 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: figma-to-code
|
|
3
|
-
description: '
|
|
3
|
+
description: 'Converts a Figma frame or component directly into production-ready UI code in a single pass, fetching a compact design-token-aware node tree from the Figma REST API and reusing the host project components and styles. Use when the user shares a figma.com link and explicitly asks to build, code, or implement it right away, without an intermediate spec review step. Supports React, Vue, Svelte, Angular, and plain HTML/CSS.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Figma To Code
|
|
6
|
+
# Figma To Code
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Fetches a compact, design-token-aware node tree for a Figma frame and immediately builds the component in the host project, reusing its existing components and styles.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Requires Node.js >= 16.7. The scripts have zero dependencies (no `npm install`).
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
## Strict Guardrails: No Browser Scraping / Automation
|
|
12
|
+
## Boundaries
|
|
15
13
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
> 1. **Figma Canvas is WebGL/Wasm**: Figma renders design canvas elements inside an HTML5 `<canvas>` via WebAssembly. There are NO inspectable HTML DOM elements for frames, layers, texts, or styles. Browser automation cannot extract Figma nodes or properties.
|
|
20
|
-
> 2. **Never search for local browser binaries**: Do not search OS application directories (e.g., `/Applications`, `Program Files`, `/usr/bin`) or run browser automation scripts.
|
|
21
|
-
> 3. **API Errors Are Final**: If `fetch_figma.js` returns an API error (e.g., 401 Unauthorized, 403 Forbidden, or 429 Rate Limited), **report the error directly to the user**. Guide them to check their `FIGMA_ACCESS_TOKEN`, permissions, or wait out rate limits. Do NOT attempt browser scraping fallbacks.
|
|
22
|
-
|
|
23
|
-
---
|
|
14
|
+
- **Never open Figma URLs with browser tools** (Playwright, Puppeteer, Chrome DevTools). The Figma canvas is WebGL, so there is no DOM to read. Do not search for local browser binaries.
|
|
15
|
+
- **API errors are final**: report them to the user. Never fall back to scraping.
|
|
16
|
+
- If the user only wants to inspect, document, or plan the design, stop and suggest the `figma-extractor` skill instead.
|
|
24
17
|
|
|
25
|
-
##
|
|
18
|
+
## Workflow
|
|
26
19
|
|
|
27
|
-
|
|
28
|
-
* **Max 5 requests per minute** per file key (sliding window limit).
|
|
29
|
-
* **2.5s inter-request pacing** between consecutive requests.
|
|
30
|
-
* **Persistent Circuit Breaker**: If Figma returns HTTP 429, the script records the lockout time locally in `.figma_ratelimit.json` inside the user's home directory. All future calls to that file key are **immediately blocked with zero network traffic**, preventing Figma from extending the lockout penalty.
|
|
31
|
-
|
|
32
|
-
### Agent Behavioral Rules (Zero-Hammer Protocol)
|
|
33
|
-
1. **Single-Shot Execution**: Run `fetch_figma.js` **once** per target frame or component.
|
|
34
|
-
2. **Never Retry on Failure**: If `fetch_figma.js` returns an error, **DO NOT retry in a loop**. Report the error directly to the user.
|
|
35
|
-
3. **Handling `FIGMA_CIRCUIT_BREAKER_ACTIVE`**: If the circuit breaker trips, inform the user that the file key is on cooldown, and suggest duplicating the file in Figma Drafts (Right-click $\rightarrow$ **Duplicate**) to get a fresh URL.
|
|
36
|
-
|
|
37
|
-
---
|
|
20
|
+
Copy this checklist and track your progress:
|
|
38
21
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
- **macOS / Linux**: `export FIGMA_ACCESS_TOKEN="figd_your_token_here"` (or `FIGMA_TOKEN`)
|
|
46
|
-
- **Windows (PowerShell)**: `[Environment]::SetEnvironmentVariable("FIGMA_ACCESS_TOKEN", "figd_your_token_here", "User")` or `$env:FIGMA_ACCESS_TOKEN="figd_your_token_here"` in `$PROFILE`
|
|
47
|
-
2. **Workspace `.env` File**:
|
|
48
|
-
```env
|
|
49
|
-
FIGMA_ACCESS_TOKEN=figd_your_token_here
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### Corporate Proxy & SSL Certificates
|
|
53
|
-
If you are behind a corporate proxy or firewall with self-signed SSL certificates, enable SSL verification bypass:
|
|
54
|
-
```env
|
|
55
|
-
FIGMA_IGNORE_SSL=true
|
|
22
|
+
```
|
|
23
|
+
Build Progress:
|
|
24
|
+
- [ ] 1. Discover the host project (stack, UI primitives, tokens, icons)
|
|
25
|
+
- [ ] 2. Fetch the node tree (once)
|
|
26
|
+
- [ ] 3. Build the component following the build rules
|
|
27
|
+
- [ ] 4. Validate and fix
|
|
56
28
|
```
|
|
57
29
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
> [!IMPORTANT]
|
|
61
|
-
> **Figma Starter plans enforce a strict limit of 20 Tier 1 requests/month.**
|
|
62
|
-
> Both `GET /v1/files/:key/nodes` and `GET /v1/images/:key` count as Tier 1 endpoints.
|
|
63
|
-
>
|
|
64
|
-
> 1. **Default to AST-only extraction**: Extracting AST without `-i` consumes **only 1 Tier 1 call**. The JSON AST contains 100% of layout rules (flexbox, padding, gap), dimensions, hex colors, corner radii, and text content needed for code generation.
|
|
65
|
-
> 2. **DO NOT pass `-i` / `--image` by default**: Only add `-i` if the user explicitly requests downloading a visual preview screenshot.
|
|
66
|
-
|
|
67
|
-
---
|
|
68
|
-
|
|
69
|
-
## Agent Execution Instructions
|
|
30
|
+
**1. Discover the host project**: check `package.json` (framework, styling, icon library), reusable components in `components/ui/` or `src/components/`, and theme files (`tailwind.config.*`, `theme.css`, `globals.css`).
|
|
70
31
|
|
|
71
|
-
|
|
32
|
+
**2. Fetch the node tree** (1 Tier 1 API call; JSON is printed to stdout):
|
|
72
33
|
|
|
73
34
|
```bash
|
|
74
|
-
# Recommended: Extract compact AST (1 Tier 1 call)
|
|
75
35
|
node "<skill-dir>/scripts/fetch_figma.js" "<FigmaURL>"
|
|
76
|
-
|
|
77
|
-
# Optional: With companion preview image (2 Tier 1 calls)
|
|
78
|
-
node "<skill-dir>/scripts/fetch_figma.js" "<FigmaURL>" -i
|
|
79
36
|
```
|
|
80
37
|
|
|
81
|
-
|
|
82
|
-
Substitute `<skill-dir>` with the directory where this skill is installed — **never guess another agent's folder** (always keep double quotes around the script path for Windows/macOS/Linux compatibility):
|
|
83
|
-
- **Standard Skills (`SKILL.md`)**: `<skill-dir>` is the exact parent directory of this `SKILL.md` file.
|
|
84
|
-
- **Cursor Rule (`.cursor/rules/figma-to-code.mdc`)**: `<skill-dir>` is the sibling `.cursor/skills/figma-to-code` directory (replace `rules/figma-to-code.mdc` with `skills/figma-to-code`).
|
|
38
|
+
For large frames, add `--shallow-instances` (collapses instance internals into props) or `--depth 2`. All flags, the output schema, token setup per OS, and proxy options: see [REFERENCE.md](REFERENCE.md) (located at `<skill-dir>/REFERENCE.md`).
|
|
85
39
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
## Usage & Command Formats
|
|
40
|
+
**3. Build**: follow the [Build rules](#build-rules), adapting syntax to the detected stack.
|
|
89
41
|
|
|
90
|
-
|
|
42
|
+
**4. Validate and fix**
|
|
91
43
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
44
|
+
1. Run the project's existing checks: `typecheck` or `lint` scripts from `package.json`, or `npx tsc --noEmit` when TypeScript is already installed. Never install new dependencies to do this.
|
|
45
|
+
2. If checks fail in the files you created or changed, fix them and run the checks again. Repeat until they pass.
|
|
46
|
+
3. Report pre-existing failures in other files instead of fixing them.
|
|
47
|
+
4. If a preview image was downloaded (`image.path` in the output), compare it visually with the result.
|
|
95
48
|
|
|
96
|
-
|
|
97
|
-
node "<skill-dir>/scripts/fetch_figma.js" "https://www.figma.com/design/:fileKey/:name?node-id=4023-474" -i
|
|
49
|
+
## Build rules
|
|
98
50
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
51
|
+
1. **Reuse existing components (no div soup)**: when an `INSTANCE` matches an existing component, import and render it with the spec props (`<Button variant="primary" size="large" hasIcon>Confirm Order</Button>`). Never rebuild existing primitives from raw elements.
|
|
52
|
+
2. **Layout**: `layoutMode: "HORIZONTAL"` → flex row; `"VERTICAL"` → flex column; `itemSpacing` → `gap`; `padding` → padding; `primaryAxisAlignItems` / `counterAxisAlignItems` → `justify-*` / `items-*`. Prefer the matching `*Token` when present.
|
|
53
|
+
3. **Colors and typography**: never guess values. Use the semantic `token` when present (mapped to the project CSS variable or Tailwind class), otherwise the exact hex `color`. Map font size, weight, and line height to existing typography tokens or classes.
|
|
54
|
+
4. **Icons and vectors** (`VECTOR` nodes, `isSvg: true`, or icon instances): normalize the name by stripping `icon/`, `ic_`, `ico-` (`icon/search` → `search`), then resolve in order:
|
|
55
|
+
1. Local assets or components in `components/icons/`, `src/assets/`, or `public/` only (no repo-wide searches).
|
|
56
|
+
2. The icon library installed in `package.json` (e.g. `import { Search } from 'lucide-react'`).
|
|
57
|
+
3. An accessible placeholder with a `TODO: Missing icon 'search'` comment. Never invent raw SVG `<path d="...">` coordinates.
|
|
58
|
+
5. **Image fills** (`fills: [{ type: "IMAGE" }]`): apply only the spec styling (size, radius, `scaleMode: "FILL"` → `object-cover`, `"FIT"` → `object-contain`). Never fetch or invent image URLs. Render `<img src="" alt="...">` with a `TODO` comment naming the layer and its size.
|
|
102
59
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
| Flag | Shorthand | Description |
|
|
106
|
-
| :--- | :--- | :--- |
|
|
107
|
-
| `--image`, `--download-image` | `-i` | Download and save rendered preview image from Figma (Tier 1 call; optional). |
|
|
108
|
-
| `--image-path <path>` | `-o <path>` | Custom local file path to save preview image (implies `--image`). |
|
|
109
|
-
| `--tokens`, `--variables` | | Output only the design token dictionary (colors, spacing, radii) for theme setup. |
|
|
110
|
-
| `--shallow-instances` | | Collapse internal sub-layers of component instances into clean props. |
|
|
111
|
-
| `--pretty` | | Pretty-print JSON with 2-space indentation (default is compact single-line JSON). |
|
|
112
|
-
| `--include-tokens` | | Include full design tokens dictionary alongside node AST. |
|
|
113
|
-
| `--include-ids` | | Retain internal Figma node IDs on each node in the tree. |
|
|
114
|
-
| `--raw` | | Return full, unpruned raw Figma API AST. |
|
|
115
|
-
| `--depth <number>` | | Limit node tree traversal depth (e.g. `--depth 2` for top-level overview). |
|
|
116
|
-
| `--scale <1\|2\|3\|4>` | | Render resolution multiplier for preview images (default: `2`). |
|
|
117
|
-
| `--format <png\|svg\|jpg>` | | Rendered image file format (default: `png`). |
|
|
118
|
-
| `--no-variables` | | Skip querying `/variables/local`. |
|
|
119
|
-
| `--help` | `-h` | Show help message. |
|
|
60
|
+
## Resolving `<skill-dir>`
|
|
120
61
|
|
|
121
|
-
|
|
62
|
+
Substitute `<skill-dir>` with the directory where this skill is installed. Never guess another agent's folder, and keep the double quotes around the script path (Windows/macOS/Linux):
|
|
122
63
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
### 1. Resolved Design Tokens
|
|
126
|
-
When a layer uses Figma variables (design tokens), the extractor attaches semantic token names alongside the computed values:
|
|
127
|
-
|
|
128
|
-
```json
|
|
129
|
-
{
|
|
130
|
-
"name": "Card Container",
|
|
131
|
-
"type": "FRAME",
|
|
132
|
-
"layoutMode": "VERTICAL",
|
|
133
|
-
"padding": { "top": 16, "right": 16, "bottom": 16, "left": 16 },
|
|
134
|
-
"paddingToken": "spacing/md",
|
|
135
|
-
"itemSpacing": 12,
|
|
136
|
-
"itemSpacingToken": "spacing/sm",
|
|
137
|
-
"cornerRadius": 8,
|
|
138
|
-
"cornerRadiusToken": "radii/lg",
|
|
139
|
-
"fills": [
|
|
140
|
-
{
|
|
141
|
-
"type": "SOLID",
|
|
142
|
-
"color": "#1877F2",
|
|
143
|
-
"token": "colors/brand/primary"
|
|
144
|
-
}
|
|
145
|
-
]
|
|
146
|
-
}
|
|
147
|
-
```
|
|
64
|
+
- **Standard skills (`SKILL.md`)**: the parent directory of this `SKILL.md` file.
|
|
65
|
+
- **Cursor rule (`.cursor/rules/figma-to-code.mdc`)**: the sibling `.cursor/skills/figma-to-code` directory.
|
|
148
66
|
|
|
149
|
-
|
|
150
|
-
When an `INSTANCE` node is present, internal property hashes are converted into clean JavaScript props and linked to the master component name:
|
|
151
|
-
|
|
152
|
-
```json
|
|
153
|
-
{
|
|
154
|
-
"name": "Submit Button",
|
|
155
|
-
"type": "INSTANCE",
|
|
156
|
-
"component": {
|
|
157
|
-
"name": "Button",
|
|
158
|
-
"variant": "Variant=Primary, Size=Large"
|
|
159
|
-
},
|
|
160
|
-
"props": {
|
|
161
|
-
"variant": "Primary",
|
|
162
|
-
"size": "Large",
|
|
163
|
-
"hasIcon": true,
|
|
164
|
-
"label": "Confirm Order"
|
|
165
|
-
},
|
|
166
|
-
"bounds": { "width": 140, "height": 44 }
|
|
167
|
-
}
|
|
168
|
-
```
|
|
67
|
+
## Quota rules (Zero-Hammer Protocol)
|
|
169
68
|
|
|
170
|
-
|
|
69
|
+
The script enforces a local rate gate and a persistent circuit breaker, but the agent must also follow these rules:
|
|
171
70
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
1. **Using Existing UI Components**:
|
|
177
|
-
- For `INSTANCE` nodes with resolved `component.name` and `props`:
|
|
178
|
-
- Check if your codebase already has this component (e.g. `<Button />`, `<Input />`, `<Modal />`).
|
|
179
|
-
- Directly render: `<Button variant="primary" size="large" hasIcon>Confirm Order</Button>` instead of building raw HTML divs.
|
|
180
|
-
2. **Applying Semantic Design Tokens**:
|
|
181
|
-
- When a `token` is present (e.g., `colors/brand/primary`, `spacing/md`):
|
|
182
|
-
- Map to your project's Tailwind class (`bg-brand-primary`, `p-md`, `rounded-lg`) or CSS variable (`var(--color-brand-primary)`).
|
|
183
|
-
- Avoid hardcoding hex colors or pixel values when tokens are available.
|
|
184
|
-
3. **Layout & Flexbox**:
|
|
185
|
-
- `HORIZONTAL` $\rightarrow$ `flex flex-row` (`display: flex; flex-direction: row;`).
|
|
186
|
-
- `VERTICAL` $\rightarrow$ `flex flex-col` (`display: flex; flex-direction: column;`).
|
|
187
|
-
- `itemSpacing` $\rightarrow$ CSS `gap`.
|
|
188
|
-
- `primaryAxisAlignItems` & `counterAxisAlignItems` $\rightarrow$ `justify-*` and `items-*`.
|
|
189
|
-
4. **Icon & Vector Resolution Hierarchy**:
|
|
190
|
-
- For `VECTOR` nodes or icon instances, normalize the name (strip prefixes `icon/`, `ic_`, `ico-`).
|
|
191
|
-
- **Step 1 (Targeted Local Assets/Components)**: Look for matching files in `components/icons/`, `src/assets/`, or `public/` (e.g. `<SearchIcon />`, `/icons/search.svg`). Avoid unbounded repo searches.
|
|
192
|
-
- **Step 2 (Installed Icon Library)**: If not found, import from packages in `package.json` (e.g., `lucide-react`, `@heroicons/react`).
|
|
193
|
-
- **Step 3 (Semantic Fallback)**: If not found, render an accessible placeholder (`<span className="..." aria-hidden="true" />`) with a `TODO: Missing icon 'name'` comment. Never hallucinate raw SVG `<path d="...">` coordinates.
|
|
194
|
-
5. **Image Layer Handling (`fills: [{ type: "IMAGE" }]`)**:
|
|
195
|
-
- Focus exclusively on applying the exact styling from the Figma spec: dimensions (`width`, `height`), border radius (`rounded-*`), and scale mode (`scaleMode: "FILL"` $\rightarrow$ `object-cover`, `"FIT"` $\rightarrow$ `object-contain`).
|
|
196
|
-
- Do **NOT** attempt to resolve, fetch, or hallucinate image files or external URLs (never invent Unsplash or third-party links).
|
|
197
|
-
- Render a standard `<img>` tag with `src=""` and a concise `TODO` comment specifying the target image layer.
|
|
198
|
-
6. **Visual Verification**:
|
|
199
|
-
- Inspect the downloaded preview image (`output.image.path`) to ensure pixel-perfect fidelity.
|
|
71
|
+
1. Run `fetch_figma.js` **once** per target frame or component. **Never retry in a loop.**
|
|
72
|
+
2. **Do not pass `-i`** unless the user explicitly requests a preview image. The JSON already contains layout, dimensions, colors, radii, typography, and text.
|
|
73
|
+
3. Figma Starter plans and View seats have very small monthly Tier 1 quotas, so every call matters.
|
|
200
74
|
|
|
201
|
-
|
|
75
|
+
## Errors
|
|
202
76
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
- **Node
|
|
209
|
-
- Alert the user that the node ID could not be found in the specified file.
|
|
210
|
-
- **Corporate Proxy / Self-Signed SSL (`FIGMA_SSL_CERTIFICATE_ERROR`)**:
|
|
211
|
-
- Instruct the user to add `FIGMA_IGNORE_SSL=true` to `.env` or set it in their environment.
|
|
212
|
-
- **Rate Limited (`FIGMA_RATE_LIMIT_EXCEEDED` / `FIGMA_CIRCUIT_BREAKER_ACTIVE`)**:
|
|
213
|
-
- Figma REST API has strict per-minute and monthly rate limits. If rate limited or the circuit breaker trips, report the cooldown to the user and suggest duplicating the file in Figma Drafts to get a fresh URL.
|
|
77
|
+
| Error code | Action |
|
|
78
|
+
| :--- | :--- |
|
|
79
|
+
| `FIGMA_ACCESS_TOKEN is not set` / `FIGMA_TOKEN_EXPIRED_OR_INVALID` | Tell the user the token is missing, invalid, or expired. They create one in **Figma Settings → Personal Access Tokens** and set `FIGMA_ACCESS_TOKEN` (setup per OS in REFERENCE.md). |
|
|
80
|
+
| Node not found | Report that the `node-id` does not exist in the file. |
|
|
81
|
+
| `FIGMA_SSL_CERTIFICATE_ERROR` | Corporate proxy or self-signed certificate: suggest `FIGMA_IGNORE_SSL=true` in `.env`. |
|
|
82
|
+
| `FIGMA_RATE_LIMIT_EXCEEDED` / `FIGMA_CIRCUIT_BREAKER_ACTIVE` | Report the cooldown. Suggest duplicating the file in Figma Drafts (Right-click → **Duplicate**) for a fresh URL, or exporting the selection with the companion [Figma Node JSON Extractor](https://www.figma.com/community/plugin/1691244420692136789/figma-node-json-extractor) plugin and building from that JSON. |
|
|
@@ -1382,6 +1382,7 @@ Usage:
|
|
|
1382
1382
|
Options:
|
|
1383
1383
|
--image, -i Download rendered preview image from Figma (Tier 1 call; optional)
|
|
1384
1384
|
--image-path, -o <path> Target path for saved preview image (implies --image)
|
|
1385
|
+
--force, -f Ignore existing local preview image and re-fetch from Figma
|
|
1385
1386
|
--tokens, --variables Export only the design token dictionary (colors, spacing, radii)
|
|
1386
1387
|
--shallow-instances Collapse internal layers of component instances into props
|
|
1387
1388
|
--include-tokens Include complete tokens dictionary in node output
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pedroab0/skills",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Curated collection of modular, production-ready skills for AI coding agents (Claude Code, Cursor, Kiro, OpenCode, Antigravity)",
|
|
5
5
|
"bin": {
|
|
6
6
|
"skills": "bin/cli.js",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"node": ">=16.7.0"
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
|
-
"test": "node figma-extractor/scripts/test_fetch_figma.js && node figma-to-code/scripts/test_fetch_figma.js && node figma-node-builder/scripts/test_inspect_spec.js && node test/test_cli.js",
|
|
14
|
+
"test": "node figma-extractor/scripts/test_fetch_figma.js && node figma-to-code/scripts/test_fetch_figma.js && node figma-node-builder/scripts/test_inspect_spec.js && node test/test_cli.js && node test/test_skills.js",
|
|
15
15
|
"install-skills": "node ./bin/cli.js"
|
|
16
16
|
},
|
|
17
17
|
"repository": {
|