@ufira/vibma 1.0.0-rc5 → 1.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/dist/mcp.cjs CHANGED
@@ -98,9 +98,9 @@ Use help(topic: "<endpoint>") for endpoint details.
98
98
  Use help(topic: "<endpoint>.<method>") for method details.`;
99
99
  var helpEndpoints = {
100
100
  "components": {
101
- "summary": '# components\nCreate and manage reusable components and variant sets.\n\nMethods:\n clone Duplicate nodes [create]\n audit Run lint on a node \u2014 returns severity-ranked findings [read]\n reparent Move nodes into a new parent [edit]\n list List local component names (variant sets as single entries) [read]\n get Get component detail \u2014 property definitions + optional node tree for structural inspection [read]\n create Create components [create]\n update Add, edit, or delete component properties [edit]\n delete Delete components or component sets [edit]\n\n// depth: omit \u2192 id+name stubs | 0 \u2192 props + child stubs | N \u2192 recurse N | -1 \u2192 full tree\n// fields: whitelist e.g. ["fills","opacity"] \u2014 id, name, type always included. Pass ["*"] for all.\n// layoutSizingHorizontal/Vertical: FIXED | HUG | FILL \u2014 how the node sizes within auto-layout.\n// Colors: fillVariableName/strokeVariableName bind by name \u2014 preferred over raw color values.\n// Note: node-based endpoints (frames, text, instances, components) use `results` as the list key.\n// Standalone endpoints (styles, variables, variable_collections) use `items`. Components.list uses `items` (catalog view).\n// ---\n// visible: false hides the node. Omitted from response when true (the default).\n// locked: true prevents editing in Figma UI. Omitted when false (the default).\n// rotation: degrees (0-360). Omitted when 0.\n// blendMode: layer blend mode. Omitted when PASS_THROUGH (the default).\n// layoutPositioning: ABSOLUTE = floating inside auto-layout parent. Omitted when AUTO (the default).\n// minWidth/maxWidth/minHeight/maxHeight: responsive constraints for auto-layout children.\n// constraints: position behavior in non-auto-layout parents. Ignored inside auto-layout frames.\n// bindings: bind design variables to node properties. field uses slash path: "fills/0/color" (first fill), "strokes/0/color", "opacity", "width", "height", "cornerRadius", "paddingLeft", "itemSpacing".\n// explicitMode: pin a variable mode on this node. Use { collectionName, modeName } (preferred) or { collectionId, modeId }.\n// properties: escape hatch \u2014 set any Figma node property directly. Use only when no dedicated field exists.\ninterface Node {\n id: string; name: string; type: string;\n visible?: boolean; // omitted when true\n locked?: boolean; // omitted when false\n opacity?: number; // omitted when 1\n rotation?: number; // omitted when 0\n blendMode?: string; // omitted when PASS_THROUGH\n layoutPositioning?: "AUTO" | "ABSOLUTE";\n layoutSizingHorizontal?: "FIXED" | "HUG" | "FILL";\n layoutSizingVertical?: "FIXED" | "HUG" | "FILL";\n minWidth?: number; maxWidth?: number; minHeight?: number; maxHeight?: number;\n absoluteBoundingBox: { x: number; y: number; width: number; height: number };\n fills?: Paint[]; // solid: {type: "SOLID", color: {r, g, b, a}}\n strokes?: Paint[];\n effects?: Effect[]; // DROP_SHADOW | INNER_SHADOW | LAYER_BLUR | BACKGROUND_BLUR\n children?: NodeStub[]; // stubs: {id, name, type} \u2014 use depth to expand\n}\n// PatchItem uses flat params matching create shape \u2014 no nested sub-objects.\n// Fill/stroke/corner/layout/text params are identical to frames.create and text.create.\n// Unknown keys produce a warning, preventing silent failures.\n// Components are reusable design elements. Instances stay linked to the component and inherit changes.\n// Workflow: create component (with properties) \u2192 add children \u2192 create instances via instances.create.\n// ---\n// A component set (variant set) groups related components as variants (e.g. Button/Primary, Button/Secondary).\n// Property types: BOOLEAN (toggle visibility), TEXT (editable text), INSTANCE_SWAP (swap child instance), VARIANT (variant picker).\n// exposeText: when creating from_node, text children become editable TEXT properties on the component.\n// Auto-bind: TEXT properties auto-bind to text children with matching names (case-insensitive).\n// Example: properties:[{propertyName:"Label", type:"TEXT", defaultValue:"Click"}] binds to a child text node named "Label".\n// text.create accepts componentPropertyName to bind on creation \u2014 walks up ancestors to find the nearest component.\n// For nested text (text inside frames inside a component), componentPropertyName resolves via ancestor walk. Alternatively, pass componentId explicitly.\n// For existing nodes with many text children, prefer components(method:"create", type:"from_node", exposeText:true) \u2014 it auto-discovers, creates TEXT properties, and binds all text nodes in one operation.\n// Property keys: read returns clean names ("Label"), write requires the #suffix ("Label#1:0"). Call components.get(id) to discover exact keys before edit/delete.\n// ComponentItem accepts the same params as FrameItem (layout, fill, stroke, sizing, min/max).\n// A component IS a frame \u2014 create it directly with all layout properties, then add children.\n// SIZING: Components with text need a width constraint \u2014 set width + layoutSizingHorizontal:"FIXED".\n// Without it, text won\'t wrap and the component grows unboundedly.\n// HUG on both axes is only correct for intrinsically-sized elements (buttons, badges, icons).\n// action: "add" (default) \u2014 requires type + defaultValue. "edit" \u2014 pass defaultValue to change value, name to rename property. "delete" \u2014 just propertyName#suffix.\n// action: "rename_variant" \u2014 renames a variant option VALUE (not the property). Pass defaultValue=current option name, name=new option name.\n// For VARIANT properties: "edit" with defaultValue reorders children to set the default variant.\n// Adding variants: clone an existing variant into the set with a new name. See guidelines(topic:"component-structure") for workflow.\n\nUse components(method: "help", topic: "<method>") for method details.',
101
+ "summary": '# components\nCreate and manage reusable components and variant sets.\n\nMethods:\n clone Duplicate nodes [create]\n audit Run lint on a node \u2014 returns severity-ranked findings [read]\n reparent Move nodes into a new parent [edit]\n list List local component names (variant sets as single entries) [read]\n get Get component detail \u2014 property definitions + optional node tree for structural inspection [read]\n create Create components [create]\n commit Commit a staged component \u2014 unwraps from [STAGED] container into the original target location. [edit]\n update Add, edit, or delete component properties [edit]\n delete Delete components or component sets [edit]\n\n// depth: omit \u2192 id+name stubs | 0 \u2192 props + child stubs | N \u2192 recurse N | -1 \u2192 full tree\n// fields: whitelist e.g. ["fills","opacity"] \u2014 id, name, type always included. Pass ["*"] for all.\n// layoutSizingHorizontal/Vertical: FIXED | HUG | FILL \u2014 how the node sizes within auto-layout.\n// Colors: fillVariableName/strokeVariableName bind by name \u2014 preferred over raw color values.\n// Note: node-based endpoints (frames, text, instances, components) use `results` as the list key.\n// Standalone endpoints (styles, variables, variable_collections) use `items`. Components.list uses `items` (catalog view).\n// ---\n// visible: false hides the node. Omitted from response when true (the default).\n// locked: true prevents editing in Figma UI. Omitted when false (the default).\n// rotation: degrees (0-360). Omitted when 0.\n// blendMode: layer blend mode. Omitted when PASS_THROUGH (the default).\n// layoutPositioning: ABSOLUTE = floating inside auto-layout parent. Omitted when AUTO (the default).\n// minWidth/maxWidth/minHeight/maxHeight: responsive constraints for auto-layout children.\n// constraints: position behavior in non-auto-layout parents. Ignored inside auto-layout frames.\n// bindings: bind design variables to node properties. field uses slash path: "fills/0/color" (first fill), "strokes/0/color", "opacity", "width", "height", "cornerRadius", "paddingLeft", "itemSpacing".\n// explicitMode: pin a variable mode on this node. Use { collectionName, modeName } (preferred) or { collectionId, modeId }.\n// properties: escape hatch \u2014 set any Figma node property directly. Use only when no dedicated field exists.\ninterface Node {\n id: string; name: string; type: string;\n visible?: boolean; // omitted when true\n locked?: boolean; // omitted when false\n opacity?: number; // omitted when 1\n rotation?: number; // omitted when 0\n blendMode?: string; // omitted when PASS_THROUGH\n layoutPositioning?: "AUTO" | "ABSOLUTE";\n layoutSizingHorizontal?: "FIXED" | "HUG" | "FILL";\n layoutSizingVertical?: "FIXED" | "HUG" | "FILL";\n minWidth?: number; maxWidth?: number; minHeight?: number; maxHeight?: number;\n absoluteBoundingBox: { x: number; y: number; width: number; height: number };\n fills?: Paint[]; // solid: {type: "SOLID", color: {r, g, b, a}}\n strokes?: Paint[];\n effects?: Effect[]; // DROP_SHADOW | INNER_SHADOW | LAYER_BLUR | BACKGROUND_BLUR\n children?: NodeStub[]; // stubs: {id, name, type} \u2014 use depth to expand\n}\n// PatchItem uses flat params matching create shape \u2014 no nested sub-objects.\n// Fill/stroke/corner/layout/text params are identical to frames.create and text.create.\n// Unknown keys produce a warning, preventing silent failures.\n// Components are reusable design elements. Instances stay linked to the component and inherit changes.\n// Workflow: create component (with properties) \u2192 add children \u2192 create instances via instances.create.\n// ---\n// A component set (variant set) groups related components as variants (e.g. Button/Primary, Button/Secondary).\n// Property types: BOOLEAN (toggle visibility), TEXT (editable text), INSTANCE_SWAP (swap child instance), VARIANT (variant picker).\n// exposeText: when creating from_node, text children become editable TEXT properties on the component.\n// Auto-bind: TEXT properties auto-bind to text children with matching names (case-insensitive).\n// Example: properties:[{propertyName:"Label", type:"TEXT", defaultValue:"Click"}] binds to a child text node named "Label".\n// text.create accepts componentPropertyName to bind on creation \u2014 walks up ancestors to find the nearest component.\n// For nested text (text inside frames inside a component), componentPropertyName resolves via ancestor walk. Alternatively, pass componentId explicitly.\n// For existing nodes with many text children, prefer components(method:"create", type:"from_node", exposeText:true) \u2014 it auto-discovers, creates TEXT properties, and binds all text nodes in one operation.\n// Property keys: read returns clean names ("Label"), write requires the #suffix ("Label#1:0"). Call components.get(id) to discover exact keys before edit/delete.\n// ComponentItem accepts the same params as FrameItem (layout, fill, stroke, sizing, min/max).\n// A component IS a frame \u2014 create it directly with all layout properties, then add children.\n// SIZING: Components with text need a width constraint \u2014 set width + layoutSizingHorizontal:"FIXED".\n// Without it, text won\'t wrap and the component grows unboundedly.\n// HUG on both axes is only correct for intrinsically-sized elements (buttons, badges, icons).\n// action: "add" (default) \u2014 requires type + defaultValue. "edit" \u2014 pass defaultValue to change value, name to rename property. "delete" \u2014 just propertyName#suffix.\n// action: "rename_variant" \u2014 renames a variant option VALUE (not the property). Pass defaultValue=current option name, name=new option name.\n// For VARIANT properties: "edit" with defaultValue reorders children to set the default variant.\n// Adding variants: clone an existing variant into the set with a new name. See guidelines(topic:"component-structure") for workflow.\n\nUse components(method: "help", topic: "<method>") for method details.',
102
102
  "methods": {
103
- "clone": "# components.clone\nDuplicate nodes\n\nParams:\n id (string, optional) \u2014 Node ID\n name (string, optional) \u2014 Rename the clone (set before appending to parent \u2014 required when cloning a variant into its component set to avoid duplicate names)\n parentId (string, optional) \u2014 Parent node ID. Omit to place on current page.\n x (number, optional) \u2014 X position (default: 0)\n y (number, optional) \u2014 Y position (default: 0)\n items (array, optional) \u2014 Batch: [{id, name?, parentId?, x?, y?}, ...]. Alternative to single-item params.\n id (string, required) \u2014 Node ID to clone\n name (string, optional) \u2014 Rename the clone\n parentId (string, optional) \u2014 Target parent\n x (number, optional)\n y (number, optional)\n depth (number, optional) \u2014 Response detail: omit for id+name only. 0=properties + child stubs. N=recurse N levels. -1=unlimited.",
103
+ "clone": "# components.clone\nDuplicate nodes\n\nParams:\n id (string, optional) \u2014 Node ID\n name (string, optional) \u2014 Rename the clone (set before appending to parent \u2014 required when cloning a variant into its component set to avoid duplicate names)\n parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.\n x (number, optional) \u2014 X position (default: 0)\n y (number, optional) \u2014 Y position (default: 0)\n items (array, optional) \u2014 Batch: [{id, name?, parentId?, x?, y?}, ...]. Alternative to single-item params.\n id (string, required) \u2014 Node ID to clone\n name (string, optional) \u2014 Rename the clone\n parentId (string, optional) \u2014 Target parent\n x (number, optional)\n y (number, optional)\n depth (number, optional) \u2014 Response detail: omit for id+name only. 0=properties + child stubs. N=recurse N levels. -1=unlimited.",
104
104
  "audit": `# components.audit
105
105
  Run lint on a node \u2014 returns severity-ranked findings
106
106
 
@@ -123,7 +123,7 @@ Discriminant: type (component | from_node | variant_set)
123
123
 
124
124
  ## component \u2014 Create component with full frame properties (layout, fill, stroke, sizing). A component IS a frame \u2014 build directly, no need to create a frame first.
125
125
  name (string, required) \u2014 Component name
126
- parentId (string, optional) \u2014 Parent node ID. Omit to place on current page.
126
+ parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
127
127
  x (number, optional) \u2014 X position (default: 0)
128
128
  y (number, optional) \u2014 Y position (default: 0)
129
129
  width (number, optional) \u2014 Width in px (omit to shrink-to-content via HUG)
@@ -156,7 +156,7 @@ Discriminant: type (component | from_node | variant_set)
156
156
  bottomLeftRadius (string, optional)
157
157
  effectStyleName (string, optional) \u2014 Effect style name (e.g. 'Shadow/Card') for shadows, blurs
158
158
  layoutMode (NONE | HORIZONTAL | VERTICAL, optional) \u2014 Layout direction (default: auto \u2014 NONE when width+height set, otherwise inferred from layout props)
159
- layoutWrap (NO_WRAP | WRAP, optional)
159
+ layoutWrap (NO_WRAP | WRAP, optional) \u2014 Wrap children to new rows (HORIZONTAL layout only \u2014 Figma does not support WRAP on VERTICAL layouts). Use column frames inside a HORIZONTAL parent for vertical grid patterns.
160
160
  padding (string, optional) \u2014 All edges (number) or variable name (string). Per-edge: paddingTop, paddingRight, paddingBottom, paddingLeft.
161
161
  paddingTop (string, optional)
162
162
  paddingRight (string, optional)
@@ -174,6 +174,8 @@ Discriminant: type (component | from_node | variant_set)
174
174
  maxHeight (number, optional) \u2014 Max height for responsive auto-layout
175
175
  overflowDirection (NONE | HORIZONTAL | VERTICAL | BOTH, optional) \u2014 Scroll overflow in prototype (default: NONE)
176
176
  description (string, optional) \u2014 Component description (shown in Figma's component panel)
177
+ children (array, optional) \u2014 Inline child nodes \u2014 build nested trees in one call. Types: text: {type:"text", text, componentPropertyName?, fontFamily?, fontSize?, fontWeight?, fontStyle?, fontColor?, layoutSizingHorizontal?}. frame: {type:"frame", name?, layoutMode?, fillColor?, width?, layoutSizingHorizontal?, children?}. instance: {type:"instance", componentId, componentPropertyName?, variantProperties?, properties?}. component: {type:"component", name, children?}. All params from text/frame endpoints are supported on their respective types. componentPropertyName auto-creates and binds a TEXT (text) or INSTANCE_SWAP (instance) property. Always set layoutSizingHorizontal + layoutSizingVertical on children inside auto-layout parents (FILL, HUG, or FIXED). Example: children:[{type:"text", text:"Label", componentPropertyName:"Label", fontSize:14, fontColorVariableName:"text/primary", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}, {type:"frame", name:"Actions", layoutMode:"HORIZONTAL", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG", itemSpacing:8, children:[{type:"instance", componentId:"1:2", componentPropertyName:"Action", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}]}]
178
+
177
179
  properties (array, optional) \u2014 Component properties to define at creation: [{propertyName, type, defaultValue}]. TEXT properties for inline children with componentPropertyName are created automatically.
178
180
  propertyName (string, required) \u2014 Property name
179
181
  type (BOOLEAN | TEXT | INSTANCE_SWAP, required) \u2014 Property type
@@ -182,11 +184,12 @@ Discriminant: type (component | from_node | variant_set)
182
184
 
183
185
  ## from_node \u2014 Convert existing nodes to components. Text children auto-exposed as editable properties (exposeText: true).
184
186
  nodeId (string, required) \u2014 Node ID to convert
187
+ name (string, optional) \u2014 Rename the component (default: keeps the node's current name)
185
188
  exposeText (boolean, optional) \u2014 Auto-expose text as editable properties (default: true)
186
189
 
187
190
  ## variant_set \u2014 Combine components into a variant set. The resulting set is a frame \u2014 accepts all frame properties for layout/styling.
188
191
  name (string, optional) \u2014 Node name
189
- parentId (string, optional) \u2014 Parent node ID. Omit to place on current page.
192
+ parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
190
193
  x (number, optional) \u2014 X position (default: 0)
191
194
  y (number, optional) \u2014 Y position (default: 0)
192
195
  width (number, optional) \u2014 Width in px (omit to shrink-to-content via HUG)
@@ -219,7 +222,7 @@ Discriminant: type (component | from_node | variant_set)
219
222
  bottomLeftRadius (string, optional)
220
223
  effectStyleName (string, optional) \u2014 Effect style name (e.g. 'Shadow/Card') for shadows, blurs
221
224
  layoutMode (NONE | HORIZONTAL | VERTICAL, optional) \u2014 Layout direction (default: auto \u2014 NONE when width+height set, otherwise inferred from layout props)
222
- layoutWrap (NO_WRAP | WRAP, optional)
225
+ layoutWrap (NO_WRAP | WRAP, optional) \u2014 Wrap children to new rows (HORIZONTAL layout only \u2014 Figma does not support WRAP on VERTICAL layouts). Use column frames inside a HORIZONTAL parent for vertical grid patterns.
223
226
  padding (string, optional) \u2014 All edges (number) or variable name (string). Per-edge: paddingTop, paddingRight, paddingBottom, paddingLeft.
224
227
  paddingTop (string, optional)
225
228
  paddingRight (string, optional)
@@ -237,7 +240,9 @@ Discriminant: type (component | from_node | variant_set)
237
240
  maxHeight (number, optional) \u2014 Max height for responsive auto-layout
238
241
  overflowDirection (NONE | HORIZONTAL | VERTICAL | BOTH, optional) \u2014 Scroll overflow in prototype (default: NONE)
239
242
  componentIds (string[], optional) \u2014 Existing component IDs to combine (min 2). Alternative to children.
240
- variantPropertyName (string, optional) \u2014 Rename the auto-generated variant property (default: 'Property 1')`,
243
+ variantPropertyName (string, optional) \u2014 Rename the auto-generated variant property (default: 'Property 1')
244
+ children (array, optional) \u2014 Inline variant components. Each must be {type:"component", name, children?, ...frame_params}. All variants must share the same child structure. Alternative to componentIds \u2014 do not combine both.`,
245
+ "commit": '# components.commit\nCommit a staged component \u2014 unwraps from [STAGED] container into the original target location.\n\nExample: components(method:"commit", id:"1:234")\n\nParams:\n id (string, required) \u2014 Staged node ID to commit',
241
246
  "update": '# components.update\nAdd, edit, or delete component properties\n\nExample: components(method:"update", items:[{id:"1:23", propertyName:"Label", action:"edit", defaultValue:"Click Me"}])\n\nParams:\n items (UpdatePropertyItem[], required) \u2014 Array of {id, propertyName, action?, type?, defaultValue?, name?, preferredValues?}\n id (string, required) \u2014 Component or component set ID\n propertyName (string, required) \u2014 Property name with #suffix for edit/delete (e.g. "Label#1:0"). Call components.get to find exact keys. For add, plain name works.\n action (add | edit | delete | rename_variant, optional) \u2014 "add" (default): requires type + defaultValue. "edit": pass defaultValue to change default, name to rename property. "delete": just propertyName. "rename_variant": pass defaultValue=current option name, name=new option name.\n type (BOOLEAN | TEXT | INSTANCE_SWAP | VARIANT, optional) \u2014 Property type (required for add)\n defaultValue (string_or_boolean, optional) \u2014 Default value (add/edit). For rename_variant: the CURRENT option name to rename\n name (string, optional) \u2014 New name \u2014 for edit: renames the property itself, for rename_variant: the new option value name\n preferredValues (array, optional) \u2014 Preferred values for INSTANCE_SWAP\n depth (number, optional) \u2014 Response detail: omit for id+name only. 0=properties + child stubs. N=recurse N levels. -1=unlimited.',
242
247
  "delete": "# components.delete\nDelete components or component sets\n\nParams:\n id (string, required) \u2014 Component or component set ID"
243
248
  }
@@ -268,7 +273,7 @@ Discriminant: type (component | from_node | variant_set)
268
273
  }
269
274
  },
270
275
  "frames": {
271
- "summary": '# frames\nCreate and manage frames, shapes, auto-layout containers, sections, and SVG nodes.\n\nMethods:\n get Get serialized node data [read]\n list Search for nodes (returns stubs only \u2014 use get with depth for full properties) [read]\n update Patch node properties [edit]\n delete Delete nodes [edit]\n clone Duplicate nodes [create]\n audit Run lint on a node \u2014 returns severity-ranked findings [read]\n reparent Move nodes into a new parent [edit]\n create Create frame-like containers [create]\n export Export a node as PNG, JPG, SVG, SVG_STRING, or PDF [read]\n\n// depth: omit \u2192 id+name stubs | 0 \u2192 props + child stubs | N \u2192 recurse N | -1 \u2192 full tree\n// fields: whitelist e.g. ["fills","opacity"] \u2014 id, name, type always included. Pass ["*"] for all.\n// layoutSizingHorizontal/Vertical: FIXED | HUG | FILL \u2014 how the node sizes within auto-layout.\n// Colors: fillVariableName/strokeVariableName bind by name \u2014 preferred over raw color values.\n// Note: node-based endpoints (frames, text, instances, components) use `results` as the list key.\n// Standalone endpoints (styles, variables, variable_collections) use `items`. Components.list uses `items` (catalog view).\n// ---\n// visible: false hides the node. Omitted from response when true (the default).\n// locked: true prevents editing in Figma UI. Omitted when false (the default).\n// rotation: degrees (0-360). Omitted when 0.\n// blendMode: layer blend mode. Omitted when PASS_THROUGH (the default).\n// layoutPositioning: ABSOLUTE = floating inside auto-layout parent. Omitted when AUTO (the default).\n// minWidth/maxWidth/minHeight/maxHeight: responsive constraints for auto-layout children.\n// constraints: position behavior in non-auto-layout parents. Ignored inside auto-layout frames.\n// bindings: bind design variables to node properties. field uses slash path: "fills/0/color" (first fill), "strokes/0/color", "opacity", "width", "height", "cornerRadius", "paddingLeft", "itemSpacing".\n// explicitMode: pin a variable mode on this node. Use { collectionName, modeName } (preferred) or { collectionId, modeId }.\n// properties: escape hatch \u2014 set any Figma node property directly. Use only when no dedicated field exists.\ninterface Node {\n id: string; name: string; type: string;\n visible?: boolean; // omitted when true\n locked?: boolean; // omitted when false\n opacity?: number; // omitted when 1\n rotation?: number; // omitted when 0\n blendMode?: string; // omitted when PASS_THROUGH\n layoutPositioning?: "AUTO" | "ABSOLUTE";\n layoutSizingHorizontal?: "FIXED" | "HUG" | "FILL";\n layoutSizingVertical?: "FIXED" | "HUG" | "FILL";\n minWidth?: number; maxWidth?: number; minHeight?: number; maxHeight?: number;\n absoluteBoundingBox: { x: number; y: number; width: number; height: number };\n fills?: Paint[]; // solid: {type: "SOLID", color: {r, g, b, a}}\n strokes?: Paint[];\n effects?: Effect[]; // DROP_SHADOW | INNER_SHADOW | LAYER_BLUR | BACKGROUND_BLUR\n children?: NodeStub[]; // stubs: {id, name, type} \u2014 use depth to expand\n}\n// PatchItem uses flat params matching create shape \u2014 no nested sub-objects.\n// Fill/stroke/corner/layout/text params are identical to frames.create and text.create.\n// Unknown keys produce a warning, preventing silent failures.\n// Frames are the primary container in Figma. Use auto_layout for responsive containers.\n// Sizing: FIXED = explicit size, HUG = shrink to children, FILL = expand to fill parent.\n// Fill: pass fills:[{type:"SOLID", color:"#hex"}] or [] for transparent. Shorthand: fillColor:"#3B82F6" (auto-binds to matching variable/style).\n// Also: fillVariableName:"bg/primary", fillStyleName:"Surface/Primary".\n// Stroke: pass strokes:[{type:"SOLID", color:"#hex"}] or [] to clear. Shorthand: strokeColor:"#000", strokeVariableName:"border/default".\n// Token fields (cornerRadius, opacity, itemSpacing, padding, strokeWeight): pass number for value, string for variable name/ID.\n// ---\n// SIZING: Always think about both axes. Containers with text need a width constraint \u2014 set width + layoutSizingHorizontal:"FIXED".\n// HUG/HUG is only correct for intrinsically-sized elements (buttons, badges, icons).\n// Smart defaults inside auto-layout parent: cross-axis defaults to FILL, primary axis stays HUG.\n// FILL only works inside an auto-layout parent. Use FIXED for top-level frames.\n// minWidth/maxWidth/minHeight/maxHeight: responsive constraints for auto-layout children.\n// clipsContent: true (default) clips children to the frame bounds. Set false for overflow-visible.\n// Sections are top-level organizers (like artboards) \u2014 they cannot be nested inside frames.\n// Shape primitives: rectangle, ellipse, line \u2014 for decorative/visual elements (not containers).\n// group: wraps existing nodes into a Group. boolean_operation: UNION/SUBTRACT/INTERSECT/EXCLUDE combines shapes.\n// SVG create: pass raw SVG markup string (e.g. "<svg>...</svg>") \u2014 Figma converts it to vector nodes.\n\nUse frames(method: "help", topic: "<method>") for method details.',
276
+ "summary": '# frames\nCreate and manage frames, shapes, auto-layout containers, sections, and SVG nodes.\n\nMethods:\n get Get serialized node data [read]\n list Search for nodes (returns stubs only \u2014 use get with depth for full properties) [read]\n update Patch node properties [edit]\n delete Delete nodes [edit]\n clone Duplicate nodes [create]\n audit Run lint on a node \u2014 returns severity-ranked findings [read]\n reparent Move nodes into a new parent [edit]\n create Create frame-like containers [create]\n commit Commit a staged node \u2014 unwraps from [STAGED] container into the original target location. [edit]\n export Export a node as PNG, JPG, SVG, SVG_STRING, or PDF [read]\n\n// depth: omit \u2192 id+name stubs | 0 \u2192 props + child stubs | N \u2192 recurse N | -1 \u2192 full tree\n// fields: whitelist e.g. ["fills","opacity"] \u2014 id, name, type always included. Pass ["*"] for all.\n// layoutSizingHorizontal/Vertical: FIXED | HUG | FILL \u2014 how the node sizes within auto-layout.\n// Colors: fillVariableName/strokeVariableName bind by name \u2014 preferred over raw color values.\n// Note: node-based endpoints (frames, text, instances, components) use `results` as the list key.\n// Standalone endpoints (styles, variables, variable_collections) use `items`. Components.list uses `items` (catalog view).\n// ---\n// visible: false hides the node. Omitted from response when true (the default).\n// locked: true prevents editing in Figma UI. Omitted when false (the default).\n// rotation: degrees (0-360). Omitted when 0.\n// blendMode: layer blend mode. Omitted when PASS_THROUGH (the default).\n// layoutPositioning: ABSOLUTE = floating inside auto-layout parent. Omitted when AUTO (the default).\n// minWidth/maxWidth/minHeight/maxHeight: responsive constraints for auto-layout children.\n// constraints: position behavior in non-auto-layout parents. Ignored inside auto-layout frames.\n// bindings: bind design variables to node properties. field uses slash path: "fills/0/color" (first fill), "strokes/0/color", "opacity", "width", "height", "cornerRadius", "paddingLeft", "itemSpacing".\n// explicitMode: pin a variable mode on this node. Use { collectionName, modeName } (preferred) or { collectionId, modeId }.\n// properties: escape hatch \u2014 set any Figma node property directly. Use only when no dedicated field exists.\ninterface Node {\n id: string; name: string; type: string;\n visible?: boolean; // omitted when true\n locked?: boolean; // omitted when false\n opacity?: number; // omitted when 1\n rotation?: number; // omitted when 0\n blendMode?: string; // omitted when PASS_THROUGH\n layoutPositioning?: "AUTO" | "ABSOLUTE";\n layoutSizingHorizontal?: "FIXED" | "HUG" | "FILL";\n layoutSizingVertical?: "FIXED" | "HUG" | "FILL";\n minWidth?: number; maxWidth?: number; minHeight?: number; maxHeight?: number;\n absoluteBoundingBox: { x: number; y: number; width: number; height: number };\n fills?: Paint[]; // solid: {type: "SOLID", color: {r, g, b, a}}\n strokes?: Paint[];\n effects?: Effect[]; // DROP_SHADOW | INNER_SHADOW | LAYER_BLUR | BACKGROUND_BLUR\n children?: NodeStub[]; // stubs: {id, name, type} \u2014 use depth to expand\n}\n// PatchItem uses flat params matching create shape \u2014 no nested sub-objects.\n// Fill/stroke/corner/layout/text params are identical to frames.create and text.create.\n// Unknown keys produce a warning, preventing silent failures.\n// Frames are the primary container in Figma. Use auto_layout for responsive containers.\n// Sizing: FIXED = explicit size, HUG = shrink to children, FILL = expand to fill parent.\n// Fill: pass fills:[{type:"SOLID", color:"#hex"}] or [] for transparent. Shorthand: fillColor:"#3B82F6" (auto-binds to matching variable/style).\n// Also: fillVariableName:"bg/primary", fillStyleName:"Surface/Primary".\n// Stroke: pass strokes:[{type:"SOLID", color:"#hex"}] or [] to clear. Shorthand: strokeColor:"#000", strokeVariableName:"border/default".\n// Token fields (cornerRadius, opacity, itemSpacing, padding, strokeWeight): pass number for value, string for variable name/ID.\n// ---\n// SIZING: Always think about both axes. Containers with text need a width constraint \u2014 set width + layoutSizingHorizontal:"FIXED".\n// HUG/HUG is only correct for intrinsically-sized elements (buttons, badges, icons).\n// Smart defaults inside auto-layout parent: cross-axis defaults to FILL, primary axis stays HUG.\n// FILL only works inside an auto-layout parent. Use FIXED for top-level frames.\n// minWidth/maxWidth/minHeight/maxHeight: responsive constraints for auto-layout children.\n// clipsContent: true (default) clips children to the frame bounds. Set false for overflow-visible.\n// Sections are top-level organizers (like artboards) \u2014 they cannot be nested inside frames.\n// Shape primitives: rectangle, ellipse, line \u2014 for decorative/visual elements (not containers).\n// group: wraps existing nodes into a Group. boolean_operation: UNION/SUBTRACT/INTERSECT/EXCLUDE combines shapes.\n// SVG create: pass raw SVG markup string (e.g. "<svg>...</svg>") \u2014 Figma converts it to vector nodes.\n\nUse frames(method: "help", topic: "<method>") for method details.',
272
277
  "methods": {
273
278
  "get": '# frames.get\nGet serialized node data\n\nParams:\n id (string, required) \u2014 Node ID\n fields (string[], optional) \u2014 Property whitelist. Identity fields (id, name, type) always included. Omit for stubs on list, full on get. Pass ["*"] for all.\n depth (number, optional) \u2014 Response detail: omit for id+name only. 0=properties + child stubs. N=recurse N levels. -1=unlimited.\n verbose (boolean, optional) \u2014 Include all properties (bounding box, constraints, text style details). Default false \u2014 returns slim, actionable output.',
274
279
  "list": '# frames.list\nSearch for nodes (returns stubs only \u2014 use get with depth for full properties)\n\nParams:\n query (string, optional) \u2014 Name search query (case-insensitive substring match)\n types (string[], optional) \u2014 Filter by node types (e.g. ["FRAME", "TEXT"])\n parentId (string, optional) \u2014 Search only within this subtree\n fields (string[], optional) \u2014 Property whitelist. Identity fields (id, name, type) always included. Omit for stubs on list, full on get. Pass ["*"] for all.\n offset (number, optional) \u2014 Skip N items for pagination (default 0)\n limit (number, optional) \u2014 Max items per page (default 100)',
@@ -303,7 +308,7 @@ Params:
303
308
  blendMode (PASS_THROUGH | NORMAL | DARKEN | MULTIPLY | LINEAR_BURN | COLOR_BURN | LIGHTEN | SCREEN | LINEAR_DODGE | COLOR_DODGE | OVERLAY | SOFT_LIGHT | HARD_LIGHT | DIFFERENCE | EXCLUSION | HUE | SATURATION | COLOR | LUMINOSITY, optional)
304
309
  effectStyleName (string, optional) \u2014 Effect style name (e.g. 'Shadow/Card') for shadows, blurs
305
310
  layoutMode (NONE | HORIZONTAL | VERTICAL, optional) \u2014 Layout direction (default: NONE)
306
- layoutWrap (NO_WRAP | WRAP, optional)
311
+ layoutWrap (NO_WRAP | WRAP, optional) \u2014 Wrap children to new rows (HORIZONTAL layout only \u2014 Figma does not support WRAP on VERTICAL layouts). Use column frames inside a HORIZONTAL parent for vertical grid patterns.
307
312
  padding (string, optional) \u2014 All edges (number) or variable name (string). Per-edge: paddingTop, paddingRight, paddingBottom, paddingLeft.
308
313
  paddingTop (string, optional)
309
314
  paddingRight (string, optional)
@@ -324,6 +329,10 @@ Params:
324
329
  fontFamily (string, optional) \u2014 Font family
325
330
  fontStyle (string, optional) \u2014 Font variant e.g. "Bold", "Italic" \u2014 overrides fontWeight
326
331
  fontWeight (number, optional) \u2014 100-900. Ignored when fontStyle is set.
332
+ lineHeight (number | {value, unit: "PIXELS"|"PERCENT"|"AUTO"}, optional)
333
+ letterSpacing (number | {value, unit: "PIXELS"|"PERCENT"}, optional)
334
+ textCase (ORIGINAL | UPPER | LOWER | TITLE | SMALL_CAPS | SMALL_CAPS_FORCED, optional)
335
+ textDecoration (NONE | UNDERLINE | STRIKETHROUGH, optional)
327
336
  fontColor (Color, optional) \u2014 Shorthand \u2014 sets text color (auto-binds to matching variable/style)
328
337
  fontColorVariableName (string, optional) \u2014 Bind color variable by name e.g. 'text/primary'
329
338
  fontColorStyleName (string, optional) \u2014 Apply paint style \u2014 overrides fontColor
@@ -351,7 +360,7 @@ Params:
351
360
  exportSettings (array, optional) \u2014 Export settings
352
361
  properties (object, optional) \u2014 Direct Figma API props (escape hatch)`,
353
362
  "delete": "# frames.delete\nDelete nodes\n\nParams:\n id (string, optional) \u2014 Single node ID\n items (array, optional) \u2014 Batch: [{id}, ...]\n id (string, optional)",
354
- "clone": "# frames.clone\nDuplicate nodes\n\nParams:\n id (string, optional) \u2014 Node ID\n name (string, optional) \u2014 Rename the clone (set before appending to parent \u2014 required when cloning a variant into its component set to avoid duplicate names)\n parentId (string, optional) \u2014 Parent node ID. Omit to place on current page.\n x (number, optional) \u2014 X position (default: 0)\n y (number, optional) \u2014 Y position (default: 0)\n items (array, optional) \u2014 Batch: [{id, name?, parentId?, x?, y?}, ...]. Alternative to single-item params.\n id (string, required) \u2014 Node ID to clone\n name (string, optional) \u2014 Rename the clone\n parentId (string, optional) \u2014 Target parent\n x (number, optional)\n y (number, optional)\n depth (number, optional) \u2014 Response detail: omit for id+name only. 0=properties + child stubs. N=recurse N levels. -1=unlimited.",
363
+ "clone": "# frames.clone\nDuplicate nodes\n\nParams:\n id (string, optional) \u2014 Node ID\n name (string, optional) \u2014 Rename the clone (set before appending to parent \u2014 required when cloning a variant into its component set to avoid duplicate names)\n parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.\n x (number, optional) \u2014 X position (default: 0)\n y (number, optional) \u2014 Y position (default: 0)\n items (array, optional) \u2014 Batch: [{id, name?, parentId?, x?, y?}, ...]. Alternative to single-item params.\n id (string, required) \u2014 Node ID to clone\n name (string, optional) \u2014 Rename the clone\n parentId (string, optional) \u2014 Target parent\n x (number, optional)\n y (number, optional)\n depth (number, optional) \u2014 Response detail: omit for id+name only. 0=properties + child stubs. N=recurse N levels. -1=unlimited.",
355
364
  "audit": `# frames.audit
356
365
  Run lint on a node \u2014 returns severity-ranked findings
357
366
 
@@ -372,7 +381,7 @@ Discriminant: type (frame | auto_layout | section | rectangle | ellipse | line |
372
381
 
373
382
  ## frame \u2014 General-purpose frame \u2014 shrinks to content by default, static when width+height given
374
383
  name (string, optional) \u2014 Node name
375
- parentId (string, optional) \u2014 Parent node ID. Omit to place on current page.
384
+ parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
376
385
  x (number, optional) \u2014 X position (default: 0)
377
386
  y (number, optional) \u2014 Y position (default: 0)
378
387
  width (number, optional) \u2014 Width in px (omit to shrink-to-content via HUG)
@@ -405,7 +414,7 @@ Discriminant: type (frame | auto_layout | section | rectangle | ellipse | line |
405
414
  bottomLeftRadius (string, optional)
406
415
  effectStyleName (string, optional) \u2014 Effect style name (e.g. 'Shadow/Card') for shadows, blurs
407
416
  layoutMode (NONE | HORIZONTAL | VERTICAL, optional) \u2014 Layout direction (default: auto \u2014 NONE when width+height set, otherwise inferred from layout props)
408
- layoutWrap (NO_WRAP | WRAP, optional)
417
+ layoutWrap (NO_WRAP | WRAP, optional) \u2014 Wrap children to new rows (HORIZONTAL layout only \u2014 Figma does not support WRAP on VERTICAL layouts). Use column frames inside a HORIZONTAL parent for vertical grid patterns.
409
418
  padding (string, optional) \u2014 All edges (number) or variable name (string). Per-edge: paddingTop, paddingRight, paddingBottom, paddingLeft.
410
419
  paddingTop (string, optional)
411
420
  paddingRight (string, optional)
@@ -423,10 +432,12 @@ Discriminant: type (frame | auto_layout | section | rectangle | ellipse | line |
423
432
  maxHeight (number, optional) \u2014 Max height for responsive auto-layout
424
433
  overflowDirection (NONE | HORIZONTAL | VERTICAL | BOTH, optional) \u2014 Scroll overflow in prototype (default: NONE)
425
434
  clipsContent (boolean, optional)
435
+ children (array, optional) \u2014 Inline child nodes \u2014 build nested trees in one call. Types: text: {type:"text", text, fontFamily?, fontSize?, fontWeight?, fontStyle?, fontColor?, layoutSizingHorizontal?}. frame: {type:"frame", name?, layoutMode?, fillColor?, width?, layoutSizingHorizontal?, children?}. instance: {type:"instance", componentId, variantProperties?, properties?}. component: {type:"component", name, children?}. All params from text/frame endpoints are supported on their respective types. Always set layoutSizingHorizontal + layoutSizingVertical on children inside auto-layout parents (FILL, HUG, or FIXED). Example: children:[{type:"text", text:"Title", fontSize:20, layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}, {type:"frame", name:"Row", layoutMode:"HORIZONTAL", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG", itemSpacing:8, children:[{type:"instance", componentId:"1:2", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}]}] Inside components: add componentPropertyName to auto-bind TEXT or INSTANCE_SWAP properties.
436
+
426
437
 
427
438
  ## auto_layout \u2014 Auto-layout frame that arranges children automatically
428
439
  name (string, optional) \u2014 Node name
429
- parentId (string, optional) \u2014 Parent node ID. Omit to place on current page.
440
+ parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
430
441
  x (number, optional) \u2014 X position (default: 0)
431
442
  y (number, optional) \u2014 Y position (default: 0)
432
443
  width (number, optional) \u2014 Width in px (omit to shrink-to-content via HUG)
@@ -459,7 +470,7 @@ Discriminant: type (frame | auto_layout | section | rectangle | ellipse | line |
459
470
  bottomLeftRadius (string, optional)
460
471
  effectStyleName (string, optional) \u2014 Effect style name (e.g. 'Shadow/Card') for shadows, blurs
461
472
  layoutMode (HORIZONTAL | VERTICAL, required) \u2014 Primary axis direction
462
- layoutWrap (NO_WRAP | WRAP, optional)
473
+ layoutWrap (NO_WRAP | WRAP, optional) \u2014 Wrap children to new rows (HORIZONTAL layout only \u2014 Figma does not support WRAP on VERTICAL layouts). Use column frames inside a HORIZONTAL parent for vertical grid patterns.
463
474
  padding (string, optional) \u2014 All edges (number) or variable name (string). Per-edge: paddingTop, paddingRight, paddingBottom, paddingLeft.
464
475
  paddingTop (string, optional)
465
476
  paddingRight (string, optional)
@@ -478,10 +489,12 @@ Discriminant: type (frame | auto_layout | section | rectangle | ellipse | line |
478
489
  overflowDirection (NONE | HORIZONTAL | VERTICAL | BOTH, optional) \u2014 Scroll overflow in prototype (default: NONE)
479
490
  clipsContent (boolean, optional)
480
491
  nodeIds (string[], optional) \u2014 Existing node IDs to wrap into auto-layout
492
+ children (array, optional) \u2014 Inline child nodes \u2014 build nested trees in one call. Types: text: {type:"text", text, fontFamily?, fontSize?, fontWeight?, fontStyle?, fontColor?, layoutSizingHorizontal?}. frame: {type:"frame", name?, layoutMode?, fillColor?, width?, layoutSizingHorizontal?, children?}. instance: {type:"instance", componentId, variantProperties?, properties?}. component: {type:"component", name, children?}. All params from text/frame endpoints are supported on their respective types. Always set layoutSizingHorizontal + layoutSizingVertical on children inside auto-layout parents (FILL, HUG, or FIXED). Example: children:[{type:"text", text:"Title", fontSize:20, layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}, {type:"frame", name:"Row", layoutMode:"HORIZONTAL", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG", itemSpacing:8, children:[{type:"instance", componentId:"1:2", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}]}] Inside components: add componentPropertyName to auto-bind TEXT or INSTANCE_SWAP properties.
493
+
481
494
 
482
495
  ## section \u2014 Figma section (top-level organizer)
483
496
  name (string, required) \u2014 Section name
484
- parentId (string, optional) \u2014 Parent node ID. Omit to place on current page.
497
+ parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
485
498
  x (number, optional) \u2014 X position (default: 0)
486
499
  y (number, optional) \u2014 Y position (default: 0)
487
500
  width (number, optional) \u2014 Width (default: 500)
@@ -493,7 +506,7 @@ Discriminant: type (frame | auto_layout | section | rectangle | ellipse | line |
493
506
 
494
507
  ## rectangle \u2014 Rectangle shape node
495
508
  name (string, optional) \u2014 Layer name (default: 'Rectangle')
496
- parentId (string, optional) \u2014 Parent node ID. Omit to place on current page.
509
+ parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
497
510
  x (number, optional) \u2014 X position (default: 0)
498
511
  y (number, optional) \u2014 Y position (default: 0)
499
512
  width (number, optional) \u2014 Width in px (default: 100)
@@ -517,7 +530,7 @@ Discriminant: type (frame | auto_layout | section | rectangle | ellipse | line |
517
530
 
518
531
  ## ellipse \u2014 Ellipse/circle shape node
519
532
  name (string, optional) \u2014 Layer name (default: 'Ellipse')
520
- parentId (string, optional) \u2014 Parent node ID. Omit to place on current page.
533
+ parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
521
534
  x (number, optional) \u2014 X position (default: 0)
522
535
  y (number, optional) \u2014 Y position (default: 0)
523
536
  width (number, optional) \u2014 Width in px (default: 100)
@@ -536,7 +549,7 @@ Discriminant: type (frame | auto_layout | section | rectangle | ellipse | line |
536
549
 
537
550
  ## line \u2014 Line shape node
538
551
  name (string, optional) \u2014 Layer name (default: 'Line')
539
- parentId (string, optional) \u2014 Parent node ID. Omit to place on current page.
552
+ parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
540
553
  x (number, optional) \u2014 X position (default: 0)
541
554
  y (number, optional) \u2014 Y position (default: 0)
542
555
  length (number, optional) \u2014 Line length in px (default: 100)
@@ -551,24 +564,25 @@ Discriminant: type (frame | auto_layout | section | rectangle | ellipse | line |
551
564
  ## group \u2014 Group existing nodes together
552
565
  nodeIds (string[], required) \u2014 Node IDs to group (min 1)
553
566
  name (string, optional) \u2014 Group name
554
- parentId (string, optional) \u2014 Parent node ID. Omit to place on current page.
567
+ parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
555
568
 
556
569
  ## boolean_operation \u2014 Combine shapes with boolean operations (union, subtract, intersect, exclude)
557
570
  operation (UNION | SUBTRACT | INTERSECT | EXCLUDE, required) \u2014 Boolean operation type
558
571
  nodeIds (string[], required) \u2014 Node IDs to combine (min 2, first node is the base for SUBTRACT)
559
572
  name (string, optional) \u2014 Result node name
560
- parentId (string, optional) \u2014 Parent node ID. Omit to place on current page.
573
+ parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
561
574
 
562
575
  ## svg \u2014 Create node from SVG markup
563
576
  svg (string, required) \u2014 SVG markup string
564
577
  name (string, optional) \u2014 Layer name (default: 'SVG')
565
- parentId (string, optional) \u2014 Parent node ID. Omit to place on current page.
578
+ parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
566
579
  x (number, optional) \u2014 X position (default: 0)
567
580
  y (number, optional) \u2014 Y position (default: 0)
568
581
  fillStyleName (string, optional) \u2014 Paint style to apply to vector fills
569
582
  fillVariableName (string, optional) \u2014 Color variable by name for vector fills
570
583
  strokeStyleName (string, optional) \u2014 Paint style to apply to vector strokes
571
584
  strokeVariableName (string, optional) \u2014 Color variable by name for vector strokes`,
585
+ "commit": '# frames.commit\nCommit a staged node \u2014 unwraps from [STAGED] container into the original target location.\n\nExample: frames(method:"commit", id:"1:234")\n\nParams:\n id (string, required) \u2014 Staged node ID to commit',
572
586
  "export": "# frames.export\nExport a node as PNG, JPG, SVG, SVG_STRING, or PDF\n\nParams:\n id (string, required) \u2014 Node ID to export\n format (PNG | JPG | SVG | SVG_STRING | PDF, optional) \u2014 Export format (default: PNG). SVG_STRING returns raw SVG text.\n scale (number, optional) \u2014 Export scale (default: 1, only for PNG/JPG)"
573
587
  }
574
588
  },
@@ -577,7 +591,7 @@ Discriminant: type (frame | auto_layout | section | rectangle | ellipse | line |
577
591
  "methods": {
578
592
  "list": '# instances.list\nSearch for nodes (returns stubs only \u2014 use get with depth for full properties)\n\nParams:\n query (string, optional) \u2014 Name search query (case-insensitive substring match)\n types (string[], optional) \u2014 Filter by node types (e.g. ["FRAME", "TEXT"])\n parentId (string, optional) \u2014 Search only within this subtree\n fields (string[], optional) \u2014 Property whitelist. Identity fields (id, name, type) always included. Omit for stubs on list, full on get. Pass ["*"] for all.\n offset (number, optional) \u2014 Skip N items for pagination (default 0)\n limit (number, optional) \u2014 Max items per page (default 100)',
579
593
  "delete": "# instances.delete\nDelete nodes\n\nParams:\n id (string, optional) \u2014 Single node ID\n items (array, optional) \u2014 Batch: [{id}, ...]\n id (string, optional)",
580
- "clone": "# instances.clone\nDuplicate nodes\n\nParams:\n id (string, optional) \u2014 Node ID\n name (string, optional) \u2014 Rename the clone (set before appending to parent \u2014 required when cloning a variant into its component set to avoid duplicate names)\n parentId (string, optional) \u2014 Parent node ID. Omit to place on current page.\n x (number, optional) \u2014 X position (default: 0)\n y (number, optional) \u2014 Y position (default: 0)\n items (array, optional) \u2014 Batch: [{id, name?, parentId?, x?, y?}, ...]. Alternative to single-item params.\n id (string, required) \u2014 Node ID to clone\n name (string, optional) \u2014 Rename the clone\n parentId (string, optional) \u2014 Target parent\n x (number, optional)\n y (number, optional)\n depth (number, optional) \u2014 Response detail: omit for id+name only. 0=properties + child stubs. N=recurse N levels. -1=unlimited.",
594
+ "clone": "# instances.clone\nDuplicate nodes\n\nParams:\n id (string, optional) \u2014 Node ID\n name (string, optional) \u2014 Rename the clone (set before appending to parent \u2014 required when cloning a variant into its component set to avoid duplicate names)\n parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.\n x (number, optional) \u2014 X position (default: 0)\n y (number, optional) \u2014 Y position (default: 0)\n items (array, optional) \u2014 Batch: [{id, name?, parentId?, x?, y?}, ...]. Alternative to single-item params.\n id (string, required) \u2014 Node ID to clone\n name (string, optional) \u2014 Rename the clone\n parentId (string, optional) \u2014 Target parent\n x (number, optional)\n y (number, optional)\n depth (number, optional) \u2014 Response detail: omit for id+name only. 0=properties + child stubs. N=recurse N levels. -1=unlimited.",
581
595
  "audit": `# instances.audit
582
596
  Run lint on a node \u2014 returns severity-ranked findings
583
597
 
@@ -618,7 +632,7 @@ Params:
618
632
  y (number, optional)
619
633
  width (number, optional) \u2014 Override width (resize)
620
634
  height (number, optional) \u2014 Override height (resize)
621
- parentId (string, optional) \u2014 Parent node ID. Omit to place on current page.
635
+ parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
622
636
  depth (number, optional) \u2014 Response detail: omit for id+name only. 0=properties + child stubs. N=recurse N levels. -1=unlimited.`,
623
637
  "update": `# instances.update
624
638
  Set instance properties
@@ -653,7 +667,7 @@ Params:
653
667
  blendMode (PASS_THROUGH | NORMAL | DARKEN | MULTIPLY | LINEAR_BURN | COLOR_BURN | LIGHTEN | SCREEN | LINEAR_DODGE | COLOR_DODGE | OVERLAY | SOFT_LIGHT | HARD_LIGHT | DIFFERENCE | EXCLUSION | HUE | SATURATION | COLOR | LUMINOSITY, optional)
654
668
  effectStyleName (string, optional) \u2014 Effect style name (e.g. 'Shadow/Card') for shadows, blurs
655
669
  layoutMode (NONE | HORIZONTAL | VERTICAL, optional) \u2014 Layout direction (default: NONE)
656
- layoutWrap (NO_WRAP | WRAP, optional)
670
+ layoutWrap (NO_WRAP | WRAP, optional) \u2014 Wrap children to new rows (HORIZONTAL layout only \u2014 Figma does not support WRAP on VERTICAL layouts). Use column frames inside a HORIZONTAL parent for vertical grid patterns.
657
671
  padding (string, optional) \u2014 All edges (number) or variable name (string). Per-edge: paddingTop, paddingRight, paddingBottom, paddingLeft.
658
672
  paddingTop (string, optional)
659
673
  paddingRight (string, optional)
@@ -674,6 +688,10 @@ Params:
674
688
  fontFamily (string, optional) \u2014 Font family
675
689
  fontStyle (string, optional) \u2014 Font variant e.g. "Bold", "Italic" \u2014 overrides fontWeight
676
690
  fontWeight (number, optional) \u2014 100-900. Ignored when fontStyle is set.
691
+ lineHeight (number | {value, unit: "PIXELS"|"PERCENT"|"AUTO"}, optional)
692
+ letterSpacing (number | {value, unit: "PIXELS"|"PERCENT"}, optional)
693
+ textCase (ORIGINAL | UPPER | LOWER | TITLE | SMALL_CAPS | SMALL_CAPS_FORCED, optional)
694
+ textDecoration (NONE | UNDERLINE | STRIKETHROUGH, optional)
677
695
  fontColor (Color, optional) \u2014 Shorthand \u2014 sets text color (auto-binds to matching variable/style)
678
696
  fontColorVariableName (string, optional) \u2014 Bind color variable by name e.g. 'text/primary'
679
697
  fontColorStyleName (string, optional) \u2014 Apply paint style \u2014 overrides fontColor
@@ -771,7 +789,7 @@ Use lint(method: "help", topic: "<method>") for method details.`,
771
789
  "summary": '# prototyping\nManage prototype interactions, reactions, and navigation flows.\n\nMethods:\n get Get reactions and overflow direction on a node [read]\n add Add a prototype reaction to a node [edit]\n set Replace all reactions on a node (raw reactions array) [edit]\n remove Remove a reaction from a node by index [edit]\n\n// Reactions wire up interactions: trigger (ON_CLICK, ON_HOVER, ...) \u2192 action (navigate, swap, overlay).\n// Common patterns: button ON_CLICK \u2192 NAVIGATE to detail frame; card ON_HOVER \u2192 CHANGE_TO hover variant.\n// Multi-action: pass actions[] array to run multiple actions on one trigger (e.g. navigate + set variable mode).\n// ---\n// IMPORTANT: destination rules depend on navigation type:\n// NAVIGATE/SWAP/OVERLAY/SCROLL_TO \u2192 destination must be a top-level frame (direct child of a page). Nested frames are rejected.\n// CHANGE_TO \u2192 destination must be a variant (COMPONENT inside a COMPONENT_SET). Used for hover/state swaps within the same component.\n// ---\n// TRIGGERS: ON_CLICK | ON_HOVER | ON_PRESS | ON_DRAG | AFTER_TIMEOUT(timeout) | MOUSE_ENTER(delay) | MOUSE_LEAVE(delay) | ON_KEY_DOWN(keyCodes)\n// NAVIGATION: NAVIGATE (go to frame) | SWAP (swap overlay) | OVERLAY (show overlay) | SCROLL_TO | CHANGE_TO (swap component variant)\n// TRANSITIONS: DISSOLVE | SMART_ANIMATE | MOVE_IN | MOVE_OUT | PUSH | SLIDE_IN | SLIDE_OUT (+ direction for directional)\n// EASING: EASE_IN | EASE_OUT | EASE_IN_AND_OUT | LINEAR | GENTLE | QUICK | BOUNCY | SLOW\n// ACTIONS: NODE (navigate/swap) | BACK (go back) | CLOSE (close overlay) | URL (open link) | SET_VARIABLE_MODE (switch theme/mode)\n\nUse prototyping(method: "help", topic: "<method>") for method details.',
772
790
  "methods": {
773
791
  "get": "# prototyping.get\nGet reactions and overflow direction on a node\n\nParams:\n id (string, required) \u2014 Node ID",
774
- "add": '# prototyping.add\nAdd a prototype reaction to a node\n\nExample: prototyping(method:"add", id:"btn-1", trigger:"ON_CLICK", destination:"detail-frame-id", navigation:"NAVIGATE")\n\nParams:\n id (string, required) \u2014 Node ID\n trigger (ON_CLICK | ON_HOVER | ON_PRESS | ON_DRAG | AFTER_TIMEOUT | MOUSE_ENTER | MOUSE_LEAVE | ON_KEY_DOWN, required) \u2014 Trigger type\n triggerDelay (number, optional) \u2014 Delay in ms for AFTER_TIMEOUT / MOUSE_ENTER / MOUSE_LEAVE triggers\n triggerKeyCodes (number[], optional) \u2014 Key codes for ON_KEY_DOWN trigger\n triggerDevice (KEYBOARD | XBOX_ONE | PS4 | SWITCH_PRO, optional) \u2014 Device for ON_KEY_DOWN (default: KEYBOARD)\n destination (string, optional) \u2014 Target node ID (required for NODE actions). NAVIGATE/SWAP/OVERLAY: must be a top-level frame. CHANGE_TO: must be a variant (component inside a component set).\n navigation (NAVIGATE | SWAP | OVERLAY | SCROLL_TO | CHANGE_TO, optional) \u2014 Navigation type (default: NAVIGATE)\n transition (DISSOLVE | SMART_ANIMATE | MOVE_IN | MOVE_OUT | PUSH | SLIDE_IN | SLIDE_OUT | INSTANT, optional) \u2014 Transition animation (default: DISSOLVE). INSTANT = no animation.\n transitionDirection (LEFT | RIGHT | TOP | BOTTOM, optional) \u2014 Direction for MOVE_IN, MOVE_OUT, PUSH, SLIDE_IN, SLIDE_OUT\n duration (number, optional) \u2014 Transition duration in seconds (default: 0.3)\n easing (EASE_IN | EASE_OUT | EASE_IN_AND_OUT | LINEAR | GENTLE | QUICK | BOUNCY | SLOW, optional) \u2014 Easing function (default: EASE_OUT)\n actionType (NODE | BACK | CLOSE | URL | SET_VARIABLE_MODE, optional) \u2014 Action type (default: NODE). SET_VARIABLE_MODE switches a variable collection mode.\n url (string, optional) \u2014 URL for URL action type\n collectionName (string, optional) \u2014 Variable collection name (for SET_VARIABLE_MODE)\n modeName (string, optional) \u2014 Mode name to switch to (for SET_VARIABLE_MODE)\n resetScrollPosition (boolean, optional) \u2014 Reset scroll position on navigate (default: true)\n actions (array, optional) \u2014 Multi-action: [{actionType, destination?, navigation?, collectionName?, modeName?, ...}]. Overrides single-action params.',
792
+ "add": '# prototyping.add\nAdd a prototype reaction to a node\n\nExample: prototyping(method:"add", items:[{id:"btn-1", trigger:"ON_CLICK", destination:"frame-2", navigation:"NAVIGATE", transition:"SMART_ANIMATE"}, {id:"btn-2", trigger:"ON_CLICK", destination:"frame-3"}])\n\nParams:\n id (string, optional) \u2014 Node ID\n trigger (ON_CLICK | ON_HOVER | ON_PRESS | ON_DRAG | AFTER_TIMEOUT | MOUSE_ENTER | MOUSE_LEAVE | ON_KEY_DOWN, optional) \u2014 Trigger type\n triggerDelay (number, optional) \u2014 Delay in ms for AFTER_TIMEOUT / MOUSE_ENTER / MOUSE_LEAVE triggers\n triggerKeyCodes (number[], optional) \u2014 Key codes for ON_KEY_DOWN trigger\n triggerDevice (KEYBOARD | XBOX_ONE | PS4 | SWITCH_PRO, optional) \u2014 Device for ON_KEY_DOWN (default: KEYBOARD)\n destination (string, optional) \u2014 Target node ID (required for NODE actions). NAVIGATE/SWAP/OVERLAY: must be a top-level frame. CHANGE_TO: must be a variant (component inside a component set).\n navigation (NAVIGATE | SWAP | OVERLAY | SCROLL_TO | CHANGE_TO, optional) \u2014 Navigation type (default: NAVIGATE)\n transition (DISSOLVE | SMART_ANIMATE | MOVE_IN | MOVE_OUT | PUSH | SLIDE_IN | SLIDE_OUT | INSTANT, optional) \u2014 Transition animation (default: DISSOLVE). INSTANT = no animation.\n transitionDirection (LEFT | RIGHT | TOP | BOTTOM, optional) \u2014 Direction for MOVE_IN, MOVE_OUT, PUSH, SLIDE_IN, SLIDE_OUT\n duration (number, optional) \u2014 Transition duration in seconds (default: 0.3)\n easing (EASE_IN | EASE_OUT | EASE_IN_AND_OUT | LINEAR | GENTLE | QUICK | BOUNCY | SLOW, optional) \u2014 Easing function (default: EASE_OUT)\n actionType (NODE | BACK | CLOSE | URL | SET_VARIABLE_MODE, optional) \u2014 Action type (default: NODE). SET_VARIABLE_MODE switches a variable collection mode.\n url (string, optional) \u2014 URL for URL action type\n collectionName (string, optional) \u2014 Variable collection name (for SET_VARIABLE_MODE)\n modeName (string, optional) \u2014 Mode name to switch to (for SET_VARIABLE_MODE)\n resetScrollPosition (boolean, optional) \u2014 Reset scroll position on navigate (default: true)\n actions (array, optional) \u2014 Multi-action: [{actionType, destination?, navigation?, collectionName?, modeName?, ...}]. Overrides single-action params.\n items (array, optional) \u2014 Batch: array of {id, trigger, destination?, ...} reaction items\n id (string, required) \u2014 Node ID\n trigger (ON_CLICK | ON_HOVER | ON_PRESS | ON_DRAG | AFTER_TIMEOUT | MOUSE_ENTER | MOUSE_LEAVE | ON_KEY_DOWN, required) \u2014 Trigger type\n destination (string, optional) \u2014 Target node ID\n navigation (NAVIGATE | SWAP | OVERLAY | SCROLL_TO | CHANGE_TO, optional)\n transition (DISSOLVE | SMART_ANIMATE | MOVE_IN | MOVE_OUT | PUSH | SLIDE_IN | SLIDE_OUT | INSTANT, optional)\n transitionDirection (LEFT | RIGHT | TOP | BOTTOM, optional)\n duration (number, optional)\n easing (EASE_IN | EASE_OUT | EASE_IN_AND_OUT | LINEAR | GENTLE | QUICK | BOUNCY | SLOW, optional)\n actionType (NODE | BACK | CLOSE | URL | SET_VARIABLE_MODE, optional)\n triggerDelay (number, optional)\n url (string, optional)\n collectionName (string, optional)\n modeName (string, optional)\n resetScrollPosition (boolean, optional)\n actions (array, optional)',
775
793
  "set": "# prototyping.set\nReplace all reactions on a node (raw reactions array)\n\nParams:\n id (string, required) \u2014 Node ID\n reactions (array, required) \u2014 Full reactions array \u2014 [{trigger:{type}, actions:[{type, destinationId, navigation, transition}]}]",
776
794
  "remove": "# prototyping.remove\nRemove a reaction from a node by index\n\nParams:\n id (string, required) \u2014 Node ID\n index (number, required) \u2014 Reaction index (0-based)"
777
795
  }
@@ -788,8 +806,8 @@ Use lint(method: "help", topic: "<method>") for method details.`,
788
806
  "methods": {
789
807
  "list": '# styles.list\nList local styles with optional type filter\n\nParams:\n type (paint | text | effect | grid, optional) \u2014 Filter by style type\n fields (string[], optional) \u2014 Property whitelist. Identity fields (id, name, type) always included. Omit for stubs on list, full on get. Pass ["*"] for all.\n offset (number, optional) \u2014 Skip N items for pagination (default 0)\n limit (number, optional) \u2014 Max items per page (default 100)',
790
808
  "get": '# styles.get\nGet full style detail by ID\n\nParams:\n id (string, required) \u2014 Style ID or name\n fields (string[], optional) \u2014 Property whitelist. Identity fields (id, name, type) always included. Omit for stubs on list, full on get. Pass ["*"] for all.',
791
- "create": '# styles.create\nCreate local styles\n\nExample: styles(method:"create", type:"effect", name:"Shadow/Medium", effects:[{type:"DROP_SHADOW", color:"#00000040", offset:{x:0,y:4}, radius:8}])\n\nDiscriminant: type (paint | text | effect | grid)\n\n ## paint \u2014 Paint/color style\n name (string, required) \u2014 Style name\n color (Color, optional) \u2014 Color value. Optional when colorVariableName is provided.\n colorVariableName (string, optional) \u2014 Bind to a COLOR variable by name (style tracks the variable). Can be used alone \u2014 color is resolved from the variable.\n description (string, optional) \u2014 Style description\n\n ## text \u2014 Text style\n name (string, required) \u2014 Style name\n fontFamily (string, required) \u2014 Font family\n fontStyle (string, optional) \u2014 Font style (default: Regular)\n fontSize (number, required) \u2014 Font size\n lineHeight (line_height, optional)\n letterSpacing (letter_spacing, optional)\n textCase (ORIGINAL | UPPER | LOWER | TITLE | SMALL_CAPS | SMALL_CAPS_FORCED, optional)\n textDecoration (NONE | UNDERLINE | STRIKETHROUGH, optional)\n paragraphIndent (number, optional) \u2014 Paragraph indent (px)\n paragraphSpacing (number, optional) \u2014 Paragraph spacing (px)\n leadingTrim (CAP_HEIGHT | NONE, optional) \u2014 Leading trim mode\n description (string, optional) \u2014 Style description\n\n ## effect \u2014 Effect style\n name (string, required) \u2014 Style name\n effects (array, required) \u2014 Array of Effect objects\n description (string, optional) \u2014 Style description\n\n ## grid \u2014 Grid/layout grid style\n name (string, required) \u2014 Style name\n layoutGrids (array, required) \u2014 Array of LayoutGrid objects\n description (string, optional) \u2014 Style description',
792
- "update": '# styles.update\nUpdate styles by ID or name\n\nExample: styles(method:"update", items:[{id:"Surface/Primary", color:"#F5F5F5"}])\n\nParams:\n type (paint | text | effect | grid, optional) \u2014 Style type hint for strict validation (optional, auto-detected)\n items (PatchStyleItem[], required) \u2014 Array of {id, ...fields} to update\n id (string, required) \u2014 Style ID or name\n name (string, optional) \u2014 Rename the style\n description (string, optional) \u2014 Style description\n color (Color, optional) \u2014 New color (paint styles)\n colorVariableName (string, optional) \u2014 Bind to a COLOR variable by name (paint styles)\n fontFamily (string, optional)\n fontStyle (string, optional)\n fontSize (number, optional)\n lineHeight (line_height, optional)\n letterSpacing (letter_spacing, optional)\n textCase (ORIGINAL | UPPER | LOWER | TITLE | SMALL_CAPS | SMALL_CAPS_FORCED, optional)\n textDecoration (NONE | UNDERLINE | STRIKETHROUGH, optional)\n paragraphIndent (number, optional) \u2014 Paragraph indent (px)\n paragraphSpacing (number, optional) \u2014 Paragraph spacing (px)\n leadingTrim (CAP_HEIGHT | NONE, optional)\n effects (array, optional) \u2014 Array of Effect objects\n layoutGrids (array, optional) \u2014 Array of LayoutGrid objects (grid styles)',
809
+ "create": '# styles.create\nCreate local styles\n\nExample: styles(method:"create", type:"effect", name:"Shadow/Medium", effects:[{type:"DROP_SHADOW", color:"#00000040", offset:{x:0,y:4}, radius:8}])\n\nDiscriminant: type (paint | text | effect | grid)\n\n ## paint \u2014 Paint/color style\n name (string, required) \u2014 Style name\n color (Color, optional) \u2014 Color value. Optional when colorVariableName is provided.\n colorVariableName (string, optional) \u2014 Bind to a COLOR variable by name (style tracks the variable). Can be used alone \u2014 color is resolved from the variable.\n description (string, optional) \u2014 Style description\n\n ## text \u2014 Text style\n name (string, required) \u2014 Style name\n fontFamily (string, required) \u2014 Font family\n fontStyle (string, optional) \u2014 Font style (default: Regular)\n fontSize (number, required) \u2014 Font size\n lineHeight (number | {value, unit: "PIXELS"|"PERCENT"|"AUTO"}, optional)\n letterSpacing (number | {value, unit: "PIXELS"|"PERCENT"}, optional)\n textCase (ORIGINAL | UPPER | LOWER | TITLE | SMALL_CAPS | SMALL_CAPS_FORCED, optional)\n textDecoration (NONE | UNDERLINE | STRIKETHROUGH, optional)\n paragraphIndent (number, optional) \u2014 Paragraph indent (px)\n paragraphSpacing (number, optional) \u2014 Paragraph spacing (px)\n leadingTrim (CAP_HEIGHT | NONE, optional) \u2014 Leading trim mode\n description (string, optional) \u2014 Style description\n\n ## effect \u2014 Effect style\n name (string, required) \u2014 Style name\n effects (array, required) \u2014 Array of Effect objects\n description (string, optional) \u2014 Style description\n\n ## grid \u2014 Grid/layout grid style\n name (string, required) \u2014 Style name\n layoutGrids (array, required) \u2014 Array of LayoutGrid objects\n description (string, optional) \u2014 Style description',
810
+ "update": '# styles.update\nUpdate styles by ID or name\n\nExample: styles(method:"update", items:[{id:"Surface/Primary", color:"#F5F5F5"}])\n\nParams:\n type (paint | text | effect | grid, optional) \u2014 Style type hint for strict validation (optional, auto-detected)\n items (PatchStyleItem[], required) \u2014 Array of {id, ...fields} to update\n id (string, required) \u2014 Style ID or name\n name (string, optional) \u2014 Rename the style\n description (string, optional) \u2014 Style description\n color (Color, optional) \u2014 New color (paint styles)\n colorVariableName (string, optional) \u2014 Bind to a COLOR variable by name (paint styles)\n fontFamily (string, optional)\n fontStyle (string, optional)\n fontSize (number, optional)\n lineHeight (number | {value, unit: "PIXELS"|"PERCENT"|"AUTO"}, optional)\n letterSpacing (number | {value, unit: "PIXELS"|"PERCENT"}, optional)\n textCase (ORIGINAL | UPPER | LOWER | TITLE | SMALL_CAPS | SMALL_CAPS_FORCED, optional)\n textDecoration (NONE | UNDERLINE | STRIKETHROUGH, optional)\n paragraphIndent (number, optional) \u2014 Paragraph indent (px)\n paragraphSpacing (number, optional) \u2014 Paragraph spacing (px)\n leadingTrim (CAP_HEIGHT | NONE, optional)\n effects (array, optional) \u2014 Array of Effect objects\n layoutGrids (array, optional) \u2014 Array of LayoutGrid objects (grid styles)',
793
811
  "delete": "# styles.delete\nDelete styles\n\nParams:\n id (string, optional) \u2014 Style ID or name\n items (array, optional) \u2014 Batch: [{id}, ...]\n id (string, required) \u2014 Style ID or name"
794
812
  }
795
813
  },
@@ -829,7 +847,7 @@ Params:
829
847
  blendMode (PASS_THROUGH | NORMAL | DARKEN | MULTIPLY | LINEAR_BURN | COLOR_BURN | LIGHTEN | SCREEN | LINEAR_DODGE | COLOR_DODGE | OVERLAY | SOFT_LIGHT | HARD_LIGHT | DIFFERENCE | EXCLUSION | HUE | SATURATION | COLOR | LUMINOSITY, optional)
830
848
  effectStyleName (string, optional) \u2014 Effect style name (e.g. 'Shadow/Card') for shadows, blurs
831
849
  layoutMode (NONE | HORIZONTAL | VERTICAL, optional) \u2014 Layout direction (default: NONE)
832
- layoutWrap (NO_WRAP | WRAP, optional)
850
+ layoutWrap (NO_WRAP | WRAP, optional) \u2014 Wrap children to new rows (HORIZONTAL layout only \u2014 Figma does not support WRAP on VERTICAL layouts). Use column frames inside a HORIZONTAL parent for vertical grid patterns.
833
851
  padding (string, optional) \u2014 All edges (number) or variable name (string). Per-edge: paddingTop, paddingRight, paddingBottom, paddingLeft.
834
852
  paddingTop (string, optional)
835
853
  paddingRight (string, optional)
@@ -850,6 +868,10 @@ Params:
850
868
  fontFamily (string, optional) \u2014 Font family
851
869
  fontStyle (string, optional) \u2014 Font variant e.g. "Bold", "Italic" \u2014 overrides fontWeight
852
870
  fontWeight (number, optional) \u2014 100-900. Ignored when fontStyle is set.
871
+ lineHeight (number | {value, unit: "PIXELS"|"PERCENT"|"AUTO"}, optional)
872
+ letterSpacing (number | {value, unit: "PIXELS"|"PERCENT"}, optional)
873
+ textCase (ORIGINAL | UPPER | LOWER | TITLE | SMALL_CAPS | SMALL_CAPS_FORCED, optional)
874
+ textDecoration (NONE | UNDERLINE | STRIKETHROUGH, optional)
853
875
  fontColor (Color, optional) \u2014 Shorthand \u2014 sets text color (auto-binds to matching variable/style)
854
876
  fontColorVariableName (string, optional) \u2014 Bind color variable by name e.g. 'text/primary'
855
877
  fontColorStyleName (string, optional) \u2014 Apply paint style \u2014 overrides fontColor
@@ -877,7 +899,7 @@ Params:
877
899
  exportSettings (array, optional) \u2014 Export settings
878
900
  properties (object, optional) \u2014 Direct Figma API props (escape hatch)`,
879
901
  "delete": "# text.delete\nDelete nodes\n\nParams:\n id (string, optional) \u2014 Single node ID\n items (array, optional) \u2014 Batch: [{id}, ...]\n id (string, optional)",
880
- "clone": "# text.clone\nDuplicate nodes\n\nParams:\n id (string, optional) \u2014 Node ID\n name (string, optional) \u2014 Rename the clone (set before appending to parent \u2014 required when cloning a variant into its component set to avoid duplicate names)\n parentId (string, optional) \u2014 Parent node ID. Omit to place on current page.\n x (number, optional) \u2014 X position (default: 0)\n y (number, optional) \u2014 Y position (default: 0)\n items (array, optional) \u2014 Batch: [{id, name?, parentId?, x?, y?}, ...]. Alternative to single-item params.\n id (string, required) \u2014 Node ID to clone\n name (string, optional) \u2014 Rename the clone\n parentId (string, optional) \u2014 Target parent\n x (number, optional)\n y (number, optional)\n depth (number, optional) \u2014 Response detail: omit for id+name only. 0=properties + child stubs. N=recurse N levels. -1=unlimited.",
902
+ "clone": "# text.clone\nDuplicate nodes\n\nParams:\n id (string, optional) \u2014 Node ID\n name (string, optional) \u2014 Rename the clone (set before appending to parent \u2014 required when cloning a variant into its component set to avoid duplicate names)\n parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.\n x (number, optional) \u2014 X position (default: 0)\n y (number, optional) \u2014 Y position (default: 0)\n items (array, optional) \u2014 Batch: [{id, name?, parentId?, x?, y?}, ...]. Alternative to single-item params.\n id (string, required) \u2014 Node ID to clone\n name (string, optional) \u2014 Rename the clone\n parentId (string, optional) \u2014 Target parent\n x (number, optional)\n y (number, optional)\n depth (number, optional) \u2014 Response detail: omit for id+name only. 0=properties + child stubs. N=recurse N levels. -1=unlimited.",
881
903
  "audit": `# text.audit
882
904
  Run lint on a node \u2014 returns severity-ranked findings
883
905
 
@@ -901,11 +923,15 @@ Params:
901
923
  x (number, optional)
902
924
  y (number, optional)
903
925
  width (number, optional) \u2014 Fixed width in px \u2014 implies layoutSizingHorizontal: FIXED and textAutoResize: HEIGHT
904
- parentId (string, optional) \u2014 Parent node ID. Omit to place on current page.
926
+ parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
905
927
  fontFamily (string, optional) \u2014 Font family (default: Inter). Use fonts.list to find installed fonts.
906
928
  fontStyle (string, optional) \u2014 Font variant e.g. "Bold", "Italic" \u2014 overrides fontWeight
907
929
  fontSize (number, optional) \u2014 Font size (default: 14)
908
930
  fontWeight (number, optional) \u2014 100-900 (default: 400). Ignored when fontStyle is set.
931
+ lineHeight (number | {value, unit: "PIXELS"|"PERCENT"|"AUTO"}, optional)
932
+ letterSpacing (number | {value, unit: "PIXELS"|"PERCENT"}, optional)
933
+ textCase (ORIGINAL | UPPER | LOWER | TITLE | SMALL_CAPS | SMALL_CAPS_FORCED, optional)
934
+ textDecoration (NONE | UNDERLINE | STRIKETHROUGH, optional)
909
935
  fills (array, optional) \u2014 Text color paints \u2014 e.g. [{type: 'SOLID', color: '#hex'}]. Same as node fills.
910
936
  fontColor (Color, optional) \u2014 Shorthand \u2014 sets text color (auto-binds to matching variable/style)
911
937
  fontColorVariableName (string, optional) \u2014 Bind color variable by name e.g. 'text/primary'
@@ -941,7 +967,7 @@ Params:
941
967
  variables (array, optional) \u2014 Variables to create inside this collection
942
968
  name (string, required) \u2014 Variable name (unique within collection)
943
969
  type (COLOR | FLOAT | STRING | BOOLEAN, required) \u2014 Variable type
944
- value (variable_value, optional) \u2014 Shorthand \u2014 sets the default mode value. Use valuesByMode for multi-mode.
970
+ value (variable_value, optional) \u2014 Sets all modes to this value. Use valuesByMode for per-mode control.
945
971
  valuesByMode (object, optional) \u2014 Values keyed by mode name (e.g. {"Light": "#FFF", "Dark": "#111"})
946
972
  description (string, optional)
947
973
  scopes (string[], optional) \u2014 Restrict where variable can be applied (default: ALL_SCOPES)`,
@@ -953,11 +979,11 @@ Params:
953
979
  }
954
980
  },
955
981
  "variables": {
956
- "summary": '# variables\nSearch and update design variables within a collection.\n\nMethods:\n list Search variables within a collection [read]\n get Get variable detail by name [read]\n create Create variables in a collection. Use valuesByMode for multi-mode, or value for default mode only. [create]\n update Update variable metadata and/or set values [edit]\n delete Delete variables [edit]\n\n// Search and update variables within a collection. collectionId is required on all methods.\n// Use variable_collections to create full token sets (collection + modes + variables in one call).\n// ---\n// query: prefix match first, then substring. "bg/" matches bg/canvas, bg/surface, etc.\n// valuesByMode: values keyed by mode name. value is shorthand for the default mode.\n// Aliases: {type: "VARIABLE_ALIAS", name: "other/variable"}.\n// scopes: ALL_SCOPES, TEXT_CONTENT, WIDTH_HEIGHT, GAP, CORNER_RADIUS, ALL_FILLS, FRAME_FILL, SHAPE_FILL,\n// TEXT_FILL, STROKE_COLOR, STROKE_FLOAT, EFFECT_FLOAT, EFFECT_COLOR, OPACITY, FONT_FAMILY, FONT_STYLE,\n// FONT_WEIGHT, FONT_SIZE, LINE_HEIGHT, LETTER_SPACING, PARAGRAPH_SPACING, PARAGRAPH_INDENT\n\nUse variables(method: "help", topic: "<method>") for method details.',
982
+ "summary": '# variables\nSearch and update design variables within a collection.\n\nMethods:\n list Search variables within a collection [read]\n get Get variable detail by name [read]\n create Create variables in a collection. Use valuesByMode for per-mode control, or value to set all modes at once. [create]\n update Update variable metadata and/or set values [edit]\n delete Delete variables [edit]\n\n// Search and update variables within a collection. collectionId is required on all methods.\n// Use variable_collections to create full token sets (collection + modes + variables in one call).\n// ---\n// query: prefix match first, then substring. "bg/" matches bg/canvas, bg/surface, etc.\n// valuesByMode: values keyed by mode name. On create, value sets all modes; on update, value sets the default mode only.\n// Aliases: {type: "VARIABLE_ALIAS", name: "other/variable"}.\n// scopes: ALL_SCOPES, TEXT_CONTENT, WIDTH_HEIGHT, GAP, CORNER_RADIUS, ALL_FILLS, FRAME_FILL, SHAPE_FILL,\n// TEXT_FILL, STROKE_COLOR, STROKE_FLOAT, EFFECT_FLOAT, EFFECT_COLOR, OPACITY, FONT_FAMILY, FONT_STYLE,\n// FONT_WEIGHT, FONT_SIZE, LINE_HEIGHT, LETTER_SPACING, PARAGRAPH_SPACING, PARAGRAPH_INDENT\n\nUse variables(method: "help", topic: "<method>") for method details.',
957
983
  "methods": {
958
984
  "list": '# variables.list\nSearch variables within a collection\n\nExample: variables(method:"list", collectionId:"Colors", query:"bg/")\n\nParams:\n collectionId (string, required) \u2014 Collection ID or name\n query (string, optional) \u2014 Search query \u2014 prefix match first, then substring fallback\n type (COLOR | FLOAT | STRING | BOOLEAN, optional) \u2014 Filter by variable type\n fields (string[], optional) \u2014 Property whitelist. Identity fields (id, name, type) always included. Omit for stubs on list, full on get. Pass ["*"] for all.\n offset (number, optional) \u2014 Skip N items for pagination (default 0)\n limit (number, optional) \u2014 Max items per page (default 100)',
959
985
  "get": '# variables.get\nGet variable detail by name\n\nParams:\n name (string, required) \u2014 Variable name (unique within collection)\n collectionId (string, required) \u2014 Collection ID or name\n fields (string[], optional) \u2014 Property whitelist. Identity fields (id, name, type) always included. Omit for stubs on list, full on get. Pass ["*"] for all.',
960
- "create": '# variables.create\nCreate variables in a collection. Use valuesByMode for multi-mode, or value for default mode only.\n\nExample: variables(method:"create", collectionId:"Colors", items:[{name:"bg/primary", type:"COLOR", valuesByMode:{"Light":"#FFF","Dark":"#111"}, scopes:["ALL_FILLS"]}])\n\nParams:\n collectionId (string, required) \u2014 Collection ID or name\n items (VariableCreateItem[], required) \u2014 Array of variables to create\n name (string, required) \u2014 Variable name (must be unique within collection)\n type (COLOR | FLOAT | STRING | BOOLEAN, required) \u2014 Variable type\n value (variable_value, optional) \u2014 Shorthand \u2014 sets the default mode value. Use valuesByMode for multi-mode.\n valuesByMode (object, optional) \u2014 Values keyed by mode name (e.g. {"Light": "#FFF", "Dark": "#111"}). Takes precedence over value.\n description (string, optional) \u2014 Variable description\n scopes (string[], optional) \u2014 Restrict where variable can be applied (default: ALL_SCOPES)',
986
+ "create": '# variables.create\nCreate variables in a collection. Use valuesByMode for per-mode control, or value to set all modes at once.\n\nExample: variables(method:"create", collectionId:"Colors", items:[{name:"bg/primary", type:"COLOR", valuesByMode:{"Light":"#FFF","Dark":"#111"}, scopes:["ALL_FILLS"]}])\n\nParams:\n collectionId (string, required) \u2014 Collection ID or name\n items (VariableCreateItem[], required) \u2014 Array of variables to create\n name (string, required) \u2014 Variable name (must be unique within collection)\n type (COLOR | FLOAT | STRING | BOOLEAN, required) \u2014 Variable type\n value (variable_value, optional) \u2014 Sets all modes to this value. Use valuesByMode for per-mode control.\n valuesByMode (object, optional) \u2014 Values keyed by mode name (e.g. {"Light": "#FFF", "Dark": "#111"}). Takes precedence over value.\n description (string, optional) \u2014 Variable description\n scopes (string[], optional) \u2014 Restrict where variable can be applied (default: ALL_SCOPES)',
961
987
  "update": '# variables.update\nUpdate variable metadata and/or set values\n\nExample: variables(method:"update", collectionId:"Colors", items:[{name:"bg/primary", valuesByMode:{"Light":"#FFF","Dark":"#222"}}])\n\nParams:\n collectionId (string, required) \u2014 Collection ID or name\n items (VariableUpdateItem[], required) \u2014 Array of variable updates\n name (string, required) \u2014 Variable name\n rename (string, optional) \u2014 Rename the variable\n description (string, optional) \u2014 Set description\n scopes (string[], optional) \u2014 Update scopes\n value (variable_value, optional) \u2014 Shorthand \u2014 sets the default mode value. Use valuesByMode for multi-mode.\n valuesByMode (object, optional) \u2014 Values keyed by mode name. Takes precedence over value.',
962
988
  "delete": "# variables.delete\nDelete variables\n\nParams:\n collectionId (string, required) \u2014 Collection ID or name\n name (string, optional) \u2014 Variable name\n items (array, optional) \u2014 Batch: [{name}, ...]\n name (string, required)"
963
989
  }
@@ -1043,6 +1069,7 @@ function registerTools(server2, sendCommand, caps2, tools2) {
1043
1069
  }
1044
1070
  if (tool.validate) tool.validate(params);
1045
1071
  const command = resolveCommand(tool, params);
1072
+ params._caps = caps2;
1046
1073
  const result = await sendCommand(command, params, timeout);
1047
1074
  const format = tool.methodFormatters?.[params.method] ?? defaultFormat;
1048
1075
  return format(result);
@@ -1162,12 +1189,12 @@ function filterMethodsByTier(schema, caps2, methodTiers) {
1162
1189
  var tools = [
1163
1190
  {
1164
1191
  name: "components",
1165
- description: '/** Create and manage reusable components and variant sets. Use method "help" for detailed parameter docs. */\n clone (id?, name?, parentId?, x?, y?, items?: { id: string; name?: string; parentId?: string; x?: number; y?: number }[], depth?) \u2192 { results: {id}[] } // Duplicate nodes\n audit (id, rules?, maxDepth?, maxFindings?, minSeverity?: error|unsafe|heuristic|style|verbose, skipInstances?) \u2192 { nodeId?, nodeName?, categories? } // Run lint on a node \u2014 returns severity-ranked findings\n reparent (items: { id: string; parentId: string; index?: number }[]) \u2192 { results: "ok"[] } // Move nodes into a new parent\n list (query?, offset?, limit?) \u2192 { totalCount, items } // List local component names (variant sets as single entries)\n get (id?, names?, depth?, verbose?) \u2192 { results, _truncated? } // Get component detail \u2014 property definitions + optional node tree for structural inspection\n create (type: component|from_node|variant_set, items: (ComponentItem | FromNodeItem | VariantSetItem)[]) \u2192 { results: {id}[] } // Create components\n update (items: UpdatePropertyItem[], depth?) \u2192 { results: ("ok" | {error})[] } // Add, edit, or delete component properties\n delete (id) \u2192 { results: "ok"[] } // Delete components or component sets\n// depth: omit \u2192 id+name stubs | 0 \u2192 props + child stubs | N \u2192 recurse N | -1 \u2192 full tree\n// fields: whitelist e.g. ["fills","opacity"] \u2014 id, name, type always included. Pass ["*"] for all.\n// layoutSizingHorizontal/Vertical: FIXED | HUG | FILL \u2014 how the node sizes within auto-layout.\n// Colors: fillVariableName/strokeVariableName bind by name \u2014 preferred over raw color values.\n// Note: node-based endpoints (frames, text, instances, components) use `results` as the list key.\n// Standalone endpoints (styles, variables, variable_collections) use `items`. Components.list uses `items` (catalog view).',
1192
+ description: '/** Create and manage reusable components and variant sets. Use method "help" for detailed parameter docs. */\n clone (id?, name?, parentId?, x?, y?, items?: { id: string; name?: string; parentId?: string; x?: number; y?: number }[], depth?) \u2192 { results: {id}[] } // Duplicate nodes\n audit (id, rules?, maxDepth?, maxFindings?, minSeverity?: error|unsafe|heuristic|style|verbose, skipInstances?) \u2192 { nodeId?, nodeName?, categories? } // Run lint on a node \u2014 returns severity-ranked findings\n reparent (items: { id: string; parentId: string; index?: number }[]) \u2192 { results: "ok"[] } // Move nodes into a new parent\n list (query?, offset?, limit?) \u2192 { totalCount, items } // List local component names (variant sets as single entries)\n get (id?, names?, depth?, verbose?) \u2192 { results, _truncated? } // Get component detail \u2014 property definitions + optional node tree for structural inspection\n create (type: component|from_node|variant_set, items: (ComponentItem | FromNodeItem | VariantSetItem)[]) \u2192 { results: {id}[] } // Create components\n commit (id) \u2192 { results: {id}[] } // Commit a staged component \u2014 unwraps from [STAGED] container into the original target location.\n update (items: UpdatePropertyItem[], depth?) \u2192 { results: ("ok" | {error})[] } // Add, edit, or delete component properties\n delete (id) \u2192 { results: "ok"[] } // Delete components or component sets\n// depth: omit \u2192 id+name stubs | 0 \u2192 props + child stubs | N \u2192 recurse N | -1 \u2192 full tree\n// fields: whitelist e.g. ["fills","opacity"] \u2014 id, name, type always included. Pass ["*"] for all.\n// layoutSizingHorizontal/Vertical: FIXED | HUG | FILL \u2014 how the node sizes within auto-layout.\n// Colors: fillVariableName/strokeVariableName bind by name \u2014 preferred over raw color values.\n// Note: node-based endpoints (frames, text, instances, components) use `results` as the list key.\n// Standalone endpoints (styles, variables, variable_collections) use `items`. Components.list uses `items` (catalog view).',
1166
1193
  schema: (caps2) => filterMethodsByTier({
1167
- method: import_zod4.z.enum(["clone", "audit", "reparent", "list", "get", "create", "update", "delete", "help"]),
1194
+ method: import_zod4.z.enum(["clone", "audit", "reparent", "list", "get", "create", "commit", "update", "delete", "help"]),
1168
1195
  id: import_zod4.z.string().optional().describe("Node ID"),
1169
1196
  name: import_zod4.z.string().optional().describe("Rename the clone (set before appending to parent \u2014 required when cloning a variant into its component set to avoid duplicate names)"),
1170
- parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place on current page."),
1197
+ parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place at current page root."),
1171
1198
  x: import_zod4.z.coerce.number().optional().describe("X position (default: 0)"),
1172
1199
  y: import_zod4.z.coerce.number().optional().describe("Y position (default: 0)"),
1173
1200
  items: flexJson(import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()))).optional().describe("Array of {id, ...properties} to clone/reparent/update"),
@@ -1184,10 +1211,13 @@ var tools = [
1184
1211
  verbose: import_zod4.z.boolean().optional().describe("Include all properties (bounding box, constraints, text style details). Default false \u2014 returns slim, actionable output."),
1185
1212
  type: import_zod4.z.enum(["component", "from_node", "variant_set"]).optional().describe("Discriminant for create method"),
1186
1213
  topic: import_zod4.z.string().optional().describe('Help topic \u2014 method name for endpoint help, e.g. "create"')
1187
- }, caps2, { "clone": "create", "audit": "read", "reparent": "edit", "list": "read", "get": "read", "create": "create", "update": "edit", "delete": "edit", "help": "read" }),
1214
+ }, caps2, { "clone": "create", "audit": "read", "reparent": "edit", "list": "read", "get": "read", "create": "create", "commit": "edit", "update": "edit", "delete": "edit", "help": "read" }),
1188
1215
  tier: "read",
1189
1216
  validate: (params) => {
1190
1217
  const m = params.method;
1218
+ if (m === "commit") {
1219
+ if (params.id === void 0) throw new Error('commit requires "id"');
1220
+ }
1191
1221
  if (m === "delete") {
1192
1222
  if (params.id === void 0) throw new Error('delete requires "id"');
1193
1223
  }
@@ -1204,7 +1234,7 @@ var tools = [
1204
1234
  const schemas = {
1205
1235
  "component": import_zod4.z.object({
1206
1236
  name: import_zod4.z.string().describe("Component name"),
1207
- parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place on current page."),
1237
+ parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place at current page root."),
1208
1238
  x: import_zod4.z.coerce.number().optional().describe("X position (default: 0)"),
1209
1239
  y: import_zod4.z.coerce.number().optional().describe("Y position (default: 0)"),
1210
1240
  width: import_zod4.z.coerce.number().optional().describe("Width in px (omit to shrink-to-content via HUG)"),
@@ -1237,7 +1267,7 @@ var tools = [
1237
1267
  bottomLeftRadius: token.optional(),
1238
1268
  effectStyleName: import_zod4.z.string().optional().describe("Effect style name (e.g. 'Shadow/Card') for shadows, blurs"),
1239
1269
  layoutMode: import_zod4.z.enum(["NONE", "HORIZONTAL", "VERTICAL"]).optional().describe("Layout direction (default: auto \u2014 NONE when width+height set, otherwise inferred from layout props)"),
1240
- layoutWrap: import_zod4.z.enum(["NO_WRAP", "WRAP"]).optional(),
1270
+ layoutWrap: import_zod4.z.enum(["NO_WRAP", "WRAP"]).optional().describe("Wrap children to new rows (HORIZONTAL layout only \u2014 Figma does not support WRAP on VERTICAL layouts). Use column frames inside a HORIZONTAL parent for vertical grid patterns."),
1241
1271
  padding: token.optional().describe("All edges (number) or variable name (string). Per-edge: paddingTop, paddingRight, paddingBottom, paddingLeft."),
1242
1272
  paddingTop: token.optional(),
1243
1273
  paddingRight: token.optional(),
@@ -1255,15 +1285,17 @@ var tools = [
1255
1285
  maxHeight: import_zod4.z.coerce.number().optional().describe("Max height for responsive auto-layout"),
1256
1286
  overflowDirection: import_zod4.z.enum(["NONE", "HORIZONTAL", "VERTICAL", "BOTH"]).optional().describe("Scroll overflow in prototype (default: NONE)"),
1257
1287
  description: import_zod4.z.string().optional().describe("Component description (shown in Figma's component panel)"),
1288
+ children: flexJson(import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()))).optional().describe('Inline child nodes \u2014 build nested trees in one call. Types: text: {type:"text", text, componentPropertyName?, fontFamily?, fontSize?, fontWeight?, fontStyle?, fontColor?, layoutSizingHorizontal?}. frame: {type:"frame", name?, layoutMode?, fillColor?, width?, layoutSizingHorizontal?, children?}. instance: {type:"instance", componentId, componentPropertyName?, variantProperties?, properties?}. component: {type:"component", name, children?}. All params from text/frame endpoints are supported on their respective types. componentPropertyName auto-creates and binds a TEXT (text) or INSTANCE_SWAP (instance) property. Always set layoutSizingHorizontal + layoutSizingVertical on children inside auto-layout parents (FILL, HUG, or FIXED). Example: children:[{type:"text", text:"Label", componentPropertyName:"Label", fontSize:14, fontColorVariableName:"text/primary", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}, {type:"frame", name:"Actions", layoutMode:"HORIZONTAL", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG", itemSpacing:8, children:[{type:"instance", componentId:"1:2", componentPropertyName:"Action", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}]}]\n'),
1258
1289
  properties: flexJson(import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()))).optional().describe("Component properties to define at creation: [{propertyName, type, defaultValue}]. TEXT properties for inline children with componentPropertyName are created automatically.")
1259
1290
  }).passthrough(),
1260
1291
  "from_node": import_zod4.z.object({
1261
1292
  nodeId: import_zod4.z.string().describe("Node ID to convert"),
1293
+ name: import_zod4.z.string().optional().describe("Rename the component (default: keeps the node's current name)"),
1262
1294
  exposeText: flexBool(import_zod4.z.boolean()).optional().describe("Auto-expose text as editable properties (default: true)")
1263
1295
  }).passthrough(),
1264
1296
  "variant_set": import_zod4.z.object({
1265
1297
  name: import_zod4.z.string().optional().describe("Node name"),
1266
- parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place on current page."),
1298
+ parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place at current page root."),
1267
1299
  x: import_zod4.z.coerce.number().optional().describe("X position (default: 0)"),
1268
1300
  y: import_zod4.z.coerce.number().optional().describe("Y position (default: 0)"),
1269
1301
  width: import_zod4.z.coerce.number().optional().describe("Width in px (omit to shrink-to-content via HUG)"),
@@ -1296,7 +1328,7 @@ var tools = [
1296
1328
  bottomLeftRadius: token.optional(),
1297
1329
  effectStyleName: import_zod4.z.string().optional().describe("Effect style name (e.g. 'Shadow/Card') for shadows, blurs"),
1298
1330
  layoutMode: import_zod4.z.enum(["NONE", "HORIZONTAL", "VERTICAL"]).optional().describe("Layout direction (default: auto \u2014 NONE when width+height set, otherwise inferred from layout props)"),
1299
- layoutWrap: import_zod4.z.enum(["NO_WRAP", "WRAP"]).optional(),
1331
+ layoutWrap: import_zod4.z.enum(["NO_WRAP", "WRAP"]).optional().describe("Wrap children to new rows (HORIZONTAL layout only \u2014 Figma does not support WRAP on VERTICAL layouts). Use column frames inside a HORIZONTAL parent for vertical grid patterns."),
1300
1332
  padding: token.optional().describe("All edges (number) or variable name (string). Per-edge: paddingTop, paddingRight, paddingBottom, paddingLeft."),
1301
1333
  paddingTop: token.optional(),
1302
1334
  paddingRight: token.optional(),
@@ -1314,7 +1346,8 @@ var tools = [
1314
1346
  maxHeight: import_zod4.z.coerce.number().optional().describe("Max height for responsive auto-layout"),
1315
1347
  overflowDirection: import_zod4.z.enum(["NONE", "HORIZONTAL", "VERTICAL", "BOTH"]).optional().describe("Scroll overflow in prototype (default: NONE)"),
1316
1348
  componentIds: flexJson(import_zod4.z.array(import_zod4.z.string())).optional().describe("Existing component IDs to combine (min 2). Alternative to children."),
1317
- variantPropertyName: import_zod4.z.string().optional().describe("Rename the auto-generated variant property (default: 'Property 1')")
1349
+ variantPropertyName: import_zod4.z.string().optional().describe("Rename the auto-generated variant property (default: 'Property 1')"),
1350
+ children: flexJson(import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()))).optional().describe('Inline variant components. Each must be {type:"component", name, children?, ...frame_params}. All variants must share the same child structure. Alternative to componentIds \u2014 do not combine both.')
1318
1351
  }).passthrough()
1319
1352
  };
1320
1353
  const s = params.type && schemas[params.type];
@@ -1359,7 +1392,7 @@ var tools = [
1359
1392
  }
1360
1393
  }
1361
1394
  },
1362
- commandMap: { "clone": "components.clone", "audit": "components.audit", "reparent": "components.reparent", "list": "components.list", "get": "components.get", "create": "components.create", "update": "components.update", "delete": "components.delete" }
1395
+ commandMap: { "clone": "components.clone", "audit": "components.audit", "reparent": "components.reparent", "list": "components.list", "get": "components.get", "create": "components.create", "commit": "components.commit", "update": "components.update", "delete": "components.delete" }
1363
1396
  },
1364
1397
  {
1365
1398
  name: "connection",
@@ -1409,9 +1442,9 @@ var tools = [
1409
1442
  },
1410
1443
  {
1411
1444
  name: "frames",
1412
- description: '/** Create and manage frames, shapes, auto-layout containers, sections, and SVG nodes. Use method "help" for detailed parameter docs. */\n get (id, fields?, depth?, verbose?) \u2192 { results: Node[], _truncated?, _notice? } // Get serialized node data\n list (query?, types?, parentId?, fields?, offset?, limit?) \u2192 { totalCount, returned?, offset?, limit?, results } // Search for nodes (returns stubs only \u2014 use get with depth for full properties)\n update (items: PatchItem[]) \u2192 { results: ("ok" | {error})[] } // Patch node properties\n delete (id?, items?: { id?: string }[]) \u2192 { results: "ok"[] } // Delete nodes\n clone (id?, name?, parentId?, x?, y?, items?: { id: string; name?: string; parentId?: string; x?: number; y?: number }[], depth?) \u2192 { results: {id}[] } // Duplicate nodes\n audit (id, rules?, maxDepth?, maxFindings?, minSeverity?: error|unsafe|heuristic|style|verbose, skipInstances?) \u2192 { nodeId?, nodeName?, categories? } // Run lint on a node \u2014 returns severity-ranked findings\n reparent (items: { id: string; parentId: string; index?: number }[]) \u2192 { results: "ok"[] } // Move nodes into a new parent\n create (type: frame|auto_layout|section|rectangle|ellipse|line|group|boolean_operation|svg, items: (FrameItem | AutoLayoutItem | SectionItem | RectangleItem | EllipseItem | LineItem | GroupItem | BooleanOperationItem | SvgItem)[]) \u2192 { results: {id}[] } // Create frame-like containers\n export (id, format?: PNG|JPG|SVG|SVG_STRING|PDF, scale?) \u2192 { imageData?, mimeType? } // Export a node as PNG, JPG, SVG, SVG_STRING, or PDF\n// depth: omit \u2192 id+name stubs | 0 \u2192 props + child stubs | N \u2192 recurse N | -1 \u2192 full tree\n// fields: whitelist e.g. ["fills","opacity"] \u2014 id, name, type always included. Pass ["*"] for all.\n// layoutSizingHorizontal/Vertical: FIXED | HUG | FILL \u2014 how the node sizes within auto-layout.\n// Colors: fillVariableName/strokeVariableName bind by name \u2014 preferred over raw color values.\n// Note: node-based endpoints (frames, text, instances, components) use `results` as the list key.\n// Standalone endpoints (styles, variables, variable_collections) use `items`. Components.list uses `items` (catalog view).',
1445
+ description: '/** Create and manage frames, shapes, auto-layout containers, sections, and SVG nodes. Use method "help" for detailed parameter docs. */\n get (id, fields?, depth?, verbose?) \u2192 { results: Node[], _truncated?, _notice? } // Get serialized node data\n list (query?, types?, parentId?, fields?, offset?, limit?) \u2192 { totalCount, returned?, offset?, limit?, results } // Search for nodes (returns stubs only \u2014 use get with depth for full properties)\n update (items: PatchItem[]) \u2192 { results: ("ok" | {error})[] } // Patch node properties\n delete (id?, items?: { id?: string }[]) \u2192 { results: "ok"[] } // Delete nodes\n clone (id?, name?, parentId?, x?, y?, items?: { id: string; name?: string; parentId?: string; x?: number; y?: number }[], depth?) \u2192 { results: {id}[] } // Duplicate nodes\n audit (id, rules?, maxDepth?, maxFindings?, minSeverity?: error|unsafe|heuristic|style|verbose, skipInstances?) \u2192 { nodeId?, nodeName?, categories? } // Run lint on a node \u2014 returns severity-ranked findings\n reparent (items: { id: string; parentId: string; index?: number }[]) \u2192 { results: "ok"[] } // Move nodes into a new parent\n create (type: frame|auto_layout|section|rectangle|ellipse|line|group|boolean_operation|svg, items: (FrameItem | AutoLayoutItem | SectionItem | RectangleItem | EllipseItem | LineItem | GroupItem | BooleanOperationItem | SvgItem)[]) \u2192 { results: {id}[] } // Create frame-like containers\n commit (id) \u2192 { results: {id}[] } // Commit a staged node \u2014 unwraps from [STAGED] container into the original target location.\n export (id, format?: PNG|JPG|SVG|SVG_STRING|PDF, scale?) \u2192 { imageData?, mimeType? } // Export a node as PNG, JPG, SVG, SVG_STRING, or PDF\n// depth: omit \u2192 id+name stubs | 0 \u2192 props + child stubs | N \u2192 recurse N | -1 \u2192 full tree\n// fields: whitelist e.g. ["fills","opacity"] \u2014 id, name, type always included. Pass ["*"] for all.\n// layoutSizingHorizontal/Vertical: FIXED | HUG | FILL \u2014 how the node sizes within auto-layout.\n// Colors: fillVariableName/strokeVariableName bind by name \u2014 preferred over raw color values.\n// Note: node-based endpoints (frames, text, instances, components) use `results` as the list key.\n// Standalone endpoints (styles, variables, variable_collections) use `items`. Components.list uses `items` (catalog view).',
1413
1446
  schema: (caps2) => filterMethodsByTier({
1414
- method: import_zod4.z.enum(["get", "list", "update", "delete", "clone", "audit", "reparent", "create", "export", "help"]),
1447
+ method: import_zod4.z.enum(["get", "list", "update", "delete", "clone", "audit", "reparent", "create", "commit", "export", "help"]),
1415
1448
  id: import_zod4.z.string().optional().describe("Node ID"),
1416
1449
  fields: flexJson(import_zod4.z.array(import_zod4.z.string())).optional().describe('Property whitelist. Identity fields (id, name, type) always included. Omit for stubs on list, full on get. Pass ["*"] for all.'),
1417
1450
  depth: import_zod4.z.coerce.number().optional().describe("Response detail: omit for id+name only. 0=properties + child stubs. N=recurse N levels. -1=unlimited."),
@@ -1434,10 +1467,13 @@ var tools = [
1434
1467
  format: import_zod4.z.enum(["PNG", "JPG", "SVG", "SVG_STRING", "PDF"]).optional().describe("Export format (default: PNG). SVG_STRING returns raw SVG text."),
1435
1468
  scale: import_zod4.z.coerce.number().optional().describe("Export scale (default: 1, only for PNG/JPG)"),
1436
1469
  topic: import_zod4.z.string().optional().describe('Help topic \u2014 method name for endpoint help, e.g. "create"')
1437
- }, caps2, { "get": "read", "list": "read", "update": "edit", "delete": "edit", "clone": "create", "audit": "read", "reparent": "edit", "create": "create", "export": "read", "help": "read" }),
1470
+ }, caps2, { "get": "read", "list": "read", "update": "edit", "delete": "edit", "clone": "create", "audit": "read", "reparent": "edit", "create": "create", "commit": "edit", "export": "read", "help": "read" }),
1438
1471
  tier: "read",
1439
1472
  validate: (params) => {
1440
1473
  const m = params.method;
1474
+ if (m === "commit") {
1475
+ if (params.id === void 0) throw new Error('commit requires "id"');
1476
+ }
1441
1477
  if (m === "export") {
1442
1478
  if (params.id === void 0) throw new Error('export requires "id"');
1443
1479
  }
@@ -1446,7 +1482,7 @@ var tools = [
1446
1482
  const schemas = {
1447
1483
  "frame": import_zod4.z.object({
1448
1484
  name: import_zod4.z.string().optional().describe("Node name"),
1449
- parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place on current page."),
1485
+ parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place at current page root."),
1450
1486
  x: import_zod4.z.coerce.number().optional().describe("X position (default: 0)"),
1451
1487
  y: import_zod4.z.coerce.number().optional().describe("Y position (default: 0)"),
1452
1488
  width: import_zod4.z.coerce.number().optional().describe("Width in px (omit to shrink-to-content via HUG)"),
@@ -1479,7 +1515,7 @@ var tools = [
1479
1515
  bottomLeftRadius: token.optional(),
1480
1516
  effectStyleName: import_zod4.z.string().optional().describe("Effect style name (e.g. 'Shadow/Card') for shadows, blurs"),
1481
1517
  layoutMode: import_zod4.z.enum(["NONE", "HORIZONTAL", "VERTICAL"]).optional().describe("Layout direction (default: auto \u2014 NONE when width+height set, otherwise inferred from layout props)"),
1482
- layoutWrap: import_zod4.z.enum(["NO_WRAP", "WRAP"]).optional(),
1518
+ layoutWrap: import_zod4.z.enum(["NO_WRAP", "WRAP"]).optional().describe("Wrap children to new rows (HORIZONTAL layout only \u2014 Figma does not support WRAP on VERTICAL layouts). Use column frames inside a HORIZONTAL parent for vertical grid patterns."),
1483
1519
  padding: token.optional().describe("All edges (number) or variable name (string). Per-edge: paddingTop, paddingRight, paddingBottom, paddingLeft."),
1484
1520
  paddingTop: token.optional(),
1485
1521
  paddingRight: token.optional(),
@@ -1496,11 +1532,12 @@ var tools = [
1496
1532
  minHeight: import_zod4.z.coerce.number().optional().describe("Min height for responsive auto-layout"),
1497
1533
  maxHeight: import_zod4.z.coerce.number().optional().describe("Max height for responsive auto-layout"),
1498
1534
  overflowDirection: import_zod4.z.enum(["NONE", "HORIZONTAL", "VERTICAL", "BOTH"]).optional().describe("Scroll overflow in prototype (default: NONE)"),
1499
- clipsContent: flexBool(import_zod4.z.boolean()).optional()
1535
+ clipsContent: flexBool(import_zod4.z.boolean()).optional(),
1536
+ children: flexJson(import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()))).optional().describe('Inline child nodes \u2014 build nested trees in one call. Types: text: {type:"text", text, fontFamily?, fontSize?, fontWeight?, fontStyle?, fontColor?, layoutSizingHorizontal?}. frame: {type:"frame", name?, layoutMode?, fillColor?, width?, layoutSizingHorizontal?, children?}. instance: {type:"instance", componentId, variantProperties?, properties?}. component: {type:"component", name, children?}. All params from text/frame endpoints are supported on their respective types. Always set layoutSizingHorizontal + layoutSizingVertical on children inside auto-layout parents (FILL, HUG, or FIXED). Example: children:[{type:"text", text:"Title", fontSize:20, layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}, {type:"frame", name:"Row", layoutMode:"HORIZONTAL", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG", itemSpacing:8, children:[{type:"instance", componentId:"1:2", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}]}] Inside components: add componentPropertyName to auto-bind TEXT or INSTANCE_SWAP properties.\n')
1500
1537
  }).passthrough(),
1501
1538
  "auto_layout": import_zod4.z.object({
1502
1539
  name: import_zod4.z.string().optional().describe("Node name"),
1503
- parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place on current page."),
1540
+ parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place at current page root."),
1504
1541
  x: import_zod4.z.coerce.number().optional().describe("X position (default: 0)"),
1505
1542
  y: import_zod4.z.coerce.number().optional().describe("Y position (default: 0)"),
1506
1543
  width: import_zod4.z.coerce.number().optional().describe("Width in px (omit to shrink-to-content via HUG)"),
@@ -1533,7 +1570,7 @@ var tools = [
1533
1570
  bottomLeftRadius: token.optional(),
1534
1571
  effectStyleName: import_zod4.z.string().optional().describe("Effect style name (e.g. 'Shadow/Card') for shadows, blurs"),
1535
1572
  layoutMode: import_zod4.z.enum(["HORIZONTAL", "VERTICAL"]).describe("Primary axis direction"),
1536
- layoutWrap: import_zod4.z.enum(["NO_WRAP", "WRAP"]).optional(),
1573
+ layoutWrap: import_zod4.z.enum(["NO_WRAP", "WRAP"]).optional().describe("Wrap children to new rows (HORIZONTAL layout only \u2014 Figma does not support WRAP on VERTICAL layouts). Use column frames inside a HORIZONTAL parent for vertical grid patterns."),
1537
1574
  padding: token.optional().describe("All edges (number) or variable name (string). Per-edge: paddingTop, paddingRight, paddingBottom, paddingLeft."),
1538
1575
  paddingTop: token.optional(),
1539
1576
  paddingRight: token.optional(),
@@ -1551,11 +1588,12 @@ var tools = [
1551
1588
  maxHeight: import_zod4.z.coerce.number().optional().describe("Max height for responsive auto-layout"),
1552
1589
  overflowDirection: import_zod4.z.enum(["NONE", "HORIZONTAL", "VERTICAL", "BOTH"]).optional().describe("Scroll overflow in prototype (default: NONE)"),
1553
1590
  clipsContent: flexBool(import_zod4.z.boolean()).optional(),
1554
- nodeIds: flexJson(import_zod4.z.array(import_zod4.z.string())).optional().describe("Existing node IDs to wrap into auto-layout")
1591
+ nodeIds: flexJson(import_zod4.z.array(import_zod4.z.string())).optional().describe("Existing node IDs to wrap into auto-layout"),
1592
+ children: flexJson(import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()))).optional().describe('Inline child nodes \u2014 build nested trees in one call. Types: text: {type:"text", text, fontFamily?, fontSize?, fontWeight?, fontStyle?, fontColor?, layoutSizingHorizontal?}. frame: {type:"frame", name?, layoutMode?, fillColor?, width?, layoutSizingHorizontal?, children?}. instance: {type:"instance", componentId, variantProperties?, properties?}. component: {type:"component", name, children?}. All params from text/frame endpoints are supported on their respective types. Always set layoutSizingHorizontal + layoutSizingVertical on children inside auto-layout parents (FILL, HUG, or FIXED). Example: children:[{type:"text", text:"Title", fontSize:20, layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}, {type:"frame", name:"Row", layoutMode:"HORIZONTAL", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG", itemSpacing:8, children:[{type:"instance", componentId:"1:2", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}]}] Inside components: add componentPropertyName to auto-bind TEXT or INSTANCE_SWAP properties.\n')
1555
1593
  }).passthrough(),
1556
1594
  "section": import_zod4.z.object({
1557
1595
  name: import_zod4.z.string().describe("Section name"),
1558
- parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place on current page."),
1596
+ parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place at current page root."),
1559
1597
  x: import_zod4.z.coerce.number().optional().describe("X position (default: 0)"),
1560
1598
  y: import_zod4.z.coerce.number().optional().describe("Y position (default: 0)"),
1561
1599
  width: import_zod4.z.coerce.number().optional().describe("Width (default: 500)"),
@@ -1567,7 +1605,7 @@ var tools = [
1567
1605
  }).passthrough(),
1568
1606
  "rectangle": import_zod4.z.object({
1569
1607
  name: import_zod4.z.string().optional().describe("Layer name (default: 'Rectangle')"),
1570
- parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place on current page."),
1608
+ parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place at current page root."),
1571
1609
  x: import_zod4.z.coerce.number().optional().describe("X position (default: 0)"),
1572
1610
  y: import_zod4.z.coerce.number().optional().describe("Y position (default: 0)"),
1573
1611
  width: import_zod4.z.coerce.number().optional().describe("Width in px (default: 100)"),
@@ -1591,7 +1629,7 @@ var tools = [
1591
1629
  }).passthrough(),
1592
1630
  "ellipse": import_zod4.z.object({
1593
1631
  name: import_zod4.z.string().optional().describe("Layer name (default: 'Ellipse')"),
1594
- parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place on current page."),
1632
+ parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place at current page root."),
1595
1633
  x: import_zod4.z.coerce.number().optional().describe("X position (default: 0)"),
1596
1634
  y: import_zod4.z.coerce.number().optional().describe("Y position (default: 0)"),
1597
1635
  width: import_zod4.z.coerce.number().optional().describe("Width in px (default: 100)"),
@@ -1610,7 +1648,7 @@ var tools = [
1610
1648
  }).passthrough(),
1611
1649
  "line": import_zod4.z.object({
1612
1650
  name: import_zod4.z.string().optional().describe("Layer name (default: 'Line')"),
1613
- parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place on current page."),
1651
+ parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place at current page root."),
1614
1652
  x: import_zod4.z.coerce.number().optional().describe("X position (default: 0)"),
1615
1653
  y: import_zod4.z.coerce.number().optional().describe("Y position (default: 0)"),
1616
1654
  length: import_zod4.z.coerce.number().optional().describe("Line length in px (default: 100)"),
@@ -1625,18 +1663,18 @@ var tools = [
1625
1663
  "group": import_zod4.z.object({
1626
1664
  nodeIds: import_zod4.z.array(import_zod4.z.string()).describe("Node IDs to group (min 1)"),
1627
1665
  name: import_zod4.z.string().optional().describe("Group name"),
1628
- parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place on current page.")
1666
+ parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place at current page root.")
1629
1667
  }).passthrough(),
1630
1668
  "boolean_operation": import_zod4.z.object({
1631
1669
  operation: import_zod4.z.enum(["UNION", "SUBTRACT", "INTERSECT", "EXCLUDE"]).describe("Boolean operation type"),
1632
1670
  nodeIds: import_zod4.z.array(import_zod4.z.string()).describe("Node IDs to combine (min 2, first node is the base for SUBTRACT)"),
1633
1671
  name: import_zod4.z.string().optional().describe("Result node name"),
1634
- parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place on current page.")
1672
+ parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place at current page root.")
1635
1673
  }).passthrough(),
1636
1674
  "svg": import_zod4.z.object({
1637
1675
  svg: import_zod4.z.string().describe("SVG markup string"),
1638
1676
  name: import_zod4.z.string().optional().describe("Layer name (default: 'SVG')"),
1639
- parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place on current page."),
1677
+ parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place at current page root."),
1640
1678
  x: import_zod4.z.coerce.number().optional().describe("X position (default: 0)"),
1641
1679
  y: import_zod4.z.coerce.number().optional().describe("Y position (default: 0)"),
1642
1680
  fillStyleName: import_zod4.z.string().optional().describe("Paint style to apply to vector fills"),
@@ -1663,7 +1701,7 @@ var tools = [
1663
1701
  }
1664
1702
  }
1665
1703
  },
1666
- commandMap: { "get": "frames.get", "list": "frames.list", "update": "frames.update", "delete": "frames.delete", "clone": "frames.clone", "audit": "frames.audit", "reparent": "frames.reparent", "create": "frames.create", "export": "frames.export" }
1704
+ commandMap: { "get": "frames.get", "list": "frames.list", "update": "frames.update", "delete": "frames.delete", "clone": "frames.clone", "audit": "frames.audit", "reparent": "frames.reparent", "create": "frames.create", "commit": "frames.commit", "export": "frames.export" }
1667
1705
  },
1668
1706
  {
1669
1707
  name: "instances",
@@ -1726,7 +1764,7 @@ var tools = [
1726
1764
  y: import_zod4.z.coerce.number().optional(),
1727
1765
  width: import_zod4.z.coerce.number().optional().describe("Override width (resize)"),
1728
1766
  height: import_zod4.z.coerce.number().optional().describe("Override height (resize)"),
1729
- parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place on current page.")
1767
+ parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place at current page root.")
1730
1768
  }).passthrough();
1731
1769
  try {
1732
1770
  params.items = import_zod4.z.array(itemSchema).parse(params.items);
@@ -1770,7 +1808,7 @@ var tools = [
1770
1808
  blendMode: import_zod4.z.enum(["PASS_THROUGH", "NORMAL", "DARKEN", "MULTIPLY", "LINEAR_BURN", "COLOR_BURN", "LIGHTEN", "SCREEN", "LINEAR_DODGE", "COLOR_DODGE", "OVERLAY", "SOFT_LIGHT", "HARD_LIGHT", "DIFFERENCE", "EXCLUSION", "HUE", "SATURATION", "COLOR", "LUMINOSITY"]).optional(),
1771
1809
  effectStyleName: import_zod4.z.string().optional().describe("Effect style name (e.g. 'Shadow/Card') for shadows, blurs"),
1772
1810
  layoutMode: import_zod4.z.enum(["NONE", "HORIZONTAL", "VERTICAL"]).optional().describe("Layout direction (default: NONE)"),
1773
- layoutWrap: import_zod4.z.enum(["NO_WRAP", "WRAP"]).optional(),
1811
+ layoutWrap: import_zod4.z.enum(["NO_WRAP", "WRAP"]).optional().describe("Wrap children to new rows (HORIZONTAL layout only \u2014 Figma does not support WRAP on VERTICAL layouts). Use column frames inside a HORIZONTAL parent for vertical grid patterns."),
1774
1812
  padding: token.optional().describe("All edges (number) or variable name (string). Per-edge: paddingTop, paddingRight, paddingBottom, paddingLeft."),
1775
1813
  paddingTop: token.optional(),
1776
1814
  paddingRight: token.optional(),
@@ -1791,6 +1829,10 @@ var tools = [
1791
1829
  fontFamily: import_zod4.z.string().optional().describe("Font family"),
1792
1830
  fontStyle: import_zod4.z.string().optional().describe('Font variant e.g. "Bold", "Italic" \u2014 overrides fontWeight'),
1793
1831
  fontWeight: import_zod4.z.number().optional().describe("100-900. Ignored when fontStyle is set."),
1832
+ lineHeight: lineHeight.optional(),
1833
+ letterSpacing: letterSpacing.optional(),
1834
+ textCase: import_zod4.z.enum(["ORIGINAL", "UPPER", "LOWER", "TITLE", "SMALL_CAPS", "SMALL_CAPS_FORCED"]).optional(),
1835
+ textDecoration: import_zod4.z.enum(["NONE", "UNDERLINE", "STRIKETHROUGH"]).optional(),
1794
1836
  fontColor: colorRgba.optional().describe("Shorthand \u2014 sets text color (auto-binds to matching variable/style)"),
1795
1837
  fontColorVariableName: import_zod4.z.string().optional().describe("Bind color variable by name e.g. 'text/primary'"),
1796
1838
  fontColorStyleName: import_zod4.z.string().optional().describe("Apply paint style \u2014 overrides fontColor"),
@@ -1938,7 +1980,7 @@ var tools = [
1938
1980
  },
1939
1981
  {
1940
1982
  name: "prototyping",
1941
- description: '/** Manage prototype interactions, reactions, and navigation flows. Use method "help" for detailed parameter docs. */\n get (id) \u2192 { reactions?, overflowDirection? } // Get reactions and overflow direction on a node\n add (id, trigger: ON_CLICK|ON_HOVER|ON_PRESS|ON_DRAG|AFTER_TIMEOUT|MOUSE_ENTER|MOUSE_LEAVE|ON_KEY_DOWN, triggerDelay?, triggerKeyCodes?, triggerDevice?: KEYBOARD|XBOX_ONE|PS4|SWITCH_PRO, destination?, navigation?: NAVIGATE|SWAP|OVERLAY|SCROLL_TO|CHANGE_TO, transition?: DISSOLVE|SMART_ANIMATE|MOVE_IN|MOVE_OUT|PUSH|SLIDE_IN|SLIDE_OUT|INSTANT, transitionDirection?: LEFT|RIGHT|TOP|BOTTOM, duration?, easing?: EASE_IN|EASE_OUT|EASE_IN_AND_OUT|LINEAR|GENTLE|QUICK|BOUNCY|SLOW, actionType?: NODE|BACK|CLOSE|URL|SET_VARIABLE_MODE, url?, collectionName?, modeName?, resetScrollPosition?, actions?) \u2192 { results: "ok"[] } // Add a prototype reaction to a node\n set (id, reactions) \u2192 { results: "ok"[] } // Replace all reactions on a node (raw reactions array)\n remove (id, index) \u2192 { results: "ok"[] } // Remove a reaction from a node by index\n// Reactions wire up interactions: trigger (ON_CLICK, ON_HOVER, ...) \u2192 action (navigate, swap, overlay).\n// Common patterns: button ON_CLICK \u2192 NAVIGATE to detail frame; card ON_HOVER \u2192 CHANGE_TO hover variant.\n// Multi-action: pass actions[] array to run multiple actions on one trigger (e.g. navigate + set variable mode).',
1983
+ description: '/** Manage prototype interactions, reactions, and navigation flows. Use method "help" for detailed parameter docs. */\n get (id) \u2192 { reactions?, overflowDirection? } // Get reactions and overflow direction on a node\n add (id?, trigger?: ON_CLICK|ON_HOVER|ON_PRESS|ON_DRAG|AFTER_TIMEOUT|MOUSE_ENTER|MOUSE_LEAVE|ON_KEY_DOWN, triggerDelay?, triggerKeyCodes?, triggerDevice?: KEYBOARD|XBOX_ONE|PS4|SWITCH_PRO, destination?, navigation?: NAVIGATE|SWAP|OVERLAY|SCROLL_TO|CHANGE_TO, transition?: DISSOLVE|SMART_ANIMATE|MOVE_IN|MOVE_OUT|PUSH|SLIDE_IN|SLIDE_OUT|INSTANT, transitionDirection?: LEFT|RIGHT|TOP|BOTTOM, duration?, easing?: EASE_IN|EASE_OUT|EASE_IN_AND_OUT|LINEAR|GENTLE|QUICK|BOUNCY|SLOW, actionType?: NODE|BACK|CLOSE|URL|SET_VARIABLE_MODE, url?, collectionName?, modeName?, resetScrollPosition?, actions?, items?: { id: string; trigger: "ON_CLICK" | "ON_HOVER" | "ON_PRESS" | "ON_DRAG" | "AFTER_TIMEOUT" | "MOUSE_ENTER" | "MOUSE_LEAVE" | "ON_KEY_DOWN"; destination?: string; navigation?: "NAVIGATE" | "SWAP" | "OVERLAY" | "SCROLL_TO" | "CHANGE_TO"; transition?: "DISSOLVE" | "SMART_ANIMATE" | "MOVE_IN" | "MOVE_OUT" | "PUSH" | "SLIDE_IN" | "SLIDE_OUT" | "INSTANT"; transitionDirection?: "LEFT" | "RIGHT" | "TOP" | "BOTTOM"; duration?: number; easing?: "EASE_IN" | "EASE_OUT" | "EASE_IN_AND_OUT" | "LINEAR" | "GENTLE" | "QUICK" | "BOUNCY" | "SLOW"; actionType?: "NODE" | "BACK" | "CLOSE" | "URL" | "SET_VARIABLE_MODE"; triggerDelay?: number; url?: string; collectionName?: string; modeName?: string; resetScrollPosition?: boolean; actions?: unknown[] }[]) \u2192 { results: "ok"[] } // Add a prototype reaction to a node\n set (id, reactions) \u2192 { results: "ok"[] } // Replace all reactions on a node (raw reactions array)\n remove (id, index) \u2192 { results: "ok"[] } // Remove a reaction from a node by index\n// Reactions wire up interactions: trigger (ON_CLICK, ON_HOVER, ...) \u2192 action (navigate, swap, overlay).\n// Common patterns: button ON_CLICK \u2192 NAVIGATE to detail frame; card ON_HOVER \u2192 CHANGE_TO hover variant.\n// Multi-action: pass actions[] array to run multiple actions on one trigger (e.g. navigate + set variable mode).',
1942
1984
  schema: (caps2) => filterMethodsByTier({
1943
1985
  method: import_zod4.z.enum(["get", "add", "set", "remove", "help"]),
1944
1986
  id: import_zod4.z.string().optional().describe("Node ID"),
@@ -1958,6 +2000,7 @@ var tools = [
1958
2000
  modeName: import_zod4.z.string().optional().describe("Mode name to switch to (for SET_VARIABLE_MODE)"),
1959
2001
  resetScrollPosition: flexBool(import_zod4.z.boolean()).optional().describe("Reset scroll position on navigate (default: true)"),
1960
2002
  actions: flexJson(import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()))).optional().describe("Multi-action: [{actionType, destination?, navigation?, collectionName?, modeName?, ...}]. Overrides single-action params."),
2003
+ items: flexJson(import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()))).optional().describe("Batch: array of {id, trigger, destination?, ...} reaction items"),
1961
2004
  reactions: flexJson(import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()))).optional().describe("Full reactions array \u2014 [{trigger:{type}, actions:[{type, destinationId, navigation, transition}]}]"),
1962
2005
  index: import_zod4.z.coerce.number().optional().describe("Reaction index (0-based)"),
1963
2006
  topic: import_zod4.z.string().optional().describe('Help topic \u2014 method name for endpoint help, e.g. "create"')
@@ -1968,10 +2011,6 @@ var tools = [
1968
2011
  if (m === "get") {
1969
2012
  if (params.id === void 0) throw new Error('get requires "id"');
1970
2013
  }
1971
- if (m === "add") {
1972
- if (params.id === void 0) throw new Error('add requires "id"');
1973
- if (params.trigger === void 0) throw new Error('add requires "trigger"');
1974
- }
1975
2014
  if (m === "set") {
1976
2015
  if (params.id === void 0) throw new Error('set requires "id"');
1977
2016
  if (params.reactions === void 0) throw new Error('set requires "reactions"');
@@ -1980,6 +2019,39 @@ var tools = [
1980
2019
  if (params.id === void 0) throw new Error('remove requires "id"');
1981
2020
  if (params.index === void 0) throw new Error('remove requires "index"');
1982
2021
  }
2022
+ if (!params.items) return;
2023
+ if (m === "add") {
2024
+ const itemSchema = import_zod4.z.object({
2025
+ id: import_zod4.z.string().describe("Node ID"),
2026
+ trigger: import_zod4.z.enum(["ON_CLICK", "ON_HOVER", "ON_PRESS", "ON_DRAG", "AFTER_TIMEOUT", "MOUSE_ENTER", "MOUSE_LEAVE", "ON_KEY_DOWN"]).describe("Trigger type"),
2027
+ destination: import_zod4.z.string().optional().describe("Target node ID"),
2028
+ navigation: import_zod4.z.enum(["NAVIGATE", "SWAP", "OVERLAY", "SCROLL_TO", "CHANGE_TO"]).optional(),
2029
+ transition: import_zod4.z.enum(["DISSOLVE", "SMART_ANIMATE", "MOVE_IN", "MOVE_OUT", "PUSH", "SLIDE_IN", "SLIDE_OUT", "INSTANT"]).optional(),
2030
+ transitionDirection: import_zod4.z.enum(["LEFT", "RIGHT", "TOP", "BOTTOM"]).optional(),
2031
+ duration: import_zod4.z.coerce.number().optional(),
2032
+ easing: import_zod4.z.enum(["EASE_IN", "EASE_OUT", "EASE_IN_AND_OUT", "LINEAR", "GENTLE", "QUICK", "BOUNCY", "SLOW"]).optional(),
2033
+ actionType: import_zod4.z.enum(["NODE", "BACK", "CLOSE", "URL", "SET_VARIABLE_MODE"]).optional(),
2034
+ triggerDelay: import_zod4.z.coerce.number().optional(),
2035
+ url: import_zod4.z.string().optional(),
2036
+ collectionName: import_zod4.z.string().optional(),
2037
+ modeName: import_zod4.z.string().optional(),
2038
+ resetScrollPosition: flexBool(import_zod4.z.boolean()).optional(),
2039
+ actions: flexJson(import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()))).optional()
2040
+ }).passthrough();
2041
+ try {
2042
+ params.items = import_zod4.z.array(itemSchema).parse(params.items);
2043
+ } catch (e) {
2044
+ if (e instanceof import_zod4.z.ZodError) {
2045
+ throw new Error(e.issues.map((i) => {
2046
+ const path = i.path.join(".");
2047
+ const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
2048
+ const desc = shape?.[i.path[1]]?.description;
2049
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
2050
+ }).join("; "));
2051
+ }
2052
+ throw e;
2053
+ }
2054
+ }
1983
2055
  },
1984
2056
  commandMap: { "get": "prototyping.get", "add": "prototyping.add", "set": "prototyping.set", "remove": "prototyping.remove" }
1985
2057
  },
@@ -2169,11 +2241,15 @@ var tools = [
2169
2241
  x: import_zod4.z.number().optional(),
2170
2242
  y: import_zod4.z.number().optional(),
2171
2243
  width: import_zod4.z.number().optional().describe("Fixed width in px \u2014 implies layoutSizingHorizontal: FIXED and textAutoResize: HEIGHT"),
2172
- parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place on current page."),
2244
+ parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place at current page root."),
2173
2245
  fontFamily: import_zod4.z.string().optional().describe("Font family (default: Inter). Use fonts.list to find installed fonts."),
2174
2246
  fontStyle: import_zod4.z.string().optional().describe('Font variant e.g. "Bold", "Italic" \u2014 overrides fontWeight'),
2175
2247
  fontSize: import_zod4.z.number().optional().describe("Font size (default: 14)"),
2176
2248
  fontWeight: import_zod4.z.number().optional().describe("100-900 (default: 400). Ignored when fontStyle is set."),
2249
+ lineHeight: lineHeight.optional(),
2250
+ letterSpacing: letterSpacing.optional(),
2251
+ textCase: import_zod4.z.enum(["ORIGINAL", "UPPER", "LOWER", "TITLE", "SMALL_CAPS", "SMALL_CAPS_FORCED"]).optional(),
2252
+ textDecoration: import_zod4.z.enum(["NONE", "UNDERLINE", "STRIKETHROUGH"]).optional(),
2177
2253
  fills: import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown())).optional().describe("Text color paints \u2014 e.g. [{type: 'SOLID', color: '#hex'}]. Same as node fills."),
2178
2254
  fontColor: colorRgba.optional().describe("Shorthand \u2014 sets text color (auto-binds to matching variable/style)"),
2179
2255
  fontColorVariableName: import_zod4.z.string().optional().describe("Bind color variable by name e.g. 'text/primary'"),
@@ -2373,7 +2449,7 @@ var tools = [
2373
2449
  },
2374
2450
  {
2375
2451
  name: "variables",
2376
- description: '/** Search and update design variables within a collection. Use method "help" for detailed parameter docs. */\n list (collectionId, query?, type?: COLOR|FLOAT|STRING|BOOLEAN, fields?, offset?, limit?) \u2192 { totalCount, items } // Search variables within a collection\n get (name, collectionId, fields?) \u2192 { name, type, collectionId, valuesByMode: Record<string, number | boolean | string | Color | {type: "VARIABLE_ALIAS", name: string}>, description?, scopes? } // Get variable detail by name\n create (collectionId, items: VariableCreateItem[]) \u2192 { results: {name}[] } // Create variables in a collection. Use valuesByMode for multi-mode, or value for default mode only.\n update (collectionId, items: VariableUpdateItem[]) \u2192 { results: ("ok" | {error})[] } // Update variable metadata and/or set values\n delete (collectionId, name?, items?: { name: string }[]) \u2192 { results: "ok"[] } // Delete variables\n// Search and update variables within a collection. collectionId is required on all methods.\n// Use variable_collections to create full token sets (collection + modes + variables in one call).\n// Shared types:\n// Color: hex "#FF0000" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}',
2452
+ description: '/** Search and update design variables within a collection. Use method "help" for detailed parameter docs. */\n list (collectionId, query?, type?: COLOR|FLOAT|STRING|BOOLEAN, fields?, offset?, limit?) \u2192 { totalCount, items } // Search variables within a collection\n get (name, collectionId, fields?) \u2192 { name, type, collectionId, valuesByMode: Record<string, number | boolean | string | Color | {type: "VARIABLE_ALIAS", name: string}>, description?, scopes? } // Get variable detail by name\n create (collectionId, items: VariableCreateItem[]) \u2192 { results: {name}[] } // Create variables in a collection. Use valuesByMode for per-mode control, or value to set all modes at once.\n update (collectionId, items: VariableUpdateItem[]) \u2192 { results: ("ok" | {error})[] } // Update variable metadata and/or set values\n delete (collectionId, name?, items?: { name: string }[]) \u2192 { results: "ok"[] } // Delete variables\n// Search and update variables within a collection. collectionId is required on all methods.\n// Use variable_collections to create full token sets (collection + modes + variables in one call).\n// Shared types:\n// Color: hex "#FF0000" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}',
2377
2453
  schema: (caps2) => filterMethodsByTier({
2378
2454
  method: import_zod4.z.enum(["list", "get", "create", "update", "delete", "help"]),
2379
2455
  collectionId: import_zod4.z.string().optional().describe("Collection ID or name"),
@@ -2410,7 +2486,7 @@ var tools = [
2410
2486
  const itemSchema = import_zod4.z.object({
2411
2487
  name: import_zod4.z.string().describe("Variable name (must be unique within collection)"),
2412
2488
  type: import_zod4.z.enum(["COLOR", "FLOAT", "STRING", "BOOLEAN"]).describe("Variable type"),
2413
- value: variableValue.optional().describe("Shorthand \u2014 sets the default mode value. Use valuesByMode for multi-mode."),
2489
+ value: variableValue.optional().describe("Sets all modes to this value. Use valuesByMode for per-mode control."),
2414
2490
  valuesByMode: import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()).optional().describe('Values keyed by mode name (e.g. {"Light": "#FFF", "Dark": "#111"}). Takes precedence over value.'),
2415
2491
  description: import_zod4.z.string().optional().describe("Variable description"),
2416
2492
  scopes: flexJson(import_zod4.z.array(import_zod4.z.string())).optional().describe("Restrict where variable can be applied (default: ALL_SCOPES)")
@@ -2521,9 +2597,9 @@ var guidelinesList = [
2521
2597
  }
2522
2598
  ];
2523
2599
  var guidelinesContent = {
2524
- "component-structure": '# Component Structure\n\nComponents need correct sizing, property bindings, and token usage to work well as instances.\n\n## Width Constraints\n\nComponents with text content need a width \u2014 otherwise text never wraps.\n\n- Set `width` and `layoutSizingHorizontal:"FIXED"` on cards, panels, list items\n- HUG on both axes is only correct for buttons, badges, icons \u2014 intrinsically-sized elements\n\n## Property Bindings\n\nEvery text node inside a component should be bound to a TEXT property so instances can edit the content.\n\n- After creation: `frames(method:"update", items:[{id:"<textNodeId>", componentPropertyName:"<propName>"}])`\n- For existing nodes with many text children: `components(method:"create", type:"from_node", exposeText:true)`\n\nOrphaned properties (defined but not bound to any node) should be deleted:\n```\ncomponents(method:"update", items:[{id, propertyName:"<key>", action:"delete"}])\n```\n\n## Variant Sets\n\nGroup related components as variants \u2014 don\'t leave them as separate components.\n\n- Name variants with the property format: `Style=Primary`, `Style=Secondary`\n- Combine: `components(method:"create", type:"variant_set", items:[{componentIds:[...], name:"Button"}])`\n- Instances pick variants via `variantProperties:{"Style":"Primary"}`\n\n### Adding Variants to an Existing Set\n\nClone an existing variant into the same set with a new name. The `name` param is required \u2014 without it, the duplicate name corrupts the set.\n\n**Add a new value to an existing dimension** (e.g. State=Hover):\n```\ncomponents(method:"clone", id:"<variant_id>", name:"Style=Primary, State=Hover", parentId:"<set_id>")\n```\nClone one variant per combination. For a Style\xD7State set, adding State=Hover requires two clones (one per Style). Use batch `items` for efficiency:\n```\ncomponents(method:"clone", items:[\n {id:"<Primary/Default>", name:"Style=Primary, State=Hover", parentId:"<set_id>"},\n {id:"<Secondary/Default>", name:"Style=Secondary, State=Hover", parentId:"<set_id>"}\n])\n```\nThen patch the new variants: `frames(method:"update", items:[{id:"<new>", fillVariableName:"color/hover"}])`\n\n**Add a new dimension** (e.g. Size=sm to a Style\xD7State set):\n1. Batch rename existing variants to include the new dimension: `frames(method:"update", items:[{id:"<each>", name:"..., Size=md"}])`\n2. Batch clone all variants with the new value: `components(method:"clone", items:[{id:"<each>", name:"..., Size=sm", parentId:"<set_id>"}])`\n3. Batch patch the new variants: `frames(method:"update", items:[{id:"<each>", padding:8, minHeight:32}])`\n\nProperty bindings (TEXT, INSTANCE_SWAP) are preserved on cloned variants.\n\n## Checking\n\nRun `components(method:"audit", id)` \u2014 checks both lint rules and property bindings in one call.',
2600
+ "component-structure": '# Component Structure\n\nComponents need correct sizing, property bindings, and token usage to work well as instances.\n\n## Width Constraints\n\nComponents with text content need a width \u2014 otherwise text never wraps.\n\n- Set `width` and `layoutSizingHorizontal:"FIXED"` on cards, panels, list items\n- HUG on both axes is only correct for buttons, badges, icons \u2014 intrinsically-sized elements\n\n## Property Bindings\n\nEvery text node inside a component should be bound to a TEXT property so instances can edit the content.\n\n- On creation: `children:[{type:"text", text:"Title", componentPropertyName:"Title"}]` auto-creates and binds\n- On creation: `children:[{type:"text", text:"Title", componentPropertyName:"Title"}]` auto-creates and binds\n- After creation: `frames(method:"update", items:[{id:"<textNodeId>", componentPropertyName:"<propName>"}])`\n- For existing nodes with many text children: `components(method:"create", type:"from_node", exposeText:true)`\n\nOrphaned properties (defined but not bound to any node) should be deleted:\n```\ncomponents(method:"update", items:[{id, propertyName:"<key>", action:"delete"}])\n```\n\n## Variant Sets\n\nGroup related components as variants \u2014 don\'t leave them as separate components.\n\n- Name variants with the property format: `Style=Primary`, `Style=Secondary`\n- Combine: `components(method:"create", type:"variant_set", items:[{componentIds:[...], name:"Button"}])`\n- Instances pick variants via `variantProperties:{"Style":"Primary"}`\n\n### Adding Variants to an Existing Set\n\nClone an existing variant into the same set with a new name. The `name` param is required \u2014 without it, the duplicate name corrupts the set.\n\n**Add a new value to an existing dimension** (e.g. State=Hover):\n```\ncomponents(method:"clone", id:"<variant_id>", name:"Style=Primary, State=Hover", parentId:"<set_id>")\n```\nClone one variant per combination. For a Style\xD7State set, adding State=Hover requires two clones (one per Style). Use batch `items` for efficiency:\n```\ncomponents(method:"clone", items:[\n {id:"<Primary/Default>", name:"Style=Primary, State=Hover", parentId:"<set_id>"},\n {id:"<Secondary/Default>", name:"Style=Secondary, State=Hover", parentId:"<set_id>"}\n])\n```\nThen patch the new variants: `frames(method:"update", items:[{id:"<new>", fillVariableName:"color/hover"}])`\n\n**Add a new dimension** (e.g. Size=sm to a Style\xD7State set):\n1. Batch rename existing variants to include the new dimension: `frames(method:"update", items:[{id:"<each>", name:"..., Size=md"}])`\n2. Batch clone all variants with the new value: `components(method:"clone", items:[{id:"<each>", name:"..., Size=sm", parentId:"<set_id>"}])`\n3. Batch patch the new variants: `frames(method:"update", items:[{id:"<each>", padding:8, minHeight:32}])`\n\nProperty bindings (TEXT, INSTANCE_SWAP) are preserved on cloned variants.\n\n## Checking\n\nRun `components(method:"audit", id)` \u2014 checks both lint rules and property bindings in one call.',
2525
2601
  "library-components": '# Working with Library Components\n\nLibrary components are read-only \u2014 they come from external team libraries and cannot be edited in the current file.\n\n## Reading\n\nWhen reading nodes, library instances appear as stubs with their overridable properties:\n```\n{name: "Header", type: "INSTANCE", componentProperties: {"Platform": "Desktop"}}\n```\n\nLibrary internals are hidden: no `componentId`, no variable names, no style names. You see resolved values (hex colors, numbers) instead.\n\n## Using\n\nPlace library instances via `instances(method:"create", items:[{componentId:"<id>"}])` when you have a local component ID. For library components, instances are already placed by the designer \u2014 interact via `instances(method:"update")` to set properties.\n\n## Customizing\n\nTo edit a library component, clone it into the local file first:\n\n```\ncomponents(method:"clone", id:"<instanceId>")\n```\n\nThis resolves the instance to its source component (or full component set) and creates a local copy with a new ID. Edit the local copy freely \u2014 it is independent of the library.\n\nDo not attempt to `components(method:"get")` or `components(method:"update")` a library component directly \u2014 these will error.\n\n## Overriding Instance Properties\n\nUse `instances(method:"update")` to change overridable properties on library instances:\n```\ninstances(method:"update", items:[{id:"<instanceId>", properties:{"Label":"New Text", "State":"Hover"}}])\n```\n\nProperty names are clean (no hash suffixes needed for update \u2014 the system resolves partial keys).',
2526
- "responsive-designs": '# Responsive Sizing\n\n## Workflow: Top-Down Sizing\n\nBuild layouts from the outside in:\n\n1. **Set the container first.** Every container needs an explicit width \u2014 either `width` + `layoutSizingHorizontal:"FIXED"` for shells and bounded panels, or `layoutSizingHorizontal:"FILL"` inside an auto-layout parent. Set `layoutMode` (VERTICAL or HORIZONTAL) and spacing/padding.\n2. **Children fill the container.** Use `layoutSizingHorizontal:"FILL"` on children so they stretch to the available space. Use `layoutSizingVertical:"HUG"` so height follows content.\n3. **Only leaves use HUG on both axes.** Buttons, badges, icons \u2014 elements with short, predictable content that should shrink-wrap.\n\nThis ensures every level of the tree has a clear width constraint. Text wraps, FILL children stretch, and the layout adapts when the container resizes.\n\nAlways set BOTH axes explicitly on every node. Omitting sizing leads to unintended defaults.\n\n## FIXED / FILL / HUG\n\n- **FIXED** \u2014 explicit bounded widths: page shell, sidebar, modal max-width, specimen frames\n- **FILL** \u2014 children that adapt to parent: cards, rows, panels, nav stacks, text that should wrap. Use `minWidth`/`maxWidth` for responsive constraints.\n- **HUG** \u2014 content-sized leaves only: icons, badges, pills, button labels\n\n## Anti-patterns: HUG/HUG\n\nHUG on both axes is the most common cause of broken layouts. It means "shrink to fit my content on both axes" \u2014 the container has no opinion about its own size and collapses to whatever its children measure.\n\n**Why HUG/HUG breaks designs:**\n\n1. **Text never wraps.** A HUG-width container grows to fit the longest text line. Body text becomes a single very long line instead of wrapping at a readable width. The design looks correct with short placeholder text but breaks with real content.\n\n2. **Layouts don\'t adapt.** HUG/HUG containers ignore their parent\'s width. A card inside a responsive column won\'t stretch to fill available space \u2014 it stays at its content width, leaving gaps or overflowing.\n\n3. **FILL children become under-constrained.** A child with `layoutSizingHorizontal:"FILL"` inside a HUG-width parent has no space to fill \u2014 the parent defers its width to its children, but the FILL child defers its width to the parent. The result is under-constrained sizing that produces unpredictable or collapsed layouts.\n\n4. **Cascading failures.** One HUG/HUG container at the top of a tree forces every child to resolve its own width. The entire layout becomes rigid and content-dependent instead of responsive.\n\n**HUG/HUG is only correct for:**\n- Buttons, pills, badges, chips \u2014 intrinsically-sized leaf elements with short, predictable content\n- Icon containers with fixed-size children\n- Inline tags and status indicators\n\n**For everything else, set at least one axis to FIXED or FILL:**\n- Cards, panels, list rows \u2192 `layoutSizingHorizontal:"FILL"`, vertical `HUG`. Add `minWidth`/`maxWidth` for responsive bounds.\n- Shells, sidebars, modals \u2192 `width` + `layoutSizingHorizontal:"FIXED"`, vertical `FILL` or `HUG`\n- Full-width sections \u2192 `layoutSizingHorizontal:"FILL"`, `layoutSizingVertical:"HUG"`\n\n## Component Sizing\n\nComponent roots use `FILL` when placed in a parent \u2014 they adapt to context, not a fixed specimen width. Use `FIXED` only for the specimen (the component definition itself when it needs a specific preview width).\n\nExample sidebar item:\n- Instance: `FILL` in parent nav stack\n- Icon child: fixed 18x18\n- Label child: `FILL`\n- Badge child: `HUG`\n\n## Text Sizing\n\n- Body text inside containers: prefer `FILL` width, `HUG` height (auto-wraps)\n- Single-line labels: prefer `FILL` horizontal (truncates if needed)\n- Standalone headings: `HUG` is fine\n\nInside auto-layout parents, target `layoutSizingHorizontal:"FILL"` + `layoutSizingVertical:"HUG"` + `textAutoResize:"HEIGHT"` for text that should wrap. These are not auto-applied \u2014 set them explicitly on text.create or text.update.\n\n## Checklist\n\nBefore finalizing a layout, verify:\n1. No container with text has HUG on the horizontal axis (unless it\'s a button/badge)\n2. Children use FILL on the axis that should absorb available space \u2014 not blindly on both axes. Compact controls in horizontal rows often stay HUG vertically.\n3. Top-level containers have an explicit width (FIXED) or stretch to their parent (FILL)\n4. Run `lint(method:"check", nodeId:"<rootId>", rules:["composition"])` to catch overflow-parent, unbounded-hug, and fixed-in-autolayout issues',
2602
+ "responsive-designs": '# Responsive Sizing\n\n## Workflow: Top-Down Sizing\n\nBuild layouts from the outside in:\n\n1. **Set the container first.** Every container needs an explicit width \u2014 either `width` + `layoutSizingHorizontal:"FIXED"` for shells and bounded panels, or `layoutSizingHorizontal:"FILL"` inside an auto-layout parent. Set `layoutMode` (VERTICAL or HORIZONTAL) and spacing/padding.\n2. **Children fill the container.** Use `layoutSizingHorizontal:"FILL"` on children so they stretch to the available space. Use `layoutSizingVertical:"HUG"` so height follows content.\n3. **Only leaves use HUG on both axes.** Buttons, badges, icons \u2014 elements with short, predictable content that should shrink-wrap.\n\nThis ensures every level of the tree has a clear width constraint. Text wraps, FILL children stretch, and the layout adapts when the container resizes.\n\nAlways set BOTH axes explicitly on every node. Omitting sizing leads to unintended defaults.\n\n## FIXED / FILL / HUG\n\n- **FIXED** \u2014 explicit bounded widths: page shell, sidebar, modal max-width, specimen frames\n- **FILL** \u2014 children that adapt to parent: cards, rows, panels, nav stacks, text that should wrap. Use `minWidth`/`maxWidth` for responsive constraints.\n- **HUG** \u2014 content-sized leaves only: icons, badges, pills, button labels\n\n## Anti-patterns: HUG/HUG\n\nHUG on both axes is the most common cause of broken layouts. It means "shrink to fit my content on both axes" \u2014 the container has no opinion about its own size and collapses to whatever its children measure.\n\n**Why HUG/HUG breaks designs:**\n\n1. **Text never wraps.** A HUG-width container grows to fit the longest text line. Body text becomes a single very long line instead of wrapping at a readable width. The design looks correct with short placeholder text but breaks with real content.\n\n2. **Layouts don\'t adapt.** HUG/HUG containers ignore their parent\'s width. A card inside a responsive column won\'t stretch to fill available space \u2014 it stays at its content width, leaving gaps or overflowing.\n\n3. **FILL children become under-constrained.** A child with `layoutSizingHorizontal:"FILL"` inside a HUG-width parent has no space to fill \u2014 the parent defers its width to its children, but the FILL child defers its width to the parent. The result is under-constrained sizing that produces unpredictable or collapsed layouts.\n\n4. **Cascading failures.** One HUG/HUG container at the top of a tree forces every child to resolve its own width. The entire layout becomes rigid and content-dependent instead of responsive.\n\n**HUG/HUG is only correct for:**\n- Buttons, pills, badges, chips \u2014 intrinsically-sized leaf elements with short, predictable content\n- Icon containers with fixed-size children\n- Inline tags and status indicators\n\n**For everything else, set at least one axis to FIXED or FILL:**\n- Cards, panels, list rows \u2192 `layoutSizingHorizontal:"FILL"`, vertical `HUG`. Add `minWidth`/`maxWidth` for responsive bounds.\n- Shells, sidebars, modals \u2192 `width` + `layoutSizingHorizontal:"FIXED"`, vertical `FILL` or `HUG`\n- Full-width sections \u2192 `layoutSizingHorizontal:"FILL"`, `layoutSizingVertical:"HUG"`\n\n## Wrapping Layouts (layoutWrap)\n\n`layoutWrap: WRAP` enables children to flow into new rows when they exceed the container width \u2014 like CSS `flex-wrap`. This only works with **HORIZONTAL** auto-layout. Figma does not support wrap on VERTICAL layouts.\n\n**When to use wrap:**\n- Card grids with a fixed number of columns at a known width\n- Tag/chip collections where items flow into multiple rows\n- Any layout where items should reflow based on available width\n\n**Horizontal wrap pattern:**\n```\nframes.create(type: "auto_layout", layoutMode: "HORIZONTAL", layoutWrap: "WRAP",\n itemSpacing: "space/16", counterAxisSpacing: "space/16")\n```\nChildren use FIXED width to control column count. `counterAxisSpacing` sets the gap between wrapped rows.\n\n**Vertical grid alternative:**\nSince VERTICAL layouts cannot wrap, build column-based grids by nesting VERTICAL columns inside a HORIZONTAL parent:\n```\nouter (HORIZONTAL, itemSpacing: 20, FILL width)\n col-1 (VERTICAL, FILL width, HUG height, itemSpacing: 20)\n col-2 (VERTICAL, FILL width, HUG height, itemSpacing: 20)\n col-3 (VERTICAL, FILL width, HUG height, itemSpacing: 20)\n```\nEach column gets equal width via FILL. Reparent items into columns for column-first ordering. This handles variable card heights per column independently.\n\n## Component Sizing\n\nComponent roots use `FILL` when placed in a parent \u2014 they adapt to context, not a fixed specimen width. Use `FIXED` only for the specimen (the component definition itself when it needs a specific preview width).\n\nExample sidebar item:\n- Instance: `FILL` in parent nav stack\n- Icon child: fixed 18x18\n- Label child: `FILL`\n- Badge child: `HUG`\n\n## Text Sizing\n\n- Body text inside containers: prefer `FILL` width, `HUG` height (auto-wraps)\n- Single-line labels: prefer `FILL` horizontal (truncates if needed)\n- Standalone headings: `HUG` is fine\n\nInside auto-layout parents, target `layoutSizingHorizontal:"FILL"` + `layoutSizingVertical:"HUG"` + `textAutoResize:"HEIGHT"` for text that should wrap. These are not auto-applied \u2014 set them explicitly on text.create or text.update.\n\n## Checklist\n\nBefore finalizing a layout, verify:\n1. No container with text has HUG on the horizontal axis (unless it\'s a button/badge)\n2. Children use FILL on the axis that should absorb available space \u2014 not blindly on both axes. Compact controls in horizontal rows often stay HUG vertically.\n3. Top-level containers have an explicit width (FIXED) or stretch to their parent (FILL)\n4. Run `lint(method:"check", nodeId:"<rootId>", rules:["composition"])` to catch overflow-parent, unbounded-hug, and fixed-in-autolayout issues',
2527
2603
  "token-discipline": '# Token Discipline\n\nEvery color, spacing value, and text style should come from a design token \u2014 not hardcoded values.\n\n## Colors\n\nBind fills and strokes to color variables instead of hex values.\n\n- Fill: `fillVariableName:"bg/primary"` or `fillStyleName:"Surface/Primary"`\n- Stroke: `strokeVariableName:"border/default"`\n- Text color: `fontColorVariableName:"text/primary"`\n\nIf no matching variable exists, create one first:\n```\nvariables(method:"create", collectionId:"Colors", items:[{name:"bg/accent", type:"COLOR", valuesByMode:{"Light":"#E8F0FE","Dark":"#1A3A5C"}, scopes:["ALL_FILLS"]}])\n```\n\n## Spacing and Radius\n\nPass a variable name string instead of a number for cornerRadius, padding, itemSpacing, strokeWeight, opacity.\n\n- `cornerRadius:"radius/8"` not `cornerRadius:8`\n- `paddingTop:"space/16"` not `paddingTop:16`\n- `itemSpacing:"space/8"` not `itemSpacing:8`\n\nCreate FLOAT variables with appropriate scopes:\n```\nvariables(method:"create", collectionId:"Metrics", items:[{name:"space/12", type:"FLOAT", value:12, scopes:["GAP","WIDTH_HEIGHT"]}])\n```\n\n## Text Styles\n\nApply text styles by name \u2014 don\'t set fontSize/fontFamily/fontWeight manually.\n\n- `textStyleName:"Body/M"` on text.create or frames.update\n- Create styles with `styles(method:"create", type:"text", items:[{name:"Body/M", fontFamily:"Inter", fontSize:14, lineHeight:{value:20, unit:"PIXELS"}}])`\n\n## Common Scopes\n\nCOLOR variables:\n- `ALL_FILLS` \u2014 background fills\n- `TEXT_FILL` \u2014 text color\n- `STROKE_COLOR` \u2014 borders and outlines\n\nFLOAT variables:\n- `GAP`, `WIDTH_HEIGHT` \u2014 spacing and padding\n- `CORNER_RADIUS` \u2014 border radius\n- `STROKE_FLOAT` \u2014 stroke weight\n- `OPACITY` \u2014 transparency\n\n## Checking\n\nLint rules `hardcoded-color`, `hardcoded-token`, `no-text-style` catch unbound values. Run `audit` on any node to check.',
2528
2604
  "vibma-workflow": '# Vibma Workflow\n\nWork with the tool in a predictable sequence: read before writing, create parents before children, verify after mutations.\n\n## Build Order\n\n1. `connection.create` \u2192 `connection.get` to verify\n2. Inspect existing structure: `document.get`, `variables.list`, `styles.list`, `components.list`\n3. Create design tokens: variable collections \u2192 variables \u2192 text styles \u2192 effect styles\n4. Create components from tokens\n5. Assemble screens from component instances\n6. Verify with `lint.check` and `frames.export`\n\n## Parent-First Rule\n\nCreate parent containers before children. Dependent creates must be sequential \u2014 never parallelize when the child needs the parent ID.\n\n## Component Creation\n\nBuild components early \u2014 they are the building blocks for screens. A component IS a frame: create it directly with layout properties, then add children.\n\n- Use `components.create(type: "component")` with properties for TEXT, BOOLEAN, INSTANCE_SWAP\n- TEXT properties auto-bind to child text nodes with matching names\n- Group related components into variant sets with `components.create(type: "variant_set")` for state dimensions (Style, Size, State)\n- Use flat components (not variant sets) for INSTANCE_SWAP slots like icons or avatars\n- Assemble screens from `instances.create`, not by cloning frames\n\n## Placement Rule\n\nAlways pass `x` and `y` for top-level nodes and clones. Do not stack everything at `0,0`.\n\n## Instance Rule\n\nCall `components.get` or `instances.get` to discover property keys (including `#suffix`) before setting overrides. Do not guess property names.\n\n## Verify After Mutations\n\n`"ok"` means the write succeeded, not that the result is correct. Read back the node after clone, swap, mode pinning, or large batch updates.'
2529
2605
  };