conductor-figma 1.0.2 → 3.0.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 +20 -0
- package/README.md +59 -153
- package/bin/conductor.js +1 -75
- package/figma-plugin/code.js +755 -0
- package/figma-plugin/manifest.json +14 -0
- package/figma-plugin/ui.html +77 -0
- package/package.json +25 -16
- package/src/bridge.js +60 -0
- package/src/design/intelligence.js +273 -294
- package/src/server.js +82 -196
- package/src/tools/handlers.js +145 -463
- package/src/tools/registry.js +1144 -336
- package/src/blueprints.js +0 -775
- package/src/design/craftguide.js +0 -181
- package/src/design/exporter.js +0 -72
- package/src/index.js +0 -33
- package/src/orchestrator.js +0 -100
- package/src/relay.js +0 -176
package/src/tools/registry.js
CHANGED
|
@@ -1,344 +1,1152 @@
|
|
|
1
1
|
// ═══════════════════════════════════════════
|
|
2
|
-
// CONDUCTOR — Tool Registry
|
|
2
|
+
// CONDUCTOR v3 — Tool Registry (150+ Tools)
|
|
3
3
|
// ═══════════════════════════════════════════
|
|
4
|
-
// All 61 MCP tools, organized by category.
|
|
5
|
-
// Each tool has: name, description, category, inputSchema, handler reference.
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
description: '
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
5
|
+
function tool(name, desc, params, category) {
|
|
6
|
+
return { name, description: desc, inputSchema: { type: 'object', properties: params, required: Object.keys(params).filter(k => params[k]._required) }, category }
|
|
7
|
+
}
|
|
8
|
+
function req(type, desc) { return { type, description: desc, _required: true } }
|
|
9
|
+
function opt(type, desc, def) { return { type, description: desc + (def !== undefined ? ` (default: ${def})` : '') } }
|
|
10
|
+
function enm(values, desc, def) { return { type: 'string', enum: values, description: desc + (def ? ` (default: ${def})` : '') } }
|
|
11
|
+
|
|
12
|
+
// ═══ CREATE & LAYOUT (25) ═══
|
|
13
|
+
const CREATE = {
|
|
14
|
+
create_frame: tool('create_frame', 'Create a frame (screen, section, card, container). Automatically applies auto-layout with design-intelligent defaults.', {
|
|
15
|
+
name: req('string', 'Frame name (semantic: "Hero Section", "Card", "Sidebar")'),
|
|
16
|
+
width: opt('number', 'Width in pixels. Omit for hug-contents.'),
|
|
17
|
+
height: opt('number', 'Height in pixels. Omit for hug-contents.'),
|
|
18
|
+
direction: enm(['VERTICAL','HORIZONTAL'], 'Layout direction', 'VERTICAL'),
|
|
19
|
+
padding: opt('number', 'Equal padding all sides (8px grid snapped)'),
|
|
20
|
+
paddingTop: opt('number', 'Top padding'), paddingRight: opt('number', 'Right padding'),
|
|
21
|
+
paddingBottom: opt('number', 'Bottom padding'), paddingLeft: opt('number', 'Left padding'),
|
|
22
|
+
gap: opt('number', 'Space between children (8px grid)'),
|
|
23
|
+
fill: opt('string', 'Background color hex'),
|
|
24
|
+
cornerRadius: opt('number', 'Corner radius'),
|
|
25
|
+
primaryAxisAlignItems: enm(['MIN','CENTER','MAX','SPACE_BETWEEN'], 'Main axis alignment'),
|
|
26
|
+
counterAxisAlignItems: enm(['MIN','CENTER','MAX','STRETCH'], 'Cross axis alignment'),
|
|
27
|
+
primaryAxisSizingMode: enm(['FIXED','HUG','FILL'], 'Main axis sizing'),
|
|
28
|
+
counterAxisSizingMode: enm(['FIXED','HUG','FILL'], 'Cross axis sizing'),
|
|
29
|
+
parentId: opt('string', 'Parent node ID to nest inside'),
|
|
30
|
+
x: opt('number', 'X position on canvas'), y: opt('number', 'Y position on canvas'),
|
|
31
|
+
}, 'create'),
|
|
32
|
+
|
|
33
|
+
create_text: tool('create_text', 'Create text with design-intelligent typography. Font weight is auto-resolved (e.g. "bold" → "Bold", "600" → "Semi Bold").', {
|
|
34
|
+
text: req('string', 'Text content (use \\n for line breaks)'),
|
|
35
|
+
fontSize: opt('number', 'Font size in px', 16),
|
|
36
|
+
color: opt('string', 'Text color hex', '#ffffff'),
|
|
37
|
+
fontFamily: opt('string', 'Font family', 'Inter'),
|
|
38
|
+
fontWeight: opt('string', 'Weight: thin/light/regular/medium/semibold/bold/extrabold or 100-900', 'Regular'),
|
|
39
|
+
textAlignHorizontal: enm(['LEFT','CENTER','RIGHT','JUSTIFIED'], 'Horizontal alignment'),
|
|
40
|
+
textAlignVertical: enm(['TOP','CENTER','BOTTOM'], 'Vertical alignment'),
|
|
41
|
+
lineHeight: opt('number', 'Line height in px or ratio (1.5 = 150%)'),
|
|
42
|
+
letterSpacing: opt('number', 'Letter spacing in px'),
|
|
43
|
+
textDecoration: enm(['NONE','UNDERLINE','STRIKETHROUGH'], 'Text decoration'),
|
|
44
|
+
textCase: enm(['ORIGINAL','UPPER','LOWER','TITLE'], 'Text case transform'),
|
|
45
|
+
maxWidth: opt('number', 'Maximum text width for wrapping'),
|
|
46
|
+
parentId: opt('string', 'Parent node ID'),
|
|
47
|
+
}, 'create'),
|
|
48
|
+
|
|
49
|
+
create_rectangle: tool('create_rectangle', 'Create a rectangle shape.', {
|
|
50
|
+
name: opt('string', 'Name', 'Rectangle'),
|
|
51
|
+
width: req('number', 'Width'), height: req('number', 'Height'),
|
|
52
|
+
fill: opt('string', 'Fill color hex'),
|
|
53
|
+
cornerRadius: opt('number', 'Corner radius'), opacity: opt('number', 'Opacity 0-1'),
|
|
54
|
+
parentId: opt('string', 'Parent node ID'),
|
|
55
|
+
}, 'create'),
|
|
56
|
+
|
|
57
|
+
create_ellipse: tool('create_ellipse', 'Create a circle or oval.', {
|
|
58
|
+
name: opt('string', 'Name', 'Ellipse'),
|
|
59
|
+
width: req('number', 'Width'), height: req('number', 'Height'),
|
|
60
|
+
fill: opt('string', 'Fill color hex'), opacity: opt('number', 'Opacity 0-1'),
|
|
61
|
+
parentId: opt('string', 'Parent node ID'),
|
|
62
|
+
}, 'create'),
|
|
63
|
+
|
|
64
|
+
create_line: tool('create_line', 'Create a line or divider.', {
|
|
65
|
+
name: opt('string', 'Name', 'Line'),
|
|
66
|
+
length: req('number', 'Line length'), direction: enm(['HORIZONTAL','VERTICAL'], 'Direction', 'HORIZONTAL'),
|
|
67
|
+
strokeColor: opt('string', 'Stroke color'), strokeWeight: opt('number', 'Stroke weight', 1),
|
|
68
|
+
parentId: opt('string', 'Parent node ID'),
|
|
69
|
+
}, 'create'),
|
|
70
|
+
|
|
71
|
+
create_svg_node: tool('create_svg_node', 'Create a vector graphic from SVG markup. Use for icons, logos, illustrations.', {
|
|
72
|
+
svg: req('string', 'SVG markup string'),
|
|
73
|
+
name: opt('string', 'Node name'),
|
|
74
|
+
width: opt('number', 'Target width'), height: opt('number', 'Target height'),
|
|
75
|
+
parentId: opt('string', 'Parent node ID'),
|
|
76
|
+
}, 'create'),
|
|
77
|
+
|
|
78
|
+
create_component: tool('create_component', 'Create a reusable component from the current selection or a new frame.', {
|
|
79
|
+
name: req('string', 'Component name'),
|
|
80
|
+
description: opt('string', 'Component description'),
|
|
81
|
+
fromNodeId: opt('string', 'Node ID to convert to component'),
|
|
82
|
+
width: opt('number', 'Width'), height: opt('number', 'Height'),
|
|
83
|
+
parentId: opt('string', 'Parent node ID'),
|
|
84
|
+
}, 'create'),
|
|
85
|
+
|
|
86
|
+
create_component_instance: tool('create_component_instance', 'Instantiate an existing component.', {
|
|
87
|
+
componentId: req('string', 'Component node ID to instantiate'),
|
|
88
|
+
parentId: opt('string', 'Parent to place instance in'),
|
|
89
|
+
overrides: opt('object', 'Property overrides: { "Text Label": "New text", "fill": "#ff0000" }'),
|
|
90
|
+
}, 'create'),
|
|
91
|
+
|
|
92
|
+
create_component_set: tool('create_component_set', 'Combine component variants into a variant set.', {
|
|
93
|
+
name: req('string', 'Component set name'),
|
|
94
|
+
componentIds: { type:'array', items:{type:'string'}, description:'Array of component IDs to combine', _required:true },
|
|
95
|
+
}, 'create'),
|
|
96
|
+
|
|
97
|
+
create_smart_component: tool('create_smart_component', 'Create a design-intelligent component with proper auto-layout, padding, and sizing. Uses component intelligence defaults.', {
|
|
98
|
+
type: req('string', 'Component type: button, input, card, avatar, badge, chip, switch, checkbox, radio, toast, tooltip, modal, dropdown, tabs, table, progress, skeleton, divider'),
|
|
99
|
+
variant: opt('string', 'Variant: default, sm, lg, icon, compact, spacious, pill, thin'),
|
|
100
|
+
label: opt('string', 'Text label for the component'),
|
|
101
|
+
brandColor: opt('string', 'Brand/accent color hex'),
|
|
102
|
+
mode: enm(['dark','light'], 'Color mode', 'dark'),
|
|
103
|
+
parentId: opt('string', 'Parent node ID'),
|
|
104
|
+
}, 'create'),
|
|
105
|
+
|
|
106
|
+
set_auto_layout: tool('set_auto_layout', 'Configure auto-layout on a frame. All spacing is 8px grid-snapped.', {
|
|
107
|
+
nodeId: req('string', 'Target node ID'),
|
|
108
|
+
direction: enm(['VERTICAL','HORIZONTAL'], 'Direction'),
|
|
109
|
+
padding: opt('number', 'Uniform padding'),
|
|
110
|
+
paddingTop: opt('number',''), paddingRight: opt('number',''), paddingBottom: opt('number',''), paddingLeft: opt('number',''),
|
|
111
|
+
gap: opt('number', 'Gap between children'),
|
|
112
|
+
primaryAxisAlignItems: enm(['MIN','CENTER','MAX','SPACE_BETWEEN'], 'Main axis'),
|
|
113
|
+
counterAxisAlignItems: enm(['MIN','CENTER','MAX','STRETCH'], 'Cross axis'),
|
|
114
|
+
primaryAxisSizingMode: enm(['FIXED','HUG','FILL'], 'Main sizing'),
|
|
115
|
+
counterAxisSizingMode: enm(['FIXED','HUG','FILL'], 'Cross sizing'),
|
|
116
|
+
}, 'create'),
|
|
117
|
+
|
|
118
|
+
create_section: tool('create_section', 'Create a design-intelligent page section (hero, features, pricing, CTA, testimonials, FAQ, footer, stats, logos, comparison, team).', {
|
|
119
|
+
type: req('string', 'Section type: hero, features, pricing, cta, testimonials, faq, footer, stats, logos, comparison, team, newsletter'),
|
|
120
|
+
content: opt('object', 'Content data: { title, subtitle, items[], ... }'),
|
|
121
|
+
brandColor: opt('string', 'Brand color hex'),
|
|
122
|
+
mode: enm(['dark','light'], 'Color mode', 'dark'),
|
|
123
|
+
width: opt('number', 'Frame width', 1440),
|
|
124
|
+
parentId: opt('string', 'Parent node ID'),
|
|
125
|
+
}, 'create'),
|
|
126
|
+
|
|
127
|
+
create_page: tool('create_page', 'Create a complete page design with multiple sections. Design-intelligent layout, spacing, and typography throughout.', {
|
|
128
|
+
type: req('string', 'Page type: landing, pricing, dashboard, settings, login, signup, profile, blog, docs, 404'),
|
|
129
|
+
content: opt('object', 'Page content: { brand, title, features[], stats[], tiers[], ... }'),
|
|
130
|
+
brandColor: opt('string', 'Brand color hex'),
|
|
131
|
+
mode: enm(['dark','light'], 'Color mode', 'dark'),
|
|
132
|
+
width: opt('number', 'Frame width', 1440),
|
|
133
|
+
}, 'create'),
|
|
134
|
+
|
|
135
|
+
create_table_frame: tool('create_table_frame', 'Create a data table with headers, rows, and proper spacing.', {
|
|
136
|
+
columns: { type:'array', items:{type:'string'}, description:'Column headers', _required:true },
|
|
137
|
+
rows: opt('array', 'Row data: arrays of cell values'),
|
|
138
|
+
brandColor: opt('string', 'Accent color'),
|
|
139
|
+
parentId: opt('string', 'Parent node'),
|
|
140
|
+
}, 'create'),
|
|
141
|
+
|
|
142
|
+
create_form: tool('create_form', 'Create a form layout with labeled inputs, validation states, and submit button.', {
|
|
143
|
+
fields: { type:'array', items:{type:'object'}, description:'Fields: [{ label, type: "text|email|password|select|textarea", required }]', _required:true },
|
|
144
|
+
submitLabel: opt('string', 'Submit button text', 'Submit'),
|
|
145
|
+
brandColor: opt('string', 'Accent color'),
|
|
146
|
+
parentId: opt('string', 'Parent node'),
|
|
147
|
+
}, 'create'),
|
|
148
|
+
|
|
149
|
+
create_nav_bar: tool('create_nav_bar', 'Create a navigation bar with logo, links, and CTA button.', {
|
|
150
|
+
brand: opt('string', 'Brand name', 'acme'),
|
|
151
|
+
items: opt('array', 'Nav items: ["Features", "Pricing", "Docs"]'),
|
|
152
|
+
ctaText: opt('string', 'CTA button text'),
|
|
153
|
+
width: opt('number', 'Width', 1440),
|
|
154
|
+
brandColor: opt('string', 'Accent color'),
|
|
155
|
+
parentId: opt('string', 'Parent node'),
|
|
156
|
+
}, 'create'),
|
|
157
|
+
|
|
158
|
+
create_card_grid: tool('create_card_grid', 'Create a grid of cards with proper spacing and alignment.', {
|
|
159
|
+
columns: opt('number', 'Number of columns', 3),
|
|
160
|
+
cards: opt('array', 'Card data: [{ title, description, icon }]'),
|
|
161
|
+
brandColor: opt('string', 'Accent color'),
|
|
162
|
+
parentId: opt('string', 'Parent node'),
|
|
163
|
+
}, 'create'),
|
|
164
|
+
|
|
165
|
+
create_sidebar_layout: tool('create_sidebar_layout', 'Create a sidebar + main content layout with proper proportions.', {
|
|
166
|
+
sidebarWidth: opt('number', 'Sidebar width', 260),
|
|
167
|
+
totalWidth: opt('number', 'Total width', 1440),
|
|
168
|
+
brandColor: opt('string', 'Accent color'),
|
|
169
|
+
parentId: opt('string', 'Parent node'),
|
|
170
|
+
}, 'create'),
|
|
171
|
+
|
|
172
|
+
create_footer: tool('create_footer', 'Create a page footer with columns, links, and copyright.', {
|
|
173
|
+
brand: opt('string', 'Brand name'),
|
|
174
|
+
columns: opt('array', 'Footer columns: [{ title, links: ["Link 1", "Link 2"] }]'),
|
|
175
|
+
width: opt('number', 'Width', 1440),
|
|
176
|
+
brandColor: opt('string', 'Accent color'),
|
|
177
|
+
parentId: opt('string', 'Parent node'),
|
|
178
|
+
}, 'create'),
|
|
179
|
+
|
|
180
|
+
create_header: tool('create_header', 'Create a page header/hero with heading, subheading, and CTA.', {
|
|
181
|
+
heading: opt('string', 'Main heading'),
|
|
182
|
+
subheading: opt('string', 'Subheading text'),
|
|
183
|
+
ctaText: opt('string', 'CTA button text'),
|
|
184
|
+
width: opt('number', 'Width', 1440),
|
|
185
|
+
brandColor: opt('string', 'Accent color'),
|
|
186
|
+
parentId: opt('string', 'Parent node'),
|
|
187
|
+
}, 'create'),
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// ═══ MODIFY & STYLE (25) ═══
|
|
191
|
+
const MODIFY = {
|
|
192
|
+
modify_node: tool('modify_node', 'Modify properties of any existing node.', {
|
|
193
|
+
nodeId: req('string', 'Target node ID'),
|
|
194
|
+
x: opt('number','X'), y: opt('number','Y'), width: opt('number','Width'), height: opt('number','Height'),
|
|
195
|
+
name: opt('string','Name'), visible: opt('boolean','Visibility'), locked: opt('boolean','Lock'),
|
|
196
|
+
opacity: opt('number','Opacity 0-1'), rotation: opt('number','Rotation degrees'),
|
|
197
|
+
cornerRadius: opt('number','Corner radius'), fill: opt('string','Fill color'),
|
|
198
|
+
}, 'modify'),
|
|
199
|
+
|
|
200
|
+
set_fill: tool('set_fill', 'Set fill on a node. Supports solid, linear gradient, radial gradient, and multiple fills.', {
|
|
201
|
+
nodeId: req('string', 'Target node ID'),
|
|
202
|
+
type: enm(['SOLID','LINEAR','RADIAL','ANGULAR','DIAMOND'], 'Fill type', 'SOLID'),
|
|
203
|
+
color: opt('string', 'Solid fill hex color'),
|
|
204
|
+
gradient: opt('object', '{ angle, stops: [{ position: 0-1, color: "#hex" }] }'),
|
|
205
|
+
opacity: opt('number', 'Fill opacity 0-1'),
|
|
206
|
+
fills: opt('array', 'Array of fill objects for multiple fills'),
|
|
207
|
+
}, 'modify'),
|
|
208
|
+
|
|
209
|
+
set_stroke: tool('set_stroke', 'Add border/stroke to a node.', {
|
|
210
|
+
nodeId: req('string', 'Target node ID'),
|
|
211
|
+
color: opt('string', 'Stroke color hex'), weight: opt('number', 'Stroke weight', 1),
|
|
212
|
+
align: enm(['INSIDE','OUTSIDE','CENTER'], 'Stroke alignment', 'INSIDE'),
|
|
213
|
+
dashPattern: opt('array', 'Dash pattern array, e.g. [4, 4]'),
|
|
214
|
+
opacity: opt('number', 'Stroke opacity'),
|
|
215
|
+
}, 'modify'),
|
|
216
|
+
|
|
217
|
+
set_effects: tool('set_effects', 'Add shadows, blur, or background blur effects.', {
|
|
218
|
+
nodeId: req('string', 'Target node ID'),
|
|
219
|
+
shadow: opt('object', '{ color, offsetX, offsetY, blur, spread }'),
|
|
220
|
+
innerShadow: opt('object', '{ color, offsetX, offsetY, blur, spread }'),
|
|
221
|
+
blur: opt('number', 'Layer blur amount'),
|
|
222
|
+
backgroundBlur: opt('number', 'Background blur (glassmorphism)'),
|
|
223
|
+
preset: enm(['sm','md','lg','xl'], 'Use preset shadow size'),
|
|
224
|
+
}, 'modify'),
|
|
225
|
+
|
|
226
|
+
set_image_fill: tool('set_image_fill', 'Set an image fill on a node from URL.', {
|
|
227
|
+
nodeId: req('string', 'Target node ID'),
|
|
228
|
+
url: req('string', 'Image URL'),
|
|
229
|
+
scaleMode: enm(['FILL','FIT','CROP','TILE'], 'Scale mode', 'FILL'),
|
|
230
|
+
}, 'modify'),
|
|
231
|
+
|
|
232
|
+
style_text_range: tool('style_text_range', 'Apply mixed styling within a text node. Style specific character ranges differently.', {
|
|
233
|
+
nodeId: req('string', 'Text node ID'),
|
|
234
|
+
ranges: { type:'array', items:{type:'object'}, description:'Array of { start, end, fontSize, fontWeight, color, textDecoration }', _required:true },
|
|
235
|
+
}, 'modify'),
|
|
236
|
+
|
|
237
|
+
set_constraints: tool('set_constraints', 'Set responsive constraints on a node.', {
|
|
238
|
+
nodeId: req('string', 'Target node ID'),
|
|
239
|
+
horizontal: enm(['MIN','CENTER','MAX','STRETCH','SCALE'], 'Horizontal constraint'),
|
|
240
|
+
vertical: enm(['MIN','CENTER','MAX','STRETCH','SCALE'], 'Vertical constraint'),
|
|
241
|
+
}, 'modify'),
|
|
242
|
+
|
|
243
|
+
delete_node: tool('delete_node', 'Remove a node from the canvas.', {
|
|
244
|
+
nodeId: req('string', 'Node ID to delete'),
|
|
245
|
+
}, 'modify'),
|
|
246
|
+
|
|
247
|
+
move_to_parent: tool('move_to_parent', 'Move a node into a different parent frame.', {
|
|
248
|
+
nodeId: req('string', 'Node to move'),
|
|
249
|
+
parentId: req('string', 'New parent ID'),
|
|
250
|
+
index: opt('number', 'Position index within parent'),
|
|
251
|
+
}, 'modify'),
|
|
252
|
+
|
|
253
|
+
duplicate_node: tool('duplicate_node', 'Duplicate a node.', {
|
|
254
|
+
nodeId: req('string', 'Node to duplicate'),
|
|
255
|
+
count: opt('number', 'Number of duplicates', 1),
|
|
256
|
+
offsetX: opt('number', 'X offset per copy'), offsetY: opt('number', 'Y offset per copy'),
|
|
257
|
+
}, 'modify'),
|
|
258
|
+
|
|
259
|
+
group_nodes: tool('group_nodes', 'Group multiple nodes together.', {
|
|
260
|
+
nodeIds: { type:'array', items:{type:'string'}, description:'Node IDs to group', _required:true },
|
|
261
|
+
name: opt('string', 'Group name'),
|
|
262
|
+
}, 'modify'),
|
|
263
|
+
|
|
264
|
+
ungroup_nodes: tool('ungroup_nodes', 'Ungroup a group node.', {
|
|
265
|
+
nodeId: req('string', 'Group node to ungroup'),
|
|
266
|
+
}, 'modify'),
|
|
267
|
+
|
|
268
|
+
resize_node: tool('resize_node', 'Resize a node with optional constraint preservation.', {
|
|
269
|
+
nodeId: req('string', 'Node to resize'),
|
|
270
|
+
width: opt('number', 'New width'), height: opt('number', 'New height'),
|
|
271
|
+
preserveAspect: opt('boolean', 'Maintain aspect ratio'),
|
|
272
|
+
}, 'modify'),
|
|
273
|
+
|
|
274
|
+
align_nodes: tool('align_nodes', 'Align multiple nodes relative to each other.', {
|
|
275
|
+
nodeIds: { type:'array', items:{type:'string'}, description:'Nodes to align', _required:true },
|
|
276
|
+
alignment: enm(['LEFT','CENTER','RIGHT','TOP','MIDDLE','BOTTOM','DISTRIBUTE_H','DISTRIBUTE_V'], 'Alignment type'),
|
|
277
|
+
}, 'modify'),
|
|
278
|
+
|
|
279
|
+
set_corner_radius: tool('set_corner_radius', 'Set corner radius with per-corner control.', {
|
|
280
|
+
nodeId: req('string', 'Target node'),
|
|
281
|
+
radius: opt('number', 'Uniform radius'),
|
|
282
|
+
topLeft: opt('number',''), topRight: opt('number',''), bottomRight: opt('number',''), bottomLeft: opt('number',''),
|
|
283
|
+
}, 'modify'),
|
|
284
|
+
|
|
285
|
+
set_opacity: tool('set_opacity', 'Set node opacity.', {
|
|
286
|
+
nodeId: req('string', 'Target node'), opacity: req('number', 'Opacity 0-1'),
|
|
287
|
+
}, 'modify'),
|
|
288
|
+
|
|
289
|
+
set_blend_mode: tool('set_blend_mode', 'Set blend mode.', {
|
|
290
|
+
nodeId: req('string', 'Target node'),
|
|
291
|
+
blendMode: enm(['NORMAL','MULTIPLY','SCREEN','OVERLAY','DARKEN','LIGHTEN','COLOR_DODGE','COLOR_BURN','HARD_LIGHT','SOFT_LIGHT','DIFFERENCE','EXCLUSION','HUE','SATURATION','COLOR','LUMINOSITY'], 'Blend mode'),
|
|
292
|
+
}, 'modify'),
|
|
293
|
+
|
|
294
|
+
set_clip_content: tool('set_clip_content', 'Toggle clip content on a frame.', {
|
|
295
|
+
nodeId: req('string', 'Frame node'), clip: req('boolean', 'Clip content'),
|
|
296
|
+
}, 'modify'),
|
|
297
|
+
|
|
298
|
+
rename_node: tool('rename_node', 'Rename a node.', {
|
|
299
|
+
nodeId: req('string', 'Target node'), name: req('string', 'New name'),
|
|
300
|
+
}, 'modify'),
|
|
301
|
+
|
|
302
|
+
lock_node: tool('lock_node', 'Lock/unlock a node.', {
|
|
303
|
+
nodeId: req('string', 'Target node'), locked: req('boolean', 'Lock state'),
|
|
304
|
+
}, 'modify'),
|
|
305
|
+
|
|
306
|
+
set_visibility: tool('set_visibility', 'Show/hide a node.', {
|
|
307
|
+
nodeId: req('string', 'Target node'), visible: req('boolean', 'Visibility'),
|
|
308
|
+
}, 'modify'),
|
|
309
|
+
|
|
310
|
+
reorder_node: tool('reorder_node', 'Change z-order of a node.', {
|
|
311
|
+
nodeId: req('string', 'Target node'),
|
|
312
|
+
direction: enm(['FRONT','BACK','FORWARD','BACKWARD'], 'Reorder direction'),
|
|
313
|
+
}, 'modify'),
|
|
314
|
+
|
|
315
|
+
set_layout_sizing: tool('set_layout_sizing', 'Set how a child behaves in auto-layout.', {
|
|
316
|
+
nodeId: req('string', 'Child node'),
|
|
317
|
+
horizontal: enm(['FIXED','HUG','FILL'], 'Horizontal sizing'),
|
|
318
|
+
vertical: enm(['FIXED','HUG','FILL'], 'Vertical sizing'),
|
|
319
|
+
}, 'modify'),
|
|
320
|
+
|
|
321
|
+
flatten_node: tool('flatten_node', 'Flatten a node into a single vector.', {
|
|
322
|
+
nodeId: req('string', 'Node to flatten'),
|
|
323
|
+
}, 'modify'),
|
|
324
|
+
|
|
325
|
+
set_rotation: tool('set_rotation', 'Rotate a node.', {
|
|
326
|
+
nodeId: req('string', 'Target node'), angle: req('number', 'Rotation in degrees'),
|
|
327
|
+
}, 'modify'),
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// ═══ VECTOR & BOOLEAN (8) ═══
|
|
331
|
+
const VECTOR = {
|
|
332
|
+
create_vector: tool('create_vector', 'Draw custom vector paths using SVG-like path data.', {
|
|
333
|
+
name: opt('string', 'Vector name'),
|
|
334
|
+
pathData: req('string', 'SVG path data (M, L, C, Q, Z commands)'),
|
|
335
|
+
fill: opt('string', 'Fill color'), stroke: opt('string', 'Stroke color'),
|
|
336
|
+
strokeWeight: opt('number', 'Stroke weight'),
|
|
337
|
+
parentId: opt('string', 'Parent node ID'),
|
|
338
|
+
}, 'vector'),
|
|
339
|
+
|
|
340
|
+
boolean_operation: tool('boolean_operation', 'Perform boolean operations on shapes.', {
|
|
341
|
+
operation: enm(['UNION','SUBTRACT','INTERSECT','EXCLUDE'], 'Boolean operation type'),
|
|
342
|
+
nodeIds: { type:'array', items:{type:'string'}, description:'Node IDs (first is base shape)', _required:true },
|
|
343
|
+
}, 'vector'),
|
|
344
|
+
|
|
345
|
+
create_polygon: tool('create_polygon', 'Create a regular polygon.', {
|
|
346
|
+
sides: req('number', 'Number of sides (3=triangle, 5=pentagon, 6=hexagon, etc.)'),
|
|
347
|
+
size: req('number', 'Diameter'),
|
|
348
|
+
fill: opt('string', 'Fill color'), name: opt('string', 'Name'),
|
|
349
|
+
parentId: opt('string', 'Parent node ID'),
|
|
350
|
+
}, 'vector'),
|
|
351
|
+
|
|
352
|
+
create_star: tool('create_star', 'Create a star shape.', {
|
|
353
|
+
points: opt('number', 'Number of points', 5),
|
|
354
|
+
outerRadius: req('number', 'Outer radius'),
|
|
355
|
+
innerRadius: opt('number', 'Inner radius (ratio to outer)'),
|
|
356
|
+
fill: opt('string', 'Fill color'), name: opt('string', 'Name'),
|
|
357
|
+
parentId: opt('string', 'Parent node ID'),
|
|
358
|
+
}, 'vector'),
|
|
359
|
+
|
|
360
|
+
offset_path: tool('offset_path', 'Offset/expand a vector path.', {
|
|
361
|
+
nodeId: req('string', 'Vector node'), offset: req('number', 'Offset amount'),
|
|
362
|
+
}, 'vector'),
|
|
363
|
+
|
|
364
|
+
create_arrow: tool('create_arrow', 'Create an arrow shape.', {
|
|
365
|
+
length: req('number', 'Arrow length'), direction: enm(['RIGHT','LEFT','UP','DOWN'], 'Direction', 'RIGHT'),
|
|
366
|
+
strokeWeight: opt('number', 'Weight', 2), color: opt('string', 'Color'),
|
|
367
|
+
parentId: opt('string', 'Parent node ID'),
|
|
368
|
+
}, 'vector'),
|
|
369
|
+
|
|
370
|
+
create_icon: tool('create_icon', 'Create a common UI icon from built-in set.', {
|
|
371
|
+
icon: req('string', 'Icon name: arrow-right, arrow-left, arrow-up, arrow-down, check, x, plus, minus, search, menu, settings, user, heart, star, home, mail, phone, calendar, clock, bell, lock, unlock, eye, eye-off, edit, trash, download, upload, link, external-link, copy, share, filter, sort, grid, list, chevron-right, chevron-left, chevron-down, chevron-up'),
|
|
372
|
+
size: opt('number', 'Icon size', 24), color: opt('string', 'Color'),
|
|
373
|
+
parentId: opt('string', 'Parent node ID'),
|
|
374
|
+
}, 'vector'),
|
|
375
|
+
|
|
376
|
+
create_divider: tool('create_divider', 'Create a horizontal or vertical divider line.', {
|
|
377
|
+
direction: enm(['HORIZONTAL','VERTICAL'], 'Direction', 'HORIZONTAL'),
|
|
378
|
+
length: opt('number', 'Length (auto-fills parent if omitted)'),
|
|
379
|
+
color: opt('string', 'Color'), thickness: opt('number', 'Thickness', 1),
|
|
380
|
+
parentId: opt('string', 'Parent node ID'),
|
|
381
|
+
}, 'vector'),
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// ═══ READ & INSPECT (18) ═══
|
|
385
|
+
const READ = {
|
|
386
|
+
get_selection: tool('get_selection', 'Get the currently selected nodes with full properties.', {}, 'read'),
|
|
387
|
+
|
|
388
|
+
get_page_structure: tool('get_page_structure', 'Get the full page layer tree with types, names, and hierarchy.', {
|
|
389
|
+
depth: opt('number', 'Max depth to traverse', 3),
|
|
390
|
+
pageId: opt('string', 'Page ID (uses current page if omitted)'),
|
|
391
|
+
}, 'read'),
|
|
392
|
+
|
|
393
|
+
get_node_info: tool('get_node_info', 'Get detailed properties of a specific node including fills, effects, auto-layout, and text styles.', {
|
|
394
|
+
nodeId: req('string', 'Node ID to inspect'),
|
|
395
|
+
}, 'read'),
|
|
396
|
+
|
|
397
|
+
get_nodes_info: tool('get_nodes_info', 'Get detailed properties of multiple nodes.', {
|
|
398
|
+
nodeIds: { type:'array', items:{type:'string'}, description:'Array of node IDs', _required:true },
|
|
399
|
+
}, 'read'),
|
|
400
|
+
|
|
401
|
+
find_nodes: tool('find_nodes', 'Search for nodes by name, type, or properties.', {
|
|
402
|
+
query: opt('string', 'Search by name (partial match)'),
|
|
403
|
+
type: enm(['FRAME','TEXT','RECTANGLE','ELLIPSE','LINE','COMPONENT','INSTANCE','GROUP','VECTOR','BOOLEAN_OPERATION','SECTION'], 'Filter by type'),
|
|
404
|
+
withinId: opt('string', 'Search within this node'),
|
|
405
|
+
}, 'read'),
|
|
406
|
+
|
|
407
|
+
get_local_styles: tool('get_local_styles', 'Get all local paint, text, and effect styles in the file.', {}, 'read'),
|
|
408
|
+
|
|
409
|
+
get_local_variables: tool('get_local_variables', 'Get all local variable collections and variables.', {}, 'read'),
|
|
410
|
+
|
|
411
|
+
list_components: tool('list_components', 'List all components in the file.', {
|
|
412
|
+
pageId: opt('string', 'Filter to specific page'),
|
|
413
|
+
}, 'read'),
|
|
414
|
+
|
|
415
|
+
list_pages: tool('list_pages', 'List all pages in the document.', {}, 'read'),
|
|
416
|
+
|
|
417
|
+
get_document_info: tool('get_document_info', 'Get document name, pages, and metadata.', {}, 'read'),
|
|
418
|
+
|
|
419
|
+
set_selection: tool('set_selection', 'Select nodes and optionally scroll viewport to them.', {
|
|
420
|
+
nodeIds: { type:'array', items:{type:'string'}, description:'Node IDs to select', _required:true },
|
|
421
|
+
zoomToFit: opt('boolean', 'Scroll and zoom to show selection', true),
|
|
422
|
+
}, 'read'),
|
|
423
|
+
|
|
424
|
+
set_focus: tool('set_focus', 'Focus viewport on a specific node.', {
|
|
425
|
+
nodeId: req('string', 'Node to focus on'),
|
|
426
|
+
zoom: opt('number', 'Zoom level 0.1-10'),
|
|
427
|
+
}, 'read'),
|
|
428
|
+
|
|
429
|
+
get_annotations: tool('get_annotations', 'Get all annotations/comments on the document or a specific node.', {
|
|
430
|
+
nodeId: opt('string', 'Node to get annotations for'),
|
|
431
|
+
}, 'read'),
|
|
432
|
+
|
|
433
|
+
set_annotation: tool('set_annotation', 'Create or update an annotation with markdown support.', {
|
|
434
|
+
nodeId: req('string', 'Node to annotate'),
|
|
435
|
+
text: req('string', 'Annotation text (markdown supported)'),
|
|
436
|
+
}, 'read'),
|
|
437
|
+
|
|
438
|
+
list_available_fonts: tool('list_available_fonts', 'Get all fonts available in the Figma file.', {}, 'read'),
|
|
439
|
+
|
|
440
|
+
read_node_css: tool('read_node_css', 'Get CSS representation of a node (for developer handoff).', {
|
|
441
|
+
nodeId: req('string', 'Node to get CSS for'),
|
|
442
|
+
format: enm(['css','tailwind','react-inline'], 'Output format', 'css'),
|
|
443
|
+
}, 'read'),
|
|
444
|
+
|
|
445
|
+
get_selection_colors: tool('get_selection_colors', 'Extract all colors used in the current selection.', {}, 'read'),
|
|
446
|
+
|
|
447
|
+
measure_distance: tool('measure_distance', 'Measure distance between two nodes.', {
|
|
448
|
+
nodeId1: req('string', 'First node'), nodeId2: req('string', 'Second node'),
|
|
449
|
+
}, 'read'),
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// ═══ VARIABLES & TOKENS (10) ═══
|
|
453
|
+
const VARIABLES = {
|
|
454
|
+
create_variable_collection: tool('create_variable_collection', 'Create a design token collection with modes (e.g. Light/Dark).', {
|
|
455
|
+
name: req('string', 'Collection name (e.g. "Colors", "Spacing")'),
|
|
456
|
+
modes: opt('array', 'Mode names, e.g. ["Light", "Dark"]'),
|
|
457
|
+
}, 'variables'),
|
|
458
|
+
|
|
459
|
+
create_variable: tool('create_variable', 'Create a design variable/token.', {
|
|
460
|
+
name: req('string', 'Variable name (e.g. "primary-500", "spacing-md")'),
|
|
461
|
+
collectionId: req('string', 'Collection ID'),
|
|
462
|
+
type: enm(['COLOR','FLOAT','STRING','BOOLEAN'], 'Variable type'),
|
|
463
|
+
value: req('string', 'Value (hex for COLOR, number for FLOAT, etc.)'),
|
|
464
|
+
modeValues: opt('object', 'Values per mode: { "Light": "#000", "Dark": "#fff" }'),
|
|
465
|
+
}, 'variables'),
|
|
466
|
+
|
|
467
|
+
bind_variable: tool('bind_variable', 'Bind a variable to a node property.', {
|
|
468
|
+
nodeId: req('string', 'Target node'),
|
|
469
|
+
property: req('string', 'Property to bind: fills, strokes, cornerRadius, paddingTop, etc.'),
|
|
470
|
+
variableId: req('string', 'Variable ID to bind'),
|
|
471
|
+
}, 'variables'),
|
|
472
|
+
|
|
473
|
+
get_variables: tool('get_variables', 'List all variable collections and their variables.', {}, 'variables'),
|
|
474
|
+
|
|
475
|
+
update_variable: tool('update_variable', 'Update a variable value.', {
|
|
476
|
+
variableId: req('string', 'Variable ID'),
|
|
477
|
+
value: req('string', 'New value'),
|
|
478
|
+
mode: opt('string', 'Mode to update (updates default if omitted)'),
|
|
479
|
+
}, 'variables'),
|
|
480
|
+
|
|
481
|
+
delete_variable: tool('delete_variable', 'Delete a variable.', {
|
|
482
|
+
variableId: req('string', 'Variable to delete'),
|
|
483
|
+
}, 'variables'),
|
|
484
|
+
|
|
485
|
+
create_design_tokens: tool('create_design_tokens', 'Generate a complete design token system from a brand color. Creates color, spacing, radius, and typography collections.', {
|
|
486
|
+
brandColor: req('string', 'Primary brand color hex'),
|
|
487
|
+
name: opt('string', 'Token set name', 'Design System'),
|
|
488
|
+
withModes: opt('boolean', 'Create Light + Dark modes', true),
|
|
489
|
+
}, 'variables'),
|
|
490
|
+
|
|
491
|
+
import_tokens: tool('import_tokens', 'Import design tokens from JSON (W3C Design Token format).', {
|
|
492
|
+
json: req('string', 'JSON string of design tokens'),
|
|
493
|
+
collectionName: opt('string', 'Collection name'),
|
|
494
|
+
}, 'variables'),
|
|
495
|
+
|
|
496
|
+
export_tokens: tool('export_tokens', 'Export all design tokens as JSON, CSS custom properties, SCSS, or Tailwind config.', {
|
|
497
|
+
format: enm(['json','css','scss','tailwind'], 'Export format', 'json'),
|
|
498
|
+
}, 'variables'),
|
|
499
|
+
|
|
500
|
+
swap_mode: tool('swap_mode', 'Switch the active mode on a variable collection.', {
|
|
501
|
+
collectionId: req('string', 'Collection ID'),
|
|
502
|
+
mode: req('string', 'Mode name to activate'),
|
|
503
|
+
}, 'variables'),
|
|
336
504
|
}
|
|
337
505
|
|
|
338
|
-
|
|
339
|
-
|
|
506
|
+
// ═══ EXPORT & CODE (10) ═══
|
|
507
|
+
const EXPORT = {
|
|
508
|
+
export_as_svg: tool('export_as_svg', 'Export a node as SVG markup.', {
|
|
509
|
+
nodeId: req('string', 'Node to export'),
|
|
510
|
+
}, 'export'),
|
|
511
|
+
|
|
512
|
+
export_as_png: tool('export_as_png', 'Export a node as PNG.', {
|
|
513
|
+
nodeId: req('string', 'Node to export'),
|
|
514
|
+
scale: opt('number', 'Scale factor', 2),
|
|
515
|
+
}, 'export'),
|
|
516
|
+
|
|
517
|
+
export_to_react: tool('export_to_react', 'Generate React + Tailwind code from a Figma node tree.', {
|
|
518
|
+
nodeId: req('string', 'Root node to convert'),
|
|
519
|
+
framework: enm(['react-tailwind','react-css','html-css','vue','svelte'], 'Output framework', 'react-tailwind'),
|
|
520
|
+
componentName: opt('string', 'Root component name'),
|
|
521
|
+
}, 'export'),
|
|
522
|
+
|
|
523
|
+
export_design_specs: tool('export_design_specs', 'Generate design specifications document for developer handoff.', {
|
|
524
|
+
nodeId: req('string', 'Node to document'),
|
|
525
|
+
format: enm(['markdown','json','html'], 'Spec format', 'markdown'),
|
|
526
|
+
}, 'export'),
|
|
527
|
+
|
|
528
|
+
export_assets: tool('export_assets', 'Batch export all exportable assets (icons, images) from a node tree.', {
|
|
529
|
+
nodeId: req('string', 'Root node'),
|
|
530
|
+
format: enm(['svg','png','pdf'], 'Export format', 'svg'),
|
|
531
|
+
scale: opt('number', 'Scale factor', 1),
|
|
532
|
+
}, 'export'),
|
|
533
|
+
|
|
534
|
+
screenshot: tool('screenshot', 'Take a screenshot of the current canvas view or a specific node.', {
|
|
535
|
+
nodeId: opt('string', 'Node to screenshot (uses viewport if omitted)'),
|
|
536
|
+
scale: opt('number', 'Scale factor', 2),
|
|
537
|
+
}, 'export'),
|
|
538
|
+
|
|
539
|
+
copy_css: tool('copy_css', 'Copy CSS properties of a node to clipboard.', {
|
|
540
|
+
nodeId: req('string', 'Node to get CSS for'),
|
|
541
|
+
}, 'export'),
|
|
542
|
+
|
|
543
|
+
generate_stylesheet: tool('generate_stylesheet', 'Generate a complete stylesheet from a design file.', {
|
|
544
|
+
pageId: opt('string', 'Page ID'),
|
|
545
|
+
format: enm(['css','scss','tailwind'], 'Output format', 'css'),
|
|
546
|
+
}, 'export'),
|
|
547
|
+
|
|
548
|
+
export_color_palette: tool('export_color_palette', 'Export all colors used as a palette.', {
|
|
549
|
+
format: enm(['json','css','scss','tailwind','figma-tokens'], 'Format', 'json'),
|
|
550
|
+
}, 'export'),
|
|
551
|
+
|
|
552
|
+
export_typography: tool('export_typography', 'Export all text styles as a typography system.', {
|
|
553
|
+
format: enm(['json','css','scss','tailwind'], 'Format', 'json'),
|
|
554
|
+
}, 'export'),
|
|
555
|
+
|
|
556
|
+
export_component_inventory: tool('export_component_inventory', 'Export a complete inventory of all components with usage counts.', {
|
|
557
|
+
format: enm(['json','markdown','csv'], 'Format', 'json'),
|
|
558
|
+
}, 'export'),
|
|
559
|
+
|
|
560
|
+
export_spacing_tokens: tool('export_spacing_tokens', 'Export all spacing values used as a spacing token system.', {
|
|
561
|
+
format: enm(['json','css','scss','tailwind'], 'Format', 'json'),
|
|
562
|
+
}, 'export'),
|
|
340
563
|
}
|
|
341
564
|
|
|
342
|
-
|
|
343
|
-
|
|
565
|
+
// ═══ ACCESSIBILITY & LINT (12) ═══
|
|
566
|
+
const ACCESSIBILITY = {
|
|
567
|
+
audit_accessibility: tool('audit_accessibility', 'Run a full accessibility audit on a node tree. Checks contrast, touch targets, font sizes, focus indicators.', {
|
|
568
|
+
nodeId: req('string', 'Root node to audit'),
|
|
569
|
+
}, 'accessibility'),
|
|
570
|
+
|
|
571
|
+
check_contrast: tool('check_contrast', 'Check color contrast ratio between two colors.', {
|
|
572
|
+
foreground: req('string', 'Foreground color hex'),
|
|
573
|
+
background: req('string', 'Background color hex'),
|
|
574
|
+
}, 'accessibility'),
|
|
575
|
+
|
|
576
|
+
fix_touch_targets: tool('fix_touch_targets', 'Auto-fix all touch targets below 44px in a node tree.', {
|
|
577
|
+
nodeId: req('string', 'Root node to fix'),
|
|
578
|
+
}, 'accessibility'),
|
|
579
|
+
|
|
580
|
+
lint_design: tool('lint_design', 'Run design lint rules: spacing consistency, naming conventions, color usage, font sizes, alignment.', {
|
|
581
|
+
nodeId: req('string', 'Root node to lint'),
|
|
582
|
+
rules: opt('array', 'Specific rules to check. Omit for all.'),
|
|
583
|
+
}, 'accessibility'),
|
|
584
|
+
|
|
585
|
+
fix_spacing: tool('fix_spacing', 'Auto-fix all spacing values to nearest 8px grid value.', {
|
|
586
|
+
nodeId: req('string', 'Root node to fix'),
|
|
587
|
+
grid: opt('number', 'Grid size', 8),
|
|
588
|
+
}, 'accessibility'),
|
|
589
|
+
|
|
590
|
+
check_naming: tool('check_naming', 'Check layer naming conventions. Flags generic names like "Frame 123", "Group 5".', {
|
|
591
|
+
nodeId: req('string', 'Root node to check'),
|
|
592
|
+
}, 'accessibility'),
|
|
593
|
+
|
|
594
|
+
suggest_improvements: tool('suggest_improvements', 'AI-powered design improvement suggestions based on the design intelligence engine.', {
|
|
595
|
+
nodeId: req('string', 'Node to analyze'),
|
|
596
|
+
}, 'accessibility'),
|
|
597
|
+
|
|
598
|
+
validate_component: tool('validate_component', 'Validate a component follows design system rules.', {
|
|
599
|
+
nodeId: req('string', 'Component to validate'),
|
|
600
|
+
}, 'accessibility'),
|
|
601
|
+
|
|
602
|
+
check_consistency: tool('check_consistency', 'Check for inconsistent colors, fonts, spacing, and radii across a design.', {
|
|
603
|
+
nodeId: req('string', 'Root node to check'),
|
|
604
|
+
}, 'accessibility'),
|
|
605
|
+
|
|
606
|
+
generate_a11y_report: tool('generate_a11y_report', 'Generate a detailed accessibility compliance report.', {
|
|
607
|
+
nodeId: req('string', 'Root node'),
|
|
608
|
+
standard: enm(['WCAG-AA','WCAG-AAA'], 'Compliance standard', 'WCAG-AA'),
|
|
609
|
+
format: enm(['markdown','json','html'], 'Report format', 'markdown'),
|
|
610
|
+
}, 'accessibility'),
|
|
611
|
+
|
|
612
|
+
color_blindness_check: tool('color_blindness_check', 'Simulate color blindness on a design to check for issues.', {
|
|
613
|
+
nodeId: req('string', 'Node to check'),
|
|
614
|
+
type: enm(['protanopia','deuteranopia','tritanopia','achromatopsia'], 'Color blindness type'),
|
|
615
|
+
}, 'accessibility'),
|
|
616
|
+
|
|
617
|
+
responsive_check: tool('responsive_check', 'Check if a design handles different viewport widths correctly.', {
|
|
618
|
+
nodeId: req('string', 'Root frame to check'),
|
|
619
|
+
breakpoints: opt('array', 'Widths to check, e.g. [375, 768, 1024, 1440]'),
|
|
620
|
+
}, 'accessibility'),
|
|
344
621
|
}
|
|
622
|
+
|
|
623
|
+
// ═══ BATCH OPERATIONS (12) ═══
|
|
624
|
+
const BATCH = {
|
|
625
|
+
batch_rename: tool('batch_rename', 'Rename multiple nodes using a pattern.', {
|
|
626
|
+
nodeIds: { type:'array', items:{type:'string'}, description:'Nodes to rename', _required:true },
|
|
627
|
+
pattern: req('string', 'Name pattern. Use {n} for number, {name} for current name. E.g. "Card {n}"'),
|
|
628
|
+
startNumber: opt('number', 'Starting number', 1),
|
|
629
|
+
}, 'batch'),
|
|
630
|
+
|
|
631
|
+
batch_style: tool('batch_style', 'Apply style changes to multiple nodes at once.', {
|
|
632
|
+
nodeIds: { type:'array', items:{type:'string'}, description:'Target nodes', _required:true },
|
|
633
|
+
changes: req('object', 'Style changes: { fill, opacity, cornerRadius, fontSize, fontWeight, ... }'),
|
|
634
|
+
}, 'batch'),
|
|
635
|
+
|
|
636
|
+
batch_replace_text: tool('batch_replace_text', 'Find and replace text across multiple text nodes.', {
|
|
637
|
+
find: req('string', 'Text to find'),
|
|
638
|
+
replace: req('string', 'Replacement text'),
|
|
639
|
+
nodeId: opt('string', 'Scope to search within (uses whole page if omitted)'),
|
|
640
|
+
matchCase: opt('boolean', 'Case sensitive', false),
|
|
641
|
+
}, 'batch'),
|
|
642
|
+
|
|
643
|
+
batch_replace_color: tool('batch_replace_color', 'Replace a color across all nodes.', {
|
|
644
|
+
find: req('string', 'Color to find (hex)'),
|
|
645
|
+
replace: req('string', 'Replacement color (hex)'),
|
|
646
|
+
nodeId: opt('string', 'Scope node'),
|
|
647
|
+
}, 'batch'),
|
|
648
|
+
|
|
649
|
+
batch_resize: tool('batch_resize', 'Resize multiple nodes.', {
|
|
650
|
+
nodeIds: { type:'array', items:{type:'string'}, description:'Target nodes', _required:true },
|
|
651
|
+
width: opt('number','New width'), height: opt('number','New height'),
|
|
652
|
+
scale: opt('number', 'Scale factor'),
|
|
653
|
+
}, 'batch'),
|
|
654
|
+
|
|
655
|
+
batch_align: tool('batch_align', 'Align multiple nodes.', {
|
|
656
|
+
nodeIds: { type:'array', items:{type:'string'}, description:'Nodes to align', _required:true },
|
|
657
|
+
horizontal: enm(['LEFT','CENTER','RIGHT','DISTRIBUTE'], 'H alignment'),
|
|
658
|
+
vertical: enm(['TOP','MIDDLE','BOTTOM','DISTRIBUTE'], 'V alignment'),
|
|
659
|
+
}, 'batch'),
|
|
660
|
+
|
|
661
|
+
batch_delete: tool('batch_delete', 'Delete multiple nodes.', {
|
|
662
|
+
nodeIds: { type:'array', items:{type:'string'}, description:'Nodes to delete', _required:true },
|
|
663
|
+
}, 'batch'),
|
|
664
|
+
|
|
665
|
+
batch_duplicate: tool('batch_duplicate', 'Duplicate multiple nodes.', {
|
|
666
|
+
nodeIds: { type:'array', items:{type:'string'}, description:'Nodes to duplicate', _required:true },
|
|
667
|
+
offsetX: opt('number', 'X offset per copy'), offsetY: opt('number', 'Y offset per copy'),
|
|
668
|
+
}, 'batch'),
|
|
669
|
+
|
|
670
|
+
batch_set_visibility: tool('batch_set_visibility', 'Show/hide multiple nodes.', {
|
|
671
|
+
nodeIds: { type:'array', items:{type:'string'}, description:'Target nodes', _required:true },
|
|
672
|
+
visible: req('boolean', 'Visibility state'),
|
|
673
|
+
}, 'batch'),
|
|
674
|
+
|
|
675
|
+
batch_lock: tool('batch_lock', 'Lock/unlock multiple nodes.', {
|
|
676
|
+
nodeIds: { type:'array', items:{type:'string'}, description:'Target nodes', _required:true },
|
|
677
|
+
locked: req('boolean', 'Lock state'),
|
|
678
|
+
}, 'batch'),
|
|
679
|
+
|
|
680
|
+
select_all_by_type: tool('select_all_by_type', 'Select all nodes of a specific type.', {
|
|
681
|
+
type: enm(['FRAME','TEXT','RECTANGLE','ELLIPSE','COMPONENT','INSTANCE','GROUP'], 'Node type'),
|
|
682
|
+
withinId: opt('string', 'Scope node'),
|
|
683
|
+
}, 'batch'),
|
|
684
|
+
|
|
685
|
+
clean_hidden_layers: tool('clean_hidden_layers', 'Remove all hidden layers from a node tree.', {
|
|
686
|
+
nodeId: req('string', 'Root node to clean'),
|
|
687
|
+
dryRun: opt('boolean', 'Preview changes without deleting', false),
|
|
688
|
+
}, 'batch'),
|
|
689
|
+
|
|
690
|
+
batch_set_font: tool('batch_set_font', 'Change font family on all text nodes in a scope.', {
|
|
691
|
+
fontFamily: req('string', 'New font family'),
|
|
692
|
+
nodeId: opt('string', 'Scope'),
|
|
693
|
+
}, 'batch'),
|
|
694
|
+
|
|
695
|
+
batch_round_values: tool('batch_round_values', 'Round all dimensions, positions, and spacing to whole pixels.', {
|
|
696
|
+
nodeId: req('string', 'Root node'),
|
|
697
|
+
}, 'batch'),
|
|
698
|
+
|
|
699
|
+
batch_remove_strokes: tool('batch_remove_strokes', 'Remove all strokes from nodes in a scope.', {
|
|
700
|
+
nodeId: req('string', 'Root node'),
|
|
701
|
+
}, 'batch'),
|
|
702
|
+
|
|
703
|
+
batch_remove_effects: tool('batch_remove_effects', 'Remove all effects from nodes in a scope.', {
|
|
704
|
+
nodeId: req('string', 'Root node'),
|
|
705
|
+
}, 'batch'),
|
|
706
|
+
|
|
707
|
+
batch_set_corner_radius: tool('batch_set_corner_radius', 'Set corner radius on all frames/rectangles in scope.', {
|
|
708
|
+
nodeId: req('string', 'Root node'),
|
|
709
|
+
radius: req('number', 'Corner radius'),
|
|
710
|
+
}, 'batch'),
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// ═══ DESIGN SYSTEM (10) ═══
|
|
714
|
+
const DESIGN_SYSTEM = {
|
|
715
|
+
scan_design_system: tool('scan_design_system', 'Scan a file and extract the implied design system: colors, fonts, spacing, components.', {
|
|
716
|
+
pageId: opt('string', 'Page to scan'),
|
|
717
|
+
}, 'design-system'),
|
|
718
|
+
|
|
719
|
+
create_style_guide: tool('create_style_guide', 'Generate a visual style guide page from the current design system.', {
|
|
720
|
+
brandColor: opt('string', 'Brand color to use'),
|
|
721
|
+
mode: enm(['dark','light'], 'Mode', 'dark'),
|
|
722
|
+
}, 'design-system'),
|
|
723
|
+
|
|
724
|
+
detect_inconsistencies: tool('detect_inconsistencies', 'Find design inconsistencies: off-grid spacing, non-standard colors, mismatched fonts.', {
|
|
725
|
+
nodeId: opt('string', 'Scope node'),
|
|
726
|
+
}, 'design-system'),
|
|
727
|
+
|
|
728
|
+
normalize_design: tool('normalize_design', 'Auto-fix a design to match the implied design system. Snaps spacing, normalizes colors, fixes font weights.', {
|
|
729
|
+
nodeId: req('string', 'Root node to normalize'),
|
|
730
|
+
dryRun: opt('boolean', 'Preview changes', false),
|
|
731
|
+
}, 'design-system'),
|
|
732
|
+
|
|
733
|
+
extract_components: tool('extract_components', 'Find repeated patterns and suggest component extraction.', {
|
|
734
|
+
nodeId: req('string', 'Root node to analyze'),
|
|
735
|
+
}, 'design-system'),
|
|
736
|
+
|
|
737
|
+
get_design_craft_guide: tool('get_design_craft_guide', 'Get the professional design rules: typography, color, spacing, anti-AI-slop patterns. Use this before creating any design.', {}, 'design-system'),
|
|
738
|
+
|
|
739
|
+
suggest_color_palette: tool('suggest_color_palette', 'Generate a color palette from a single brand color.', {
|
|
740
|
+
brandColor: req('string', 'Brand color hex'),
|
|
741
|
+
mode: enm(['dark','light','both'], 'Mode', 'both'),
|
|
742
|
+
}, 'design-system'),
|
|
743
|
+
|
|
744
|
+
suggest_type_scale: tool('suggest_type_scale', 'Generate a typography scale.', {
|
|
745
|
+
baseSize: opt('number', 'Base font size', 16),
|
|
746
|
+
ratio: enm(['minor2','major2','minor3','major3','perfect4','aug4','perfect5','golden'], 'Scale ratio', 'major2'),
|
|
747
|
+
}, 'design-system'),
|
|
748
|
+
|
|
749
|
+
import_design_system: tool('import_design_system', 'Import a design system from JSON config and create all tokens, styles, and components.', {
|
|
750
|
+
config: req('string', 'JSON config string with colors, fonts, spacing, components'),
|
|
751
|
+
}, 'design-system'),
|
|
752
|
+
|
|
753
|
+
compare_to_system: tool('compare_to_system', 'Compare a design to the established design system and flag deviations.', {
|
|
754
|
+
nodeId: req('string', 'Node to compare'),
|
|
755
|
+
}, 'design-system'),
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
// ═══ RESPONSIVE (5) ═══
|
|
759
|
+
const RESPONSIVE = {
|
|
760
|
+
create_responsive_variant: tool('create_responsive_variant', 'Create mobile/tablet/desktop variants of a frame.', {
|
|
761
|
+
nodeId: req('string', 'Source frame'),
|
|
762
|
+
breakpoints: opt('array', 'Target widths', [375, 768, 1440]),
|
|
763
|
+
}, 'responsive'),
|
|
764
|
+
|
|
765
|
+
set_breakpoint: tool('set_breakpoint', 'Resize a frame to a standard breakpoint.', {
|
|
766
|
+
nodeId: req('string', 'Frame to resize'),
|
|
767
|
+
breakpoint: enm(['mobile','tablet','desktop','wide'], 'Breakpoint'),
|
|
768
|
+
}, 'responsive'),
|
|
769
|
+
|
|
770
|
+
convert_to_responsive: tool('convert_to_responsive', 'Convert fixed-width designs to responsive auto-layout.', {
|
|
771
|
+
nodeId: req('string', 'Root frame to convert'),
|
|
772
|
+
}, 'responsive'),
|
|
773
|
+
|
|
774
|
+
generate_mobile: tool('generate_mobile', 'Generate a mobile-optimized version of a desktop design.', {
|
|
775
|
+
nodeId: req('string', 'Desktop frame'),
|
|
776
|
+
width: opt('number', 'Mobile width', 375),
|
|
777
|
+
}, 'responsive'),
|
|
778
|
+
|
|
779
|
+
stack_for_mobile: tool('stack_for_mobile', 'Convert horizontal layouts to vertical stacking for mobile.', {
|
|
780
|
+
nodeId: req('string', 'Frame with horizontal layout'),
|
|
781
|
+
}, 'responsive'),
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
// ═══ TYPOGRAPHY (10) ═══
|
|
785
|
+
const TYPOGRAPHY = {
|
|
786
|
+
type_scale_apply: tool('type_scale_apply', 'Apply a type scale to all text in a frame. Maps headings, body, and caption sizes to the scale.', {
|
|
787
|
+
nodeId: req('string', 'Root frame'),
|
|
788
|
+
ratio: enm(['minor2','major2','minor3','major3','perfect4','aug4','perfect5','golden'], 'Scale ratio', 'major2'),
|
|
789
|
+
baseSize: opt('number', 'Base font size', 16),
|
|
790
|
+
}, 'typography'),
|
|
791
|
+
|
|
792
|
+
type_audit: tool('type_audit', 'Find every unique text style in a page. Flag off-scale sizes, inconsistent weights, and orphaned styles.', {
|
|
793
|
+
nodeId: opt('string', 'Scope node (page if omitted)'),
|
|
794
|
+
}, 'typography'),
|
|
795
|
+
|
|
796
|
+
type_set_hierarchy: tool('type_set_hierarchy', 'Set heading levels with proper size, weight, and line-height ratios.', {
|
|
797
|
+
nodeId: req('string', 'Root frame'),
|
|
798
|
+
levels: opt('number', 'Number of heading levels', 6),
|
|
799
|
+
}, 'typography'),
|
|
800
|
+
|
|
801
|
+
type_check_measure: tool('type_check_measure', 'Check line length (45-75 chars optimal), line-height, and letter-spacing for readability.', {
|
|
802
|
+
nodeId: req('string', 'Text node or frame to check'),
|
|
803
|
+
}, 'typography'),
|
|
804
|
+
|
|
805
|
+
type_normalize: tool('type_normalize', 'Normalize all text to the nearest type scale value. Fix off-scale sizes.', {
|
|
806
|
+
nodeId: req('string', 'Root frame'),
|
|
807
|
+
ratio: enm(['minor2','major2','minor3','major3','perfect4'], 'Scale ratio', 'major2'),
|
|
808
|
+
}, 'typography'),
|
|
809
|
+
|
|
810
|
+
type_list_styles: tool('type_list_styles', 'List all text styles with usage count.', {
|
|
811
|
+
nodeId: opt('string', 'Scope'),
|
|
812
|
+
}, 'typography'),
|
|
813
|
+
|
|
814
|
+
type_pair_suggest: tool('type_pair_suggest', 'Suggest font pairings based on currently loaded fonts.', {
|
|
815
|
+
primaryFont: opt('string', 'Primary font family'),
|
|
816
|
+
}, 'typography'),
|
|
817
|
+
|
|
818
|
+
type_replace_font: tool('type_replace_font', 'Replace one font family with another across all text nodes.', {
|
|
819
|
+
find: req('string', 'Font to replace'),
|
|
820
|
+
replace: req('string', 'Replacement font'),
|
|
821
|
+
nodeId: opt('string', 'Scope'),
|
|
822
|
+
}, 'typography'),
|
|
823
|
+
|
|
824
|
+
set_text_content: tool('set_text_content', 'Update text content of a text node without changing styles.', {
|
|
825
|
+
nodeId: req('string', 'Text node ID'),
|
|
826
|
+
text: req('string', 'New text content'),
|
|
827
|
+
}, 'typography'),
|
|
828
|
+
|
|
829
|
+
type_create_style: tool('type_create_style', 'Create a local text style from a text node.', {
|
|
830
|
+
nodeId: req('string', 'Text node to create style from'),
|
|
831
|
+
name: req('string', 'Style name'),
|
|
832
|
+
}, 'typography'),
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// ═══ COLOR (10) ═══
|
|
836
|
+
const COLOR = {
|
|
837
|
+
color_palette_generate: tool('color_palette_generate', 'Generate a full color palette (50-950 shades) from a base color.', {
|
|
838
|
+
baseColor: req('string', 'Base color hex'),
|
|
839
|
+
steps: opt('number', 'Number of shade steps', 10),
|
|
840
|
+
}, 'color'),
|
|
841
|
+
|
|
842
|
+
color_extract: tool('color_extract', 'Extract all unique colors from a frame and organize by usage frequency.', {
|
|
843
|
+
nodeId: req('string', 'Root node'),
|
|
844
|
+
}, 'color'),
|
|
845
|
+
|
|
846
|
+
color_harmonize: tool('color_harmonize', 'Generate harmonious colors: complementary, triadic, analogous, split-complementary.', {
|
|
847
|
+
baseColor: req('string', 'Base color hex'),
|
|
848
|
+
scheme: enm(['complementary','triadic','analogous','split-complementary','tetradic','monochromatic'], 'Color scheme'),
|
|
849
|
+
}, 'color'),
|
|
850
|
+
|
|
851
|
+
color_darkmode: tool('color_darkmode', 'Generate a dark mode variant of a frame, mapping all colors intelligently.', {
|
|
852
|
+
nodeId: req('string', 'Frame to convert'),
|
|
853
|
+
brandColor: opt('string', 'Brand color to preserve'),
|
|
854
|
+
}, 'color'),
|
|
855
|
+
|
|
856
|
+
color_lightmode: tool('color_lightmode', 'Generate a light mode variant of a dark frame.', {
|
|
857
|
+
nodeId: req('string', 'Frame to convert'),
|
|
858
|
+
brandColor: opt('string', 'Brand color to preserve'),
|
|
859
|
+
}, 'color'),
|
|
860
|
+
|
|
861
|
+
color_check_all: tool('color_check_all', 'Check WCAG contrast for every text/background pair in a frame.', {
|
|
862
|
+
nodeId: req('string', 'Root frame'),
|
|
863
|
+
standard: enm(['AA','AAA'], 'WCAG standard', 'AA'),
|
|
864
|
+
}, 'color'),
|
|
865
|
+
|
|
866
|
+
color_create_style: tool('color_create_style', 'Create a local color style.', {
|
|
867
|
+
name: req('string', 'Style name (e.g. "Primary/500")'),
|
|
868
|
+
color: req('string', 'Color hex'),
|
|
869
|
+
}, 'color'),
|
|
870
|
+
|
|
871
|
+
color_apply_style: tool('color_apply_style', 'Apply a color style to a node.', {
|
|
872
|
+
nodeId: req('string', 'Target node'),
|
|
873
|
+
styleName: req('string', 'Style name to apply'),
|
|
874
|
+
property: enm(['fill','stroke'], 'Property to apply to', 'fill'),
|
|
875
|
+
}, 'color'),
|
|
876
|
+
|
|
877
|
+
color_replace_global: tool('color_replace_global', 'Replace a color across the entire document (all pages).', {
|
|
878
|
+
find: req('string', 'Color to find (hex)'),
|
|
879
|
+
replace: req('string', 'Replacement color (hex)'),
|
|
880
|
+
}, 'color'),
|
|
881
|
+
|
|
882
|
+
color_generate_semantic: tool('color_generate_semantic', 'Generate a full semantic color system (bg, surface, border, text, brand, status) from one brand color.', {
|
|
883
|
+
brandColor: req('string', 'Brand color hex'),
|
|
884
|
+
mode: enm(['dark','light','both'], 'Color mode', 'both'),
|
|
885
|
+
}, 'color'),
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
// ═══ PROTOTYPE & INTERACTION (10) ═══
|
|
889
|
+
const PROTOTYPE = {
|
|
890
|
+
create_prototype_link: tool('create_prototype_link', 'Create a prototype navigation link between two frames.', {
|
|
891
|
+
fromNodeId: req('string', 'Source node (trigger)'),
|
|
892
|
+
toNodeId: req('string', 'Destination frame'),
|
|
893
|
+
trigger: enm(['ON_CLICK','ON_HOVER','ON_PRESS','ON_DRAG','AFTER_TIMEOUT','MOUSE_ENTER','MOUSE_LEAVE','MOUSE_DOWN','MOUSE_UP'], 'Interaction trigger', 'ON_CLICK'),
|
|
894
|
+
transition: enm(['INSTANT','DISSOLVE','SLIDE_IN','SLIDE_OUT','PUSH','MOVE_IN','MOVE_OUT','SMART_ANIMATE'], 'Transition type', 'DISSOLVE'),
|
|
895
|
+
duration: opt('number', 'Transition duration ms', 300),
|
|
896
|
+
}, 'prototype'),
|
|
897
|
+
|
|
898
|
+
create_scroll_behavior: tool('create_scroll_behavior', 'Set scroll behavior on a frame.', {
|
|
899
|
+
nodeId: req('string', 'Frame node'),
|
|
900
|
+
direction: enm(['HORIZONTAL','VERTICAL','BOTH','NONE'], 'Scroll direction'),
|
|
901
|
+
overflow: enm(['VISIBLE','HIDDEN','SCROLL'], 'Overflow behavior', 'SCROLL'),
|
|
902
|
+
}, 'prototype'),
|
|
903
|
+
|
|
904
|
+
set_overflow: tool('set_overflow', 'Set overflow clipping on a frame.', {
|
|
905
|
+
nodeId: req('string', 'Frame node'),
|
|
906
|
+
clip: req('boolean', 'Clip content'),
|
|
907
|
+
}, 'prototype'),
|
|
908
|
+
|
|
909
|
+
create_overlay: tool('create_overlay', 'Set up a frame as a modal/overlay in prototype mode.', {
|
|
910
|
+
nodeId: req('string', 'Overlay frame'),
|
|
911
|
+
position: enm(['CENTER','TOP_LEFT','TOP_CENTER','TOP_RIGHT','BOTTOM_LEFT','BOTTOM_CENTER','BOTTOM_RIGHT','MANUAL'], 'Overlay position', 'CENTER'),
|
|
912
|
+
closeOnClickOutside: opt('boolean', 'Close when clicking outside', true),
|
|
913
|
+
backgroundDim: opt('number', 'Background dim opacity 0-1', 0.5),
|
|
914
|
+
}, 'prototype'),
|
|
915
|
+
|
|
916
|
+
set_fixed_position: tool('set_fixed_position', 'Pin a layer so it stays fixed during scroll (sticky nav, floating button).', {
|
|
917
|
+
nodeId: req('string', 'Node to pin'),
|
|
918
|
+
position: enm(['TOP','BOTTOM','LEFT','RIGHT'], 'Fixed position'),
|
|
919
|
+
}, 'prototype'),
|
|
920
|
+
|
|
921
|
+
create_hover_state: tool('create_hover_state', 'Create a hover variant interaction on a component.', {
|
|
922
|
+
nodeId: req('string', 'Component or instance'),
|
|
923
|
+
hoverVariant: req('string', 'Variant name for hover state'),
|
|
924
|
+
}, 'prototype'),
|
|
925
|
+
|
|
926
|
+
create_flow: tool('create_flow', 'Create a prototype flow starting point.', {
|
|
927
|
+
nodeId: req('string', 'Starting frame'),
|
|
928
|
+
name: req('string', 'Flow name'),
|
|
929
|
+
}, 'prototype'),
|
|
930
|
+
|
|
931
|
+
list_flows: tool('list_flows', 'List all prototype flows in the file.', {}, 'prototype'),
|
|
932
|
+
|
|
933
|
+
remove_prototype_link: tool('remove_prototype_link', 'Remove a prototype connection.', {
|
|
934
|
+
nodeId: req('string', 'Node to remove connection from'),
|
|
935
|
+
}, 'prototype'),
|
|
936
|
+
|
|
937
|
+
set_transition: tool('set_transition', 'Set the default transition for all prototype links on a frame.', {
|
|
938
|
+
nodeId: req('string', 'Frame node'),
|
|
939
|
+
transition: enm(['INSTANT','DISSOLVE','SLIDE_IN','SMART_ANIMATE'], 'Transition'),
|
|
940
|
+
duration: opt('number', 'Duration ms', 300),
|
|
941
|
+
easing: enm(['LINEAR','EASE_IN','EASE_OUT','EASE_IN_OUT','EASE_IN_BACK','EASE_OUT_BACK','CUSTOM_SPRING'], 'Easing', 'EASE_OUT'),
|
|
942
|
+
}, 'prototype'),
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
// ═══ PAGE MANAGEMENT (8) ═══
|
|
946
|
+
const PAGE = {
|
|
947
|
+
create_new_page: tool('create_new_page', 'Create a new page in the document.', {
|
|
948
|
+
name: req('string', 'Page name'),
|
|
949
|
+
}, 'page'),
|
|
950
|
+
|
|
951
|
+
switch_page: tool('switch_page', 'Switch to a different page.', {
|
|
952
|
+
pageId: req('string', 'Page ID or name'),
|
|
953
|
+
}, 'page'),
|
|
954
|
+
|
|
955
|
+
duplicate_page: tool('duplicate_page', 'Duplicate an entire page.', {
|
|
956
|
+
pageId: req('string', 'Page to duplicate'),
|
|
957
|
+
name: opt('string', 'New page name'),
|
|
958
|
+
}, 'page'),
|
|
959
|
+
|
|
960
|
+
delete_page: tool('delete_page', 'Delete a page.', {
|
|
961
|
+
pageId: req('string', 'Page to delete'),
|
|
962
|
+
}, 'page'),
|
|
963
|
+
|
|
964
|
+
rename_page: tool('rename_page', 'Rename a page.', {
|
|
965
|
+
pageId: req('string', 'Page ID'),
|
|
966
|
+
name: req('string', 'New name'),
|
|
967
|
+
}, 'page'),
|
|
968
|
+
|
|
969
|
+
sort_pages: tool('sort_pages', 'Sort pages alphabetically or by custom order.', {
|
|
970
|
+
order: enm(['ALPHABETICAL','REVERSE','CUSTOM'], 'Sort order'),
|
|
971
|
+
customOrder: opt('array', 'Array of page IDs in desired order'),
|
|
972
|
+
}, 'page'),
|
|
973
|
+
|
|
974
|
+
merge_pages: tool('merge_pages', 'Move all content from one page into another.', {
|
|
975
|
+
sourcePageId: req('string', 'Page to merge from'),
|
|
976
|
+
targetPageId: req('string', 'Page to merge into'),
|
|
977
|
+
}, 'page'),
|
|
978
|
+
|
|
979
|
+
page_overview: tool('page_overview', 'Get an overview of all pages: name, frame count, component count.', {}, 'page'),
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
// ═══ LIBRARY & COMPONENTS EXTENDED (8) ═══
|
|
983
|
+
const LIBRARY = {
|
|
984
|
+
search_library: tool('search_library', 'Search for components across local file and team libraries.', {
|
|
985
|
+
query: req('string', 'Search query'),
|
|
986
|
+
scope: enm(['LOCAL','TEAM','ALL'], 'Search scope', 'ALL'),
|
|
987
|
+
}, 'library'),
|
|
988
|
+
|
|
989
|
+
list_team_libraries: tool('list_team_libraries', 'List all available team libraries.', {}, 'library'),
|
|
990
|
+
|
|
991
|
+
swap_component: tool('swap_component', 'Swap one component instance for another.', {
|
|
992
|
+
instanceId: req('string', 'Instance to swap'),
|
|
993
|
+
newComponentId: req('string', 'New component ID'),
|
|
994
|
+
preserveOverrides: opt('boolean', 'Keep existing overrides', true),
|
|
995
|
+
}, 'library'),
|
|
996
|
+
|
|
997
|
+
detach_instance: tool('detach_instance', 'Detach a component instance to a regular frame.', {
|
|
998
|
+
nodeId: req('string', 'Instance to detach'),
|
|
999
|
+
}, 'library'),
|
|
1000
|
+
|
|
1001
|
+
reset_overrides: tool('reset_overrides', 'Reset all overrides on a component instance.', {
|
|
1002
|
+
nodeId: req('string', 'Instance node'),
|
|
1003
|
+
}, 'library'),
|
|
1004
|
+
|
|
1005
|
+
component_audit: tool('component_audit', 'Audit components: find detached instances, missing components, unused variants.', {
|
|
1006
|
+
nodeId: opt('string', 'Scope'),
|
|
1007
|
+
}, 'library'),
|
|
1008
|
+
|
|
1009
|
+
batch_swap_component: tool('batch_swap_component', 'Swap all instances of one component for another across the file.', {
|
|
1010
|
+
oldComponentId: req('string', 'Component to replace'),
|
|
1011
|
+
newComponentId: req('string', 'Replacement component'),
|
|
1012
|
+
}, 'library'),
|
|
1013
|
+
|
|
1014
|
+
publish_components: tool('publish_components', 'Mark components as ready to publish to team library.', {
|
|
1015
|
+
componentIds: { type:'array', items:{type:'string'}, description:'Components to mark', _required:true },
|
|
1016
|
+
}, 'library'),
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
// ═══ ANNOTATION & HANDOFF (10) ═══
|
|
1020
|
+
const ANNOTATION = {
|
|
1021
|
+
annotate_spacing: tool('annotate_spacing', 'Add visual spacing annotations (redlines) to a frame.', {
|
|
1022
|
+
nodeId: req('string', 'Frame to annotate'),
|
|
1023
|
+
showPadding: opt('boolean', 'Show padding values', true),
|
|
1024
|
+
showGap: opt('boolean', 'Show gap values', true),
|
|
1025
|
+
showMargin: opt('boolean', 'Show margin values', true),
|
|
1026
|
+
}, 'annotation'),
|
|
1027
|
+
|
|
1028
|
+
annotate_colors: tool('annotate_colors', 'Add color swatch annotations to a frame.', {
|
|
1029
|
+
nodeId: req('string', 'Frame to annotate'),
|
|
1030
|
+
}, 'annotation'),
|
|
1031
|
+
|
|
1032
|
+
annotate_typography: tool('annotate_typography', 'Add typography annotations (font, size, weight, line-height) to text nodes.', {
|
|
1033
|
+
nodeId: req('string', 'Frame to annotate'),
|
|
1034
|
+
}, 'annotation'),
|
|
1035
|
+
|
|
1036
|
+
create_measurement: tool('create_measurement', 'Create a measurement line between two nodes showing distance.', {
|
|
1037
|
+
nodeId1: req('string', 'First node'),
|
|
1038
|
+
nodeId2: req('string', 'Second node'),
|
|
1039
|
+
direction: enm(['HORIZONTAL','VERTICAL','AUTO'], 'Measurement direction', 'AUTO'),
|
|
1040
|
+
}, 'annotation'),
|
|
1041
|
+
|
|
1042
|
+
create_spec_sheet: tool('create_spec_sheet', 'Generate a design specification sheet next to a frame with all measurements, colors, and typography.', {
|
|
1043
|
+
nodeId: req('string', 'Frame to spec'),
|
|
1044
|
+
position: enm(['RIGHT','BELOW'], 'Where to place spec', 'RIGHT'),
|
|
1045
|
+
}, 'annotation'),
|
|
1046
|
+
|
|
1047
|
+
annotate_grid: tool('annotate_grid', 'Visualize the underlying grid and spacing system of a frame.', {
|
|
1048
|
+
nodeId: req('string', 'Frame to annotate'),
|
|
1049
|
+
gridSize: opt('number', 'Grid size to overlay', 8),
|
|
1050
|
+
}, 'annotation'),
|
|
1051
|
+
|
|
1052
|
+
annotate_hierarchy: tool('annotate_hierarchy', 'Annotate the visual hierarchy: heading levels, reading order, focal points.', {
|
|
1053
|
+
nodeId: req('string', 'Frame to annotate'),
|
|
1054
|
+
}, 'annotation'),
|
|
1055
|
+
|
|
1056
|
+
create_component_docs: tool('create_component_docs', 'Generate documentation frames for a component showing all variants, props, and usage.', {
|
|
1057
|
+
componentId: req('string', 'Component to document'),
|
|
1058
|
+
}, 'annotation'),
|
|
1059
|
+
|
|
1060
|
+
annotate_responsive: tool('annotate_responsive', 'Annotate breakpoint behavior and responsive rules on a frame.', {
|
|
1061
|
+
nodeId: req('string', 'Frame to annotate'),
|
|
1062
|
+
breakpoints: opt('array', 'Breakpoints to annotate'),
|
|
1063
|
+
}, 'annotation'),
|
|
1064
|
+
|
|
1065
|
+
create_changelog: tool('create_changelog', 'Compare two frames and generate a visual changelog showing what changed.', {
|
|
1066
|
+
beforeNodeId: req('string', 'Before frame'),
|
|
1067
|
+
afterNodeId: req('string', 'After frame'),
|
|
1068
|
+
}, 'annotation'),
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
// ═══ EFFECTS & STYLES EXTENDED (8) ═══
|
|
1072
|
+
const EFFECTS = {
|
|
1073
|
+
create_glassmorphism: tool('create_glassmorphism', 'Apply glassmorphism effect: background blur, semi-transparent fill, subtle border.', {
|
|
1074
|
+
nodeId: req('string', 'Target frame'),
|
|
1075
|
+
blur: opt('number', 'Blur amount', 16),
|
|
1076
|
+
opacity: opt('number', 'Background opacity', 0.1),
|
|
1077
|
+
}, 'effects'),
|
|
1078
|
+
|
|
1079
|
+
create_neumorphism: tool('create_neumorphism', 'Apply neumorphism effect: dual shadows (light + dark) with matching background.', {
|
|
1080
|
+
nodeId: req('string', 'Target node'),
|
|
1081
|
+
intensity: opt('number', 'Effect intensity 0-1', 0.5),
|
|
1082
|
+
}, 'effects'),
|
|
1083
|
+
|
|
1084
|
+
create_noise_texture: tool('create_noise_texture', 'Add a subtle noise/grain texture overlay to a frame.', {
|
|
1085
|
+
nodeId: req('string', 'Target frame'),
|
|
1086
|
+
opacity: opt('number', 'Noise opacity', 0.05),
|
|
1087
|
+
scale: opt('number', 'Noise scale', 1),
|
|
1088
|
+
}, 'effects'),
|
|
1089
|
+
|
|
1090
|
+
set_gradient_fill: tool('set_gradient_fill', 'Set a gradient fill with a simple angle + 2 colors API.', {
|
|
1091
|
+
nodeId: req('string', 'Target node'),
|
|
1092
|
+
startColor: req('string', 'Start color hex'),
|
|
1093
|
+
endColor: req('string', 'End color hex'),
|
|
1094
|
+
angle: opt('number', 'Gradient angle in degrees', 180),
|
|
1095
|
+
}, 'effects'),
|
|
1096
|
+
|
|
1097
|
+
create_shadow_system: tool('create_shadow_system', 'Generate a consistent shadow elevation system (sm, md, lg, xl) as effect styles.', {
|
|
1098
|
+
baseColor: opt('string', 'Shadow base color', '#000000'),
|
|
1099
|
+
scale: enm(['subtle','medium','dramatic'], 'Shadow intensity', 'medium'),
|
|
1100
|
+
}, 'effects'),
|
|
1101
|
+
|
|
1102
|
+
apply_backdrop_blur: tool('apply_backdrop_blur', 'Apply background blur (frosted glass effect) to a frame.', {
|
|
1103
|
+
nodeId: req('string', 'Target frame'),
|
|
1104
|
+
amount: opt('number', 'Blur amount', 16),
|
|
1105
|
+
}, 'effects'),
|
|
1106
|
+
|
|
1107
|
+
create_border_gradient: tool('create_border_gradient', 'Create a gradient border effect using a slightly larger frame behind.', {
|
|
1108
|
+
nodeId: req('string', 'Target node'),
|
|
1109
|
+
startColor: req('string', 'Start color hex'),
|
|
1110
|
+
endColor: req('string', 'End color hex'),
|
|
1111
|
+
width: opt('number', 'Border width', 1),
|
|
1112
|
+
}, 'effects'),
|
|
1113
|
+
|
|
1114
|
+
remove_all_effects: tool('remove_all_effects', 'Remove all effects (shadows, blurs) from a node.', {
|
|
1115
|
+
nodeId: req('string', 'Target node'),
|
|
1116
|
+
}, 'effects'),
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
// ═══ ASSEMBLE ALL TOOLS ═══
|
|
1120
|
+
export const ALL_TOOLS = {
|
|
1121
|
+
...CREATE, ...MODIFY, ...VECTOR, ...READ,
|
|
1122
|
+
...VARIABLES, ...EXPORT, ...ACCESSIBILITY,
|
|
1123
|
+
...BATCH, ...DESIGN_SYSTEM, ...RESPONSIVE,
|
|
1124
|
+
...TYPOGRAPHY, ...COLOR, ...PROTOTYPE,
|
|
1125
|
+
...PAGE, ...LIBRARY, ...ANNOTATION, ...EFFECTS,
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
export const TOOL_LIST = Object.values(ALL_TOOLS)
|
|
1129
|
+
export const TOOL_COUNT = Object.keys(ALL_TOOLS).length
|
|
1130
|
+
|
|
1131
|
+
export const CATEGORIES = {
|
|
1132
|
+
create: Object.keys(CREATE),
|
|
1133
|
+
modify: Object.keys(MODIFY),
|
|
1134
|
+
vector: Object.keys(VECTOR),
|
|
1135
|
+
read: Object.keys(READ),
|
|
1136
|
+
variables: Object.keys(VARIABLES),
|
|
1137
|
+
export: Object.keys(EXPORT),
|
|
1138
|
+
accessibility: Object.keys(ACCESSIBILITY),
|
|
1139
|
+
batch: Object.keys(BATCH),
|
|
1140
|
+
'design-system': Object.keys(DESIGN_SYSTEM),
|
|
1141
|
+
responsive: Object.keys(RESPONSIVE),
|
|
1142
|
+
typography: Object.keys(TYPOGRAPHY),
|
|
1143
|
+
color: Object.keys(COLOR),
|
|
1144
|
+
prototype: Object.keys(PROTOTYPE),
|
|
1145
|
+
page: Object.keys(PAGE),
|
|
1146
|
+
library: Object.keys(LIBRARY),
|
|
1147
|
+
annotation: Object.keys(ANNOTATION),
|
|
1148
|
+
effects: Object.keys(EFFECTS),
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
export function getTool(name) { return ALL_TOOLS[name] || null }
|
|
1152
|
+
export function getToolsByCategory(cat) { return CATEGORIES[cat] || [] }
|