conductor-figma 0.3.1 → 1.0.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "conductor-figma",
3
- "version": "0.3.1",
3
+ "version": "1.0.1",
4
4
  "description": "Design-intelligent MCP server for Figma. 61 tools across 10 categories. 8px grid, type scale ratios, auto-layout, component reuse, accessibility — real design intelligence, not shape proxying.",
5
5
  "author": "0xDragoon",
6
6
  "license": "MIT",
@@ -0,0 +1,181 @@
1
+ // ═══════════════════════════════════════════
2
+ // CONDUCTOR — Design Craft Guide
3
+ // ═══════════════════════════════════════════
4
+ // Professional design rules. The AI reads this before designing anything.
5
+ // This is what separates amateur output from production quality.
6
+
7
+ export function getDesignCraftGuide() {
8
+ return `# CONDUCTOR Design Craft Guide
9
+
10
+ You are a senior product designer working in Figma. Every frame, every text node, every color choice must follow these rules. No exceptions.
11
+
12
+ ## Layout Architecture
13
+
14
+ ### Frame Structure
15
+ - ALWAYS use auto-layout. Never absolute positioning.
16
+ - Direction: VERTICAL for page sections, HORIZONTAL for rows of items.
17
+ - Every frame needs explicit padding and gap. Never 0 unless intentional.
18
+ - Use primaryAxisSizingMode: "HUG" for content-driven frames, "FIXED" for containers with set widths.
19
+ - Use counterAxisSizingMode: "FILL" for child frames that should stretch to parent width.
20
+
21
+ ### Spacing System (8px grid)
22
+ - Base unit: 8px. All spacing values must be multiples of 8.
23
+ - Micro spacing: 4px, 8px (within components, between label and input)
24
+ - Small spacing: 12px, 16px (between related elements, card padding)
25
+ - Medium spacing: 24px, 32px (between component groups, section padding)
26
+ - Large spacing: 48px, 64px (between page sections)
27
+ - Extra large: 80px, 96px, 120px (page-level vertical rhythm)
28
+ - NEVER use: 5, 7, 10, 13, 15, 17, 22, 25, 30, 35, 50, 55, 65, 70, 75, 90, 100
29
+
30
+ ### Content Width
31
+ - Max content width: 1200px for desktop, centered in wider frames
32
+ - For a 1440px page, use 48-80px horizontal padding to create margins
33
+ - Card grid max: 3-4 columns. Never 5+ columns for content cards.
34
+ - Sidebar: 240-280px. Never wider than 320px.
35
+
36
+ ## Typography
37
+
38
+ ### Type Scale (use Inter font family)
39
+ - Display: 56-72px, Bold or Extra Bold, line-height 1.1
40
+ - H1: 40-48px, Bold, line-height 1.15
41
+ - H2: 32-36px, Bold or Semi Bold, line-height 1.2
42
+ - H3: 24-28px, Semi Bold, line-height 1.25
43
+ - H4: 18-20px, Semi Bold, line-height 1.3
44
+ - Body large: 18px, Regular, line-height 1.6
45
+ - Body: 15-16px, Regular, line-height 1.6
46
+ - Body small: 13-14px, Regular, line-height 1.5
47
+ - Caption: 11-12px, Medium, line-height 1.4
48
+ - Overline: 10-12px, Semi Bold or Bold, uppercase, letter-spacing 0.08em
49
+
50
+ ### Typography Rules
51
+ - Maximum 2 font weights per section (e.g., Bold + Regular, Semi Bold + Regular)
52
+ - Body text color should NEVER be pure white (#ffffff). Use #f0f0f8 or #e8e8f0 for dark themes.
53
+ - Muted text: #a0a0b8 for dark themes, #666680 for light themes.
54
+ - Heading to body size ratio should be at least 1.5x.
55
+ - Line length: 45-75 characters for body text. Use max-width on text containers.
56
+
57
+ ## Color
58
+
59
+ ### Dark Theme Palette
60
+ - Background levels: #09090f → #0c0c18 → #0f0f1c → #12122a → #16163a
61
+ - Each level should be visibly distinct but not jarring.
62
+ - Card backgrounds should be 1-2 levels lighter than the page background.
63
+ - Text hierarchy: #f0f0f8 (primary) → #a0a0b8 (secondary) → #686880 (tertiary)
64
+ - Dividers: #1a1a32 or #1e1e3a (subtle, never bright)
65
+ - NEVER use pure black (#000000) as a background.
66
+ - NEVER use pure white (#ffffff) as text on dark backgrounds.
67
+
68
+ ### Light Theme Palette
69
+ - Background levels: #ffffff → #f9f9fb → #f3f3f7 → #ebebf0
70
+ - Card backgrounds: #ffffff with subtle border (#e4e4ec)
71
+ - Text hierarchy: #111118 (primary) → #55556a (secondary) → #88889a (tertiary)
72
+ - Dividers: #e4e4ec
73
+
74
+ ### Brand Color Usage
75
+ - Primary brand color: buttons, links, badges, icons, active states.
76
+ - NEVER use brand color for large background areas.
77
+ - Brand color for text only in overlines, links, and badges.
78
+ - Hover states: darken brand color by 10%. Active: darken by 15%.
79
+
80
+ ## Components
81
+
82
+ ### Buttons
83
+ - Height: 36px (small), 40px (default), 48px (large), 56px (hero)
84
+ - Horizontal padding: 16px (small), 20px (default), 28px (large), 32px (hero)
85
+ - Corner radius: 8px (default), 10-12px (large/hero)
86
+ - Primary: brand color fill, white text, Semi Bold
87
+ - Secondary: transparent fill, border or muted text, Medium weight
88
+ - Ghost: transparent, text only, Medium weight
89
+ - Always center text both axes in buttons
90
+
91
+ ### Cards
92
+ - Padding: 24-32px (compact), 28-40px (standard)
93
+ - Corner radius: 12-16px
94
+ - Gap between elements inside: 12-20px
95
+ - On dark themes: use a lighter background, no border
96
+ - On light themes: white background + subtle border (#e4e4ec) + optional shadow
97
+ - Cards in a row should all be the same height (use counterAxisAlignItems: "STRETCH" on parent)
98
+
99
+ ### Navigation
100
+ - Height: 64-72px for top nav
101
+ - Logo left, links center or right, CTA button far right
102
+ - Use a spacer frame (FILL sizing) between logo and links to push them apart
103
+ - Nav links: 14px Medium, 24-32px gap between items
104
+ - Active state: brand color or bolder weight
105
+ - Add a 1px divider below the nav
106
+
107
+ ### Metric/Stat Cards
108
+ - Stack: label on top (12-13px, muted, Medium), value below (28-36px, Bold)
109
+ - Optional: change indicator below value (12-13px, green for positive, red for negative)
110
+ - Equal width cards in a horizontal row
111
+ - 20-24px gap between metric cards
112
+
113
+ ### Tables
114
+ - Header row: 40-48px height, uppercase 10-11px labels, muted color, Medium weight
115
+ - Data rows: 48-56px height, 14-15px Regular text
116
+ - Cell padding: 16-20px horizontal
117
+ - Alternating row backgrounds or horizontal dividers (not both)
118
+ - Status badges: small colored pills with 4-6px padding, rounded
119
+
120
+ ### Forms
121
+ - Input height: 40-44px
122
+ - Label: 13-14px, Medium weight, 4-8px gap below label
123
+ - Input: 14-15px Regular, 12-16px horizontal padding
124
+ - Corner radius: 8px
125
+ - Border: 1px, muted color. Focus: brand color border
126
+ - 20-24px gap between field groups
127
+
128
+ ## Section Patterns
129
+
130
+ ### Hero Section
131
+ - Vertical padding: 80-120px
132
+ - Content centered (both axes)
133
+ - Overline badge → Heading (56-72px) → Subtitle (18-20px) → Button row → Social proof
134
+ - Max heading width: ~600px
135
+ - Subtitle max width: ~500px
136
+ - 28-32px gap between heading and subtitle
137
+ - 32-40px gap between subtitle and buttons
138
+
139
+ ### Feature Section
140
+ - Heading + subtitle centered at top
141
+ - 3 cards in a row (or 2 for detailed features)
142
+ - Each card: icon/emoji → title → description → optional link
143
+ - 48px gap between heading group and card row
144
+
145
+ ### Stats/Social Proof
146
+ - Background color shift (one level different from surrounding sections)
147
+ - 3-4 stats in a horizontal row, centered
148
+ - Each stat centered: big number + label below
149
+
150
+ ### CTA Section
151
+ - Often wrapped in a card or a background shift
152
+ - Centered: heading → subtitle → button row
153
+ - Generous padding: 64-96px vertical
154
+
155
+ ### Footer
156
+ - Logo left, copyright right, spacer between
157
+ - Or: multi-column with link groups
158
+ - Divider line above
159
+ - Muted text, smaller font sizes (13px)
160
+
161
+ ## Anti-Patterns (NEVER do these)
162
+ - Never use absolute positioning. Always auto-layout.
163
+ - Never use font sizes that aren't in the type scale.
164
+ - Never use spacing values that aren't multiples of 4 or 8.
165
+ - Never put more than 3-4 cards in a row.
166
+ - Never use pure black or pure white on dark themes.
167
+ - Never make buttons without sufficient padding (minimum 16px horizontal).
168
+ - Never stack more than 4-5 levels of nesting without good reason.
169
+ - Never use inconsistent corner radii on the same page.
170
+ - Never use more than 2-3 distinct background colors per page.
171
+ - Never center-align body paragraphs (center headings only).
172
+ - Never use text smaller than 11px.
173
+ - Never create frames without naming them descriptively.
174
+
175
+ ## Naming Convention
176
+ - Pages: "Landing Page", "Pricing Page", "Dashboard"
177
+ - Sections: "Hero Section", "Features Section", "CTA Section"
178
+ - Components: "Nav CTA", "Feature Card", "Stat Card", "Price Tier"
179
+ - Layout: "Card Row", "Button Row", "Nav Links"
180
+ - Never use "Frame 1", "Rectangle 2", or auto-generated names.`;
181
+ }
package/src/index.js CHANGED
@@ -30,3 +30,4 @@ export {
30
30
  } from './design/intelligence.js';
31
31
 
32
32
  export { exportCSS, exportTailwind, exportSCSS, exportJSON, exportW3CTokens } from './design/exporter.js';
33
+ export { getDesignCraftGuide } from './design/craftguide.js';
package/src/relay.js CHANGED
@@ -15,15 +15,17 @@ import { createServer } from 'node:http';
15
15
  const FIGMA_COMMANDS = new Set([
16
16
  // Create
17
17
  'create_frame', 'create_text', 'create_rect', 'create_section', 'create_component',
18
+ 'create_ellipse', 'create_svg_node',
18
19
  // Layout
19
20
  'set_auto_layout', 'set_constraints', 'apply_grid', 'align_nodes',
20
21
  // Style
21
22
  'set_fills', 'set_strokes', 'set_effects', 'set_corner_radius', 'set_opacity',
22
23
  // Typography
23
- 'set_text_props', 'load_font',
24
+ 'set_text_props', 'load_font', 'style_text_range',
24
25
  // Read
25
26
  'get_selection', 'get_page_info', 'get_styles', 'get_components',
26
27
  'read_node', 'read_tree', 'read_spacing', 'read_colors', 'read_typography',
28
+ 'find_nodes',
27
29
  // Edit
28
30
  'rename_node', 'move_node', 'resize_node', 'delete_node',
29
31
  'clone_node', 'group_nodes', 'ungroup_node', 'reorder_node',
@@ -6,6 +6,7 @@
6
6
 
7
7
  import * as design from '../design/intelligence.js';
8
8
  import * as exporter from '../design/exporter.js';
9
+ import { getDesignCraftGuide } from '../design/craftguide.js';
9
10
 
10
11
  function text(str) {
11
12
  return { content: [{ type: 'text', text: str }] };
@@ -389,6 +390,68 @@ const HANDLERS = {
389
390
  },
390
391
  export_spec(args) { return json({ action: 'generate_spec', nodeId: args.nodeId, format: args.format || 'markdown' }); },
391
392
  export_changelog(args) { return json({ action: 'diff_frames', nodeIdA: args.nodeIdA, nodeIdB: args.nodeIdB, format: args.format || 'markdown' }); },
393
+
394
+ // ═══ DESIGN CRAFT ═══
395
+ get_design_craft_guide() {
396
+ return text(getDesignCraftGuide());
397
+ },
398
+
399
+ // ═══ CREATE (additional) ═══
400
+ create_ellipse(args) {
401
+ return json({
402
+ action: 'create_ellipse',
403
+ name: args.name || 'Ellipse',
404
+ width: args.width, height: args.height,
405
+ fill: args.fill || '#ffffff',
406
+ x: args.x, y: args.y,
407
+ parentId: args.parentId,
408
+ opacity: args.opacity,
409
+ });
410
+ },
411
+
412
+ create_line(args) {
413
+ var dir = args.direction || 'horizontal';
414
+ return json({
415
+ action: 'create_rect',
416
+ name: args.name || 'Divider',
417
+ width: dir === 'horizontal' ? args.length : 1,
418
+ height: dir === 'horizontal' ? 1 : args.length,
419
+ fill: args.color || '#1a1a32',
420
+ parentId: args.parentId,
421
+ });
422
+ },
423
+
424
+ create_svg_node(args) {
425
+ return json({
426
+ action: 'create_svg_node',
427
+ name: args.name || 'SVG',
428
+ svg: args.svg,
429
+ x: args.x, y: args.y,
430
+ parentId: args.parentId,
431
+ });
432
+ },
433
+
434
+ find_nodes(args) {
435
+ return json({
436
+ action: 'find_nodes',
437
+ query: args.query,
438
+ type: args.type,
439
+ parentId: args.parentId,
440
+ });
441
+ },
442
+
443
+ // ═══ TYPOGRAPHY (additional) ═══
444
+ style_text_range(args) {
445
+ return json({
446
+ action: 'style_text_range',
447
+ nodeId: args.nodeId,
448
+ start: args.start,
449
+ end: args.end,
450
+ fontSize: args.fontSize,
451
+ fontWeight: args.fontWeight,
452
+ color: args.color,
453
+ });
454
+ },
392
455
  };
393
456
 
394
457
  // ─── Helpers ───
@@ -5,9 +5,10 @@
5
5
  // Each tool has: name, description, category, inputSchema, handler reference.
6
6
 
7
7
  export const CATEGORIES = {
8
- create: { label: 'Create', icon: '', count: 8 },
8
+ craft: { label: 'Design Craft', icon: '', count: 1 },
9
+ create: { label: 'Create', icon: '⊞', count: 12 },
9
10
  layout: { label: 'Layout', icon: '▤', count: 7 },
10
- typography: { label: 'Typography', icon: '◆', count: 6 },
11
+ typography: { label: 'Typography', icon: '◆', count: 7 },
11
12
  color: { label: 'Color & Style', icon: '◑', count: 7 },
12
13
  components: { label: 'Components', icon: '◎', count: 6 },
13
14
  spacing: { label: 'Spacing & Grid', icon: '◧', count: 6 },
@@ -26,16 +27,40 @@ function opt(schema) { return { ...schema, optional: true }; }
26
27
  export const TOOLS = [
27
28
  // ═══ CREATE ═══
28
29
  { name: 'create_frame', category: 'create',
29
- description: 'Create an auto-layout frame with grid-aligned spacing, proper padding, and constraints.',
30
- inputSchema: { type: 'object', properties: { name: str('Frame name'), width: opt(num('Width')), height: opt(num('Height')), direction: opt(str('horizontal or vertical')), padding: opt(num('Padding (snapped to grid)')), gap: opt(num('Gap (snapped to grid)')), fill: opt(str('Background color hex')) }, required: ['name'] } },
30
+ description: 'Create a single auto-layout frame. IMPORTANT: For multi-element designs (pages, sections, dashboards), use create_page or create_section instead — they handle all nesting automatically. If using create_frame directly, ALWAYS set parentId to nest inside a parent frame, and ALWAYS set direction, padding, and gap for auto-layout.',
31
+ inputSchema: { type: 'object', properties: { name: str('Frame name'), width: opt(num('Width')), height: opt(num('Height')), direction: opt(str('VERTICAL or HORIZONTAL')), padding: opt(num('Padding in px (use multiples of 8)')), paddingTop: opt(num('Top padding')), paddingBottom: opt(num('Bottom padding')), paddingLeft: opt(num('Left padding')), paddingRight: opt(num('Right padding')), gap: opt(num('Gap between children (use multiples of 8)')), fill: opt(str('Background color hex')), cornerRadius: opt(num('Corner radius')), parentId: opt(str('REQUIRED for nesting: parent frame ID')), primaryAxisAlignItems: opt(str('MIN, CENTER, MAX, SPACE_BETWEEN')), counterAxisAlignItems: opt(str('MIN, CENTER, MAX, STRETCH')), primaryAxisSizingMode: opt(str('FIXED, HUG, FILL')), counterAxisSizingMode: opt(str('FIXED, HUG, FILL')) }, required: ['name'] } },
31
32
 
32
33
  { name: 'create_page', category: 'create',
33
- description: 'Create a full page from intent: landing, pricing, dashboard, settings, auth. Generates proper section hierarchy with auto-layout.',
34
- inputSchema: { type: 'object', properties: { pageType: str('Page type: landing, pricing, dashboard, settings, auth, blog, portfolio, docs'), title: opt(str('Page title')), sections: opt(arr('Section types to include')), brandColor: opt(str('Primary brand color hex')), darkMode: opt(bool('Generate dark mode variant')) }, required: ['pageType'] } },
34
+ description: 'THE PRIMARY TOOL FOR DESIGNING PAGES. Creates a complete, polished, production-ready page with all sections, components, and content — fully nested with auto-layout, proper spacing, and design-intelligent values. One call generates 40-80 Figma elements. Use this INSTEAD of calling create_frame/create_text individually. Supports: landing, pricing, dashboard page types. Pass brand color, title, features, stats, and other content as parameters.',
35
+ inputSchema: { type: 'object', properties: {
36
+ pageType: str('Page type: landing, pricing, dashboard'),
37
+ title: opt(str('Hero heading text')),
38
+ subtitle: opt(str('Hero subtitle text')),
39
+ brand: opt(str('Brand/company name (appears in nav and footer)')),
40
+ brandColor: opt(str('Primary brand color hex (default #6366f1)')),
41
+ ctaText: opt(str('Primary CTA button text')),
42
+ darkMode: opt(bool('Dark mode (default true)')),
43
+ width: opt(num('Page width (default 1440)')),
44
+ navItems: opt(arr('Navigation link labels')),
45
+ features: opt(arr('Feature objects with icon, title, desc fields')),
46
+ stats: opt(arr('Stat objects with value and label fields')),
47
+ tiers: opt(arr('Pricing tier objects with name, price, period, desc, features, cta, highlighted fields')),
48
+ metrics: opt(arr('Dashboard metric objects with label, value, change, positive fields')),
49
+ }, required: ['pageType'] } },
35
50
 
36
51
  { name: 'create_section', category: 'create',
37
- description: 'Create a page section: hero, features, testimonials, FAQ, CTA, pricing, stats, team. Pattern-aware with proper hierarchy.',
38
- inputSchema: { type: 'object', properties: { sectionType: str('Section type: hero, features, testimonials, faq, cta, pricing, stats, team, footer, header'), heading: opt(str('Section heading')), content: opt(str('Content description')), columns: opt(num('Number of columns for grid sections')) }, required: ['sectionType'] } },
52
+ description: 'Creates a complete page section with all child elements, auto-layout, and proper nesting. One call generates 5-20 Figma elements. Use this INSTEAD of manually building sections. Supports: hero, features, pricing, cta, testimonials, faq section types.',
53
+ inputSchema: { type: 'object', properties: {
54
+ sectionType: str('Section type: hero, features, testimonials, faq, cta, pricing'),
55
+ heading: opt(str('Section heading')),
56
+ subheading: opt(str('Section subtitle')),
57
+ brandColor: opt(str('Brand color hex')),
58
+ ctaText: opt(str('CTA button text')),
59
+ width: opt(num('Section width (default 1440)')),
60
+ features: opt(arr('Feature objects for features section')),
61
+ testimonials: opt(arr('Testimonial objects with quote, author, role')),
62
+ faqs: opt(arr('FAQ objects with q and a fields')),
63
+ }, required: ['sectionType'] } },
39
64
 
40
65
  { name: 'create_card', category: 'create',
41
66
  description: 'Create a card with proper padding, radius, shadow depth, and content hierarchy.',
@@ -277,6 +302,33 @@ export const TOOLS = [
277
302
  { name: 'export_changelog', category: 'export',
278
303
  description: 'Diff two frames and export what changed as structured markdown or JSON.',
279
304
  inputSchema: { type: 'object', properties: { nodeIdA: str('First frame (before)'), nodeIdB: str('Second frame (after)'), format: opt(str('markdown or json')) }, required: ['nodeIdA', 'nodeIdB'] } },
305
+
306
+ // ═══ DESIGN CRAFT ═══
307
+ { name: 'get_design_craft_guide', category: 'craft',
308
+ description: 'CALL THIS FIRST before any design work. Returns professional design rules: typography scales, spacing systems (8px grid), color palettes, component patterns, and anti-patterns. Following these rules is the difference between amateur and production-quality output. Read the full guide before calling any create_ tools.',
309
+ inputSchema: { type: 'object', properties: {}, required: [] } },
310
+
311
+ // ═══ CREATE (additional) ═══
312
+ { name: 'create_ellipse', category: 'create',
313
+ description: 'Create a circle or oval. Use for avatars, status indicators, decorative elements, and icon backgrounds. Set equal width and height for a perfect circle.',
314
+ inputSchema: { type: 'object', properties: { name: opt(str('Element name')), width: num('Width in px'), height: num('Height in px'), fill: opt(str('Fill color hex')), x: opt(num('X position')), y: opt(num('Y position')), parentId: opt(str('Parent frame ID')), opacity: opt(num('Opacity 0-1')) }, required: ['width', 'height'] } },
315
+
316
+ { name: 'create_line', category: 'create',
317
+ description: 'Create a horizontal or vertical line. Use for dividers between sections, separators in navigation, and visual breaks. A line is a rectangle with 1px height (horizontal) or 1px width (vertical).',
318
+ inputSchema: { type: 'object', properties: { name: opt(str('Element name')), length: num('Length in px'), direction: opt(str('horizontal or vertical (default horizontal)')), color: opt(str('Line color hex')), parentId: opt(str('Parent frame ID')) }, required: ['length'] } },
319
+
320
+ { name: 'create_svg_node', category: 'create',
321
+ description: 'Create a vector graphic from raw SVG markup. Use for icons, logos, illustrations, and any custom vector shape. Pass the SVG string directly.',
322
+ inputSchema: { type: 'object', properties: { name: opt(str('Element name')), svg: str('Raw SVG markup string'), x: opt(num('X position')), y: opt(num('Y position')), parentId: opt(str('Parent frame ID')) }, required: ['svg'] } },
323
+
324
+ { name: 'find_nodes', category: 'create',
325
+ description: 'Search for elements by name or type within a frame or the entire page. Returns matching nodes with their IDs, positions, and basic properties. Use to locate elements before editing them.',
326
+ inputSchema: { type: 'object', properties: { query: opt(str('Search by name (partial match)')), type: opt(str('Filter by type: FRAME, TEXT, RECTANGLE, ELLIPSE, COMPONENT, INSTANCE')), parentId: opt(str('Search within this frame only')) }, required: [] } },
327
+
328
+ // ═══ TYPOGRAPHY (additional) ═══
329
+ { name: 'style_text_range', category: 'typography',
330
+ description: 'Apply different styles to specific character ranges within a text node. Use for mixed-weight text (e.g., bold product name within a regular sentence), colored keywords, or size variations within a single text element.',
331
+ inputSchema: { type: 'object', properties: { nodeId: str('Text node ID'), start: num('Start character index'), end: num('End character index'), fontSize: opt(num('Font size for range')), fontWeight: opt(num('Font weight: 400, 500, 600, 700')), color: opt(str('Color hex for range')) }, required: ['nodeId', 'start', 'end'] } },
280
332
  ];
281
333
 
282
334
  export function getToolsByCategory(category) {