@nnao45/figma-use 0.1.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/CHANGELOG.md +991 -0
- package/LICENSE +22 -0
- package/README.md +569 -0
- package/SKILL.md +683 -0
- package/bin/figma-use.js +9 -0
- package/dist/cli/index.js +496 -0
- package/package.json +87 -0
- package/packages/cli/src/render/component-set.tsx +157 -0
- package/packages/cli/src/render/components.tsx +115 -0
- package/packages/cli/src/render/icon.ts +166 -0
- package/packages/cli/src/render/index.ts +47 -0
- package/packages/cli/src/render/jsx-dev-runtime.ts +6 -0
- package/packages/cli/src/render/jsx-runtime.ts +90 -0
- package/packages/cli/src/render/mini-react.ts +33 -0
- package/packages/cli/src/render/render-from-string.ts +121 -0
- package/packages/cli/src/render/render-jsx.ts +44 -0
- package/packages/cli/src/render/tree.ts +148 -0
- package/packages/cli/src/render/vars.ts +186 -0
- package/packages/cli/src/render/widget-renderer.ts +163 -0
- package/packages/plugin/src/main.ts +2747 -0
- package/packages/plugin/src/query.ts +253 -0
- package/packages/plugin/src/rpc.ts +5238 -0
- package/packages/plugin/src/ui.html +25 -0
- package/packages/plugin/src/ui.ts +74 -0
package/SKILL.md
ADDED
|
@@ -0,0 +1,683 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: figma-use
|
|
3
|
+
description: Control Figma via CLI — create shapes, frames, text, components, set styles, layout, variables, export images. Use when asked to create/modify Figma designs or automate design tasks.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# figma-use
|
|
7
|
+
|
|
8
|
+
CLI for Figma. Two modes: commands and JSX.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
# Commands
|
|
12
|
+
bun run dist/cli/index.js create frame --width 400 --height 300 --fill "#FFF" --layout VERTICAL --gap 16
|
|
13
|
+
bun run dist/cli/index.js create icon mdi:home --size 32 --color "#3B82F6"
|
|
14
|
+
bun run dist/cli/index.js set fill 1:23 "$Colors/Primary"
|
|
15
|
+
|
|
16
|
+
# JSX (props directly on elements, NOT style={{}})
|
|
17
|
+
echo '<Frame p={24} bg="#3B82F6" rounded={12}>
|
|
18
|
+
<Text size={18} color="#FFF">Hello</Text>
|
|
19
|
+
</Frame>' | bun run dist/cli/index.js render --stdin --x 100 --y 100
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Before You Start
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
bun run dist/cli/index.js status # Check connection
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
If not connected — start Figma with remote debugging:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# macOS
|
|
32
|
+
open -a Figma --args --remote-debugging-port=9222
|
|
33
|
+
|
|
34
|
+
# Windows
|
|
35
|
+
"C:\Users\%USERNAME%\AppData\Local\Figma\Figma.exe" --remote-debugging-port=9222
|
|
36
|
+
|
|
37
|
+
# Linux
|
|
38
|
+
figma --remote-debugging-port=9222
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Start Figma with `--remote-debugging-port=9222` and you're ready.
|
|
42
|
+
|
|
43
|
+
## Two Modes
|
|
44
|
+
|
|
45
|
+
**Imperative** — single operations:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
bun run dist/cli/index.js create frame --width 400 --height 300 --fill "#FFF" --radius 12
|
|
49
|
+
bun run dist/cli/index.js set fill <id> "#FF0000"
|
|
50
|
+
bun run dist/cli/index.js node move <id> --x 100 --y 200
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Declarative** — render JSX trees:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
echo '<Frame p={24} gap={16} flex="col" bg="#FFF" rounded={12}>
|
|
57
|
+
<Text size={24} weight="bold" color="#000">Title</Text>
|
|
58
|
+
<Text size={14} color="#666">Description</Text>
|
|
59
|
+
</Frame>' | bun run dist/cli/index.js render --stdin --x 100 --y 200
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
stdin supports both pure JSX and full module syntax with imports:
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
import { Frame, Text, defineComponent } from 'figma-use/render'
|
|
66
|
+
|
|
67
|
+
const Button = defineComponent(
|
|
68
|
+
'Button',
|
|
69
|
+
<Frame bg="#3B82F6" p={12} rounded={6}>
|
|
70
|
+
<Text color="#FFF">Click</Text>
|
|
71
|
+
</Frame>
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
export default () => (
|
|
75
|
+
<Frame flex="row" gap={8}>
|
|
76
|
+
<Button />
|
|
77
|
+
<Button />
|
|
78
|
+
</Frame>
|
|
79
|
+
)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Elements:** `Frame`, `Rectangle`, `Ellipse`, `Text`, `Line`, `Star`, `Polygon`, `Vector`, `Group`, `Icon`, `Image`, `Instance`
|
|
83
|
+
|
|
84
|
+
Use `<Instance>` to create component instances:
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
<Frame flex="row" gap={8}>
|
|
88
|
+
<Instance component="59763:10626" />
|
|
89
|
+
<Instance component="59763:10629" />
|
|
90
|
+
</Frame>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
⚠️ **Always use `--x` and `--y`** to position renders. Don't stack everything at (0, 0).
|
|
94
|
+
|
|
95
|
+
## Icons
|
|
96
|
+
|
|
97
|
+
150k+ icons from Iconify by name:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
bun run dist/cli/index.js create icon mdi:home
|
|
101
|
+
bun run dist/cli/index.js create icon lucide:star --size 48 --color "#F59E0B"
|
|
102
|
+
bun run dist/cli/index.js create icon heroicons:bell-solid --component # as Figma component
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
In JSX:
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
<Icon name="mdi:home" size={24} color="#3B82F6" />
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Images
|
|
112
|
+
|
|
113
|
+
Create image nodes from URL, local file, or data URI:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
bun run dist/cli/index.js create image https://example.com/photo.jpg --x 100 --y 200
|
|
117
|
+
bun run dist/cli/index.js create image ./screenshot.png --name "Reference"
|
|
118
|
+
bun run dist/cli/index.js create image ./photo.jpg --width 400 --height 300 --scale fit --radius 12
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Auto-detects native image dimensions. Supports `--scale` modes: `fill`, `fit`, `crop`, `tile`.
|
|
122
|
+
|
|
123
|
+
In JSX:
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
<Image src="https://example.com/photo.jpg" w={200} h={150} />
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Export JSX
|
|
130
|
+
|
|
131
|
+
Convert Figma nodes back to JSX code:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
bun run dist/cli/index.js export jsx <id> # Minified
|
|
135
|
+
bun run dist/cli/index.js export jsx <id> --pretty # Formatted
|
|
136
|
+
|
|
137
|
+
# Format options
|
|
138
|
+
bun run dist/cli/index.js export jsx <id> --pretty --semi --tabs
|
|
139
|
+
|
|
140
|
+
# Match vector shapes to Iconify icons (requires: npm i whaticon)
|
|
141
|
+
bun run dist/cli/index.js export jsx <id> --match-icons
|
|
142
|
+
bun run dist/cli/index.js export jsx <id> --match-icons --icon-threshold 0.85 --prefer-icons lucide,tabler
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Round-trip workflow:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
# Export → edit → re-render
|
|
149
|
+
bun run dist/cli/index.js export jsx <id> --pretty > component.tsx
|
|
150
|
+
# ... edit the file ...
|
|
151
|
+
bun run dist/cli/index.js render component.tsx --x 500 --y 0
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Compare two nodes as JSX:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
bun run dist/cli/index.js diff jsx <from-id> <to-id>
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Export Storybook (Experimental)
|
|
161
|
+
|
|
162
|
+
Export all components on current page as Storybook stories:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
fbun run dist/cli/index.js export storybook # Output to ./stories/
|
|
166
|
+
fbun run dist/cli/index.js export storybook --out ./src/stories # Custom output dir
|
|
167
|
+
fbun run dist/cli/index.js export storybook --match-icons # Match vectors to Iconify icons
|
|
168
|
+
fbun run dist/cli/index.js export storybook --no-semantic-html # Disable semantic HTML conversion
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**Semantic HTML:** By default, components are converted to semantic HTML elements based on their names:
|
|
172
|
+
|
|
173
|
+
- `Input/*`, `TextField/*` → `<input type="text">`
|
|
174
|
+
- `Textarea/*` → `<textarea>`
|
|
175
|
+
- `Checkbox/*` → `<input type="checkbox">`
|
|
176
|
+
- `Radio/*` → `<input type="radio">`
|
|
177
|
+
- `Button/*` → `<button>`
|
|
178
|
+
- `Select/*`, `Dropdown/*` → `<select>`
|
|
179
|
+
|
|
180
|
+
Use `--no-semantic-html` to disable this and keep `<Frame>` elements.
|
|
181
|
+
|
|
182
|
+
Generates `.stories.tsx` files:
|
|
183
|
+
|
|
184
|
+
- **ComponentSets** → React component with props + stories with args
|
|
185
|
+
- **VARIANT properties** → Union type props (`variant?: 'Primary' | 'Secondary'`)
|
|
186
|
+
- **TEXT properties** → Editable string props (`label?: string`)
|
|
187
|
+
- Components grouped by `/` prefix → `Button/Primary`, `Button/Secondary` → `Button.stories.tsx`
|
|
188
|
+
|
|
189
|
+
Example output for Button with variant and label:
|
|
190
|
+
|
|
191
|
+
```tsx
|
|
192
|
+
// Button.tsx
|
|
193
|
+
export interface ButtonProps {
|
|
194
|
+
label?: string
|
|
195
|
+
variant?: 'Primary' | 'Secondary'
|
|
196
|
+
}
|
|
197
|
+
export function Button({ label, variant }: ButtonProps) {
|
|
198
|
+
if (variant === 'Primary')
|
|
199
|
+
return (
|
|
200
|
+
<Frame>
|
|
201
|
+
<Text>{label}</Text>
|
|
202
|
+
</Frame>
|
|
203
|
+
)
|
|
204
|
+
// ...
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Button.stories.tsx
|
|
208
|
+
export const Primary: StoryObj<typeof Button> = {
|
|
209
|
+
args: { label: 'Click', variant: 'Primary' }
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Variables as Tokens
|
|
214
|
+
|
|
215
|
+
Reference Figma variables in any color option with `var:Name` or `$Name`:
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
bun run dist/cli/index.js create rect --width 100 --height 100 --fill 'var:Colors/Primary'
|
|
219
|
+
bun run dist/cli/index.js set fill <id> '$Brand/Accent'
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
In JSX:
|
|
223
|
+
|
|
224
|
+
```tsx
|
|
225
|
+
<Frame bg="$Colors/Primary" />
|
|
226
|
+
<Text color="var:Text/Primary">Hello</Text>
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Style Shorthands
|
|
230
|
+
|
|
231
|
+
**Size & Position:**
|
|
232
|
+
| Short | Full | Values |
|
|
233
|
+
|-------|------|--------|
|
|
234
|
+
| `w`, `h` | width, height | number or `"fill"` |
|
|
235
|
+
| `minW`, `maxW` | minWidth, maxWidth | number |
|
|
236
|
+
| `minH`, `maxH` | minHeight, maxHeight | number |
|
|
237
|
+
| `x`, `y` | position | number |
|
|
238
|
+
|
|
239
|
+
**Layout:**
|
|
240
|
+
| Short | Full | Values |
|
|
241
|
+
|-------|------|--------|
|
|
242
|
+
| `flex` | flexDirection | `"row"`, `"col"` |
|
|
243
|
+
| `gap` | spacing | number |
|
|
244
|
+
| `wrap` | layoutWrap | `true` |
|
|
245
|
+
| `justify` | justifyContent | `"start"`, `"center"`, `"end"`, `"between"` |
|
|
246
|
+
| `items` | alignItems | `"start"`, `"center"`, `"end"` |
|
|
247
|
+
| `p`, `px`, `py` | padding | number |
|
|
248
|
+
| `pt`, `pr`, `pb`, `pl` | padding sides | number |
|
|
249
|
+
| `position` | layoutPositioning | `"absolute"` |
|
|
250
|
+
| `grow` | layoutGrow | number |
|
|
251
|
+
| `stretch` | layoutAlign | `true` → STRETCH |
|
|
252
|
+
|
|
253
|
+
**Appearance:**
|
|
254
|
+
| Short | Full | Values |
|
|
255
|
+
|-------|------|--------|
|
|
256
|
+
| `bg` | fill | hex or `$Variable` |
|
|
257
|
+
| `stroke` | strokeColor | hex |
|
|
258
|
+
| `strokeWidth` | strokeWeight | number |
|
|
259
|
+
| `strokeAlign` | strokeAlign | `"inside"`, `"outside"` |
|
|
260
|
+
| `opacity` | opacity | 0..1 |
|
|
261
|
+
| `blendMode` | blendMode | `"multiply"`, etc. |
|
|
262
|
+
|
|
263
|
+
**Corners:**
|
|
264
|
+
| Short | Full | Values |
|
|
265
|
+
|-------|------|--------|
|
|
266
|
+
| `rounded` | cornerRadius | number |
|
|
267
|
+
| `roundedTL/TR/BL/BR` | individual corners | number |
|
|
268
|
+
| `cornerSmoothing` | squircle smoothing | 0..1 (iOS style) |
|
|
269
|
+
|
|
270
|
+
**Effects:**
|
|
271
|
+
| Short | Full | Values |
|
|
272
|
+
|-------|------|--------|
|
|
273
|
+
| `shadow` | dropShadow | `"0px 4px 8px rgba(0,0,0,0.25)"` |
|
|
274
|
+
| `blur` | layerBlur | number |
|
|
275
|
+
| `overflow` | clipsContent | `"hidden"` |
|
|
276
|
+
| `rotate` | rotation | degrees |
|
|
277
|
+
|
|
278
|
+
**Text:**
|
|
279
|
+
| Short | Full | Values |
|
|
280
|
+
|-------|------|--------|
|
|
281
|
+
| `size` | fontSize | number |
|
|
282
|
+
| `weight` | fontWeight | `"bold"`, number |
|
|
283
|
+
| `font` | fontFamily | string |
|
|
284
|
+
| `color` | textColor | hex |
|
|
285
|
+
|
|
286
|
+
**Grid (CSS Grid layout):**
|
|
287
|
+
| Short | Full | Values |
|
|
288
|
+
|-------|------|--------|
|
|
289
|
+
| `display` | layoutMode | `"grid"` |
|
|
290
|
+
| `cols` | gridTemplateColumns | `"100px 1fr auto"` |
|
|
291
|
+
| `rows` | gridTemplateRows | `"auto auto"` |
|
|
292
|
+
| `colGap` | columnGap | number |
|
|
293
|
+
| `rowGap` | rowGap | number |
|
|
294
|
+
|
|
295
|
+
## Components (via .figma.tsx)
|
|
296
|
+
|
|
297
|
+
First call creates master, rest create instances:
|
|
298
|
+
|
|
299
|
+
```tsx
|
|
300
|
+
import { defineComponent, Frame, Text } from 'figma-use/render'
|
|
301
|
+
|
|
302
|
+
const Card = defineComponent(
|
|
303
|
+
'Card',
|
|
304
|
+
<Frame p={24} bg="#FFF" rounded={12}>
|
|
305
|
+
<Text size={18} color="#000">
|
|
306
|
+
Card
|
|
307
|
+
</Text>
|
|
308
|
+
</Frame>
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
export default () => (
|
|
312
|
+
<Frame gap={16} flex="row">
|
|
313
|
+
<Card />
|
|
314
|
+
<Card />
|
|
315
|
+
</Frame>
|
|
316
|
+
)
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
bun run dist/cli/index.js render ./Card.figma.tsx --x 100 --y 200
|
|
321
|
+
bun run dist/cli/index.js render --examples # Full API reference
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
## Variants (ComponentSet)
|
|
325
|
+
|
|
326
|
+
```tsx
|
|
327
|
+
import { defineComponentSet, Frame, Text } from 'figma-use/render'
|
|
328
|
+
|
|
329
|
+
const Button = defineComponentSet(
|
|
330
|
+
'Button',
|
|
331
|
+
{
|
|
332
|
+
variant: ['Primary', 'Secondary'] as const,
|
|
333
|
+
size: ['Small', 'Large'] as const
|
|
334
|
+
},
|
|
335
|
+
({ variant, size }) => (
|
|
336
|
+
<Frame
|
|
337
|
+
p={size === 'Large' ? 16 : 8}
|
|
338
|
+
bg={variant === 'Primary' ? '#3B82F6' : '#E5E7EB'}
|
|
339
|
+
rounded={8}
|
|
340
|
+
>
|
|
341
|
+
<Text color={variant === 'Primary' ? '#FFF' : '#111'}>
|
|
342
|
+
{variant} {size}
|
|
343
|
+
</Text>
|
|
344
|
+
</Frame>
|
|
345
|
+
)
|
|
346
|
+
)
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
Creates real ComponentSet with all combinations.
|
|
350
|
+
|
|
351
|
+
## Diffs
|
|
352
|
+
|
|
353
|
+
Compare frames and generate patch:
|
|
354
|
+
|
|
355
|
+
```bash
|
|
356
|
+
bun run dist/cli/index.js diff create --from <id1> --to <id2>
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
```diff
|
|
360
|
+
--- /Card/Header #123:457
|
|
361
|
+
+++ /Card/Header #789:013
|
|
362
|
+
type: FRAME
|
|
363
|
+
size: 200 50
|
|
364
|
+
-fill: #FFFFFF
|
|
365
|
+
+fill: #F0F0F0
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
⚠️ Context lines need space prefix: ` size: 200 50` not `size: 200 50`
|
|
369
|
+
|
|
370
|
+
Apply with validation (supports modify, create, and delete operations):
|
|
371
|
+
|
|
372
|
+
```bash
|
|
373
|
+
bun run dist/cli/index.js diff apply patch.diff # Fails if old values don't match
|
|
374
|
+
bun run dist/cli/index.js diff apply patch.diff --dry-run # Preview
|
|
375
|
+
bun run dist/cli/index.js diff apply patch.diff --force # Skip validation
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
Visual diff (red = changed pixels):
|
|
379
|
+
|
|
380
|
+
```bash
|
|
381
|
+
bun run dist/cli/index.js diff visual --from <id1> --to <id2> --output diff.png
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
⚠️ **After initial render, use diffs or direct commands.** Don't re-render full JSX trees.
|
|
385
|
+
|
|
386
|
+
## Reconstruct (Image → Figma)
|
|
387
|
+
|
|
388
|
+
Convert a screenshot or mockup image into a Figma design:
|
|
389
|
+
|
|
390
|
+
```bash
|
|
391
|
+
# Place reference image and create working frame
|
|
392
|
+
bun run dist/cli/index.js reconstruct ./screenshot.png --name "Login Page"
|
|
393
|
+
|
|
394
|
+
# With custom position and reference opacity
|
|
395
|
+
bun run dist/cli/index.js reconstruct https://example.com/mockup.png --x 500 --y 0 --ref-opacity 0.2
|
|
396
|
+
|
|
397
|
+
# Include base64 image data in output (for AI vision analysis)
|
|
398
|
+
bun run dist/cli/index.js reconstruct ./design.png --include-data --json
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
**AI agent workflow:**
|
|
402
|
+
|
|
403
|
+
1. `reconstruct ./screenshot.png --json` — places reference image (locked, semi-transparent) and creates empty working frame
|
|
404
|
+
2. AI analyzes the image (via vision) to understand the layout
|
|
405
|
+
3. AI uses `render --parent <workingFrameId>` or `create` commands to build Figma nodes on top
|
|
406
|
+
4. Delete or hide the reference image when done
|
|
407
|
+
|
|
408
|
+
The command returns `workingFrameId`, dimensions, and position — everything the AI needs to start building.
|
|
409
|
+
|
|
410
|
+
## Query (XPath)
|
|
411
|
+
|
|
412
|
+
Find nodes using XPath selectors:
|
|
413
|
+
|
|
414
|
+
```bash
|
|
415
|
+
bun run dist/cli/index.js query "//FRAME" # All frames
|
|
416
|
+
bun run dist/cli/index.js query "//FRAME[@width < 300]" # Frames narrower than 300px
|
|
417
|
+
bun run dist/cli/index.js query "//COMPONENT[starts-with(@name, 'Button')]" # Name starts with
|
|
418
|
+
bun run dist/cli/index.js query "//FRAME[contains(@name, 'Card')]" # Name contains
|
|
419
|
+
bun run dist/cli/index.js query "//SECTION/FRAME" # Direct children
|
|
420
|
+
bun run dist/cli/index.js query "//SECTION//TEXT" # All descendants
|
|
421
|
+
bun run dist/cli/index.js query "//*[@cornerRadius > 0]" # Any node with radius
|
|
422
|
+
bun run dist/cli/index.js query "//FRAME[@width > 100 and @width < 500]" # Range
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
Attributes: `name`, `width`, `height`, `x`, `y`, `cornerRadius`, `opacity`, `visible`, `characters`, `fontSize`, `layoutMode`, `itemSpacing`
|
|
426
|
+
|
|
427
|
+
XPath functions: `contains()`, `starts-with()`, `string-length()`, `not()`, `and`, `or`
|
|
428
|
+
|
|
429
|
+
## Common Commands
|
|
430
|
+
|
|
431
|
+
```bash
|
|
432
|
+
# Create
|
|
433
|
+
bun run dist/cli/index.js create frame --width 400 --height 300 --fill "#FFF" --layout VERTICAL --gap 16
|
|
434
|
+
bun run dist/cli/index.js create text --text "Hello" --font-size 24 --fill "#000"
|
|
435
|
+
bun run dist/cli/index.js create rect --width 100 --height 50 --fill "#F00" --radius 8
|
|
436
|
+
bun run dist/cli/index.js create image ./photo.png --x 100 --y 200
|
|
437
|
+
|
|
438
|
+
# Find
|
|
439
|
+
bun run dist/cli/index.js query "//FRAME[@name = 'Header']"
|
|
440
|
+
bun run dist/cli/index.js find --name "Button"
|
|
441
|
+
bun run dist/cli/index.js find --type FRAME
|
|
442
|
+
bun run dist/cli/index.js selection get
|
|
443
|
+
|
|
444
|
+
# Explore
|
|
445
|
+
bun run dist/cli/index.js node ancestors <id> # Get parent chain (useful for navigation)
|
|
446
|
+
bun run dist/cli/index.js node bindings <id> # Get variable bindings for fills/strokes
|
|
447
|
+
bun run dist/cli/index.js page bounds # Find free space for new objects
|
|
448
|
+
bun run dist/cli/index.js variable find "Text/Neutral" # Search variables by name
|
|
449
|
+
|
|
450
|
+
# Modify
|
|
451
|
+
bun run dist/cli/index.js set fill <id> "#FF0000"
|
|
452
|
+
bun run dist/cli/index.js set radius <id> 12
|
|
453
|
+
bun run dist/cli/index.js set text <id> "New text"
|
|
454
|
+
bun run dist/cli/index.js set text-resize <id> height # Wrap text (height auto, fixed width)
|
|
455
|
+
bun run dist/cli/index.js set layout <id> --mode VERTICAL --gap 12 --padding 16
|
|
456
|
+
bun run dist/cli/index.js set layout <id> --mode GRID --cols "1fr 1fr 1fr" --rows "auto" --gap 16
|
|
457
|
+
bun run dist/cli/index.js node move <id> --x 100 --y 200
|
|
458
|
+
bun run dist/cli/index.js node resize <id> --width 300 --height 200
|
|
459
|
+
bun run dist/cli/index.js node delete <id> [id2...]
|
|
460
|
+
bun run dist/cli/index.js node to-component <id>
|
|
461
|
+
|
|
462
|
+
# Export
|
|
463
|
+
bun run dist/cli/index.js export node <id> --output design.png
|
|
464
|
+
bun run dist/cli/index.js export screenshot --output viewport.png
|
|
465
|
+
|
|
466
|
+
# Navigate
|
|
467
|
+
bun run dist/cli/index.js page list
|
|
468
|
+
bun run dist/cli/index.js page set "Page Name"
|
|
469
|
+
bun run dist/cli/index.js viewport zoom-to-fit <id>
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
Full reference: [REFERENCE.md](https://github.com/dannote/figma-use/blob/master/REFERENCE.md)
|
|
473
|
+
|
|
474
|
+
## Analyze
|
|
475
|
+
|
|
476
|
+
Discovery tools for understanding design systems:
|
|
477
|
+
|
|
478
|
+
```bash
|
|
479
|
+
# Repeated patterns — potential components
|
|
480
|
+
bun run dist/cli/index.js analyze clusters
|
|
481
|
+
bun run dist/cli/index.js analyze clusters --min-count 5
|
|
482
|
+
|
|
483
|
+
# Color palette
|
|
484
|
+
bun run dist/cli/index.js analyze colors # Usage frequency
|
|
485
|
+
bun run dist/cli/index.js analyze colors --show-similar # Find similar colors to merge
|
|
486
|
+
|
|
487
|
+
# Typography
|
|
488
|
+
bun run dist/cli/index.js analyze typography # All font combinations
|
|
489
|
+
bun run dist/cli/index.js analyze typography --group-by size
|
|
490
|
+
|
|
491
|
+
# Spacing
|
|
492
|
+
bun run dist/cli/index.js analyze spacing --grid 8 # Check 8px grid compliance
|
|
493
|
+
|
|
494
|
+
# Accessibility snapshot — extract interactive elements
|
|
495
|
+
bun run dist/cli/index.js analyze snapshot # Full page
|
|
496
|
+
bun run dist/cli/index.js analyze snapshot <id> -i # Interactive only (buttons, inputs, etc.)
|
|
497
|
+
bun run dist/cli/index.js analyze snapshot --depth 6 # Limit depth
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
**Use cases:**
|
|
501
|
+
|
|
502
|
+
- **Component extraction** — find copy-pasted elements that should be components
|
|
503
|
+
- **Design audit** — identify inconsistencies, similar-but-different elements
|
|
504
|
+
- **Design system creation** — discover existing colors, typography, spacing patterns
|
|
505
|
+
- **Onboarding** — understand structure of unfamiliar design files
|
|
506
|
+
|
|
507
|
+
Output shows counts, examples, and warnings (e.g., off-grid spacing, hardcoded colors).
|
|
508
|
+
|
|
509
|
+
## Lint (Experimental)
|
|
510
|
+
|
|
511
|
+
Check designs for consistency and accessibility issues:
|
|
512
|
+
|
|
513
|
+
```bash
|
|
514
|
+
bun run dist/cli/index.js lint # Recommended preset
|
|
515
|
+
bun run dist/cli/index.js lint --page "Components" # Lint specific page
|
|
516
|
+
bun run dist/cli/index.js lint --preset strict # Stricter rules
|
|
517
|
+
bun run dist/cli/index.js lint --preset accessibility # A11y only (contrast, touch targets)
|
|
518
|
+
bun run dist/cli/index.js lint --rule color-contrast # Single rule
|
|
519
|
+
bun run dist/cli/index.js lint -v # With fix suggestions
|
|
520
|
+
bun run dist/cli/index.js lint --json # For CI/CD
|
|
521
|
+
bun run dist/cli/index.js lint --list-rules # Show all rules
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
**Presets:** `recommended`, `strict`, `accessibility`, `design-system`
|
|
525
|
+
|
|
526
|
+
**17 rules:**
|
|
527
|
+
|
|
528
|
+
- Design tokens: `no-hardcoded-colors`, `consistent-spacing`, `consistent-radius`, `effect-style-required`
|
|
529
|
+
- Layout: `prefer-auto-layout`, `pixel-perfect`
|
|
530
|
+
- Typography: `text-style-required`, `min-text-size`, `no-mixed-styles`
|
|
531
|
+
- Accessibility: `color-contrast`, `touch-target-size`
|
|
532
|
+
- Structure: `no-default-names`, `no-hidden-layers`, `no-deeply-nested`, `no-empty-frames`, `no-groups`
|
|
533
|
+
- Components: `no-detached-instances`
|
|
534
|
+
|
|
535
|
+
Exit code 1 if errors found — use in CI pipelines.
|
|
536
|
+
|
|
537
|
+
## Output
|
|
538
|
+
|
|
539
|
+
Human-readable by default — **prefer this to save tokens**. Use `--json` only when you need to parse specific fields programmatically.
|
|
540
|
+
|
|
541
|
+
## Node IDs
|
|
542
|
+
|
|
543
|
+
Format: `session:local` (e.g., `1:23`). Inside instances: `I<instance-id>;<internal-id>`.
|
|
544
|
+
|
|
545
|
+
Get IDs from `figma-use selection get` or `figma-use node tree`.
|
|
546
|
+
|
|
547
|
+
## Colors
|
|
548
|
+
|
|
549
|
+
Hex: `#RGB`, `#RRGGBB`, `#RRGGBBAA`
|
|
550
|
+
Variables: `var:Colors/Primary` or `$Colors/Primary`
|
|
551
|
+
|
|
552
|
+
---
|
|
553
|
+
|
|
554
|
+
## Best Practices
|
|
555
|
+
|
|
556
|
+
### Always verify visually
|
|
557
|
+
|
|
558
|
+
```bash
|
|
559
|
+
bun run dist/cli/index.js export node <id> --output /tmp/check.png
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
### Always zoom after creating
|
|
563
|
+
|
|
564
|
+
```bash
|
|
565
|
+
bun run dist/cli/index.js viewport zoom-to-fit <id>
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
### Position multiple renders separately
|
|
569
|
+
|
|
570
|
+
```bash
|
|
571
|
+
echo '...' | bun run dist/cli/index.js render --stdin --x 0 --y 0
|
|
572
|
+
echo '...' | bun run dist/cli/index.js render --stdin --x 500 --y 0 # Not at same position!
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
### Copy between pages
|
|
576
|
+
|
|
577
|
+
```bash
|
|
578
|
+
bun run dist/cli/index.js node clone <id> [id2...] --json | jq -r '.[].id'
|
|
579
|
+
bun run dist/cli/index.js node set-parent <new-id> --parent <target-page-id>
|
|
580
|
+
bun run dist/cli/index.js node move <new-id> --x 50 --y 50
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
### Replace node
|
|
584
|
+
|
|
585
|
+
```bash
|
|
586
|
+
# Replace with component (creates instance)
|
|
587
|
+
bun run dist/cli/index.js node replace-with <id> --target <component-id>
|
|
588
|
+
|
|
589
|
+
# Replace with JSX from stdin
|
|
590
|
+
echo '<Icon name="lucide:x" size={16} />' | bun run dist/cli/index.js node replace-with <id> --stdin
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
### Convert to component
|
|
594
|
+
|
|
595
|
+
```bash
|
|
596
|
+
bun run dist/cli/index.js node to-component <id>
|
|
597
|
+
bun run dist/cli/index.js node to-component "1:2 1:3 1:4" # Multiple
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
### Instance internal IDs
|
|
601
|
+
|
|
602
|
+
```bash
|
|
603
|
+
bun run dist/cli/index.js set text "I123:456;789:10" "New text" # I<instance>;<internal>
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
### Row layout needs width
|
|
607
|
+
|
|
608
|
+
```bash
|
|
609
|
+
# ❌ Collapses to 1×1
|
|
610
|
+
<Frame flex="row" gap={8}>
|
|
611
|
+
|
|
612
|
+
# ✅ Explicit width
|
|
613
|
+
<Frame w={300} flex="row" gap={8}>
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
### Sections
|
|
617
|
+
|
|
618
|
+
```bash
|
|
619
|
+
bun run dist/cli/index.js create section --name "Buttons" --x 0 --y 0 --width 600 --height 200
|
|
620
|
+
bun run dist/cli/index.js node set-parent <id> --parent <section-id>
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
⚠️ Deleting section deletes all children!
|
|
624
|
+
|
|
625
|
+
### Comment-driven workflow
|
|
626
|
+
|
|
627
|
+
Wait for designer feedback and react:
|
|
628
|
+
|
|
629
|
+
```bash
|
|
630
|
+
bun run dist/cli/index.js comment watch --json
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
Output when comment arrives:
|
|
634
|
+
```json
|
|
635
|
+
{
|
|
636
|
+
"id": "123456",
|
|
637
|
+
"message": "Make this button bigger",
|
|
638
|
+
"user": { "handle": "designer" },
|
|
639
|
+
"client_meta": { "node_id": "1:23" }
|
|
640
|
+
}
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
Agent workflow — run once per comment, then restart:
|
|
644
|
+
|
|
645
|
+
1. `figma-use comment watch --json` — blocks until new comment
|
|
646
|
+
2. Parse the JSON, get `message` and `target_node` (exact element under comment)
|
|
647
|
+
3. Process the request (modify design, etc.)
|
|
648
|
+
4. Reply: `figma-use comment add "Done!" --reply <comment-id>`
|
|
649
|
+
5. Resolve: `figma-use comment resolve <comment-id>`
|
|
650
|
+
6. Exit. External runner restarts for next comment.
|
|
651
|
+
|
|
652
|
+
Options:
|
|
653
|
+
- `--timeout 60` — exit after 60s if no comment (returns `{"timeout":true}`)
|
|
654
|
+
- `--interval 5` — poll every 5s (default: 3s)
|
|
655
|
+
|
|
656
|
+
### Vector paths — iterative workflow
|
|
657
|
+
|
|
658
|
+
Draw, screenshot, adjust, repeat — like a designer tweaking Bezier curves:
|
|
659
|
+
|
|
660
|
+
```bash
|
|
661
|
+
# 1. Draw initial shape
|
|
662
|
+
bun run dist/cli/index.js create vector --path "M 50 0 L 100 100 L 0 100 Z" --fill "#F00"
|
|
663
|
+
|
|
664
|
+
# 2. Check result
|
|
665
|
+
bun run dist/cli/index.js export node <id> --output /tmp/shape.png
|
|
666
|
+
|
|
667
|
+
# 3. Adjust: scale, move, flip
|
|
668
|
+
bun run dist/cli/index.js path scale <id> --factor 0.8
|
|
669
|
+
bun run dist/cli/index.js path move <id> --dx 20 --dy -10
|
|
670
|
+
bun run dist/cli/index.js path flip <id> --axis x
|
|
671
|
+
|
|
672
|
+
# 4. Or replace path entirely
|
|
673
|
+
bun run dist/cli/index.js path set <id> "M 50 0 C 80 30 80 70 50 100 C 20 70 20 30 50 0 Z"
|
|
674
|
+
|
|
675
|
+
# 5. Screenshot again, repeat until good
|
|
676
|
+
bun run dist/cli/index.js export node <id> --output /tmp/shape.png
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
For complex illustrations, import SVG:
|
|
680
|
+
|
|
681
|
+
```bash
|
|
682
|
+
bun run dist/cli/index.js import --svg "$(cat icon.svg)"
|
|
683
|
+
```
|