conductor-figma 3.0.3 → 3.0.4

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/README.md CHANGED
@@ -1,27 +1,32 @@
1
1
  # conductor-figma
2
2
 
3
- Design-intelligent MCP server for Figma. 201 tools across 17 categories. Every tool has built-in design intelligence — 8px grid, type scales, semantic colors, accessibility checks, component defaults. Not a shape proxy. A design engine.
3
+ Design-intelligent MCP server for Figma. 201 tools across 17 categories. Every tool has built-in design intelligence — 8px grid, type scales, semantic colors, accessibility checks, component defaults. Works with Cursor and Claude Code.
4
4
 
5
5
  ```
6
6
  npx conductor-figma
7
7
  ```
8
8
 
9
- ## What makes this different
9
+ ## How to use
10
10
 
11
+ ### 1. Clone the repo (for the Figma plugin)
11
12
 
12
- **Conductor** has 201 tools with design intelligence. You say "create a button" and it knows: 44px height (touch target), 20px horizontal padding (8px grid), 10px radius, 15px Semi Bold text. Every value is intentional.
13
+ ```bash
14
+ git clone https://github.com/dragoon0x/conductor.git
15
+ ```
13
16
 
14
- ## Setup
17
+ ### 2. Import the Figma plugin
15
18
 
16
- ### 1. Figma Plugin
19
+ Open Figma Desktop:
17
20
 
18
- ```
19
- git clone https://github.com/dragoon0x/conductor.git
20
- ```
21
+ 1. Go to **Plugins → Development → Import plugin from manifest**
22
+ 2. Navigate to `conductor/figma-plugin/manifest.json`
23
+ 3. Click **Open**
24
+
25
+ The plugin is now installed. You only need to do this once.
21
26
 
22
- In Figma: **Plugins Development → Import plugin from manifest** → select `conductor/figma-plugin/manifest.json`
27
+ ### 3. Add to Cursor
23
28
 
24
- ### 2. Add to Cursor / Claude Code
29
+ Open `~/.cursor/mcp.json` and add conductor:
25
30
 
26
31
  ```json
27
32
  {
@@ -34,55 +39,140 @@ In Figma: **Plugins → Development → Import plugin from manifest** → select
34
39
  }
35
40
  ```
36
41
 
37
- ### 3. Design
42
+ Restart Cursor.
43
+
44
+ ### 4. Connect and design
45
+
46
+ 1. Open a Figma file
47
+ 2. Run the plugin: **Plugins → Development → Conductor**
48
+ 3. The plugin should show a green dot (Connected)
49
+ 4. In Cursor chat, type `@conductor` followed by any command
50
+
51
+ ### Example prompts
52
+
53
+ ```
54
+ @conductor Create a dark hero section with a big heading and a purple CTA button
55
+
56
+ @conductor Check contrast between #ffffff and #6366f1
57
+
58
+ @conductor Create a dashboard layout with sidebar, KPI cards, and chart area
59
+
60
+ @conductor Audit accessibility on my current selection
61
+
62
+ @conductor Replace all #6366f1 with #3b82f6 across the file
63
+
64
+ @conductor Export this frame as React + Tailwind code
65
+
66
+ @conductor Scan my file and show me all off-grid spacing
67
+
68
+ @conductor Generate a color palette from #6366f1
69
+ ```
70
+
71
+ ### Alternative: use local path (faster startup)
72
+
73
+ Instead of `npx`, point directly to the cloned repo:
74
+
75
+ ```json
76
+ {
77
+ "mcpServers": {
78
+ "conductor": {
79
+ "command": "node",
80
+ "args": ["/path/to/conductor/bin/conductor.js"]
81
+ }
82
+ }
83
+ }
84
+ ```
85
+
86
+ ## How it works
87
+
88
+ ```
89
+ You type in Cursor → MCP server (stdio) → WebSocket :3055 → Figma plugin → Canvas
90
+ ```
91
+
92
+ Cursor starts the MCP server automatically. The server opens a WebSocket on port 3055. The Figma plugin connects to that WebSocket and executes commands on the canvas.
93
+
94
+ ## What makes this different
95
+
96
+ Other MCP servers for Figma are API wrappers. You give exact pixel values, they obey — even when those values are wrong. Conductor applies design rules before anything touches the canvas.
97
+
98
+ You say "create a button." A typical MCP makes a rectangle. Conductor makes a 44px-tall frame with 20px horizontal padding, 10px radius, 15px Semi Bold text — because that's what a button actually is.
99
+
100
+ ## 201 tools in 17 categories
101
+
102
+ ### Create & Layout (20)
103
+ create_frame, create_text, create_rectangle, create_ellipse, create_line, create_svg_node, create_component, create_component_instance, create_component_set, create_smart_component, set_auto_layout, create_section, create_page, create_table_frame, create_form, create_nav_bar, create_card_grid, create_sidebar_layout, create_footer, create_header
104
+
105
+ ### Modify & Style (25)
106
+ modify_node, set_fill, set_stroke, set_effects, set_image_fill, style_text_range, set_constraints, delete_node, move_to_parent, duplicate_node, group_nodes, ungroup_nodes, resize_node, align_nodes, set_corner_radius, set_opacity, set_blend_mode, set_clip_content, rename_node, lock_node, set_visibility, reorder_node, set_layout_sizing, flatten_node, set_rotation
107
+
108
+ ### Vector & Shape (8)
109
+ create_vector, boolean_operation, create_polygon, create_star, offset_path, create_arrow, create_icon (35 built-in), create_divider
110
+
111
+ ### Read & Inspect (18)
112
+ get_selection, get_page_structure, get_node_info, get_nodes_info, find_nodes, get_local_styles, get_local_variables, list_components, list_pages, get_document_info, set_selection, set_focus, get_annotations, set_annotation, list_available_fonts, read_node_css, get_selection_colors, measure_distance
113
+
114
+ ### Variables & Tokens (10)
115
+ create_variable_collection, create_variable, bind_variable, get_variables, update_variable, delete_variable, create_design_tokens, import_tokens, export_tokens, swap_mode
116
+
117
+ ### Export & Code (12)
118
+ export_as_svg, export_as_png, export_to_react, export_design_specs, export_assets, screenshot, copy_css, generate_stylesheet, export_color_palette, export_typography, export_component_inventory, export_spacing_tokens
119
+
120
+ ### Accessibility & Lint (12)
121
+ audit_accessibility, check_contrast, fix_touch_targets, lint_design, fix_spacing, check_naming, suggest_improvements, validate_component, check_consistency, generate_a11y_report, color_blindness_check, responsive_check
122
+
123
+ ### Batch Operations (17)
124
+ batch_rename, batch_style, batch_replace_text, batch_replace_color, batch_resize, batch_align, batch_delete, batch_duplicate, batch_set_visibility, batch_lock, select_all_by_type, clean_hidden_layers, batch_set_font, batch_round_values, batch_remove_strokes, batch_remove_effects, batch_set_corner_radius
125
+
126
+ ### Design System (10)
127
+ scan_design_system, create_style_guide, detect_inconsistencies, normalize_design, extract_components, get_design_craft_guide, suggest_color_palette, suggest_type_scale, import_design_system, compare_to_system
128
+
129
+ ### Responsive (5)
130
+ create_responsive_variant, set_breakpoint, convert_to_responsive, generate_mobile, stack_for_mobile
131
+
132
+ ### Typography (10)
133
+ type_scale_apply, type_audit, type_set_hierarchy, type_check_measure, type_normalize, type_list_styles, type_pair_suggest, type_replace_font, set_text_content, type_create_style
134
+
135
+ ### Color (10)
136
+ color_palette_generate, color_extract, color_harmonize, color_darkmode, color_lightmode, color_check_all, color_create_style, color_apply_style, color_replace_global, color_generate_semantic
38
137
 
39
- Open Figma Run the Conductor plugin → Chat in Cursor:
138
+ ### Prototype & Interaction (10)
139
+ create_prototype_link, create_scroll_behavior, set_overflow, create_overlay, set_fixed_position, create_hover_state, create_flow, list_flows, remove_prototype_link, set_transition
40
140
 
41
- > "Create a mobile login screen with email and password fields"
141
+ ### Page Management (8)
142
+ create_new_page, switch_page, duplicate_page, delete_page, rename_page, sort_pages, merge_pages, page_overview
42
143
 
43
- > "Design a dashboard with sidebar, KPI cards, and chart area"
144
+ ### Library & Components (8)
145
+ search_library, list_team_libraries, swap_component, detach_instance, reset_overrides, component_audit, batch_swap_component, publish_components
44
146
 
45
- > "Audit the accessibility of my current selection"
147
+ ### Annotation & Handoff (10)
148
+ annotate_spacing, annotate_colors, annotate_typography, create_measurement, create_spec_sheet, annotate_grid, annotate_hierarchy, create_component_docs, annotate_responsive, create_changelog
46
149
 
47
- > "Export this frame as React + Tailwind code"
150
+ ### Effects & Styles (8)
151
+ create_glassmorphism, create_neumorphism, create_noise_texture, set_gradient_fill, create_shadow_system, apply_backdrop_blur, create_border_gradient, remove_all_effects
48
152
 
49
- ## 201 Tools in 17 Categories
153
+ ## Design intelligence engine
50
154
 
51
- | Category | Count | Highlights |
52
- |----------|-------|-----------|
53
- | Create & Layout | 20 | Frames, text, shapes, smart components (18 types), sections, pages, forms, tables, nav bars, cards, sidebars |
54
- | Modify & Style | 25 | Fills (solid + gradients), strokes, effects, image fills, text ranges, constraints, transforms |
55
- | Vector & Shape | 8 | Paths, booleans, polygons, stars, 35 built-in icons, arrows, dividers |
56
- | Read & Inspect | 18 | Selection, page tree, node info, search, CSS export, fonts, annotations, measurements |
57
- | Variables & Tokens | 10 | Collections, modes, binding, W3C import/export, full token system from brand color |
58
- | Export & Code | 12 | React + Tailwind, HTML, Vue, Svelte, SVG, PNG, design specs, stylesheets, palettes |
59
- | Accessibility & Lint | 12 | WCAG audit, contrast, touch targets, font sizes, color blindness, design lint, compliance reports |
60
- | Batch Operations | 17 | Rename patterns, bulk style, find/replace text/color, clean hidden layers, round values, set fonts |
61
- | Design System | 10 | Scan, extract, normalize, lint, style guide, palette, type scale, import/export |
62
- | Responsive | 5 | Mobile/tablet/desktop variants, breakpoints, stacking, responsive conversion |
63
- | Typography | 10 | Type scale, audit, hierarchy, measure, normalize, font replace, pairing, styles |
64
- | Color | 10 | Palette generation, harmonies, dark/light mode, contrast check, semantic systems |
65
- | Prototype | 10 | Links, transitions, overlays, scroll, hover states, flows, fixed position |
66
- | Page Management | 8 | Create, switch, duplicate, delete, rename, sort, merge, overview |
67
- | Library | 8 | Search, swap, detach, audit, batch swap, publish |
68
- | Annotation & Handoff | 10 | Spacing redlines, color swatches, typography specs, spec sheets, changelogs |
69
- | Effects & Styles | 8 | Glassmorphism, neumorphism, noise, gradients, shadow systems, border gradients |
155
+ Every tool queries the intelligence engine before touching Figma:
70
156
 
71
- ## Design Intelligence
157
+ - **8px Grid** — All spacing values snapped. snap(13) = 16.
158
+ - **Type Scale** — 7 ratio presets: Minor Second through Golden Ratio.
159
+ - **Semantic Colors** — Full palette from one brand hex. Dark + light modes.
160
+ - **Component Defaults** — 18 component types with size variants.
161
+ - **Accessibility** — WCAG AA/AAA contrast, 44px touch targets, font minimums.
162
+ - **Font Weights** — Auto-resolves "bold" → "Bold", "600" → "Semi Bold".
163
+ - **Layout Intelligence** — 13 layout presets: row, column, center, spread, sidebar, grid, form.
72
164
 
73
- Every tool queries the intelligence engine:
165
+ ## Troubleshooting
74
166
 
75
- - **8px Grid**: All spacing values snapped to 8px grid
76
- - **Type Scale**: 7 mathematical ratios (Minor Second through Golden Ratio)
77
- - **Semantic Colors**: Full palette from one brand color (dark + light modes)
78
- - **Component Defaults**: 18 component types with size variants (button, input, card, avatar, badge, chip, switch, checkbox, radio, toast, tooltip, modal, dropdown, tabs, table, progress, skeleton, divider)
79
- - **Accessibility**: WCAG AA/AAA contrast, 44px touch targets, font minimums, color blindness
80
- - **Font Weights**: Auto-resolves "bold" → "Bold", "600" → "Semi Bold"
81
- - **Layout Intelligence**: 13 layout presets (row, column, center, spread, grid, sidebar, form)
167
+ **Plugin says "Disconnected"**
168
+ The MCP server isn't running. Make sure Cursor is open and conductor is configured in mcp.json. Try sending any @conductor message in Cursor chat — that triggers the server to start.
82
169
 
83
- ## License
170
+ **Port 3055 already in use**
171
+ Kill the old process: `kill $(lsof -t -i :3055) 2>/dev/null` then restart Cursor.
84
172
 
85
- MIT. Built by [0xDragoon](https://github.com/dragoon0x).
173
+ **Cursor shows "Loading tools" forever**
174
+ Make sure you have the latest version. Run: `npx conductor-figma@latest`
175
+ Or use the local path method for faster startup.
86
176
 
87
177
  ## Disclaimer
88
178
 
@@ -96,4 +186,4 @@ MIT. Built by [0xDragoon](https://github.com/dragoon0x).
96
186
  - Users are solely responsible for ensuring their use of this software complies with all applicable laws, regulations, terms of service, and licensing agreements — including Figma's Terms of Service and API usage policies.
97
187
  - **Use at your own risk.** Always back up your Figma files before running any automated operations. The author is not responsible for any unintended modifications, deletions, or corruption of design files.
98
188
 
99
- MIT License · Copyright © 2025 0xDragoon
189
+ MIT License · Copyright 2025 0xDragoon
@@ -281,8 +281,8 @@ async function executeCommand(cmd, data) {
281
281
  const s = data.shadow
282
282
  effects.push({
283
283
  type: 'DROP_SHADOW', visible: true,
284
- color: { ...hexToRGB(s.color || '#00000040'), a: 0.25 },
285
- offset: { x: s.offsetX || s.offset?.x || 0, y: s.offsetY || s.offset?.y || 4 },
284
+ color: (function(){ var c = hexToRGB(s.color || "#00000040"); return {r:c.r,g:c.g,b:c.b,a:0.25}; })(),
285
+ offset: { x: s.offsetX || (s.offset && s.offset.x) || 0, y: s.offsetY || (s.offset && s.offset.y) || 4 },
286
286
  radius: s.blur || 8, spread: s.spread || 0,
287
287
  })
288
288
  }
@@ -427,7 +427,7 @@ async function executeCommand(cmd, data) {
427
427
  const node = getNode(data.nodeId)
428
428
  if (!node || node.type !== 'GROUP') throw new Error('Not a group')
429
429
  const parent = node.parent
430
- const children = [...node.children]
430
+ const children = Array.prototype.slice.call(node.children)
431
431
  for (const child of children) parent.appendChild(child)
432
432
  node.remove()
433
433
  return { ungrouped: children.length }
@@ -521,7 +521,7 @@ async function executeCommand(cmd, data) {
521
521
 
522
522
  case 'list_available_fonts': {
523
523
  const fonts = await figma.listAvailableFontsAsync()
524
- const families = [...new Set(fonts.map(f => f.fontName.family))].sort()
524
+ const families = Array.from(new Set(fonts.map(f => f.fontName.family))).sort()
525
525
  return { count: families.length, families: families.slice(0, 100) }
526
526
  }
527
527
 
@@ -532,7 +532,7 @@ async function executeCommand(cmd, data) {
532
532
  node.fills.forEach(f => { if (f.type === 'SOLID') colors.add(rgbToHex(f.color)) })
533
533
  }
534
534
  }
535
- return [...colors]
535
+ return Array.from(colors)
536
536
  }
537
537
 
538
538
  case 'measure_distance': {
@@ -660,7 +660,7 @@ async function executeCommand(cmd, data) {
660
660
  const newFills = n.fills.map(f => {
661
661
  if (f.type === 'SOLID' && Math.abs(f.color.r - findRgb.r) < 0.02 && Math.abs(f.color.g - findRgb.g) < 0.02 && Math.abs(f.color.b - findRgb.b) < 0.02) {
662
662
  count++
663
- return { ...f, color: hexToRGB(data.replace) }
663
+ var nf = {type:f.type,color:hexToRGB(data.replace),opacity:f.opacity}; return nf
664
664
  }
665
665
  return f
666
666
  })
@@ -717,10 +717,10 @@ async function executeCommand(cmd, data) {
717
717
  return false
718
718
  })
719
719
  return {
720
- colors: [...colors].sort(),
721
- fonts: [...fonts].sort(),
722
- radii: [...radii].sort((a,b) => a-b),
723
- spacings: [...spacings].sort((a,b) => a-b),
720
+ colors: Array.from(colors).sort(),
721
+ fonts: Array.from(fonts).sort(),
722
+ radii: Array.from(radii).sort(function(a,b){return a-b}),
723
+ spacings: Array.from(spacings).sort(function(a,b){return a-b}),
724
724
  }
725
725
  }
726
726
 
@@ -8,7 +8,7 @@
8
8
  "enableProposedApi": false,
9
9
  "editorType": ["figma"],
10
10
  "networkAccess": {
11
- "allowedDomains": ["*"],
12
- "reasoning": "Connects to local MCP WebSocket server"
11
+ "allowedDomains": ["none"],
12
+ "reasoning": "Conductor connects to a local WebSocket server only"
13
13
  }
14
14
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "conductor-figma",
3
- "version": "3.0.3",
3
+ "version": "3.0.4",
4
4
  "description": "Design-intelligent MCP server for Figma. 201 design-intelligent tools for Figma. Every tool knows typography, spacing, color, accessibility. Not a shape proxy — a design engine.",
5
5
  "author": "0xDragoon",
6
6
  "license": "MIT",
package/src/server.js CHANGED
@@ -1,12 +1,8 @@
1
- // ═══════════════════════════════════════════
2
- // CONDUCTOR v3 — MCP Server (stdio)
3
- // ═══════════════════════════════════════════
4
-
5
1
  import { TOOL_LIST, TOOL_COUNT, getTool, CATEGORIES } from './tools/registry.js'
6
2
  import { handleTool } from './tools/handlers.js'
7
3
  import { createBridge } from './bridge.js'
8
4
 
9
- var VERSION = '3.0.2'
5
+ var VERSION = '3.0.4'
10
6
  var bridge = null
11
7
  var bridgeStarted = false
12
8
 
@@ -21,34 +17,44 @@ function ensureBridge() {
21
17
  return bridge
22
18
  }
23
19
 
24
- // ─── JSON-RPC over stdio ───
25
- var buffer = ''
20
+ if (process.stdout._handle && process.stdout._handle.setBlocking) {
21
+ process.stdout._handle.setBlocking(true)
22
+ }
26
23
 
24
+ var buffer = ''
27
25
  process.stdin.setEncoding('utf8')
28
26
  process.stdin.on('data', function(chunk) {
29
27
  buffer += chunk
28
+ processBuffer()
29
+ })
30
+
31
+ function processBuffer() {
30
32
  while (true) {
31
- var headerEnd = buffer.indexOf('\r\n\r\n')
32
- if (headerEnd === -1) break
33
- var header = buffer.slice(0, headerEnd)
34
- var match = header.match(/Content-Length:\s*(\d+)/i)
35
- if (!match) { buffer = buffer.slice(headerEnd + 4); continue }
36
- var len = parseInt(match[1])
37
- var bodyStart = headerEnd + 4
38
- if (buffer.length < bodyStart + len) break
39
- var body = buffer.slice(bodyStart, bodyStart + len)
40
- buffer = buffer.slice(bodyStart + len)
41
- try {
42
- var msg = JSON.parse(body)
43
- handleMessage(msg)
44
- } catch (e) { log('Parse error:', e.message) }
33
+ var nlIdx = buffer.indexOf('\n')
34
+ if (nlIdx === -1) {
35
+ if (buffer.length > 0 && buffer[0] === '{') {
36
+ try { JSON.parse(buffer) } catch(e) { break }
37
+ tryParse(buffer)
38
+ buffer = ''
39
+ }
40
+ break
41
+ }
42
+ var line = buffer.slice(0, nlIdx).trim()
43
+ buffer = buffer.slice(nlIdx + 1)
44
+ if (line.length === 0) continue
45
+ if (line[0] === '{') tryParse(line)
45
46
  }
46
- })
47
+ }
48
+
49
+ function tryParse(str) {
50
+ try {
51
+ var msg = JSON.parse(str)
52
+ handleMessage(msg)
53
+ } catch (e) { log('Parse error:', e.message) }
54
+ }
47
55
 
48
56
  function send(msg) {
49
- var json = JSON.stringify(msg)
50
- var out = 'Content-Length: ' + Buffer.byteLength(json) + '\r\n\r\n' + json
51
- process.stdout.write(out)
57
+ process.stdout.write(JSON.stringify(msg) + '\n')
52
58
  }
53
59
 
54
60
  function respond(id, result) { send({ jsonrpc: '2.0', id: id, result: result }) }
@@ -57,21 +63,23 @@ function respondError(id, code, message) { send({ jsonrpc: '2.0', id: id, error:
57
63
  function handleMessage(msg) {
58
64
  var id = msg.id
59
65
  var method = msg.method
60
- var params = msg.params
66
+ var params = msg.params || {}
67
+
68
+ log('<- ' + method + (id !== undefined ? ' #' + id : ''))
61
69
 
62
70
  switch (method) {
63
71
  case 'initialize':
64
- // Start bridge in background, respond immediately
65
72
  ensureBridge()
66
73
  log('Conductor v' + VERSION + ' ready — ' + TOOL_COUNT + ' tools')
67
74
  respond(id, {
68
- protocolVersion: '2024-11-05',
75
+ protocolVersion: params.protocolVersion || '2024-11-05',
69
76
  capabilities: { tools: { listChanged: false } },
70
77
  serverInfo: { name: 'conductor-figma', version: VERSION },
71
78
  })
72
79
  return
73
80
 
74
81
  case 'notifications/initialized':
82
+ case 'notifications/cancelled':
75
83
  return
76
84
 
77
85
  case 'tools/list':
@@ -107,7 +115,7 @@ function handleMessage(msg) {
107
115
  return
108
116
 
109
117
  default:
110
- if (id) respondError(id, -32601, 'Unknown method: ' + method)
118
+ if (id !== undefined) respondError(id, -32601, 'Unknown method: ' + method)
111
119
  }
112
120
  }
113
121