figma-local 1.3.0 → 1.5.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/README.md +3 -1
- package/package.json +1 -1
- package/skills/figma-compare/SKILL.md +124 -0
- package/skills/figma-screenshot/SKILL.md +73 -0
- package/src/index.js +14 -14
package/README.md
CHANGED
|
@@ -395,7 +395,7 @@ fig-start --safe --here # launch from your project dir; Claude sees both you
|
|
|
395
395
|
|
|
396
396
|
## Claude Code Plugin (Skills)
|
|
397
397
|
|
|
398
|
-
figma-local ships as a Claude Code plugin with
|
|
398
|
+
figma-local ships as a Claude Code plugin with 8 skills that teach coding agents how to use it automatically:
|
|
399
399
|
|
|
400
400
|
| Skill | Triggers on |
|
|
401
401
|
|-------|------------|
|
|
@@ -405,6 +405,8 @@ figma-local ships as a Claude Code plugin with 6 skills that teach coding agents
|
|
|
405
405
|
| **figma-styles** | "style guide", "extract colors/fonts", "spacing scale" |
|
|
406
406
|
| **figma-measure** | "measure spacing", "gap between elements" |
|
|
407
407
|
| **figma-document** | "document this component", "full spec sheet", "deep breakdown" |
|
|
408
|
+
| **figma-screenshot** | "take a screenshot", "export as PNG/SVG", "capture this" |
|
|
409
|
+
| **figma-compare** | "compare", "does this match", "visual diff", "check against design" |
|
|
408
410
|
|
|
409
411
|
### Install the skills
|
|
410
412
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: figma-compare
|
|
3
|
+
description: |
|
|
4
|
+
Use this skill when the user wants to visually compare two things — two Figma elements, a screenshot vs a Figma component, two screenshots, or a design vs coded output. Triggers on: "compare", "diff", "does this match", "check against", "visual comparison", "how close is this", "spot the differences", "compare design to code", "compare these two", "are they the same". Also use when verifying coded UI matches a Figma design. Requires the fig CLI to be connected.
|
|
5
|
+
allowed-tools:
|
|
6
|
+
- Bash(fig compare *)
|
|
7
|
+
- Bash(fig compare)
|
|
8
|
+
- Bash(fig verify *)
|
|
9
|
+
- Bash(fig verify)
|
|
10
|
+
- Bash(fig screenshot *)
|
|
11
|
+
- Bash(fig screenshot)
|
|
12
|
+
- Read
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Figma Compare
|
|
16
|
+
|
|
17
|
+
Visually compare any two sources: Figma selections, node IDs, Figma links, or screenshot files. Outputs both images and a structured gap report template for analysis.
|
|
18
|
+
|
|
19
|
+
## Prerequisites
|
|
20
|
+
|
|
21
|
+
The `fig` CLI must be connected. Check with `fig daemon status`. If not connected: `fig connect --safe`.
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
### Compare current selection vs a node
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
fig compare --a selection --b "123:456"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Compare two screenshot files
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
fig compare --a design.png --b coded-output.png
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Compare a screenshot file vs a Figma node
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
fig compare --a screenshot.png --b "123:456"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Compare two Figma links
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
fig compare --a-link "https://www.figma.com/...?node-id=1-2" --b-link "https://www.figma.com/...?node-id=3-4"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Compare selection vs a Figma link
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
fig compare --a selection --b-link "https://www.figma.com/...?node-id=123-456"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Compare two nodes by ID
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
fig compare --a "123:456" --b "789:012"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Source types
|
|
62
|
+
|
|
63
|
+
The `--a` and `--b` options accept three source types:
|
|
64
|
+
|
|
65
|
+
| Source | Example | Description |
|
|
66
|
+
|--------|---------|-------------|
|
|
67
|
+
| `selection` | `--a selection` | Whatever is currently selected in Figma |
|
|
68
|
+
| Node ID | `--a "123:456"` | A specific Figma node by its ID |
|
|
69
|
+
| File path | `--a design.png` | An existing screenshot/image file on disk |
|
|
70
|
+
|
|
71
|
+
For Figma selection URLs, use `--a-link` / `--b-link` instead.
|
|
72
|
+
|
|
73
|
+
## Options
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
fig compare --a selection --b "123:456" -s 2 # 2x scale for exports
|
|
77
|
+
fig compare --a selection --b "123:456" --max 3000 # Max dimension 3000px
|
|
78
|
+
fig compare --a selection --b "123:456" --save-dir . # Save images to current dir
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Output
|
|
82
|
+
|
|
83
|
+
The command exports both sources as PNG images (saved to `/tmp/` by default) and outputs:
|
|
84
|
+
|
|
85
|
+
1. **File paths** for both images — use `Read` tool to view them
|
|
86
|
+
2. **Structured JSON** with a gap report template:
|
|
87
|
+
- `matches` — elements that are the same
|
|
88
|
+
- `differences` — table of element, property, value in A, value in B, severity
|
|
89
|
+
- `summary` — overall assessment
|
|
90
|
+
|
|
91
|
+
## Workflow: Design vs Code Comparison
|
|
92
|
+
|
|
93
|
+
1. Take a screenshot of the coded output (browser screenshot or `fig screenshot`)
|
|
94
|
+
2. Get the Figma node ID or link for the original design
|
|
95
|
+
3. Run compare:
|
|
96
|
+
```bash
|
|
97
|
+
fig compare --a coded-output.png --b-link "https://www.figma.com/...?node-id=123-456"
|
|
98
|
+
```
|
|
99
|
+
4. Read both output images to visually analyze differences
|
|
100
|
+
5. Use `fig inspect` on the Figma node to get exact specs for fixing differences
|
|
101
|
+
|
|
102
|
+
## Workflow: Before/After Comparison
|
|
103
|
+
|
|
104
|
+
1. Screenshot the current state: `fig screenshot --node "123:456" -o before.png`
|
|
105
|
+
2. Make changes in Figma
|
|
106
|
+
3. Compare: `fig compare --a before.png --b "123:456"`
|
|
107
|
+
|
|
108
|
+
## Verify command (simpler alternative)
|
|
109
|
+
|
|
110
|
+
For quick verification of a single element without a full comparison:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
fig verify # Screenshot selection for AI review
|
|
114
|
+
fig verify --node "123:456" # Verify specific node
|
|
115
|
+
fig verify --link "https://..." # Verify from Figma link
|
|
116
|
+
fig verify --compare "https://..." # Compare against a prototype URL
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Tips
|
|
120
|
+
|
|
121
|
+
- Use `--save-dir .` to save comparison images in your project directory instead of `/tmp/`
|
|
122
|
+
- For AI-powered analysis, read both output images with the `Read` tool after running compare
|
|
123
|
+
- Combine with `fig inspect --deep` on the Figma source to get exact specs for fixing any differences
|
|
124
|
+
- When comparing design to code, screenshot the browser at the same viewport width as the Figma frame for best results
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: figma-screenshot
|
|
3
|
+
description: |
|
|
4
|
+
Use this skill when the user wants to take a screenshot or export an image from Figma — current selection, a specific node, or from a Figma link. Triggers on: "screenshot", "take a screenshot", "export as PNG", "export as SVG", "capture this", "save as image", "export this frame", "get an image of". Requires the fig CLI to be connected.
|
|
5
|
+
allowed-tools:
|
|
6
|
+
- Bash(fig screenshot *)
|
|
7
|
+
- Bash(fig screenshot)
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Figma Screenshot
|
|
11
|
+
|
|
12
|
+
Export any Figma element as an image (PNG, JPG, SVG, or PDF).
|
|
13
|
+
|
|
14
|
+
## Prerequisites
|
|
15
|
+
|
|
16
|
+
The `fig` CLI must be connected. Check with `fig daemon status`. If not connected: `fig connect --safe`.
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
### Screenshot current selection
|
|
21
|
+
|
|
22
|
+
The user must select an element in Figma first, then:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
fig screenshot
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Saves to `screenshot.png` in the current directory by default.
|
|
29
|
+
|
|
30
|
+
### Screenshot from a Figma link
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
fig screenshot --link "https://www.figma.com/design/FILEID/Name?node-id=123-456"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Screenshot a specific node by ID
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
fig screenshot --node "123:456"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Options
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
fig screenshot -o design.png # Custom output file name
|
|
46
|
+
fig screenshot -s 2 # 2x scale (default is 2)
|
|
47
|
+
fig screenshot -s 4 # 4x scale for high-res
|
|
48
|
+
fig screenshot -f svg # SVG format
|
|
49
|
+
fig screenshot -f jpg # JPG format
|
|
50
|
+
fig screenshot -f pdf # PDF format
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Combine options
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
fig screenshot --link "https://..." -o hero-section.png -s 3
|
|
57
|
+
fig screenshot --node "123:456" -f svg -o icon.svg
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Export a specific node by ID (alternative)
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
fig export node "123:456" # PNG at 2x
|
|
64
|
+
fig export node "123:456" -f svg -o out.svg # SVG
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Tips
|
|
68
|
+
|
|
69
|
+
- Default scale is 2x which gives crisp images on retina displays
|
|
70
|
+
- Use `-s 1` for pixel-accurate exports (1:1 with Figma dimensions)
|
|
71
|
+
- SVG format is best for icons and vector graphics
|
|
72
|
+
- For AI verification of created components, use `fig verify` instead (optimized for smaller file size)
|
|
73
|
+
- Screenshots can be used with `fig compare` to visually diff against other screenshots or Figma nodes
|
package/src/index.js
CHANGED
|
@@ -8560,14 +8560,14 @@ Examples:
|
|
|
8560
8560
|
if (!sel || sel.length === 0) return { error: 'Nothing selected in Figma. Select a frame or layer first.' };
|
|
8561
8561
|
const node = sel[0];
|
|
8562
8562
|
function walk(n, depth) {
|
|
8563
|
-
if (depth >
|
|
8563
|
+
if (depth > 20) return { type: n.type, name: n.name };
|
|
8564
8564
|
const obj = { type: n.type, name: n.name };
|
|
8565
8565
|
if (n.width) obj.w = Math.round(n.width);
|
|
8566
8566
|
if (n.height) obj.h = Math.round(n.height);
|
|
8567
|
-
if (n.type === 'TEXT') obj.text = n.characters
|
|
8567
|
+
if (n.type === 'TEXT') obj.text = n.characters;
|
|
8568
8568
|
if (n.fills && n.fills.length) obj.fills = n.fills.map(f => f.type === 'SOLID' ? { r: Math.round(f.color.r*255), g: Math.round(f.color.g*255), b: Math.round(f.color.b*255) } : { type: f.type });
|
|
8569
8569
|
if (n.cornerRadius) obj.radius = n.cornerRadius;
|
|
8570
|
-
if (n.children) obj.children = n.children.
|
|
8570
|
+
if (n.children) obj.children = n.children.map(c => walk(c, depth + 1));
|
|
8571
8571
|
return obj;
|
|
8572
8572
|
}
|
|
8573
8573
|
return { selected: sel.length, node: walk(node, 0) };
|
|
@@ -8598,14 +8598,14 @@ Examples:
|
|
|
8598
8598
|
const node = figma.getNodeById('${nodeId}');
|
|
8599
8599
|
if (!node) return { error: 'Node ${nodeId} not found on the current page.' };
|
|
8600
8600
|
function walk(n, depth) {
|
|
8601
|
-
if (depth >
|
|
8601
|
+
if (depth > 20) return { type: n.type, name: n.name };
|
|
8602
8602
|
const obj = { type: n.type, name: n.name };
|
|
8603
8603
|
if (n.width) obj.w = Math.round(n.width);
|
|
8604
8604
|
if (n.height) obj.h = Math.round(n.height);
|
|
8605
|
-
if (n.type === 'TEXT') obj.text = n.characters
|
|
8605
|
+
if (n.type === 'TEXT') obj.text = n.characters;
|
|
8606
8606
|
if (n.fills && n.fills.length) obj.fills = n.fills.map(f => f.type === 'SOLID' ? { r: Math.round(f.color.r*255), g: Math.round(f.color.g*255), b: Math.round(f.color.b*255) } : { type: f.type });
|
|
8607
8607
|
if (n.cornerRadius) obj.radius = n.cornerRadius;
|
|
8608
|
-
if (n.children) obj.children = n.children.
|
|
8608
|
+
if (n.children) obj.children = n.children.map(c => walk(c, depth + 1));
|
|
8609
8609
|
return obj;
|
|
8610
8610
|
}
|
|
8611
8611
|
return { nodeId: '${nodeId}', node: walk(node, 0) };
|
|
@@ -8999,7 +8999,7 @@ const INSPECT_CODE = `(function() {
|
|
|
8999
8999
|
// Children summary
|
|
9000
9000
|
if (node.children && node.children.length > 0) {
|
|
9001
9001
|
spec.childCount = node.children.length;
|
|
9002
|
-
spec.children = node.children.
|
|
9002
|
+
spec.children = node.children.map(function(c) {
|
|
9003
9003
|
return { name: c.name, type: c.type, w: c.width ? Math.round(c.width) : undefined, h: c.height ? Math.round(c.height) : undefined };
|
|
9004
9004
|
});
|
|
9005
9005
|
}
|
|
@@ -9007,9 +9007,9 @@ const INSPECT_CODE = `(function() {
|
|
|
9007
9007
|
return spec;
|
|
9008
9008
|
}
|
|
9009
9009
|
|
|
9010
|
-
// Inspect all selected nodes
|
|
9010
|
+
// Inspect all selected nodes
|
|
9011
9011
|
var results = [];
|
|
9012
|
-
var count =
|
|
9012
|
+
var count = sel.length;
|
|
9013
9013
|
for (var i = 0; i < count; i++) {
|
|
9014
9014
|
results.push(inspectNode(sel[i]));
|
|
9015
9015
|
}
|
|
@@ -9083,7 +9083,7 @@ Examples:
|
|
|
9083
9083
|
${options.node ? `node = figma.getNodeById('${options.node}');` : ''}
|
|
9084
9084
|
${options.link ? `node = figma.getNodeById('${parseNodeIdFromLink(options.link)}');` : ''}
|
|
9085
9085
|
if (!node || !node.children) return [];
|
|
9086
|
-
return node.children.
|
|
9086
|
+
return node.children.map(function(c) { return c.id; });
|
|
9087
9087
|
})()`;
|
|
9088
9088
|
const childIds = await daemonExec('eval', { code: childIdsCode });
|
|
9089
9089
|
if (Array.isArray(childIds)) {
|
|
@@ -9199,7 +9199,7 @@ function formatInspectSpec(spec) {
|
|
|
9199
9199
|
if (t.textAlign) lines.push(` Text align: ${t.textAlign}`);
|
|
9200
9200
|
if (t.textDecoration) lines.push(` Decoration: ${t.textDecoration}`);
|
|
9201
9201
|
if (t.textTransform) lines.push(` Transform: ${t.textTransform}`);
|
|
9202
|
-
if (t.content) lines.push(` Content: "${t.content
|
|
9202
|
+
if (t.content) lines.push(` Content: "${t.content}"`);
|
|
9203
9203
|
}
|
|
9204
9204
|
|
|
9205
9205
|
// Effects
|
|
@@ -9530,7 +9530,7 @@ function formatCSS(node) {
|
|
|
9530
9530
|
}
|
|
9531
9531
|
lines.push('}');
|
|
9532
9532
|
if (node.text) {
|
|
9533
|
-
lines.push(chalk.gray(`/* Content: "${node.text
|
|
9533
|
+
lines.push(chalk.gray(`/* Content: "${node.text}" */`));
|
|
9534
9534
|
}
|
|
9535
9535
|
return lines.join('\n');
|
|
9536
9536
|
}
|
|
@@ -9610,7 +9610,7 @@ function formatTailwind(node) {
|
|
|
9610
9610
|
const lines = [];
|
|
9611
9611
|
lines.push(chalk.gray(`{/* ${node.name} */}`));
|
|
9612
9612
|
lines.push(`className="${classes.join(' ')}"`);
|
|
9613
|
-
if (node.text) lines.push(chalk.gray(`{/* "${node.text
|
|
9613
|
+
if (node.text) lines.push(chalk.gray(`{/* "${node.text}" */}`));
|
|
9614
9614
|
return lines.join('\n');
|
|
9615
9615
|
}
|
|
9616
9616
|
|
|
@@ -9889,7 +9889,7 @@ const DOCUMENT_CODE = `(function() {
|
|
|
9889
9889
|
}
|
|
9890
9890
|
|
|
9891
9891
|
function extractNode(node, depth) {
|
|
9892
|
-
if (depth >
|
|
9892
|
+
if (depth > 30) return null;
|
|
9893
9893
|
var n = { name: node.name, type: node.type };
|
|
9894
9894
|
|
|
9895
9895
|
// Dimensions
|