@dannote/figma-use 0.6.2 → 0.7.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 CHANGED
@@ -5,7 +5,83 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [Unreleased]
8
+ ## [0.7.0] - 2026-01-19
9
+
10
+ ### Added
11
+
12
+ - **`page current`** — show current page name and ID
13
+ ```bash
14
+ figma-use page current # Page 1 (0:1)
15
+ figma-use page current --json # {"id": "0:1", "name": "Page 1"}
16
+ ```
17
+
18
+ - **`create icon`** — add icons from Iconify (150k+ icons from 100+ sets)
19
+ ```bash
20
+ figma-use create icon mdi:home
21
+ figma-use create icon lucide:star --size 48 --color "#FFD700"
22
+ figma-use create icon heroicons:bell-solid --component # as Figma component
23
+ ```
24
+ Supports: mdi, lucide, heroicons, tabler, fa-solid, fa-regular, ri, ph, carbon, fluent, ion, bi, and more.
25
+
26
+ - **Variable references in CLI color options** — use `var:Name` or `$Name` syntax:
27
+ ```bash
28
+ figma-use create rect --x 0 --y 0 --width 100 --height 100 --fill 'var:Colors/Primary'
29
+ figma-use create icon mdi:home --color '$Brand/Accent'
30
+ ```
31
+
32
+ - **`<Icon>` primitive for JSX render** — 150k+ Iconify icons:
33
+ ```jsx
34
+ <Frame style={{ flexDirection: "row", gap: 8 }}>
35
+ <Icon icon="mdi:home" size={24} color="#3B82F6" />
36
+ <Icon icon="lucide:star" size={32} color="#F59E0B" />
37
+ </Frame>
38
+ ```
39
+ Icons are auto-preloaded before render.
40
+
41
+ - **Tailwind-like style shorthands** for JSX render:
42
+ - Size: `w`, `h` → `width`, `height`
43
+ - Colors: `bg` → `backgroundColor`, `rounded` → `borderRadius`
44
+ - Padding: `p`, `pt`, `pr`, `pb`, `pl`, `px`, `py`
45
+ - Layout: `flex` (`"row"` | `"col"`), `justify`, `items`
46
+ - Text: `size`, `font`, `weight` → `fontSize`, `fontFamily`, `fontWeight`
47
+
48
+ ```jsx
49
+ // Before (178 chars)
50
+ <Frame style={{paddingLeft: 16, paddingRight: 16, backgroundColor: "#3B82F6", borderRadius: 6, flexDirection: "row"}}>
51
+
52
+ // After (73 chars)
53
+ <Frame style={{px: 16, bg: "#3B82F6", rounded: 6, flex: "row"}}>
54
+ ```
55
+
56
+ - **`render --x` and `--y` options** — position rendered root at specific coordinates
57
+
58
+ ### Changed
59
+
60
+ - README rewritten — focused on concepts, moved command list to REFERENCE.md
61
+ - Added REFERENCE.md with full list of 100+ commands
62
+ - CLI arguments now use kebab-case: `--stroke-weight`, `--font-size`, `--min-width`, etc.
63
+
64
+ ### Fixed
65
+
66
+ - Icon child ordering in render
67
+ - White fill removed from imported SVG icons
68
+ - Test isolation and multiplayer test reliability
69
+ - TypeScript types in .figma.tsx fixtures
70
+ - ComponentSet global registry to avoid module duplication
71
+
72
+ ## [0.6.3] - 2026-01-19
73
+
74
+ ### Added
75
+
76
+ - **`diff visual`** — create visual diff between two nodes as PNG
77
+ ```bash
78
+ figma-use diff visual --from <id1> --to <id2> --output diff.png
79
+ ```
80
+ Red pixels show differences. Options: `--scale`, `--threshold`
81
+
82
+ ### Changed
83
+
84
+ - `set rotation` now uses `--angle` flag instead of positional argument (fixes negative values like `--angle -15`)
9
85
 
10
86
  ## [0.6.2] - 2026-01-19
11
87
 
package/README.md CHANGED
@@ -1,16 +1,22 @@
1
1
  # figma-use
2
2
 
3
- **CLI for Figma.** LLMs already know React and work great with CLIs this combines both.
3
+ CLI for Figma. Control it from the terminal with commands or JSX.
4
4
 
5
5
  ```bash
6
- echo '<Frame style={{padding: 24, backgroundColor: "#3B82F6", borderRadius: 12}}>
7
- <Text style={{fontSize: 18, color: "#FFF"}}>Hello Figma</Text>
6
+ echo '<Frame style={{p: 24, bg: "#3B82F6", rounded: 12}}>
7
+ <Text style={{size: 18, color: "#FFF"}}>Hello Figma</Text>
8
8
  </Frame>' | figma-use render --stdin
9
9
  ```
10
10
 
11
- No JSON schemas, no MCP protocol overhead — just JSX that any LLM can write.
11
+ ## Why
12
12
 
13
- 📄 **Includes [SKILL.md](./SKILL.md)** drop-in reference for Claude Code and other AI agents.
13
+ Figma's official MCP plugin can read files but can't modify them. This one can.
14
+
15
+ LLMs know CLI. LLMs know React. This combines both.
16
+
17
+ CLI commands are compact — easy to read, easy to generate, easy to chain. When a task involves dozens of operations, every saved token matters. MCP and JSON-RPC work too, but they add overhead.
18
+
19
+ JSX is how LLMs already think about UI. They've seen millions of React components. Describing a Figma layout as `<Frame><Text>` is natural for them — no special training, no verbose schemas.
14
20
 
15
21
  ## Demo
16
22
 
@@ -31,163 +37,122 @@ No JSON schemas, no MCP protocol overhead — just JSX that any LLM can write.
31
37
  </tr>
32
38
  </table>
33
39
 
34
- ## Why CLI over MCP?
35
-
36
- MCP servers exchange verbose JSON. CLIs are **token-efficient**:
37
-
38
- ```bash
39
- # 47 tokens
40
- figma-use create frame --width 400 --height 300 --fill "#FFF" --radius 12 --layout VERTICAL --gap 16
41
- ```
42
-
43
- vs MCP JSON request + response: **~200 tokens** for the same operation.
44
-
45
- For AI agents doing dozens of Figma operations, this adds up fast. If you still prefer MCP, see [MCP Server](#mcp-server) section.
46
-
47
- ## Why JSX?
48
-
49
- Every LLM has been trained on millions of React components. They can write this without examples:
50
-
51
- ```tsx
52
- <Frame style={{ flexDirection: 'column', gap: 16, padding: 24 }}>
53
- <Text style={{ fontSize: 24, fontWeight: 'bold' }}>Title</Text>
54
- <Text style={{ fontSize: 14, color: '#666' }}>Description</Text>
55
- </Frame>
56
- ```
57
-
58
- The `render` command takes this JSX and creates real Figma nodes — frames, text, components, auto-layout, the works.
59
-
60
40
  ## Installation
61
41
 
62
42
  ```bash
63
- bun install -g @dannote/figma-use
43
+ npm install -g @dannote/figma-use
64
44
 
65
- figma-use plugin install # Install plugin (quit Figma first)
66
- figma-use proxy # Start proxy server
45
+ figma-use plugin install # Quit Figma first
46
+ figma-use proxy # Start proxy server
67
47
  ```
68
48
 
69
49
  Open Figma → Plugins → Development → **Figma Use**
70
50
 
71
- ## Render: JSX → Figma (Experimental)
51
+ ## Two Modes
72
52
 
73
- > ⚠️ Uses Figma's internal multiplayer protocol ~100x faster than plugin API, but may break if Figma changes it.
74
-
75
- ### Setup
53
+ Imperativeone command at a time:
76
54
 
77
55
  ```bash
78
- # Terminal 1: Start Figma with debug port
79
- figma --remote-debugging-port=9222
80
-
81
- # Terminal 2: Start proxy
82
- figma-use proxy
56
+ figma-use create frame --width 400 --height 300 --fill "#FFF" --radius 12 --layout VERTICAL --gap 16
83
57
  ```
84
58
 
85
- ### Basic Usage
59
+ Or declaratively — describe the structure in JSX and render it:
86
60
 
87
61
  ```bash
88
- # From stdin
89
- echo '<Frame style={{width: 200, height: 100, backgroundColor: "#FF0000"}} />' | figma-use render --stdin
62
+ echo '<Frame style={{p: 24, gap: 16, flex: "col", bg: "#FFF", rounded: 12}}>
63
+ <Text style={{size: 24, weight: "bold", color: "#000"}}>Card Title</Text>
64
+ <Text style={{size: 14, color: "#666"}}>Description</Text>
65
+ </Frame>' | figma-use render --stdin
66
+ ```
90
67
 
91
- # From file
92
- figma-use render ./Card.figma.tsx
68
+ The stdin mode accepts pure JSX only — no variables, no logic. For components, variants, and conditions, use `.figma.tsx` files.
93
69
 
94
- # With props
95
- figma-use render ./Card.figma.tsx --props '{"title": "Hello"}'
96
- ```
70
+ ## Examples
71
+
72
+ ### Icons
97
73
 
98
- ### Supported Elements
74
+ Insert any icon from Iconify by name. No downloading, no importing, no cleanup.
99
75
 
100
- `Frame`, `Rectangle`, `Ellipse`, `Text`, `Line`, `Star`, `Polygon`, `Vector`, `Group`
76
+ ```bash
77
+ figma-use create icon mdi:home
78
+ figma-use create icon lucide:star --size 48 --color "#F59E0B"
79
+ ```
101
80
 
102
- ### Style Properties
81
+ In JSX:
103
82
 
104
83
  ```tsx
105
- // Layout
106
- flexDirection: 'row' | 'column'
107
- justifyContent: 'flex-start' | 'center' | 'flex-end' | 'space-evenly'
108
- alignItems: 'flex-start' | 'center' | 'flex-end' | 'stretch'
109
- gap: number
110
- padding: number
111
- paddingTop / paddingRight / paddingBottom / paddingLeft: number
112
-
113
- // Size & Position
114
- width: number
115
- height: number
116
- x: number
117
- y: number
118
-
119
- // Appearance
120
- backgroundColor: string // hex color
121
- borderColor: string
122
- borderWidth: number
123
- borderRadius: number
124
- opacity: number
125
-
126
- // Text
127
- fontSize: number
128
- fontFamily: string
129
- fontWeight: 'normal' | 'bold' | '100'-'900'
130
- color: string
131
- textAlign: 'left' | 'center' | 'right'
84
+ <Frame style={{ flex: "row", gap: 8 }}>
85
+ <Icon icon="mdi:home" size={24} color="#3B82F6" />
86
+ <Icon icon="lucide:star" size={32} color="#F59E0B" />
87
+ </Frame>
132
88
  ```
133
89
 
134
- ### Reusable Components
90
+ Browse 150k+ icons: [icon-sets.iconify.design](https://icon-sets.iconify.design/)
91
+
92
+ ### Components
135
93
 
136
- `defineComponent` creates a Figma Component. First usage renders the master, subsequent usages create Instances:
94
+ In a `.figma.tsx` file you can define components. First call creates the master, the rest create instances:
137
95
 
138
96
  ```tsx
139
97
  import { defineComponent, Frame, Text } from '@dannote/figma-use/render'
140
98
 
141
- const Card = defineComponent('Card',
142
- <Frame style={{ padding: 24, backgroundColor: '#FFF', borderRadius: 12 }}>
143
- <Text style={{ fontSize: 18, color: '#000' }}>Card</Text>
99
+ const Card = defineComponent(
100
+ 'Card',
101
+ <Frame style={{ p: 24, bg: '#FFF', rounded: 12 }}>
102
+ <Text style={{ size: 18, color: '#000' }}>Card</Text>
144
103
  </Frame>
145
104
  )
146
105
 
147
106
  export default () => (
148
- <Frame style={{ gap: 16, flexDirection: 'row' }}>
149
- <Card /> {/* Creates Component */}
150
- <Card /> {/* Creates Instance */}
151
- <Card /> {/* Creates Instance */}
107
+ <Frame style={{ gap: 16, flex: 'row' }}>
108
+ <Card />
109
+ <Card />
110
+ <Card />
152
111
  </Frame>
153
112
  )
154
113
  ```
155
114
 
156
- ### Component Variants
115
+ ### Variants
157
116
 
158
- `defineComponentSet` creates a Figma ComponentSet with all variant combinations:
117
+ ComponentSet with all combinations:
159
118
 
160
119
  ```tsx
161
120
  import { defineComponentSet, Frame, Text } from '@dannote/figma-use/render'
162
121
 
163
- const Button = defineComponentSet('Button', {
164
- variant: ['Primary', 'Secondary'] as const,
165
- size: ['Small', 'Large'] as const,
166
- }, ({ variant, size }) => (
167
- <Frame style={{
168
- padding: size === 'Large' ? 16 : 8,
169
- backgroundColor: variant === 'Primary' ? '#3B82F6' : '#E5E7EB',
170
- borderRadius: 8,
171
- }}>
172
- <Text style={{ color: variant === 'Primary' ? '#FFF' : '#111' }}>
173
- {variant} {size}
174
- </Text>
175
- </Frame>
176
- ))
122
+ const Button = defineComponentSet(
123
+ 'Button',
124
+ {
125
+ variant: ['Primary', 'Secondary'] as const,
126
+ size: ['Small', 'Large'] as const,
127
+ },
128
+ ({ variant, size }) => (
129
+ <Frame
130
+ style={{
131
+ p: size === 'Large' ? 16 : 8,
132
+ bg: variant === 'Primary' ? '#3B82F6' : '#E5E7EB',
133
+ rounded: 8,
134
+ }}
135
+ >
136
+ <Text style={{ color: variant === 'Primary' ? '#FFF' : '#111' }}>
137
+ {variant} {size}
138
+ </Text>
139
+ </Frame>
140
+ )
141
+ )
177
142
 
178
143
  export default () => (
179
- <Frame style={{ gap: 16, flexDirection: 'column' }}>
144
+ <Frame style={{ gap: 16, flex: 'col' }}>
180
145
  <Button variant="Primary" size="Large" />
181
146
  <Button variant="Secondary" size="Small" />
182
147
  </Frame>
183
148
  )
184
149
  ```
185
150
 
186
- This creates 4 variant components (Primary/Small, Primary/Large, Secondary/Small, Secondary/Large) inside a ComponentSet, plus instances with the requested variants.
151
+ This creates a real ComponentSet in Figma with all 4 variants, not just 4 separate buttons.
187
152
 
188
- ### Variable Bindings
153
+ ### Variables as Tokens
189
154
 
190
- Bind colors to Figma variables by name:
155
+ Bind colors to Figma variables by name. The hex value is a fallback:
191
156
 
192
157
  ```tsx
193
158
  import { defineVars, Frame, Text } from '@dannote/figma-use/render'
@@ -198,142 +163,40 @@ const colors = defineVars({
198
163
  })
199
164
 
200
165
  export default () => (
201
- <Frame style={{ backgroundColor: colors.bg }}>
166
+ <Frame style={{ bg: colors.bg }}>
202
167
  <Text style={{ color: colors.text }}>Bound to variables</Text>
203
168
  </Frame>
204
169
  )
205
170
  ```
206
171
 
207
- The `value` is a fallback. At render time, colors get bound to actual Figma variables by name.
208
-
209
- ---
210
-
211
- ## CLI Commands
212
-
213
- The `render` command is the fastest way to create complex layouts. For simpler operations or modifications, use direct commands:
214
-
215
- ### Create
216
-
217
- ```bash
218
- figma-use create frame --width 400 --height 300 --fill "#FFF" --radius 12 --layout VERTICAL --gap 16
219
- figma-use create rect --width 100 --height 50 --fill "#FF0000" --radius 8
220
- figma-use create ellipse --width 80 --height 80 --fill "#00FF00"
221
- figma-use create text --text "Hello" --fontSize 24 --fill "#000"
222
- figma-use create line --length 100 --stroke "#000"
223
- figma-use create component --width 200 --height 100
224
- figma-use create instance --component <id>
225
- ```
226
-
227
- ### Modify
228
-
229
- ```bash
230
- figma-use set fill <id> "#FF0000"
231
- figma-use set stroke <id> "#000" --weight 2
232
- figma-use set radius <id> 12
233
- figma-use set opacity <id> 0.5
234
- figma-use set text <id> "New text"
235
- figma-use set font <id> --family "Inter" --style "Bold" --size 20
236
- figma-use set layout <id> --mode VERTICAL --gap 12 --padding 16
237
- figma-use set effect <id> --type DROP_SHADOW --radius 10 --color "#00000040"
238
- ```
239
-
240
- ### Query
241
-
242
- ```bash
243
- figma-use node get <id> # Get node properties
244
- figma-use node tree # Page structure as readable tree
245
- figma-use node children <id> # List children
246
- figma-use node bounds <id> # Position, size, center point
247
- figma-use find --name "Button" # Find by name
248
- figma-use find --type FRAME # Find by type
249
- figma-use selection get # Current selection
250
- ```
251
-
252
- ### Vector Paths
253
-
254
- ```bash
255
- figma-use create vector --x 0 --y 0 --path "M 0 0 L 100 50 L 0 100 Z" --fill "#F00"
256
- figma-use path get <id> # Read path data
257
- figma-use path set <id> "M 0 0 ..." # Replace path
258
- figma-use path move <id> --dx 10 --dy -5 # Translate points
259
- figma-use path scale <id> --factor 1.5 # Scale from center
260
- figma-use path flip <id> --axis x # Mirror horizontally
261
- ```
262
-
263
- ### Export
172
+ In CLI, use `var:Colors/Primary` or `$Colors/Primary` in any color option.
264
173
 
265
- ```bash
266
- figma-use export node <id> --output design.png
267
- figma-use export screenshot --output viewport.png
268
- figma-use export selection --output selection.png
269
- ```
174
+ ### Diffs
270
175
 
271
- ### Navigate
176
+ Compare two frames and get a patch:
272
177
 
273
178
  ```bash
274
- figma-use page list
275
- figma-use page set "Page Name"
276
- figma-use viewport zoom-to-fit <ids...>
277
- ```
278
-
279
- ### Variables & Styles
280
-
281
- ```bash
282
- figma-use variable list
283
- figma-use variable create "Primary" --collection <id> --type COLOR --value "#3B82F6"
284
- figma-use style list
285
- figma-use style create-paint "Brand/Primary" --color "#E11D48"
286
- ```
287
-
288
- ### Fonts
289
-
290
- ```bash
291
- figma-use font list # All available fonts
292
- figma-use font list --family Roboto # Filter by family name
293
- ```
294
-
295
- ### Comments & History
296
-
297
- ```bash
298
- figma-use comment list # List file comments
299
- figma-use comment add "Review this" # Add comment
300
- figma-use comment add "Here" --x 200 --y 100 # Comment at position
301
- figma-use comment delete <id> # Delete comment
302
- figma-use version list # Version history
303
- figma-use me # Current user info
304
- figma-use file info # File key and name
305
- ```
306
-
307
- ### Diff (Experimental)
308
-
309
- Compare two frames and generate a unified diff patch:
310
-
311
- ```bash
312
- # Compare original vs modified version
313
179
  figma-use diff create --from 123:456 --to 789:012
314
180
  ```
315
181
 
316
- Apply patch with validation (fails if current state doesn't match expected):
317
-
318
- ```bash
319
- figma-use diff apply patch.diff # Apply from file
320
- figma-use diff apply --stdin < patch.diff # Apply from stdin
321
- figma-use diff apply patch.diff --dry-run # Preview changes
322
- figma-use diff apply patch.diff --force # Skip validation
182
+ ```diff
183
+ --- /Card/Header #123:457
184
+ +++ /Card/Header #789:013
185
+ @@ -1,5 +1,5 @@
186
+ type: FRAME
187
+ size: 200 50
188
+ pos: 0 0
189
+ -fill: #FFFFFF
190
+ +fill: #F0F0F0
191
+ -opacity: 0.8
192
+ +opacity: 1
323
193
  ```
324
194
 
325
- ### Escape Hatch
195
+ Apply the patch to the original frame. On apply, current state is validated against expected — if they don't match, it fails. There's also visual diff: overlay two PNGs and highlight differences.
326
196
 
327
- ```bash
328
- figma-use eval "return figma.currentPage.name"
329
- figma-use eval "figma.createRectangle().resize(100, 100)"
330
- ```
331
-
332
- ---
333
-
334
- ## Output
197
+ ### Inspection
335
198
 
336
- Human-readable by default:
199
+ Page tree in readable form:
337
200
 
338
201
  ```
339
202
  $ figma-use node tree
@@ -343,46 +206,46 @@ $ figma-use node tree
343
206
  "Hello World" | 24px Inter Bold
344
207
  ```
345
208
 
346
- Add `--json` for machine parsing:
209
+ Export any node or screenshot with one command.
210
+
211
+ ### Vectors
212
+
213
+ Import SVG or work with paths directly — read, modify, translate, scale, flip:
347
214
 
348
215
  ```bash
349
- figma-use node get <id> --json
216
+ figma-use path get <id>
217
+ figma-use path set <id> "M 0 0 L 100 100 Z"
218
+ figma-use path scale <id> --factor 1.5
219
+ figma-use path flip <id> --axis x
350
220
  ```
351
221
 
352
- ## For AI Agents
222
+ ## Render via Multiplayer Protocol
353
223
 
354
- **Includes ready-to-use [SKILL.md](./SKILL.md)** a comprehensive reference that teaches AI agents all commands and patterns. Works with Claude Code, Cursor, and any agent that supports skill files.
224
+ The `render` command uses Figma's internal multiplayer protocol, not just Plugin API. It's faster, but the protocol is internal and may change. Good for generation and prototyping.
355
225
 
356
- ```bash
357
- # Claude Code / pi
358
- mkdir -p ~/.claude/skills/figma-use
359
- cp node_modules/@dannote/figma-use/SKILL.md ~/.claude/skills/figma-use/
226
+ ## Full Command Reference
360
227
 
361
- # Or download directly
362
- curl -o ~/.claude/skills/figma-use/SKILL.md \
363
- https://raw.githubusercontent.com/anthropics/figma-use/main/SKILL.md
364
- ```
228
+ See [REFERENCE.md](./REFERENCE.md) for the complete list of 100+ commands.
365
229
 
366
- For simpler setups, add to your project's `AGENTS.md`:
230
+ ## For AI Agents
367
231
 
368
- ```markdown
369
- ## Figma
232
+ Includes [SKILL.md](./SKILL.md) — a reference for Claude Code, Cursor, and other agents.
370
233
 
371
- Use `figma-use` CLI. For complex layouts, use `figma-use render --stdin` with JSX.
372
- Run `figma-use --help` for all commands.
234
+ ```bash
235
+ mkdir -p ~/.claude/skills/figma-use
236
+ curl -o ~/.claude/skills/figma-use/SKILL.md \
237
+ https://raw.githubusercontent.com/dannote/figma-use/master/SKILL.md
373
238
  ```
374
239
 
375
240
  ## MCP Server
376
241
 
377
- If your client only supports MCP, the proxy exposes an endpoint at `http://localhost:38451/mcp` with 80+ auto-generated tools. Run `figma-use mcp` for config snippet.
378
-
379
- ---
242
+ The proxy exposes an MCP endpoint at `http://localhost:38451/mcp`. Run `figma-use mcp` for config.
380
243
 
381
244
  ## How It Works
382
245
 
383
246
  ```
384
247
  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
385
- AI Agent │────▶│ figma-use │────▶│ Plugin │
248
+ Terminal │────▶│ figma-use │────▶│ Plugin │
386
249
  │ │ CLI │ proxy │ WS │ │
387
250
  └─────────────┘ └──────┬──────┘ └─────────────┘
388
251
 
@@ -390,14 +253,9 @@ If your client only supports MCP, the proxy exposes an endpoint at `http://local
390
253
 
391
254
  ┌─────────────┐
392
255
  │ Figma │
393
- │ Server │
394
256
  └─────────────┘
395
257
  ```
396
258
 
397
- - **CLI commands** → Plugin API (full Figma access)
398
- - **MCP endpoint** → Same as CLI, JSON-RPC protocol
399
- - **render command** → Multiplayer protocol (~100x faster, experimental)
400
-
401
259
  ## License
402
260
 
403
261
  MIT