@dannote/figma-use 0.2.0 → 0.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/CHANGELOG.md CHANGED
@@ -7,6 +7,61 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.3.0] - 2025-01-17
11
+
12
+ ### Added
13
+
14
+ - **`render` command** — render React/TSX components directly to Figma
15
+ - From file: `figma-use render ./Card.figma.tsx`
16
+ - From stdin: `echo '<Frame style={{...}} />' | figma-use render --stdin`
17
+ - With props: `--props '{"title": "Hello"}'`
18
+ - Into parent: `--parent "1:23"`
19
+ - Dry run: `--dryRun` outputs NodeChanges JSON
20
+ - **Multiplayer WebSocket connection pooling** in proxy
21
+ - First render: ~4s (establishes connection)
22
+ - Subsequent renders: ~0.4s (10x faster!)
23
+ - Connections auto-close after 5min idle
24
+ - **React components** — `Frame`, `Text`, `Rectangle`, `Ellipse`, `Line`, `Star`, `Polygon`, `Vector`, `Component`, `Instance`, `Group`, `Page`, `View`
25
+ - **JSX intrinsic elements** — PascalCase in JSX, lowercase in output
26
+ - **culori integration** — robust color parsing (hex, rgb(), hsl(), named colors)
27
+ - `/render` endpoint in proxy for direct NodeChanges submission
28
+ - `/status` endpoint now shows multiplayer connection pool
29
+
30
+ ### Changed
31
+
32
+ - Proxy now holds persistent WebSocket connections to Figma multiplayer
33
+ - Architecture diagram updated to show dual communication paths
34
+ - 143 tests passing
35
+
36
+ ### Fixed
37
+
38
+ - TypeScript strict mode errors in tests
39
+ - NodeChanges validation before sending (must have guid)
40
+
41
+ ## [0.2.1] - 2025-01-17
42
+
43
+ ### Added
44
+
45
+ - **`profile` command** — performance profiling via Chrome DevTools Protocol
46
+ - Profile any command: `figma-use profile "get components --limit 20"`
47
+ - Shows time breakdown (Figma WASM vs JS vs GC)
48
+ - Lists top functions by CPU time
49
+ - Requires Figma with `--remote-debugging-port=9222`
50
+ - `get components --name` — filter components by name
51
+ - `get components --limit` — limit results (default 50)
52
+ - `get components --page` — filter by page
53
+ - `find --type` now works without `--name`
54
+
55
+ ### Changed
56
+
57
+ - `get components` uses early-exit recursion for better performance on large files
58
+ - `node tree --depth` now affects node count check (won't block with high depth limit)
59
+
60
+ ### Fixed
61
+
62
+ - Variant components no longer crash when accessing `componentPropertyDefinitions`
63
+ - 86 tests passing
64
+
10
65
  ## [0.2.0] - 2025-01-17
11
66
 
12
67
  ### Added
@@ -113,7 +168,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
113
168
  - Export commands: PNG/SVG/PDF export, screenshot
114
169
  - Inline styling: `--fill`, `--stroke`, `--radius` etc. on create commands
115
170
 
116
- [unreleased]: https://github.com/dannote/figma-use/compare/v0.2.0...HEAD
171
+ [unreleased]: https://github.com/dannote/figma-use/compare/v0.3.0...HEAD
172
+ [0.3.0]: https://github.com/dannote/figma-use/compare/v0.2.1...v0.3.0
173
+ [0.2.1]: https://github.com/dannote/figma-use/compare/v0.2.0...v0.2.1
117
174
  [0.2.0]: https://github.com/dannote/figma-use/compare/v0.1.5...v0.2.0
118
175
  [0.1.5]: https://github.com/dannote/figma-use/compare/v0.1.4...v0.1.5
119
176
  [0.1.4]: https://github.com/dannote/figma-use/compare/v0.1.3...v0.1.4
package/README.md CHANGED
@@ -27,16 +27,28 @@ figma-use gives AI agents **full read/write control** over Figma.
27
27
  ## How it works
28
28
 
29
29
  ```
30
- ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
31
- │ │ │ │ │ │
32
- │ AI Agent / │────▶│ figma-use │────▶│ Figma │
33
- │ CLI │ HTTP│ proxy │ WS │ Plugin │
34
- │◀────│ :38451 │◀────│
35
- │ │ │ │ │ │
36
- └─────────────────┘ └─────────────────┘ └─────────────────┘
30
+ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
31
+ │ │ │ │ │ │
32
+ │ AI Agent / │─────▶│ figma-use │─────▶│ Figma │
33
+ │ CLI │ HTTP │ proxy │ WS │ Plugin │
34
+ │◀─────│ :38451 │◀─────│
35
+ │ │ │ │ │ │
36
+ └─────────────────┘ └────────┬────────┘ └─────────────────┘
37
+
38
+ │ WebSocket (persistent)
39
+
40
+ ┌─────────────────┐
41
+ │ Figma │
42
+ │ Multiplayer │
43
+ │ Server │
44
+ └─────────────────┘
37
45
  ```
38
46
 
39
- The CLI sends commands to a local proxy server, which forwards them via WebSocket to a Figma plugin. The plugin executes commands using the Figma API and returns results.
47
+ Two communication paths:
48
+ - **Plugin API** — most commands go through the Figma plugin for full API access
49
+ - **Multiplayer WebSocket** — the `render` command writes directly to Figma's multiplayer server for ~100x faster node creation
50
+
51
+ The proxy maintains persistent connections for fast repeated operations.
40
52
 
41
53
  ## Installation
42
54
 
@@ -93,8 +105,9 @@ All create commands support inline styling — no need for separate `set` calls.
93
105
  ```bash
94
106
  figma-use node get <id> # Get node properties
95
107
  figma-use node tree [id] # Get formatted tree (default: current page)
96
- figma-use node tree --depth 2 # Limit tree depth
108
+ figma-use node tree --depth 2 # Limit tree depth (also limits node count check)
97
109
  figma-use node tree -i # Only interactive elements
110
+ figma-use node tree --force # Skip 500 node limit
98
111
  figma-use node children <id> # Get child nodes
99
112
  figma-use node delete <id> # Delete node
100
113
  figma-use node clone <id> # Clone node
@@ -225,8 +238,10 @@ figma-use viewport zoom-to-fit <ids...>
225
238
  ```bash
226
239
  figma-use find --name "Button"
227
240
  figma-use find --name "Icon" --type FRAME
241
+ figma-use find --type INSTANCE --limit 50 # Limit results (default: 100)
228
242
  figma-use get pages
229
- figma-use get components
243
+ figma-use get components --name "Button" # Filter by name
244
+ figma-use get components --limit 50 # Limit results (default: 50)
230
245
  figma-use get styles
231
246
  ```
232
247
 
@@ -243,6 +258,80 @@ figma-use group ungroup <id>
243
258
  figma-use group flatten "1:2,1:3"
244
259
  ```
245
260
 
261
+ ### Render React Components
262
+
263
+ Render TSX/JSX components directly to Figma via WebSocket (bypasses plugin API for ~100x speed):
264
+
265
+ ```bash
266
+ # From file
267
+ figma-use render ./Card.figma.tsx
268
+
269
+ # With props
270
+ figma-use render ./Card.figma.tsx --props '{"title": "Hello", "items": ["A", "B"]}'
271
+
272
+ # JSX snippet from stdin
273
+ echo '<Frame style={{width: 200, height: 100, backgroundColor: "#FF0000"}} />' | figma-use render --stdin
274
+
275
+ # Nested elements
276
+ echo '<Frame style={{padding: 20, gap: 10}}>
277
+ <Text style={{fontSize: 24}}>Title</Text>
278
+ <Rectangle style={{width: 100, height: 50, backgroundColor: "#3B82F6"}} />
279
+ </Frame>' | figma-use render --stdin
280
+
281
+ # Full component from stdin (with imports/exports)
282
+ cat component.tsx | figma-use render --stdin
283
+
284
+ # Into specific parent
285
+ figma-use render ./Card.figma.tsx --parent "1:23"
286
+
287
+ # Dry run (output NodeChanges JSON without sending)
288
+ figma-use render ./Card.figma.tsx --dryRun
289
+ ```
290
+
291
+ **Important:** The `render` command requires:
292
+ 1. Figma running with remote debugging: `figma --remote-debugging-port=9222`
293
+ 2. Proxy server running: `figma-use proxy`
294
+
295
+ The proxy maintains persistent WebSocket connections for fast repeated renders:
296
+ - First render: ~4s (establishes connection)
297
+ - Subsequent renders: ~0.4s (reuses connection)
298
+
299
+ Example component (`Card.figma.tsx`):
300
+
301
+ ```tsx
302
+ import * as React from 'react'
303
+ import { Frame, Text, Rectangle } from '@dannote/figma-use/components'
304
+
305
+ interface CardProps {
306
+ title: string
307
+ items: string[]
308
+ }
309
+
310
+ export default function Card({ title, items }: CardProps) {
311
+ return (
312
+ <Frame name="Card" style={{
313
+ width: 300,
314
+ flexDirection: 'column',
315
+ padding: 24,
316
+ gap: 16,
317
+ backgroundColor: '#FFFFFF',
318
+ borderRadius: 12,
319
+ }}>
320
+ <Text name="Title" style={{ fontSize: 24, fontWeight: 'bold', color: '#000' }}>
321
+ {title}
322
+ </Text>
323
+ <Frame name="Items" style={{ flexDirection: 'column', gap: 8 }}>
324
+ {items.map((item, i) => (
325
+ <Text key={i} style={{ fontSize: 16, color: '#666' }}>{item}</Text>
326
+ ))}
327
+ </Frame>
328
+ </Frame>
329
+ )
330
+ }
331
+ ```
332
+
333
+ Available elements: `Frame`, `Rectangle`, `Ellipse`, `Text`, `Line`, `Star`, `Polygon`, `Vector`, `Component`, `Instance`, `Group`, `Page`, `View`
334
+
246
335
  ### Advanced
247
336
 
248
337
  ```bash
@@ -255,6 +344,22 @@ figma-use eval "await figma.loadFontAsync({family: 'Inter', style: 'Bold'})"
255
344
  figma-use import --svg "<svg>...</svg>" --x 0 --y 0
256
345
  ```
257
346
 
347
+ ### Performance Profiling
348
+
349
+ Profile any command using Chrome DevTools Protocol:
350
+
351
+ ```bash
352
+ # Start Figma with debug port
353
+ /Applications/Figma.app/Contents/MacOS/Figma --remote-debugging-port=9222
354
+
355
+ # Profile a command
356
+ figma-use profile "get components --limit 20"
357
+ figma-use profile "node tree --depth 2"
358
+ figma-use profile "find --type INSTANCE"
359
+ ```
360
+
361
+ Output shows time breakdown (Figma WASM vs JS vs GC) and top functions by CPU time.
362
+
258
363
  ## Output Format
259
364
 
260
365
  Human-readable by default:
package/SKILL.md CHANGED
@@ -52,8 +52,9 @@ figma-use create text --x 0 --y 0 --text "Hello" \
52
52
  ```bash
53
53
  figma-use node get <id> # Get properties
54
54
  figma-use node tree [id] # Get formatted tree (see structure at a glance)
55
- figma-use node tree --depth 2 # Limit tree depth
55
+ figma-use node tree --depth 2 # Limit tree depth (also limits node count)
56
56
  figma-use node tree -i # Only interactive elements
57
+ figma-use node tree --force # Skip 500 node limit
57
58
  figma-use node children <id> # List children
58
59
  figma-use node move <id> --x 100 --y 200
59
60
  figma-use node resize <id> --width 300 --height 200
@@ -133,7 +134,9 @@ figma-use viewport zoom-to-fit <ids...>
133
134
  ```bash
134
135
  figma-use find --name "Button"
135
136
  figma-use find --type FRAME
136
- figma-use get components
137
+ figma-use find --type INSTANCE # All instances on page
138
+ figma-use get components --name "Button" # Filter components by name
139
+ figma-use get components --limit 50 # Limit results
137
140
  ```
138
141
 
139
142
  ### Boolean & Group
@@ -145,6 +148,36 @@ figma-use group create "1:2,1:3"
145
148
  figma-use group ungroup <id>
146
149
  ```
147
150
 
151
+ ### Render React Components
152
+
153
+ Render TSX/JSX directly to Figma (~100x faster than plugin API):
154
+
155
+ ```bash
156
+ # From file
157
+ figma-use render ./Card.figma.tsx
158
+
159
+ # JSX snippet from stdin
160
+ echo '<Frame style={{width: 200, height: 100, backgroundColor: "#FF0000"}} />' | figma-use render --stdin
161
+
162
+ # Nested elements
163
+ echo '<Frame style={{padding: 20, gap: 10, flexDirection: "column"}}>
164
+ <Text style={{fontSize: 24, color: "#000"}}>Title</Text>
165
+ <Rectangle style={{width: 100, height: 50, backgroundColor: "#3B82F6"}} />
166
+ </Frame>' | figma-use render --stdin
167
+
168
+ # With props
169
+ figma-use render ./Card.figma.tsx --props '{"title": "Hello"}'
170
+
171
+ # Into specific parent
172
+ figma-use render ./Card.figma.tsx --parent "1:23"
173
+ ```
174
+
175
+ **Requires:**
176
+ 1. Figma with `figma --remote-debugging-port=9222`
177
+ 2. Proxy running: `figma-use proxy`
178
+
179
+ Available elements: `Frame`, `Rectangle`, `Ellipse`, `Text`, `Line`, `Star`, `Polygon`, `Vector`, `Component`, `Instance`, `Group`
180
+
148
181
  ### Eval (Arbitrary Code)
149
182
 
150
183
  ```bash
@@ -0,0 +1,3 @@
1
+ import * as React from 'react'
2
+ const Frame: React.FC<any> = ({ children, ...props }) => React.createElement('frame', props, children)
3
+ export default () => (<Frame style={{width: 200, height: 100, backgroundColor: "#FF0000"}} />)
@@ -0,0 +1,3 @@
1
+ import * as React from 'react'
2
+ const Frame: React.FC<any> = ({ children, ...props }) => React.createElement('frame', props, children)
3
+ export default () => (<Frame style={{width: 200, height: 100, backgroundColor: "#FF0000"}} />)