@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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Danila Poyarkov
4
+ Copyright (c) 2026 nnao45
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,569 @@
1
+ # figma-use
2
+
3
+ CLI for Figma. Control it from the terminal — with commands or JSX.
4
+
5
+ ```bash
6
+ # Create and style
7
+ figma-use create frame --width 400 --height 300 --fill "#FFF" --layout VERTICAL --gap 16
8
+ figma-use create icon mdi:home --size 32 --color "#3B82F6"
9
+ figma-use set layout 1:23 --mode GRID --cols "1fr 1fr 1fr" --gap 16
10
+
11
+ # Or render JSX
12
+ echo '<Frame style={{display: "grid", cols: "1fr 1fr", gap: 16}}>
13
+ <Frame style={{bg: "#3B82F6", h: 100}} />
14
+ <Frame style={{bg: "#10B981", h: 100}} />
15
+ </Frame>' | figma-use render --stdin --x 100 --y 100
16
+ ```
17
+
18
+ ## Why
19
+
20
+ Figma's official MCP plugin can read files but can't modify them. This one can.
21
+
22
+ LLMs know CLI. LLMs know React. This combines both.
23
+
24
+ CLI commands are compact — easy to read, easy to generate, easy to chain. When a task involves dozens of operations, every saved token matters.
25
+
26
+ 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.
27
+
28
+ ## Demo
29
+
30
+ <table>
31
+ <tr>
32
+ <td width="50%">
33
+ <a href="https://youtu.be/9eSYVZRle7o">
34
+ <img src="https://img.youtube.com/vi/9eSYVZRle7o/maxresdefault.jpg" alt="Button components demo" width="100%">
35
+ </a>
36
+ <p align="center"><b>▶️ Button components</b></p>
37
+ </td>
38
+ <td width="50%">
39
+ <a href="https://youtu.be/efJWp2Drzb4">
40
+ <img src="https://img.youtube.com/vi/efJWp2Drzb4/maxresdefault.jpg" alt="Calendar demo" width="100%">
41
+ </a>
42
+ <p align="center"><b>▶️ Tailwind UI calendar</b></p>
43
+ </td>
44
+ </tr>
45
+ </table>
46
+
47
+ ## Installation
48
+
49
+ ```bash
50
+ npm install -g figma-use
51
+ ```
52
+
53
+ Or run directly without installing:
54
+
55
+ ```bash
56
+ npx figma-use status
57
+ ```
58
+
59
+ Start Figma with remote debugging enabled:
60
+
61
+ ```bash
62
+ # macOS
63
+ open -a Figma --args --remote-debugging-port=9222
64
+
65
+ # Windows
66
+ "C:\Users\%USERNAME%\AppData\Local\Figma\Figma.exe" --remote-debugging-port=9222
67
+
68
+ # Linux
69
+ figma --remote-debugging-port=9222
70
+ ```
71
+
72
+ Check connection:
73
+
74
+ ```bash
75
+ figma-use status
76
+ ```
77
+
78
+ That's it. No plugins to install.
79
+
80
+ ### WSL2 + Windows Figma Desktop
81
+
82
+ On WSL2, the Linux version of Figma (`figma-linux`) has known font issues — `listAvailableFontsAsync()` returns 0 fonts due to an unhandled `getModifiedFonts` message in recent versions. A reliable workaround is to connect from WSL2 to the Windows Figma desktop app instead.
83
+
84
+ **1. Start Figma on Windows with remote debugging**
85
+
86
+ ```powershell
87
+ "C:\Users\%USERNAME%\AppData\Local\Figma\Figma.exe" --remote-debugging-port=9222
88
+ ```
89
+
90
+ **2. Set up port forwarding on Windows (Admin PowerShell)**
91
+
92
+ Figma binds to `127.0.0.1:9222`, which isn't directly reachable from WSL2. Forward it:
93
+
94
+ ```powershell
95
+ netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=9222 connectaddress=127.0.0.1 connectport=9222
96
+ netsh advfirewall firewall add rule name="Figma CDP" dir=in action=allow protocol=TCP localport=9222
97
+ ```
98
+
99
+ **3. Forward localhost:9222 inside WSL2 to the Windows host**
100
+
101
+ figma-use connects to `localhost:9222`, so forward it to the Windows host IP:
102
+
103
+ ```bash
104
+ # Find your Windows host IP
105
+ ip route show default | awk '{print $3}'
106
+ # e.g. 192.168.64.1
107
+
108
+ # Forward with a one-liner Node.js TCP proxy
109
+ node -e "
110
+ const net = require('net');
111
+ const server = net.createServer(c => {
112
+ const r = net.connect(9222, '$(ip route show default | awk \'{print $3}\')', () => { c.pipe(r); r.pipe(c); });
113
+ r.on('error', () => c.destroy());
114
+ c.on('error', () => r.destroy());
115
+ });
116
+ server.listen(9222, '127.0.0.1', () => console.log('forwarding to Windows Figma'));
117
+ " &
118
+ ```
119
+
120
+ **4. Verify**
121
+
122
+ ```bash
123
+ figma-use status
124
+ # ✓ Connected to Figma
125
+ ```
126
+
127
+ All 8000+ Windows fonts are now available — no font helper issues.
128
+
129
+ ## Two Modes
130
+
131
+ Imperative — one command at a time:
132
+
133
+ ```bash
134
+ figma-use create frame --width 400 --height 300 --fill "#FFF" --radius 12 --layout VERTICAL --gap 16
135
+ ```
136
+
137
+ Or declaratively — describe the structure in JSX and render it:
138
+
139
+ ```bash
140
+ echo '<Frame style={{p: 24, gap: 16, flex: "col", bg: "#FFF", rounded: 12}}>
141
+ <Text style={{size: 24, weight: "bold", color: "#000"}}>Card Title</Text>
142
+ <Text style={{size: 14, color: "#666"}}>Description</Text>
143
+ </Frame>' | figma-use render --stdin --x 100 --y 200
144
+ ```
145
+
146
+ The stdin mode accepts pure JSX only — no variables, no logic. For components, variants, and conditions, use `.figma.tsx` files.
147
+
148
+ **Elements:** `Frame`, `Rectangle`, `Ellipse`, `Text`, `Line`, `Star`, `Polygon`, `Vector`, `Group`, `Icon`, `Image`
149
+
150
+ ## Examples
151
+
152
+ ### Icons
153
+
154
+ Insert any icon from Iconify by name. No downloading, no importing, no cleanup.
155
+
156
+ ```bash
157
+ figma-use create icon mdi:home
158
+ figma-use create icon lucide:star --size 48 --color "#F59E0B"
159
+ ```
160
+
161
+ In JSX:
162
+
163
+ ```tsx
164
+ <Frame style={{ flex: 'row', gap: 8 }}>
165
+ <Icon icon="mdi:home" size={24} color="#3B82F6" />
166
+ <Icon icon="lucide:star" size={32} color="#F59E0B" />
167
+ </Frame>
168
+ ```
169
+
170
+ Browse 150k+ icons: [icon-sets.iconify.design](https://icon-sets.iconify.design/)
171
+
172
+ ### Images
173
+
174
+ Load images from URL:
175
+
176
+ ```tsx
177
+ <Image src="https://example.com/photo.jpg" w={200} h={150} />
178
+ ```
179
+
180
+ ### Export to JSX
181
+
182
+ Convert any Figma node back to JSX:
183
+
184
+ ```bash
185
+ figma-use export jsx 123:456 --pretty
186
+ ```
187
+
188
+ Output:
189
+
190
+ ```tsx
191
+ import { Frame, Icon, Text } from 'figma-use/render'
192
+ export default function SaveButton() {
193
+ return (
194
+ <Frame name="SaveButton" w={120} h={44} bg="#1FAFBB" rounded={8} flex="row" gap={8}>
195
+ <Icon name="lucide:save" size={18} color="#FFFFFF" />
196
+ <Text size={16} color="#FFFFFF">
197
+ Save
198
+ </Text>
199
+ </Frame>
200
+ )
201
+ }
202
+ ```
203
+
204
+ Match vector shapes to Iconify icons automatically:
205
+
206
+ ```bash
207
+ npm install whaticon # Optional dependency
208
+ figma-use export jsx 123:456 --match-icons --prefer-icons lucide
209
+ ```
210
+
211
+ Compare two nodes as JSX diff:
212
+
213
+ ```bash
214
+ figma-use diff jsx 123:456 789:012
215
+ ```
216
+
217
+ ### Export to Storybook (Experimental)
218
+
219
+ Export components as Storybook stories:
220
+
221
+ ```bash
222
+ figma-use export storybook --out ./stories
223
+ figma-use export storybook --out ./stories --match-icons --prefer-icons lucide
224
+ ```
225
+
226
+ Generates `.stories.tsx` with typed props from component properties.
227
+
228
+ ### Components
229
+
230
+ In a `.figma.tsx` file you can define components. First call creates the master, the rest create instances:
231
+
232
+ ```tsx
233
+ import { defineComponent, Frame, Text } from 'figma-use/render'
234
+
235
+ const Card = defineComponent(
236
+ 'Card',
237
+ <Frame style={{ p: 24, bg: '#FFF', rounded: 12 }}>
238
+ <Text style={{ size: 18, color: '#000' }}>Card</Text>
239
+ </Frame>
240
+ )
241
+
242
+ export default () => (
243
+ <Frame style={{ gap: 16, flex: 'row' }}>
244
+ <Card />
245
+ <Card />
246
+ <Card />
247
+ </Frame>
248
+ )
249
+ ```
250
+
251
+ ### Variants
252
+
253
+ ComponentSet with all combinations:
254
+
255
+ ```tsx
256
+ import { defineComponentSet, Frame, Text } from 'figma-use/render'
257
+
258
+ const Button = defineComponentSet(
259
+ 'Button',
260
+ {
261
+ variant: ['Primary', 'Secondary'] as const,
262
+ size: ['Small', 'Large'] as const
263
+ },
264
+ ({ variant, size }) => (
265
+ <Frame
266
+ style={{
267
+ p: size === 'Large' ? 16 : 8,
268
+ bg: variant === 'Primary' ? '#3B82F6' : '#E5E7EB',
269
+ rounded: 8
270
+ }}
271
+ >
272
+ <Text style={{ color: variant === 'Primary' ? '#FFF' : '#111' }}>
273
+ {variant} {size}
274
+ </Text>
275
+ </Frame>
276
+ )
277
+ )
278
+
279
+ export default () => (
280
+ <Frame style={{ gap: 16, flex: 'col' }}>
281
+ <Button variant="Primary" size="Large" />
282
+ <Button variant="Secondary" size="Small" />
283
+ </Frame>
284
+ )
285
+ ```
286
+
287
+ This creates a real ComponentSet in Figma with all 4 variants, not just 4 separate buttons.
288
+
289
+ ### Grid Layout
290
+
291
+ CSS Grid for 2D layouts — calendars, dashboards, galleries:
292
+
293
+ ```tsx
294
+ <Frame
295
+ style={{
296
+ display: 'grid',
297
+ cols: '1fr 1fr 1fr', // 3 equal columns
298
+ rows: 'auto auto', // 2 rows
299
+ gap: 16
300
+ }}
301
+ >
302
+ <Frame style={{ bg: '#FF6B6B' }} />
303
+ <Frame style={{ bg: '#4ECDC4' }} />
304
+ <Frame style={{ bg: '#45B7D1' }} />
305
+ <Frame style={{ bg: '#96CEB4' }} />
306
+ <Frame style={{ bg: '#FFEAA7' }} />
307
+ <Frame style={{ bg: '#DDA0DD' }} />
308
+ </Frame>
309
+ ```
310
+
311
+ Supports `px`, `fr`, and `auto`/`hug`. Separate gaps with `colGap` and `rowGap`.
312
+
313
+ In CLI:
314
+
315
+ ```bash
316
+ figma-use set layout <id> --mode GRID --cols "100px 1fr 100px" --rows "auto" --gap 16
317
+ ```
318
+
319
+ ### Variables as Tokens
320
+
321
+ Bind colors to Figma variables by name. The hex value is a fallback:
322
+
323
+ ```tsx
324
+ import { defineVars, Frame, Text } from 'figma-use/render'
325
+
326
+ const colors = defineVars({
327
+ bg: { name: 'Colors/Gray/50', value: '#F8FAFC' },
328
+ text: { name: 'Colors/Gray/900', value: '#0F172A' }
329
+ })
330
+
331
+ export default () => (
332
+ <Frame style={{ bg: colors.bg }}>
333
+ <Text style={{ color: colors.text }}>Bound to variables</Text>
334
+ </Frame>
335
+ )
336
+ ```
337
+
338
+ In CLI, use `var:Colors/Primary` or `$Colors/Primary` in any color option.
339
+
340
+ ### Diffs
341
+
342
+ Compare two frames and get a patch:
343
+
344
+ ```bash
345
+ figma-use diff create --from 123:456 --to 789:012
346
+ ```
347
+
348
+ ```diff
349
+ --- /Card/Header #123:457
350
+ +++ /Card/Header #789:013
351
+ @@ -1,5 +1,5 @@
352
+ type: FRAME
353
+ size: 200 50
354
+ pos: 0 0
355
+ -fill: #FFFFFF
356
+ +fill: #F0F0F0
357
+ -opacity: 0.8
358
+ +opacity: 1
359
+ ```
360
+
361
+ Apply the patch to the original frame. On apply, current state is validated against expected — if they don't match, it fails.
362
+
363
+ Visual diff highlights changed pixels in red:
364
+
365
+ ```bash
366
+ figma-use diff visual --from 49:275096 --to 49:280802 --output diff.png
367
+ ```
368
+
369
+ | Before | After | Diff |
370
+ | --------------------------------- | ------------------------------- | ------------------------------- |
371
+ | ![before](assets/diff-before.png) | ![after](assets/diff-after.png) | ![diff](assets/diff-result.png) |
372
+
373
+ ### Inspection
374
+
375
+ Page tree in readable form:
376
+
377
+ ```
378
+ $ figma-use node tree
379
+ [0] frame "Card" (1:23)
380
+ 400×300 at (0, 0) | fill: #FFFFFF | layout: col gap=16
381
+ [0] text "Title" (1:24)
382
+ "Hello World" | 24px Inter Bold
383
+ ```
384
+
385
+ Export any node or screenshot with one command.
386
+
387
+ ### Vectors
388
+
389
+ Import SVG or work with paths directly — read, modify, translate, scale, flip:
390
+
391
+ ```bash
392
+ figma-use path get <id>
393
+ figma-use path set <id> "M 0 0 L 100 100 Z"
394
+ figma-use path scale <id> --factor 1.5
395
+ figma-use path flip <id> --axis x
396
+ ```
397
+
398
+ ### Query
399
+
400
+ Find nodes using XPath selectors:
401
+
402
+ ```bash
403
+ figma-use query "//FRAME" # All frames
404
+ figma-use query "//FRAME[@width < 300]" # Narrower than 300px
405
+ figma-use query "//COMPONENT[starts-with(@name, 'Button')]" # Name starts with
406
+ figma-use query "//FRAME[contains(@name, 'Card')]" # Name contains
407
+ figma-use query "//SECTION/FRAME" # Direct children
408
+ figma-use query "//SECTION//TEXT" # All descendants
409
+ figma-use query "//*[@cornerRadius > 0]" # Any node with radius
410
+ ```
411
+
412
+ Full XPath 3.1 support — predicates, functions, arithmetic, axes.
413
+
414
+ ### Analyze
415
+
416
+ Discovery tools for understanding design systems:
417
+
418
+ ```bash
419
+ # Find repeated patterns (potential components)
420
+ figma-use analyze clusters
421
+
422
+ # Color palette — usage frequency, variables vs hardcoded
423
+ figma-use analyze colors
424
+ figma-use analyze colors --show-similar # Find colors to merge
425
+
426
+ # Typography — all font combinations
427
+ figma-use analyze typography
428
+ figma-use analyze typography --group-by size
429
+
430
+ # Spacing — gap/padding values, grid compliance
431
+ figma-use analyze spacing --grid 8
432
+
433
+ # Accessibility snapshot — extract interactive elements tree
434
+ figma-use analyze snapshot # Full page
435
+ figma-use analyze snapshot <id> -i # Interactive elements only
436
+ ```
437
+
438
+ Example output:
439
+
440
+ ```
441
+ [0] 48× frame "Header" pattern (100% match)
442
+ 1280×56 | Frame > [Frame×2, Text]
443
+ examples: 53171:21628, 53171:21704
444
+
445
+ #303030 ████████████████████ 1840× (var)
446
+ #E5E5E5 ████████████████████ 1726× (var)
447
+ #000000 ████████ 238×
448
+ ```
449
+
450
+ ### Lint (Experimental)
451
+
452
+ Check designs for consistency, accessibility, and best practices:
453
+
454
+ ```bash
455
+ figma-use lint # Recommended rules
456
+ figma-use lint --page "Components" # Lint specific page
457
+ figma-use lint --preset strict # Stricter for production
458
+ figma-use lint --preset accessibility # A11y checks only
459
+ figma-use lint -v # With fix suggestions
460
+ ```
461
+
462
+ Output:
463
+
464
+ ```
465
+ ✖ Header/Title (1:234)
466
+ ✖ Contrast ratio 2.1:1 is below AA threshold (4.5:1) color-contrast
467
+ ⚠ Touch target 32x32 is below minimum 44x44 touch-target-size
468
+
469
+ ⚠ Card/Body (1:567)
470
+ ⚠ Hardcoded fill color #1A1A1A no-hardcoded-colors
471
+ ℹ Frame with 3 children doesn't use Auto Layout prefer-auto-layout
472
+
473
+ ────────────────────────────────────────────────────────────────
474
+ ✖ 1 error ⚠ 3 warnings ℹ 1 info
475
+ ```
476
+
477
+ **17 rules** across 6 categories:
478
+
479
+ | Category | Rules |
480
+ | ------------- | ------------------------------------------------------------------------------------------ |
481
+ | Design Tokens | `no-hardcoded-colors`, `consistent-spacing`, `consistent-radius`, `effect-style-required` |
482
+ | Layout | `prefer-auto-layout`, `pixel-perfect` |
483
+ | Typography | `text-style-required`, `min-text-size`, `no-mixed-styles` |
484
+ | Accessibility | `color-contrast`, `touch-target-size` |
485
+ | Structure | `no-default-names`, `no-hidden-layers`, `no-deeply-nested`, `no-empty-frames`, `no-groups` |
486
+ | Components | `no-detached-instances` |
487
+
488
+ JSON output for CI/CD:
489
+
490
+ ```bash
491
+ figma-use lint --json > report.json
492
+ ```
493
+
494
+ ### Comment-Driven Workflow (Experimental)
495
+
496
+ AI agents can wait for Figma comments and respond:
497
+
498
+ ```bash
499
+ figma-use comment watch --json # Blocks until new comment
500
+ figma-use comment resolve <id> # Mark as done
501
+ ```
502
+
503
+ Returns comment text, author, and `target_node` — the exact element under the comment pin. Agent processes the request, resolves the comment, then runs `watch` again for the next one.
504
+
505
+ ## Full Command Reference
506
+
507
+ See [REFERENCE.md](./REFERENCE.md) for the complete list of 100+ commands.
508
+
509
+ ## MCP Server
510
+
511
+ For AI agents that support Model Context Protocol:
512
+
513
+ ```bash
514
+ figma-use mcp serve
515
+ ```
516
+
517
+ Exposes 90+ tools. See [MCP.md](./MCP.md) for setup.
518
+
519
+ ## Configuration
520
+
521
+ For Storybook export and linting, create a config file:
522
+
523
+ ```bash
524
+ figma-use init
525
+ ```
526
+
527
+ Creates `.figma-use.json`:
528
+
529
+ ```json
530
+ {
531
+ "storybook": {
532
+ "page": "Components",
533
+ "out": "./stories",
534
+ "matchIcons": true,
535
+ "preferIcons": ["lucide", "tabler"]
536
+ },
537
+ "lint": {
538
+ "preset": "recommended"
539
+ },
540
+ "format": {
541
+ "pretty": true,
542
+ "semi": false,
543
+ "singleQuote": true
544
+ }
545
+ }
546
+ ```
547
+
548
+ CLI arguments override config values.
549
+
550
+ ## For AI Agents
551
+
552
+ Includes [SKILL.md](./SKILL.md) — a reference for Claude Code, Cursor, and other agents.
553
+
554
+ ## How It Works
555
+
556
+ ```
557
+ ┌─────────────┐ ┌─────────────┐
558
+ │ Terminal │────CDP────▶│ Figma │
559
+ │ figma-use │ port 9222 │ │
560
+ └─────────────┘ └─────────────┘
561
+ ```
562
+
563
+ figma-use communicates directly with Figma via Chrome DevTools Protocol (CDP). Just start Figma with `--remote-debugging-port=9222` and you're ready.
564
+
565
+ Commands are executed via `Runtime.evaluate` in Figma's JavaScript context, with full access to the Plugin API.
566
+
567
+ ## License
568
+
569
+ MIT