@ufira/vibma 1.1.3 → 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/mcp.cjs CHANGED
@@ -102,15 +102,15 @@ Use help(topic: "<endpoint>") for endpoint details.
102
102
  Use help(topic: "<endpoint>.<method>") for method details.`;
103
103
  var helpEndpoints = {
104
104
  "annotations": {
105
- "summary": '# annotations\nRead and manage design annotations and annotation categories.\n\nMethods:\n get Read all annotations on a node (full detail with resolved category names) [read]\n list Search annotations across a subtree, optionally filtered by category [read]\n set Replace all annotations on a node [edit]\n add Add an annotation to a node [edit]\n remove Remove an annotation from a node by index [edit]\n categories List all annotation categories in the file [read]\n create_category Create a new annotation category [create]\n update_category Update an annotation category\'s label or color [edit]\n delete_category Delete an annotation category [edit]\n\n// Annotations are designer-authored notes attached to nodes \u2014 specs, intent, constraints.\n// Every node-returning endpoint includes an annotation brief: { label, properties?, categoryId? }.\n// Use this endpoint for full CRUD and to manage annotation categories.\n// Workflow: read annotations on a node with get, add new ones with add, manage categories with categories/create_category.\n// Batch: get/set/add/remove accept items:[{id, ...}] for multi-node operations, or single-item params (id, label, etc).\n// properties: measurement indicators Figma displays on the canvas \u2014 validated per node type and state.\n// labelMarkdown: rich text label supporting **bold**, *italic*, `code`, [links](url).\n// categoryId: group annotations by category (e.g. "Spacing", "Typography"). Create categories first.\n// ---\n// AnnotationPropertyType values (node-type-dependent \u2014 invalid ones are rejected with the available list):\n// Dimension: width, height, maxWidth, minWidth, maxHeight, minHeight\n// Paint: fills, strokes, effects, strokeWeight, cornerRadius, opacity\n// Text (TEXT nodes only): textStyleId, textAlignHorizontal, fontFamily, fontStyle, fontSize, fontWeight, lineHeight, letterSpacing\n// Layout (auto-layout only): itemSpacing, padding, layoutMode, alignItems\n// Instance (INSTANCE only): mainComponent\n// Grid (grid layout only): gridRowGap, gridColumnGap, gridRowCount, gridColumnCount, gridRowAnchorIndex, gridColumnAnchorIndex, gridRowSpan, gridColumnSpan\n// AnnotationCategoryColor values: yellow, orange, red, pink, violet, blue, teal, green.\n\nUse annotations(method: "help", topic: "<method>") for method details.',
105
+ "summary": '# annotations\nRead and manage design annotations and annotation categories.\n\nMethods:\n get Read all annotations on a node (full detail with resolved category names) [read]\n list Search annotations across a subtree, optionally filtered by category [read]\n set Replace all annotations on a node [edit]\n add Add an annotation to a node [edit]\n remove Remove an annotation from a node by index [edit]\n categories List all annotation categories in the file [read]\n create_category Create a new annotation category [create]\n update_category Update an annotation category\'s label or color [edit]\n delete_category Delete an annotation category [edit]\n\n// Annotations are designer-authored notes attached to nodes \u2014 specs, intent, constraints.\n// Every node-returning endpoint includes an annotation brief: { label, properties?, categoryId? }.\n// Use this endpoint for full CRUD and to manage annotation categories.\n// Workflow: read annotations on a node with get, add new ones with add, manage categories with categories/create_category.\n// Batch: get/set/add/remove accept items:[{id, ...}] for multi-node operations, or single-item params (id, label, etc).\n// properties: measurement indicators Figma displays on the canvas \u2014 validated per node type and state.\n// labelMarkdown: rich text label supporting **bold**, *italic*, `code`, [links](url).\n// categoryId: group annotations by category (e.g. "Spacing", "Typography"). Create categories first.\n// ---\n// AnnotationPropertyType values (node-type-dependent \u2014 invalid ones are rejected with the available list):\n// Dimension: width, height, maxWidth, minWidth, maxHeight, minHeight\n// Paint: fills, strokes, effects, strokeWeight, cornerRadius, opacity\n// Text (TEXT nodes only): textStyleId, textAlignHorizontal, fontFamily, fontStyle, fontSize, fontWeight, lineHeight, letterSpacing\n// Layout (auto-layout only): itemSpacing, padding, layoutMode, alignItems\n// Instance (INSTANCE only): mainComponent\n// Grid (grid layout only): gridRowGap, gridColumnGap, gridRowCount, gridColumnCount, gridRowAnchorIndex, gridColumnAnchorIndex, gridRowSpan, gridColumnSpan\n// AnnotationCategoryColor values: yellow, orange, red, pink, violet, blue, teal, green.\n\nUse annotations(method: "help", topic: "<method>") for method details.\n// Shared types:\n// Color: hex "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}\n// VariableAlias: {type: "VARIABLE_ALIAS", id: string}. The id must be a Figma VariableID; discover it via variables.get/list or variable_collections.get. Prefer colorVariableName/fillVariableName/strokeVariableName when available; Paint[] VariableAlias is mainly for precise Paint[] round-trips and gradient stop bindings.\n// Transform: [[number, number, number], [number, number, number]] (Figma Plugin API 2\xD73 matrix)\n// 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"\n// ColorStop: {position: 0-1, color: Color, boundVariables?: {color?: VariableAlias}}\n// GradientPaint: {type: "GRADIENT_LINEAR"|"GRADIENT_RADIAL"|"GRADIENT_ANGULAR"|"GRADIENT_DIAMOND", gradientTransform: Transform, gradientStops: ColorStop[], visible?: boolean, opacity?: number, blendMode?: BlendMode}. Use gradientTransform + gradientStops (basic left-to-right: [[1,0,0],[0,1,0]]); do not use CSS gradients or REST gradientHandlePositions.\n// Paint: Paint[] authoring accepts only SOLID and GRADIENT_LINEAR/GRADIENT_RADIAL/GRADIENT_ANGULAR/GRADIENT_DIAMOND. SolidPaint: {type: "SOLID", color: Color, visible?: boolean, opacity?: number, blendMode?: BlendMode, boundVariables?: {color?: VariableAlias}}. GradientPaint authoring: {type: GRADIENT_*, gradientTransform: Transform, gradientStops: ColorStop[], visible?, opacity?, blendMode?}; bind variables on gradientStops[].boundVariables.color, not top-level gradient boundVariables. Do not pass IMAGE/VIDEO/PATTERN to create/update Paint[]; those may appear only in readback metadata from existing Figma content. Use imageUrl/images for image authoring. VIDEO/PATTERN authoring is not supported here. Do not use CSS gradients or REST gradientHandlePositions.',
106
106
  "methods": {
107
- "get": '# annotations.get\nRead all annotations on a node (full detail with resolved category names)\n\nExample: annotations(method:"get", id:"1:23")\n\nParams:\n id (string, optional) \u2014 Node ID\n categoryId (string, optional) \u2014 Filter \u2014 only return annotations in this category\n items (array, optional) \u2014 Batch: [{id, categoryId?}, ...]\n id (string, required)\n categoryId (string, optional)',
108
- "list": '# annotations.list\nSearch annotations across a subtree, optionally filtered by category\n\nExample: annotations(method:"list", parentId:"1:2", categoryId:"113:0")\n\nParams:\n parentId (string, optional) \u2014 Root node to search within (default: current page)\n categoryId (string, optional) \u2014 Filter by category ID\n limit (number, optional) \u2014 Max items per page (default 100)',
109
- "set": '# annotations.set\nReplace all annotations on a node\n\nExample: annotations(method:"set", id:"1:23", annotations:[{label:"Spacing: 16px", properties:["padding"]}])\n\nParams:\n id (string, optional) \u2014 Node ID\n annotations (array, optional) \u2014 Array of annotation objects to set (replaces all existing)\n label (string, optional) \u2014 Plain text label\n labelMarkdown (string, optional) \u2014 Rich text label (Markdown)\n properties (string[], optional) \u2014 Measurement property types to display\n categoryId (string, optional) \u2014 Category ID\n items (array, optional) \u2014 Batch: [{id, annotations: [...]}, ...]\n id (string, required)\n annotations (array, required) \u2014 Annotations to set on this node',
110
- "add": '# annotations.add\nAdd an annotation to a node\n\nExample: annotations(method:"add", id:"1:23", labelMarkdown:"**Width**: 320px fixed", properties:["width"])\n\nParams:\n id (string, optional) \u2014 Node ID\n label (string, optional) \u2014 Plain text label (use label or labelMarkdown, not both)\n labelMarkdown (string, optional) \u2014 Rich text label with Markdown formatting\n properties (string[], optional) \u2014 Measurement property types to display on canvas\n categoryId (string, optional) \u2014 Category ID to group this annotation\n items (array, optional) \u2014 Batch: [{id, label?, labelMarkdown?, properties?, categoryId?}, ...]\n id (string, required)\n label (string, optional)\n labelMarkdown (string, optional)\n properties (string[], optional)\n categoryId (string, optional)',
111
- "remove": '# annotations.remove\nRemove an annotation from a node by index\n\nExample: annotations(method:"remove", id:"1:23", index:0)\n\nParams:\n id (string, optional) \u2014 Node ID\n index (number, optional) \u2014 Annotation index to remove (from get response)\n items (array, optional) \u2014 Batch: [{id, index}, ...]\n id (string, required)\n index (number, required)',
112
- "categories": '# annotations.categories\nList all annotation categories in the file\n\nExample: annotations(method:"categories")\n\nNo params.',
113
- "create_category": '# annotations.create_category\nCreate a new annotation category\n\nExample: annotations(method:"create_category", label:"Spacing", color:"blue")\n\nParams:\n label (string, required) \u2014 Category label\n color (yellow | orange | red | pink | violet | blue | teal | green, required) \u2014 Category color',
107
+ "get": '# annotations.get\nRead all annotations on a node (full detail with resolved category names)\n\nExample: annotations(method:"get", id:"1:23")\n\nParams:\n id (string, optional) \u2014 Node ID\n categoryId (string, optional) \u2014 Filter \u2014 only return annotations in this category\n items (array, optional) \u2014 Batch: [{id, categoryId?}, ...]\n id (string, required)\n categoryId (string, optional)\n\nResponse:\n { results: ({id} | {error})[] }',
108
+ "list": '# annotations.list\nSearch annotations across a subtree, optionally filtered by category\n\nExample: annotations(method:"list", parentId:"1:2", categoryId:"113:0")\n\nParams:\n parentId (string, optional) \u2014 Root node to search within (default: current page)\n categoryId (string, optional) \u2014 Filter by category ID\n limit (number, optional) \u2014 Max items per page (default 100)\n\nResponse:\n results (array, optional) \u2014 Annotations found across the subtree\n nodeId (string, optional)\n nodeName (string, optional)\n nodeType (string, optional)\n index (number, optional)\n label (string, optional)\n labelMarkdown (string, optional)\n properties (array, optional)\n category (object, optional)\n count (number, optional)\n _truncated (boolean, optional)',
109
+ "set": '# annotations.set\nReplace all annotations on a node\n\nExample: annotations(method:"set", id:"1:23", annotations:[{label:"Spacing: 16px", properties:["padding"]}])\n\nParams:\n id (string, optional) \u2014 Node ID\n annotations (array, optional) \u2014 Array of annotation objects to set (replaces all existing)\n label (string, optional) \u2014 Plain text label\n labelMarkdown (string, optional) \u2014 Rich text label (Markdown)\n properties (string[], optional) \u2014 Measurement property types to display\n categoryId (string, optional) \u2014 Category ID\n items (array, optional) \u2014 Batch: [{id, annotations: [...]}, ...]\n id (string, required)\n annotations (array, required) \u2014 Annotations to set on this node\n\nResponse:\n { results: ({id} | {error})[] }',
110
+ "add": '# annotations.add\nAdd an annotation to a node\n\nExample: annotations(method:"add", id:"1:23", labelMarkdown:"**Width**: 320px fixed", properties:["width"])\n\nParams:\n id (string, optional) \u2014 Node ID\n label (string, optional) \u2014 Plain text label (use label or labelMarkdown, not both)\n labelMarkdown (string, optional) \u2014 Rich text label with Markdown formatting\n properties (string[], optional) \u2014 Measurement property types to display on canvas\n categoryId (string, optional) \u2014 Category ID to group this annotation\n items (array, optional) \u2014 Batch: [{id, label?, labelMarkdown?, properties?, categoryId?}, ...]\n id (string, required)\n label (string, optional)\n labelMarkdown (string, optional)\n properties (string[], optional)\n categoryId (string, optional)\n\nResponse:\n { results: ({id} | {error})[] }',
111
+ "remove": '# annotations.remove\nRemove an annotation from a node by index\n\nExample: annotations(method:"remove", id:"1:23", index:0)\n\nParams:\n id (string, optional) \u2014 Node ID\n index (number, optional) \u2014 Annotation index to remove (from get response)\n items (array, optional) \u2014 Batch: [{id, index}, ...]\n id (string, required)\n index (number, required)\n\nResponse:\n { results: ({id} | {error})[] }',
112
+ "categories": '# annotations.categories\nList all annotation categories in the file\n\nExample: annotations(method:"categories")\n\nNo params.\n\nResponse:\n categories (array, optional)\n id (string, optional)\n label (string, optional)\n color (string, optional)\n isPreset (boolean, optional)',
113
+ "create_category": '# annotations.create_category\nCreate a new annotation category\n\nExample: annotations(method:"create_category", label:"Spacing", color:"blue")\n\nParams:\n label (string, required) \u2014 Category label\n color (yellow | orange | red | pink | violet | blue | teal | green, required) \u2014 Category color\n\nResponse:\n id (string, optional)\n label (string, optional)\n color (string, optional)',
114
114
  "update_category": `# annotations.update_category
115
115
  Update an annotation category's label or color
116
116
 
@@ -119,14 +119,33 @@ Example: annotations(method:"update_category", id:"cat:123", label:"Layout", col
119
119
  Params:
120
120
  id (string, required) \u2014 Category ID
121
121
  label (string, optional) \u2014 New label
122
- color (yellow | orange | red | pink | violet | blue | teal | green, optional) \u2014 New color`,
123
- "delete_category": '# annotations.delete_category\nDelete an annotation category\n\nExample: annotations(method:"delete_category", id:"cat:123")\n\nParams:\n id (string, required) \u2014 Category ID to delete'
122
+ color (yellow | orange | red | pink | violet | blue | teal | green, optional) \u2014 New color
123
+
124
+ Response:
125
+ id (string, optional)
126
+ label (string, optional)
127
+ color (string, optional)`,
128
+ "delete_category": '# annotations.delete_category\nDelete an annotation category\n\nExample: annotations(method:"delete_category", id:"cat:123")\n\nParams:\n id (string, required) \u2014 Category ID to delete\n\nResponse:\n deleted (boolean, optional)'
124
129
  }
125
130
  },
126
131
  "components": {
127
- "summary": '# components\nCreate and manage reusable components and variant sets.\n\nMethods:\n clone Duplicate nodes \u2014 produces a same-type copy (frame\u2192frame, instance\u2192instance, component\u2192component). Instance clones reference the same source component; they do not duplicate the component definition. [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.',
132
+ "summary": '# components\nCreate and manage reusable components and variant sets.\n\nMethods:\n clone Duplicate nodes \u2014 produces a same-type copy (frame\u2192frame, instance\u2192instance, component\u2192component). Instance clones reference the same source component; they do not duplicate the component definition. [create]\n scale Proportionally rescale a node subtree using Figma\'s visual Scale tool behavior. This is for visual/artifact scaling, not responsive layout resizing. [edit]\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// clipsContent: clip children to the node bounds where supported (frames/components/instances). Set false for overflow-visible layouts.\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[]; // readback Paint[]; authoring supports SOLID + gradients via gradientTransform + gradientStops\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. Paint[] authoring supports SOLID + gradients only; IMAGE/VIDEO/PATTERN are readback-only metadata.\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// Examples assume design tokens/styles already exist. Build components from tokens/styles, not raw color/spacing/type values.\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.\n// Shared types:\n// Color: hex "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}\n// VariableAlias: {type: "VARIABLE_ALIAS", id: string}. The id must be a Figma VariableID; discover it via variables.get/list or variable_collections.get. Prefer colorVariableName/fillVariableName/strokeVariableName when available; Paint[] VariableAlias is mainly for precise Paint[] round-trips and gradient stop bindings.\n// Transform: [[number, number, number], [number, number, number]] (Figma Plugin API 2\xD73 matrix)\n// 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"\n// ColorStop: {position: 0-1, color: Color, boundVariables?: {color?: VariableAlias}}\n// GradientPaint: {type: "GRADIENT_LINEAR"|"GRADIENT_RADIAL"|"GRADIENT_ANGULAR"|"GRADIENT_DIAMOND", gradientTransform: Transform, gradientStops: ColorStop[], visible?: boolean, opacity?: number, blendMode?: BlendMode}. Use gradientTransform + gradientStops (basic left-to-right: [[1,0,0],[0,1,0]]); do not use CSS gradients or REST gradientHandlePositions.\n// Effect: {type: "DROP_SHADOW"|"INNER_SHADOW"|"LAYER_BLUR"|"BACKGROUND_BLUR", radius: number, color?: {r,g,b,a} (0-1), offset?: {x, y}, spread?: number, visible?: boolean}\n// Paint: Paint[] authoring accepts only SOLID and GRADIENT_LINEAR/GRADIENT_RADIAL/GRADIENT_ANGULAR/GRADIENT_DIAMOND. SolidPaint: {type: "SOLID", color: Color, visible?: boolean, opacity?: number, blendMode?: BlendMode, boundVariables?: {color?: VariableAlias}}. GradientPaint authoring: {type: GRADIENT_*, gradientTransform: Transform, gradientStops: ColorStop[], visible?, opacity?, blendMode?}; bind variables on gradientStops[].boundVariables.color, not top-level gradient boundVariables. Do not pass IMAGE/VIDEO/PATTERN to create/update Paint[]; those may appear only in readback metadata from existing Figma content. Use imageUrl/images for image authoring. VIDEO/PATTERN authoring is not supported here. Do not use CSS gradients or REST gradientHandlePositions.\n// NodeStub: {id: string, name: string, type: string}',
128
133
  "methods": {
129
- "clone": "# components.clone\nDuplicate nodes \u2014 produces a same-type copy (frame\u2192frame, instance\u2192instance, component\u2192component). Instance clones reference the same source component; they do not duplicate the component definition.\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.",
134
+ "clone": "# components.clone\nDuplicate nodes \u2014 produces a same-type copy (frame\u2192frame, instance\u2192instance, component\u2192component). Instance clones reference the same source component; they do not duplicate the component definition.\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.\n\nResponse:\n { results: ({id} | {error})[] }",
135
+ "scale": `# components.scale
136
+ Proportionally rescale a node subtree using Figma's visual Scale tool behavior. This is for visual/artifact scaling, not responsive layout resizing.
137
+
138
+ Example: components(method:"scale", id:"1:23", factor:0.5)
139
+
140
+ Params:
141
+ id (string, optional) \u2014 Node ID to scale
142
+ factor (number, optional) \u2014 Scale factor, >= 0.01. 0.5 = 50%, 2 = 200%. Scales children, text, strokes, effects, and layout geometry from the node's top-left. On auto-layout or HUG/FILL nodes, Figma may resolve responsive sizing to fixed width/height.
143
+ items (array, optional) \u2014 Batch: [{id, factor}, ...]. Alternative to single-item params.
144
+ id (string, required) \u2014 Node ID to scale
145
+ factor (number, required) \u2014 Scale factor, >= 0.01. 0.5 = 50%, 2 = 200%.
146
+
147
+ Response:
148
+ { results: ("ok" | {error})[] }`,
130
149
  "audit": `# components.audit
131
150
  Run lint on a node \u2014 returns severity-ranked findings
132
151
 
@@ -136,189 +155,216 @@ Params:
136
155
  maxDepth (number, optional) \u2014 Max tree depth (default: 10)
137
156
  maxFindings (number, optional) \u2014 Max findings (default: 50)
138
157
  minSeverity (error | unsafe | heuristic | style | verbose, optional) \u2014 Minimum severity to report (default: style). Set to 'verbose' to include AAA contrast and line-height checks.
139
- skipInstances (boolean, optional) \u2014 Skip instance internals \u2014 findings inside instances are owned by the component (default: true)`,
140
- "reparent": "# components.reparent\nMove nodes into a new parent\n\nParams:\n items (array, required) \u2014 Array of {id, parentId, index?}\n id (string, required)\n parentId (string, required)\n index (number, optional)",
141
- "list": "# components.list\nList local component names (variant sets as single entries)\n\nParams:\n query (string, optional) \u2014 Name search query (case-insensitive substring match)\n offset (number, optional) \u2014 Skip N items for pagination (default 0)\n limit (number, optional) \u2014 Max items per page (default 100)",
142
- "get": "# components.get\nGet component detail \u2014 property definitions + optional node tree for structural inspection\n\nParams:\n id (string, optional) \u2014 Component or component set ID\n names (string[], optional) \u2014 Batch lookup by name (case-insensitive). Either id or names is required.\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.",
158
+ skipInstances (boolean, optional) \u2014 Skip instance internals \u2014 findings inside instances are owned by the component (default: true)
159
+
160
+ Response:
161
+ nodeId (string, optional)
162
+ nodeName (string, optional)
163
+ categories (array, optional) \u2014 Sorted by severity (error > unsafe > heuristic > style)`,
164
+ "reparent": '# components.reparent\nMove nodes into a new parent\n\nParams:\n items (array, required) \u2014 Array of {id, parentId, index?}\n id (string, required)\n parentId (string, required)\n index (number, optional)\n\nResponse:\n { results: ("ok" | {error})[] }',
165
+ "list": "# components.list\nList local component names (variant sets as single entries)\n\nParams:\n query (string, optional) \u2014 Name search query (case-insensitive substring match)\n offset (number, optional) \u2014 Skip N items for pagination (default 0)\n limit (number, optional) \u2014 Max items per page (default 100)\n\nResponse:\n totalCount (number, required)\n returned (number, optional)\n offset (number, optional)\n limit (number, optional)\n items (array, required)",
166
+ "get": "# components.get\nGet component detail \u2014 property definitions + optional node tree for structural inspection\n\nParams:\n id (string, optional) \u2014 Component or component set ID\n names (string[], optional) \u2014 Batch lookup by name (case-insensitive). Either id or names is required.\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.\n\nResponse:\n results (array, required) \u2014 Component summaries (without depth) or full node trees with properties merged (with depth)\n id (string, optional)\n name (string, optional)\n description (string, optional)\n properties (object, optional) \u2014 Property definitions \u2014 {name: {type, defaultValue, options?}}\n _truncated (boolean, optional)",
143
167
  "create": `# components.create
144
168
  Create components
145
169
 
146
- Example: components(method:"create", type:"component", items:[{name:"Card", layoutMode:"VERTICAL", padding:"16", itemSpacing:"8", fillVariableName:"bg/surface", children:[{type:"text", text:"Title", componentPropertyName:"Title"}, {type:"text", text:"Description", fontSize:14, componentPropertyName:"Description"}], properties:[{propertyName:"Show Icon", type:"BOOLEAN", defaultValue:true}]}])
170
+ Call shape: components(method:"create", type:"<type>", items:[{...type-specific fields...}])
171
+ Do not pass type-specific item fields at the top level; put them inside items[].
147
172
 
148
173
  Discriminant: type (component | from_node | variant_set)
174
+ Top-level params:
175
+ type (component | from_node | variant_set, required) \u2014 Selects which item shape to use
176
+ items (array, required) \u2014 One or more type-specific item objects
149
177
 
150
178
  ## 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.
151
- name (string, required) \u2014 Component name
152
- parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
153
- x (number, optional) \u2014 X position (default: 0)
154
- y (number, optional) \u2014 Y position (default: 0)
155
- width (number, optional) \u2014 Width in px (omit to shrink-to-content via HUG)
156
- height (number, optional) \u2014 Height in px (omit to shrink-to-content via HUG)
157
- rotation (number, optional) \u2014 Rotation in degrees (0-360)
158
- visible (boolean, optional) \u2014 Show/hide (default true)
159
- locked (boolean, optional) \u2014 Lock/unlock (default false)
160
- opacity (string, optional) \u2014 Opacity (0-1) or variable name
161
- 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)
162
- effectStyleName (string, optional) \u2014 Effect style name (e.g. 'Shadow/Card') for shadows, blurs
163
- fills (array, optional) \u2014 Fill paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] for transparent. Primary way to set fills.
164
- fillColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)
165
- fillStyleName (string, optional) \u2014 Paint style name for fill
166
- fillVariableName (string, optional) \u2014 Color variable by name e.g. 'bg/primary'
167
- imageUrl (string, optional) \u2014 Image source \u2014 'pexel:<id>' for Pexels photos, a public URL, or a local file path. SVGs are inserted as vectors; raster images become IMAGE fills.
168
- imageScaleMode (FILL | FIT | CROP | TILE, optional) \u2014 How the image is scaled within the frame (default: FILL)
169
- strokes (array, optional) \u2014 Stroke paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] to clear. Primary way to set strokes.
170
- strokeColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)
171
- strokeStyleName (string, optional) \u2014 Paint style name for stroke
172
- strokeVariableName (string, optional) \u2014 Color variable by name for stroke
173
- strokeWeight (string, optional) \u2014 All sides (number) or variable name (string). Per-side: strokeTopWeight, strokeBottomWeight, strokeLeftWeight, strokeRightWeight.
174
- strokeTopWeight (string, optional)
175
- strokeBottomWeight (string, optional)
176
- strokeLeftWeight (string, optional)
177
- strokeRightWeight (string, optional)
178
- strokeAlign (INSIDE | OUTSIDE | CENTER, optional) \u2014 Stroke position (default: INSIDE)
179
- cornerRadius (string, optional) \u2014 All corners (number) or variable name (string). Per-corner: topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius.
180
- topLeftRadius (string, optional)
181
- topRightRadius (string, optional)
182
- bottomRightRadius (string, optional)
183
- bottomLeftRadius (string, optional)
184
- layoutMode (NONE | HORIZONTAL | VERTICAL, optional) \u2014 Layout direction (default: auto \u2014 NONE when width+height set, otherwise inferred from layout props)
185
- 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.
186
- padding (string, optional) \u2014 All edges (number) or variable name (string). Per-edge: paddingTop, paddingRight, paddingBottom, paddingLeft.
187
- paddingTop (string, optional)
188
- paddingRight (string, optional)
189
- paddingBottom (string, optional)
190
- paddingLeft (string, optional)
191
- primaryAxisAlignItems (MIN | MAX | CENTER | SPACE_BETWEEN, optional)
192
- counterAxisAlignItems (MIN | MAX | CENTER | BASELINE, optional)
193
- itemSpacing (string, optional) \u2014 Spacing between children (number or variable name string, default: 0)
194
- counterAxisSpacing (string, optional) \u2014 Gap between wrapped rows (requires layoutWrap: WRAP)
195
- strokesIncludedInLayout (boolean, optional) \u2014 Include stroke width in layout measurements (default: false)
196
- overflowDirection (NONE | HORIZONTAL | VERTICAL | BOTH, optional) \u2014 Scroll overflow in prototype (default: NONE)
197
- layoutPositioning (AUTO | ABSOLUTE, optional) \u2014 ABSOLUTE = floating inside auto-layout parent
198
- layoutSizingHorizontal (FIXED | HUG | FILL, optional)
199
- layoutSizingVertical (FIXED | HUG | FILL, optional)
200
- minWidth (number, optional) \u2014 Min width for responsive auto-layout
201
- maxWidth (number, optional) \u2014 Max width for responsive auto-layout
202
- minHeight (number, optional) \u2014 Min height for responsive auto-layout
203
- maxHeight (number, optional) \u2014 Max height for responsive auto-layout
204
- annotations (array, optional) \u2014 Set annotations \u2014 [{label?, labelMarkdown?, properties?, categoryId?}]. Properties validated per node type.
205
- description (string, optional) \u2014 Component description (shown in Figma's component panel)
206
- 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"}]}]
179
+ Example: components(method:"create", type:"component", items:[{name:"Card", width:320, height:200, layoutMode:"VERTICAL", padding:"space/16", itemSpacing:"space/8", fillVariableName:"bg/surface", strokeVariableName:"border/subtle", strokeWeight:"stroke/1", cornerRadius:"radius/12", children:[{type:"text", name:"Title", text:"Title", componentPropertyName:"Title", textStyleName:"Heading/Medium", fontColorVariableName:"text/primary", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}]}])
180
+ Item fields for items[] when type:"component":
181
+ name (string, required) \u2014 Component name
182
+ parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
183
+ x (number, optional) \u2014 X position (default: 0)
184
+ y (number, optional) \u2014 Y position (default: 0)
185
+ width (number, optional) \u2014 Width in px (omit to shrink-to-content via HUG)
186
+ height (number, optional) \u2014 Height in px (omit to shrink-to-content via HUG)
187
+ rotation (number, optional) \u2014 Rotation in degrees (0-360)
188
+ visible (boolean, optional) \u2014 Show/hide (default true)
189
+ locked (boolean, optional) \u2014 Lock/unlock (default false)
190
+ opacity (string, optional) \u2014 Opacity (0-1) or variable name
191
+ 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)
192
+ effectStyleName (string, optional) \u2014 Effect style name (e.g. 'Shadow/Card') for shadows, blurs
193
+ fills (Paint[], optional) \u2014 Fill Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] for transparent. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables; use imageUrl/images for image authoring. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set non-image fills.
194
+ fillColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)
195
+ fillStyleName (string, optional) \u2014 Paint style name for fill
196
+ fillVariableName (string, optional) \u2014 Color variable by name e.g. 'bg/surface'
197
+ imageUrl (string, optional) \u2014 Image source \u2014 'pexel:<id>' for Pexels photos, a public URL, or a local file path. SVGs are inserted as vectors; raster images become IMAGE fills.
198
+ imageScaleMode (FILL | FIT | CROP | TILE, optional) \u2014 How the image is scaled within the frame (default: FILL)
199
+ strokes (Paint[], optional) \u2014 Stroke Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] to clear. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set strokes.
200
+ strokeColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)
201
+ strokeStyleName (string, optional) \u2014 Paint style name for stroke
202
+ strokeVariableName (string, optional) \u2014 Color variable by name for stroke
203
+ strokeWeight (string, optional) \u2014 All sides (number) or variable name (string). Per-side: strokeTopWeight, strokeBottomWeight, strokeLeftWeight, strokeRightWeight.
204
+ strokeTopWeight (string, optional)
205
+ strokeBottomWeight (string, optional)
206
+ strokeLeftWeight (string, optional)
207
+ strokeRightWeight (string, optional)
208
+ strokeAlign (INSIDE | OUTSIDE | CENTER, optional) \u2014 Stroke position (default: INSIDE)
209
+ cornerRadius (string, optional) \u2014 All corners (number) or variable name (string). Per-corner: topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius.
210
+ topLeftRadius (string, optional)
211
+ topRightRadius (string, optional)
212
+ bottomRightRadius (string, optional)
213
+ bottomLeftRadius (string, optional)
214
+ layoutMode (NONE | HORIZONTAL | VERTICAL, optional) \u2014 Layout direction (default: auto \u2014 NONE when width+height set, otherwise inferred from layout props)
215
+ 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.
216
+ padding (string, optional) \u2014 All edges (number) or variable name (string). Per-edge: paddingTop, paddingRight, paddingBottom, paddingLeft.
217
+ paddingTop (string, optional)
218
+ paddingRight (string, optional)
219
+ paddingBottom (string, optional)
220
+ paddingLeft (string, optional)
221
+ primaryAxisAlignItems (MIN | MAX | CENTER | SPACE_BETWEEN, optional)
222
+ counterAxisAlignItems (MIN | MAX | CENTER | BASELINE, optional)
223
+ itemSpacing (string, optional) \u2014 Spacing between children (number or variable name string, default: 0)
224
+ counterAxisSpacing (string, optional) \u2014 Gap between wrapped rows (requires layoutWrap: WRAP)
225
+ strokesIncludedInLayout (boolean, optional) \u2014 Include stroke width in layout measurements (default: false)
226
+ overflowDirection (NONE | HORIZONTAL | VERTICAL | BOTH, optional) \u2014 Scroll overflow in prototype (default: NONE)
227
+ layoutPositioning (AUTO | ABSOLUTE, optional) \u2014 ABSOLUTE = floating inside auto-layout parent
228
+ layoutSizingHorizontal (FIXED | HUG | FILL, optional)
229
+ layoutSizingVertical (FIXED | HUG | FILL, optional)
230
+ minWidth (number, optional) \u2014 Min width for responsive auto-layout
231
+ maxWidth (number, optional) \u2014 Max width for responsive auto-layout
232
+ minHeight (number, optional) \u2014 Min height for responsive auto-layout
233
+ maxHeight (number, optional) \u2014 Max height for responsive auto-layout
234
+ annotations (array, optional) \u2014 Set annotations \u2014 [{label?, labelMarkdown?, properties?, categoryId?}]. Properties validated per node type.
235
+ description (string, optional) \u2014 Component description (shown in Figma's component panel)
236
+ children (array, optional) \u2014 Inline child nodes \u2014 build nested trees in one call. Types: text: {type:"text", text, componentPropertyName?, textStyleName?, fontColorVariableName?, layoutSizingHorizontal?}. frame: {type:"frame", name?, layoutMode?, fillVariableName?, itemSpacing?, layoutSizingHorizontal?, children?}. instance: {type:"instance", componentId, componentPropertyName?, variantProperties?, properties?}. component: {type:"component", name, children?}. rectangle / ellipse / line: same params as the corresponding frames(method:"create", type:"rectangle"|"ellipse"|"line") branch. All params from text/frame endpoints are supported on their respective types. Inline fills/strokes accept Paint[] authoring input: SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. Do not use CSS gradients, REST gradientHandlePositions, or IMAGE/VIDEO/PATTERN in Paint[] authoring. 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:"ellipse", name:"Dot", width:6, height:6, fillVariableName:"status/active"}, {type:"text", name:"Label", text:"Button", componentPropertyName:"Label", textStyleName:"Body/Medium", fontColorVariableName:"text/primary", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}, {type:"frame", name:"Actions", layoutMode:"HORIZONTAL", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG", itemSpacing:"space/8", children:[{type:"instance", componentId:"1:2", componentPropertyName:"Action", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}]}]
207
237
 
208
- properties (array, optional) \u2014 Component properties to define at creation: [{propertyName, type, defaultValue}]. TEXT properties for inline children with componentPropertyName are created automatically.
209
- propertyName (string, required) \u2014 Property name
210
- type (BOOLEAN | TEXT | INSTANCE_SWAP, required) \u2014 Property type
211
- defaultValue (string_or_boolean, required) \u2014 Default value
212
- preferredValues (array, optional) \u2014 Preferred values for INSTANCE_SWAP
238
+ properties (array, optional) \u2014 Component properties to define at creation: [{propertyName, type, defaultValue}]. TEXT properties for inline children with componentPropertyName are created automatically.
239
+ propertyName (string, required) \u2014 Property name
240
+ type (BOOLEAN | TEXT | INSTANCE_SWAP, required) \u2014 Property type
241
+ defaultValue (string_or_boolean, required) \u2014 Default value
242
+ preferredValues (array, optional) \u2014 Preferred values for INSTANCE_SWAP
213
243
 
214
244
  ## from_node \u2014 Convert existing nodes to components. Text children auto-exposed as editable properties (exposeText: true).
215
- nodeId (string, required) \u2014 Node ID to convert
216
- name (string, optional) \u2014 Rename the component (default: keeps the node's current name)
217
- exposeText (boolean, optional) \u2014 Auto-expose text as editable properties (default: true)
245
+ Example: components(method:"create", type:"from_node", items:[{nodeId:"1:23", name:"Button", exposeText:true}])
246
+ Item fields for items[] when type:"from_node":
247
+ nodeId (string, required) \u2014 Node ID to convert
248
+ name (string, optional) \u2014 Rename the component (default: keeps the node's current name)
249
+ exposeText (boolean, optional) \u2014 Auto-expose text as editable properties (default: true)
218
250
 
219
251
  ## variant_set \u2014 Combine components into a variant set. The resulting set is a frame \u2014 accepts all frame properties for layout/styling.
220
- name (string, optional) \u2014 Node name
221
- parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
222
- x (number, optional) \u2014 X position (default: 0)
223
- y (number, optional) \u2014 Y position (default: 0)
224
- width (number, optional) \u2014 Width in px (omit to shrink-to-content via HUG)
225
- height (number, optional) \u2014 Height in px (omit to shrink-to-content via HUG)
226
- rotation (number, optional) \u2014 Rotation in degrees (0-360)
227
- visible (boolean, optional) \u2014 Show/hide (default true)
228
- locked (boolean, optional) \u2014 Lock/unlock (default false)
229
- opacity (string, optional) \u2014 Opacity (0-1) or variable name
230
- 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)
231
- effectStyleName (string, optional) \u2014 Effect style name (e.g. 'Shadow/Card') for shadows, blurs
232
- fills (array, optional) \u2014 Fill paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] for transparent. Primary way to set fills.
233
- fillColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)
234
- fillStyleName (string, optional) \u2014 Paint style name for fill
235
- fillVariableName (string, optional) \u2014 Color variable by name e.g. 'bg/primary'
236
- imageUrl (string, optional) \u2014 Image source \u2014 'pexel:<id>' for Pexels photos, a public URL, or a local file path. SVGs are inserted as vectors; raster images become IMAGE fills.
237
- imageScaleMode (FILL | FIT | CROP | TILE, optional) \u2014 How the image is scaled within the frame (default: FILL)
238
- strokes (array, optional) \u2014 Stroke paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] to clear. Primary way to set strokes.
239
- strokeColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)
240
- strokeStyleName (string, optional) \u2014 Paint style name for stroke
241
- strokeVariableName (string, optional) \u2014 Color variable by name for stroke
242
- strokeWeight (string, optional) \u2014 All sides (number) or variable name (string). Per-side: strokeTopWeight, strokeBottomWeight, strokeLeftWeight, strokeRightWeight.
243
- strokeTopWeight (string, optional)
244
- strokeBottomWeight (string, optional)
245
- strokeLeftWeight (string, optional)
246
- strokeRightWeight (string, optional)
247
- strokeAlign (INSIDE | OUTSIDE | CENTER, optional) \u2014 Stroke position (default: INSIDE)
248
- cornerRadius (string, optional) \u2014 All corners (number) or variable name (string). Per-corner: topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius.
249
- topLeftRadius (string, optional)
250
- topRightRadius (string, optional)
251
- bottomRightRadius (string, optional)
252
- bottomLeftRadius (string, optional)
253
- layoutMode (NONE | HORIZONTAL | VERTICAL, optional) \u2014 Layout direction (default: auto \u2014 NONE when width+height set, otherwise inferred from layout props)
254
- 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.
255
- padding (string, optional) \u2014 All edges (number) or variable name (string). Per-edge: paddingTop, paddingRight, paddingBottom, paddingLeft.
256
- paddingTop (string, optional)
257
- paddingRight (string, optional)
258
- paddingBottom (string, optional)
259
- paddingLeft (string, optional)
260
- primaryAxisAlignItems (MIN | MAX | CENTER | SPACE_BETWEEN, optional)
261
- counterAxisAlignItems (MIN | MAX | CENTER | BASELINE, optional)
262
- itemSpacing (string, optional) \u2014 Spacing between children (number or variable name string, default: 0)
263
- counterAxisSpacing (string, optional) \u2014 Gap between wrapped rows (requires layoutWrap: WRAP)
264
- strokesIncludedInLayout (boolean, optional) \u2014 Include stroke width in layout measurements (default: false)
265
- overflowDirection (NONE | HORIZONTAL | VERTICAL | BOTH, optional) \u2014 Scroll overflow in prototype (default: NONE)
266
- layoutPositioning (AUTO | ABSOLUTE, optional) \u2014 ABSOLUTE = floating inside auto-layout parent
267
- layoutSizingHorizontal (FIXED | HUG | FILL, optional)
268
- layoutSizingVertical (FIXED | HUG | FILL, optional)
269
- minWidth (number, optional) \u2014 Min width for responsive auto-layout
270
- maxWidth (number, optional) \u2014 Max width for responsive auto-layout
271
- minHeight (number, optional) \u2014 Min height for responsive auto-layout
272
- maxHeight (number, optional) \u2014 Max height for responsive auto-layout
273
- annotations (array, optional) \u2014 Set annotations \u2014 [{label?, labelMarkdown?, properties?, categoryId?}]. Properties validated per node type.
274
- componentIds (string[], optional) \u2014 Existing component IDs to combine (min 2). Alternative to children.
275
- variantPropertyName (string, optional) \u2014 Rename the auto-generated variant property (default: 'Property 1')
276
- 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.`,
277
- "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',
278
- "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.',
279
- "delete": "# components.delete\nDelete components or component sets\n\nParams:\n id (string, required) \u2014 Component or component set ID"
252
+ Example: components(method:"create", type:"variant_set", items:[{name:"Button", layoutMode:"HORIZONTAL", layoutSizingHorizontal:"HUG", layoutSizingVertical:"HUG", padding:"space/8", itemSpacing:"space/8", children:[{type:"component", name:"Style=Primary", minWidth:120, height:48, layoutMode:"HORIZONTAL", layoutSizingHorizontal:"HUG", layoutSizingVertical:"FIXED", padding:"space/12", cornerRadius:"radius/8", fillVariableName:"bg/accent", primaryAxisAlignItems:"CENTER", counterAxisAlignItems:"MIN", children:[{type:"text", name:"Button", text:"Button", width:72, componentPropertyName:"Button", textStyleName:"Body/Medium", fontColorVariableName:"text/inverse", textAlignHorizontal:"CENTER", textAlignVertical:"CENTER", layoutSizingHorizontal:"FIXED", layoutSizingVertical:"FILL"}]}, {type:"component", name:"Style=Secondary", minWidth:120, height:48, layoutMode:"HORIZONTAL", layoutSizingHorizontal:"HUG", layoutSizingVertical:"FIXED", padding:"space/12", cornerRadius:"radius/8", fillVariableName:"bg/surface", strokeVariableName:"border/subtle", strokeWeight:"stroke/1", primaryAxisAlignItems:"CENTER", counterAxisAlignItems:"MIN", children:[{type:"text", name:"Button", text:"Button", width:72, componentPropertyName:"Button", textStyleName:"Body/Medium", fontColorVariableName:"text/primary", textAlignHorizontal:"CENTER", textAlignVertical:"CENTER", layoutSizingHorizontal:"FIXED", layoutSizingVertical:"FILL"}]}]}])
253
+ Item fields for items[] when type:"variant_set":
254
+ name (string, optional) \u2014 Node name
255
+ parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
256
+ x (number, optional) \u2014 X position (default: 0)
257
+ y (number, optional) \u2014 Y position (default: 0)
258
+ width (number, optional) \u2014 Width in px (omit to shrink-to-content via HUG)
259
+ height (number, optional) \u2014 Height in px (omit to shrink-to-content via HUG)
260
+ rotation (number, optional) \u2014 Rotation in degrees (0-360)
261
+ visible (boolean, optional) \u2014 Show/hide (default true)
262
+ locked (boolean, optional) \u2014 Lock/unlock (default false)
263
+ opacity (string, optional) \u2014 Opacity (0-1) or variable name
264
+ 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)
265
+ effectStyleName (string, optional) \u2014 Effect style name (e.g. 'Shadow/Card') for shadows, blurs
266
+ fills (Paint[], optional) \u2014 Fill Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] for transparent. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables; use imageUrl/images for image authoring. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set non-image fills.
267
+ fillColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)
268
+ fillStyleName (string, optional) \u2014 Paint style name for fill
269
+ fillVariableName (string, optional) \u2014 Color variable by name e.g. 'bg/surface'
270
+ imageUrl (string, optional) \u2014 Image source \u2014 'pexel:<id>' for Pexels photos, a public URL, or a local file path. SVGs are inserted as vectors; raster images become IMAGE fills.
271
+ imageScaleMode (FILL | FIT | CROP | TILE, optional) \u2014 How the image is scaled within the frame (default: FILL)
272
+ strokes (Paint[], optional) \u2014 Stroke Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] to clear. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set strokes.
273
+ strokeColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)
274
+ strokeStyleName (string, optional) \u2014 Paint style name for stroke
275
+ strokeVariableName (string, optional) \u2014 Color variable by name for stroke
276
+ strokeWeight (string, optional) \u2014 All sides (number) or variable name (string). Per-side: strokeTopWeight, strokeBottomWeight, strokeLeftWeight, strokeRightWeight.
277
+ strokeTopWeight (string, optional)
278
+ strokeBottomWeight (string, optional)
279
+ strokeLeftWeight (string, optional)
280
+ strokeRightWeight (string, optional)
281
+ strokeAlign (INSIDE | OUTSIDE | CENTER, optional) \u2014 Stroke position (default: INSIDE)
282
+ cornerRadius (string, optional) \u2014 All corners (number) or variable name (string). Per-corner: topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius.
283
+ topLeftRadius (string, optional)
284
+ topRightRadius (string, optional)
285
+ bottomRightRadius (string, optional)
286
+ bottomLeftRadius (string, optional)
287
+ layoutMode (NONE | HORIZONTAL | VERTICAL, optional) \u2014 Layout direction (default: auto \u2014 NONE when width+height set, otherwise inferred from layout props)
288
+ 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.
289
+ padding (string, optional) \u2014 All edges (number) or variable name (string). Per-edge: paddingTop, paddingRight, paddingBottom, paddingLeft.
290
+ paddingTop (string, optional)
291
+ paddingRight (string, optional)
292
+ paddingBottom (string, optional)
293
+ paddingLeft (string, optional)
294
+ primaryAxisAlignItems (MIN | MAX | CENTER | SPACE_BETWEEN, optional)
295
+ counterAxisAlignItems (MIN | MAX | CENTER | BASELINE, optional)
296
+ itemSpacing (string, optional) \u2014 Spacing between children (number or variable name string, default: 0)
297
+ counterAxisSpacing (string, optional) \u2014 Gap between wrapped rows (requires layoutWrap: WRAP)
298
+ strokesIncludedInLayout (boolean, optional) \u2014 Include stroke width in layout measurements (default: false)
299
+ overflowDirection (NONE | HORIZONTAL | VERTICAL | BOTH, optional) \u2014 Scroll overflow in prototype (default: NONE)
300
+ layoutPositioning (AUTO | ABSOLUTE, optional) \u2014 ABSOLUTE = floating inside auto-layout parent
301
+ layoutSizingHorizontal (FIXED | HUG | FILL, optional)
302
+ layoutSizingVertical (FIXED | HUG | FILL, optional)
303
+ minWidth (number, optional) \u2014 Min width for responsive auto-layout
304
+ maxWidth (number, optional) \u2014 Max width for responsive auto-layout
305
+ minHeight (number, optional) \u2014 Min height for responsive auto-layout
306
+ maxHeight (number, optional) \u2014 Max height for responsive auto-layout
307
+ annotations (array, optional) \u2014 Set annotations \u2014 [{label?, labelMarkdown?, properties?, categoryId?}]. Properties validated per node type.
308
+ componentIds (string[], optional) \u2014 Existing component IDs to combine (min 2). Alternative to children.
309
+ variantPropertyName (string, optional) \u2014 Rename the auto-generated variant property (default: 'Property 1')
310
+ children (array, optional) \u2014 Inline variant components. Each must be {type:"component", name, children?, ...frame_params}. Variant children use the same inline child types as components.create, including rectangle / ellipse / line. All variants must share the same child structure. Alternative to componentIds \u2014 do not combine both.
311
+
312
+ Response:
313
+ { results: ({id} | {error})[] }
314
+ // Shared types:
315
+ // Color: hex "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}
316
+ // VariableAlias: {type: "VARIABLE_ALIAS", id: string}. The id must be a Figma VariableID; discover it via variables.get/list or variable_collections.get. Prefer colorVariableName/fillVariableName/strokeVariableName when available; Paint[] VariableAlias is mainly for precise Paint[] round-trips and gradient stop bindings.
317
+ // Transform: [[number, number, number], [number, number, number]] (Figma Plugin API 2\xD73 matrix)
318
+ // 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"
319
+ // ColorStop: {position: 0-1, color: Color, boundVariables?: {color?: VariableAlias}}
320
+ // GradientPaint: {type: "GRADIENT_LINEAR"|"GRADIENT_RADIAL"|"GRADIENT_ANGULAR"|"GRADIENT_DIAMOND", gradientTransform: Transform, gradientStops: ColorStop[], visible?: boolean, opacity?: number, blendMode?: BlendMode}. Use gradientTransform + gradientStops (basic left-to-right: [[1,0,0],[0,1,0]]); do not use CSS gradients or REST gradientHandlePositions.
321
+ // Effect: {type: "DROP_SHADOW"|"INNER_SHADOW"|"LAYER_BLUR"|"BACKGROUND_BLUR", radius: number, color?: {r,g,b,a} (0-1), offset?: {x, y}, spread?: number, visible?: boolean}
322
+ // Paint: Paint[] authoring accepts only SOLID and GRADIENT_LINEAR/GRADIENT_RADIAL/GRADIENT_ANGULAR/GRADIENT_DIAMOND. SolidPaint: {type: "SOLID", color: Color, visible?: boolean, opacity?: number, blendMode?: BlendMode, boundVariables?: {color?: VariableAlias}}. GradientPaint authoring: {type: GRADIENT_*, gradientTransform: Transform, gradientStops: ColorStop[], visible?, opacity?, blendMode?}; bind variables on gradientStops[].boundVariables.color, not top-level gradient boundVariables. Do not pass IMAGE/VIDEO/PATTERN to create/update Paint[]; those may appear only in readback metadata from existing Figma content. Use imageUrl/images for image authoring. VIDEO/PATTERN authoring is not supported here. Do not use CSS gradients or REST gradientHandlePositions.`,
323
+ "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\n\nResponse:\n { results: ({id} | {error})[] }',
324
+ "update": '# components.update\nAdd, edit, or delete component properties\n\nExample: components(method:"update", items:[{id:"1:23", propertyName:"Show Icon", action:"add", type:"BOOLEAN", defaultValue:true}])\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.\n\nResponse:\n { results: ("ok" | {error} | object)[] }',
325
+ "delete": '# components.delete\nDelete components or component sets\n\nParams:\n id (string, required) \u2014 Component or component set ID\n\nResponse:\n { results: ("ok" | {error})[] }'
280
326
  }
281
327
  },
282
328
  "connection": {
283
329
  "summary": '# connection\nManage the Figma plugin connection.\n\nMethods:\n create Join a relay channel (required first step before any other tool) [read]\n get Verify end-to-end connection to Figma [read]\n list Inspect which clients (MCP, plugin) are connected to each channel [read]\n delete Disconnect all clients (MCP server and Figma plugin) from a channel and reset its state [edit]\n\n// Connection manages the WebSocket link between the MCP server and the Figma plugin.\n// Channels are named rooms \u2014 both the MCP server and Figma plugin must join the same channel to communicate.\n// Workflow: connection(method:"create") to join a channel \u2192 connection(method:"get") to verify Figma plugin is connected.\n// If get times out (5s), the Figma plugin is not running or not on the same channel.\n// list shows all active channels and their connected clients. delete factory-resets a channel.\n\nUse connection(method: "help", topic: "<method>") for method details.',
284
330
  "methods": {
285
- "create": "# connection.create\nJoin a relay channel (required first step before any other tool)\n\nParams:\n channel (string, optional) \u2014 The channel name displayed in the Figma plugin panel. Defaults to 'vibma' if omitted.",
286
- "get": "# connection.get\nVerify end-to-end connection to Figma\n\nNo params.",
287
- "list": "# connection.list\nInspect which clients (MCP, plugin) are connected to each channel\n\nNo params.",
288
- "delete": "# connection.delete\nDisconnect all clients (MCP server and Figma plugin) from a channel and reset its state\n\nParams:\n channel (string, optional) \u2014 Channel to reset. Defaults to 'vibma'."
331
+ "create": "# connection.create\nJoin a relay channel (required first step before any other tool)\n\nParams:\n channel (string, optional) \u2014 The channel name displayed in the Figma plugin panel. Defaults to 'vibma' if omitted.\n\nResponse:\n Confirmation message with channel and port\n string",
332
+ "get": "# connection.get\nVerify end-to-end connection to Figma\n\nNo params.\n\nResponse:\n status (string, required)\n documentName (string, required) \u2014 Active Figma document name\n currentPage (string, required) \u2014 Current page name\n timestamp (number, required) \u2014 Unix timestamp",
333
+ "list": "# connection.list\nInspect which clients (MCP, plugin) are connected to each channel\n\nNo params.\n\nResponse:\n Map of channel names to their connected clients\n object",
334
+ "delete": "# connection.delete\nDisconnect all clients (MCP server and Figma plugin) from a channel and reset its state\n\nParams:\n channel (string, optional) \u2014 Channel to reset. Defaults to 'vibma'.\n\nResponse:\n Confirmation of tunnel reset\n string"
289
335
  }
290
336
  },
291
337
  "document": {
292
338
  "summary": '# document\nNavigate and manage Figma pages (canvases) in the document.\n\nMethods:\n get Get current page with top-level children [read]\n list Get document name and list all pages [read]\n set Switch to a page by ID or name. At least one of pageId or pageName must be provided. [read]\n create Create a new page [create]\n update Rename a page [edit]\n\n// A Figma document contains pages \u2014 each page is an independent canvas with its own node tree.\n// The "current page" is where all node operations happen. Use document.set to switch pages before working with nodes.\n// Page IDs look like "0:1", "1:1", etc. The first page is always "0:1".\n// get returns the current page with its top-level children as stubs. list returns all pages in the document.\n\nUse document(method: "help", topic: "<method>") for method details.',
293
339
  "methods": {
294
- "get": "# document.get\nGet current page with top-level children\n\nNo params.",
295
- "list": "# document.list\nGet document name and list all pages\n\nNo params.",
296
- "set": "# document.set\nSwitch to a page by ID or name. At least one of pageId or pageName must be provided.\n\nParams:\n pageId (string, optional) \u2014 Page ID\n pageName (string, optional) \u2014 Page name (case-insensitive, substring match)",
297
- "create": "# document.create\nCreate a new page\n\nParams:\n name (string, optional) \u2014 Page name (default: 'New Page')",
298
- "update": "# document.update\nRename a page\n\nParams:\n newName (string, required) \u2014 New page name\n pageId (string, optional) \u2014 Page ID (default: current page)"
340
+ "get": '# document.get\nGet current page with top-level children\n\nNo params.\n\nResponse:\n id (string, required)\n name (string, required)\n backgroundColor (string, optional) \u2014 Canvas background hex color (e.g. "#F5F5F5")\n children (NodeStub[], required)\n// Shared types:\n// NodeStub: {id: string, name: string, type: string}',
341
+ "list": "# document.list\nGet document name and list all pages\n\nNo params.\n\nResponse:\n name (string, required) \u2014 Document name\n currentPageId (string, required)\n pages (array, required)\n id (string, required)\n name (string, required)",
342
+ "set": "# document.set\nSwitch to a page by ID or name. At least one of pageId or pageName must be provided.\n\nParams:\n pageId (string, optional) \u2014 Page ID\n pageName (string, optional) \u2014 Page name (case-insensitive, substring match)\n\nResponse:\n id (string, required)\n name (string, required)",
343
+ "create": "# document.create\nCreate a new page\n\nParams:\n name (string, optional) \u2014 Page name (default: 'New Page')\n\nResponse:\n id (string, required) \u2014 New page ID",
344
+ "update": "# document.update\nRename a page\n\nParams:\n newName (string, required) \u2014 New page name\n pageId (string, optional) \u2014 Page ID (default: current page)\n\nResponse:\n string"
299
345
  }
300
346
  },
301
347
  "fonts": {
302
348
  "summary": '# fonts\nSearch available fonts in Figma.\n\nMethods:\n list List available font families, optionally filtered by name [read]\n\n// Returns font family names installed in the Figma environment. Use to verify a fontFamily before text.create or styles.create.\n// query filters by family name substring (case-insensitive), e.g. query:"inter" matches "Inter", "Inter Tight".\n// ---\n// Default response: just family names. Set includeStyles:true to also get available styles per family (e.g. "Regular", "Bold", "Italic").\n// Use fonts.list with query to narrow results before creating text with specific fontFamily + fontStyle.\n\nUse fonts(method: "help", topic: "<method>") for method details.',
303
349
  "methods": {
304
- "list": '# fonts.list\nList available font families, optionally filtered by name\n\nExample: fonts(method:"list", query:"inter")\n\nParams:\n query (string, optional) \u2014 Filter by family name (case-insensitive substring)\n includeStyles (boolean, optional) \u2014 Include available styles per family (default: false)\n offset (number, optional) \u2014 Skip N items for pagination (default 0)\n limit (number, optional) \u2014 Max items per page (default 100)'
350
+ "list": '# fonts.list\nList available font families, optionally filtered by name\n\nExample: fonts(method:"list", query:"inter")\n\nParams:\n query (string, optional) \u2014 Filter by family name (case-insensitive substring)\n includeStyles (boolean, optional) \u2014 Include available styles per family (default: false)\n offset (number, optional) \u2014 Skip N items for pagination (default 0)\n limit (number, optional) \u2014 Max items per page (default 100)\n\nResponse:\n count (number, required) \u2014 Number of matching families\n fonts (array, required) \u2014 Array of {family} stubs, or {family, styles[]} when includeStyles:true\n family (string, required)\n styles (array, optional)'
305
351
  }
306
352
  },
307
353
  "frames": {
308
- "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 \u2014 produces a same-type copy (frame\u2192frame, instance\u2192instance, component\u2192component). Instance clones reference the same source component; they do not duplicate the component definition. [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// Image fill: imageUrl accepts "pexel:<id>", a public URL, or a local file path. SVGs become vector nodes; raster images become IMAGE fills. imageScaleMode: FILL (default), FIT, CROP, TILE.\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.',
354
+ "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 \u2014 produces a same-type copy (frame\u2192frame, instance\u2192instance, component\u2192component). Instance clones reference the same source component; they do not duplicate the component definition. [create]\n scale Proportionally rescale a node subtree using Figma\'s visual Scale tool behavior. This is for visual/artifact scaling, not responsive layout resizing. [edit]\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// clipsContent: clip children to the node bounds where supported (frames/components/instances). Set false for overflow-visible layouts.\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[]; // readback Paint[]; authoring supports SOLID + gradients via gradientTransform + gradientStops\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. Paint[] authoring supports SOLID + gradients only; IMAGE/VIDEO/PATTERN are readback-only metadata.\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: prefer fillVariableName/fillStyleName. Use fills:[{type:"SOLID", color:"#hex"}] or gradient Paint[] (GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND) with gradientTransform + gradientStops only for one-off values; [] for transparent. Shorthand: fillColor:"#3B82F6" (auto-binds single solids).\n// Also: fillVariableName:"bg/surface", fillStyleName:"Surface/Primary". Do not use CSS gradients, REST gradientHandlePositions, or top-level gradient boundVariables.\n// Image fill: use imageUrl/images for image authoring. imageUrl accepts "pexel:<id>", a public URL, or a local file path. SVGs become vector nodes; raster images become IMAGE fills. IMAGE/VIDEO/PATTERN may appear in readback metadata only; do not pass those objects in Paint[]. imageScaleMode: FILL (default), FIT, CROP, TILE.\n// Stroke: prefer strokeVariableName/strokeStyleName. Use strokes:[{type:"SOLID", color:"#hex"}] or gradient Paint[] (GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND) with gradientTransform + gradientStops only for one-off values; [] 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// Examples assume design tokens/styles already exist. Prefer token names (fillVariableName, strokeVariableName, padding:"space/16", cornerRadius:"radius/8") over raw values in production designs.\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.\n// Shared types:\n// Color: hex "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}\n// VariableAlias: {type: "VARIABLE_ALIAS", id: string}. The id must be a Figma VariableID; discover it via variables.get/list or variable_collections.get. Prefer colorVariableName/fillVariableName/strokeVariableName when available; Paint[] VariableAlias is mainly for precise Paint[] round-trips and gradient stop bindings.\n// Transform: [[number, number, number], [number, number, number]] (Figma Plugin API 2\xD73 matrix)\n// 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"\n// ColorStop: {position: 0-1, color: Color, boundVariables?: {color?: VariableAlias}}\n// GradientPaint: {type: "GRADIENT_LINEAR"|"GRADIENT_RADIAL"|"GRADIENT_ANGULAR"|"GRADIENT_DIAMOND", gradientTransform: Transform, gradientStops: ColorStop[], visible?: boolean, opacity?: number, blendMode?: BlendMode}. Use gradientTransform + gradientStops (basic left-to-right: [[1,0,0],[0,1,0]]); do not use CSS gradients or REST gradientHandlePositions.\n// Effect: {type: "DROP_SHADOW"|"INNER_SHADOW"|"LAYER_BLUR"|"BACKGROUND_BLUR", radius: number, color?: {r,g,b,a} (0-1), offset?: {x, y}, spread?: number, visible?: boolean}\n// Paint: Paint[] authoring accepts only SOLID and GRADIENT_LINEAR/GRADIENT_RADIAL/GRADIENT_ANGULAR/GRADIENT_DIAMOND. SolidPaint: {type: "SOLID", color: Color, visible?: boolean, opacity?: number, blendMode?: BlendMode, boundVariables?: {color?: VariableAlias}}. GradientPaint authoring: {type: GRADIENT_*, gradientTransform: Transform, gradientStops: ColorStop[], visible?, opacity?, blendMode?}; bind variables on gradientStops[].boundVariables.color, not top-level gradient boundVariables. Do not pass IMAGE/VIDEO/PATTERN to create/update Paint[]; those may appear only in readback metadata from existing Figma content. Use imageUrl/images for image authoring. VIDEO/PATTERN authoring is not supported here. Do not use CSS gradients or REST gradientHandlePositions.\n// NodeStub: {id: string, name: string, type: string}',
309
355
  "methods": {
310
- "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.',
311
- "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)',
356
+ "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.\n\nResponse:\n Serialized node tree. Shape depends on depth parameter.\n results (Node[], required) \u2014 Serialized node trees\n _truncated (boolean, optional) \u2014 True when node budget exceeded\n _notice (string, optional) \u2014 Human-readable truncation notice',
357
+ "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)\n\nResponse:\n Paginated node search results (uses `results` not `items`)\n totalCount (number, required) \u2014 Total matching nodes\n returned (number, required) \u2014 Nodes in this page\n offset (number, optional)\n limit (number, optional)\n results (array, required) \u2014 Matching node stubs\n id (string, required)\n name (string, required)\n type (string, required)\n parentId (string, required)\n parentName (string, optional)\n bounds (object, optional)',
312
358
  "update": `# frames.update
313
359
  Patch node properties
314
360
 
315
361
  Params:
316
- items (PatchItem[], required) \u2014 Array of {id, ...properties} to patch
317
- fills (array, optional) \u2014 Fill paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] for transparent. Primary way to set fills.
362
+ items (PatchItem[], required) \u2014 Array of {id, ...fields} to patch
363
+ fills (Paint[], optional) \u2014 Fill Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] for transparent. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables; use imageUrl/images for image authoring. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set non-image fills.
318
364
  fillColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)
319
365
  fillStyleName (string, optional) \u2014 Paint style name for fill
320
- fillVariableName (string, optional) \u2014 Color variable by name e.g. 'bg/primary'
321
- strokes (array, optional) \u2014 Stroke paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] to clear. Primary way to set strokes.
366
+ fillVariableName (string, optional) \u2014 Color variable by name e.g. 'bg/surface'
367
+ strokes (Paint[], optional) \u2014 Stroke Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] to clear. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set strokes.
322
368
  strokeColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)
323
369
  strokeStyleName (string, optional) \u2014 Paint style name for stroke
324
370
  strokeVariableName (string, optional) \u2014 Color variable by name for stroke
@@ -393,9 +439,35 @@ Params:
393
439
  explicitMode (object, optional) \u2014 Pin variable mode \u2014 use { collectionName, modeName } (preferred) or { collectionId, modeId }
394
440
  exportSettings (array, optional) \u2014 Export settings
395
441
  annotations (array, optional) \u2014 Set annotations \u2014 [{label?, labelMarkdown?, properties?, categoryId?}]. Properties are validated per node type.
396
- properties (object, optional) \u2014 Direct Figma API props (escape hatch)`,
397
- "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)",
398
- "clone": "# frames.clone\nDuplicate nodes \u2014 produces a same-type copy (frame\u2192frame, instance\u2192instance, component\u2192component). Instance clones reference the same source component; they do not duplicate the component definition.\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.",
442
+ clipsContent (boolean, optional) \u2014 Clip children to bounds where supported (frames/components/instances).
443
+
444
+ Response:
445
+ { results: ("ok" | {error} | object)[] }
446
+ // Shared types:
447
+ // Color: hex "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}
448
+ // VariableAlias: {type: "VARIABLE_ALIAS", id: string}. The id must be a Figma VariableID; discover it via variables.get/list or variable_collections.get. Prefer colorVariableName/fillVariableName/strokeVariableName when available; Paint[] VariableAlias is mainly for precise Paint[] round-trips and gradient stop bindings.
449
+ // Transform: [[number, number, number], [number, number, number]] (Figma Plugin API 2\xD73 matrix)
450
+ // 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"
451
+ // ColorStop: {position: 0-1, color: Color, boundVariables?: {color?: VariableAlias}}
452
+ // GradientPaint: {type: "GRADIENT_LINEAR"|"GRADIENT_RADIAL"|"GRADIENT_ANGULAR"|"GRADIENT_DIAMOND", gradientTransform: Transform, gradientStops: ColorStop[], visible?: boolean, opacity?: number, blendMode?: BlendMode}. Use gradientTransform + gradientStops (basic left-to-right: [[1,0,0],[0,1,0]]); do not use CSS gradients or REST gradientHandlePositions.
453
+ // Effect: {type: "DROP_SHADOW"|"INNER_SHADOW"|"LAYER_BLUR"|"BACKGROUND_BLUR", radius: number, color?: {r,g,b,a} (0-1), offset?: {x, y}, spread?: number, visible?: boolean}
454
+ // Paint: Paint[] authoring accepts only SOLID and GRADIENT_LINEAR/GRADIENT_RADIAL/GRADIENT_ANGULAR/GRADIENT_DIAMOND. SolidPaint: {type: "SOLID", color: Color, visible?: boolean, opacity?: number, blendMode?: BlendMode, boundVariables?: {color?: VariableAlias}}. GradientPaint authoring: {type: GRADIENT_*, gradientTransform: Transform, gradientStops: ColorStop[], visible?, opacity?, blendMode?}; bind variables on gradientStops[].boundVariables.color, not top-level gradient boundVariables. Do not pass IMAGE/VIDEO/PATTERN to create/update Paint[]; those may appear only in readback metadata from existing Figma content. Use imageUrl/images for image authoring. VIDEO/PATTERN authoring is not supported here. Do not use CSS gradients or REST gradientHandlePositions.`,
455
+ "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)\n\nResponse:\n { results: ("ok" | {error})[] }',
456
+ "clone": "# frames.clone\nDuplicate nodes \u2014 produces a same-type copy (frame\u2192frame, instance\u2192instance, component\u2192component). Instance clones reference the same source component; they do not duplicate the component definition.\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.\n\nResponse:\n { results: ({id} | {error})[] }",
457
+ "scale": `# frames.scale
458
+ Proportionally rescale a node subtree using Figma's visual Scale tool behavior. This is for visual/artifact scaling, not responsive layout resizing.
459
+
460
+ Example: frames(method:"scale", id:"1:23", factor:0.5)
461
+
462
+ Params:
463
+ id (string, optional) \u2014 Node ID to scale
464
+ factor (number, optional) \u2014 Scale factor, >= 0.01. 0.5 = 50%, 2 = 200%. Scales children, text, strokes, effects, and layout geometry from the node's top-left. On auto-layout or HUG/FILL nodes, Figma may resolve responsive sizing to fixed width/height.
465
+ items (array, optional) \u2014 Batch: [{id, factor}, ...]. Alternative to single-item params.
466
+ id (string, required) \u2014 Node ID to scale
467
+ factor (number, required) \u2014 Scale factor, >= 0.01. 0.5 = 50%, 2 = 200%.
468
+
469
+ Response:
470
+ { results: ("ok" | {error})[] }`,
399
471
  "audit": `# frames.audit
400
472
  Run lint on a node \u2014 returns severity-ranked findings
401
473
 
@@ -405,299 +477,346 @@ Params:
405
477
  maxDepth (number, optional) \u2014 Max tree depth (default: 10)
406
478
  maxFindings (number, optional) \u2014 Max findings (default: 50)
407
479
  minSeverity (error | unsafe | heuristic | style | verbose, optional) \u2014 Minimum severity to report (default: style). Set to 'verbose' to include AAA contrast and line-height checks.
408
- skipInstances (boolean, optional) \u2014 Skip instance internals \u2014 findings inside instances are owned by the component (default: true)`,
409
- "reparent": "# frames.reparent\nMove nodes into a new parent\n\nParams:\n items (array, required) \u2014 Array of {id, parentId, index?}\n id (string, required)\n parentId (string, required)\n index (number, optional)",
480
+ skipInstances (boolean, optional) \u2014 Skip instance internals \u2014 findings inside instances are owned by the component (default: true)
481
+
482
+ Response:
483
+ nodeId (string, optional)
484
+ nodeName (string, optional)
485
+ categories (array, optional) \u2014 Sorted by severity (error > unsafe > heuristic > style)`,
486
+ "reparent": '# frames.reparent\nMove nodes into a new parent\n\nParams:\n items (array, required) \u2014 Array of {id, parentId, index?}\n id (string, required)\n parentId (string, required)\n index (number, optional)\n\nResponse:\n { results: ("ok" | {error})[] }',
410
487
  "create": `# frames.create
411
488
  Create frame-like containers
412
489
 
413
- Example: frames(method:"create", type:"auto_layout", layoutMode:"VERTICAL", itemSpacing:16, padding:24)
490
+ Example: frames(method:"create", type:"rectangle", items:[{name:"Gradient Box", fills:[{type:"GRADIENT_LINEAR", gradientTransform:[[1,0,0],[0,1,0]], gradientStops:[{position:0,color:"#FF6B6B"},{position:1,color:"#FFD93D"}]}]}])
491
+
492
+ Call shape: frames(method:"create", type:"<type>", items:[{...type-specific fields...}])
493
+ Do not pass type-specific item fields at the top level; put them inside items[].
414
494
 
415
495
  Discriminant: type (frame | auto_layout | section | rectangle | ellipse | line | group | boolean_operation | svg | slot)
496
+ Top-level params:
497
+ type (frame | auto_layout | section | rectangle | ellipse | line | group | boolean_operation | svg | slot, required) \u2014 Selects which item shape to use
498
+ items (array, required) \u2014 One or more type-specific item objects
416
499
 
417
500
  ## frame \u2014 General-purpose frame \u2014 shrinks to content by default, static when width+height given
418
- name (string, optional) \u2014 Node name
419
- parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
420
- x (number, optional) \u2014 X position (default: 0)
421
- y (number, optional) \u2014 Y position (default: 0)
422
- width (number, optional) \u2014 Width in px (omit to shrink-to-content via HUG)
423
- height (number, optional) \u2014 Height in px (omit to shrink-to-content via HUG)
424
- rotation (number, optional) \u2014 Rotation in degrees (0-360)
425
- visible (boolean, optional) \u2014 Show/hide (default true)
426
- locked (boolean, optional) \u2014 Lock/unlock (default false)
427
- opacity (string, optional) \u2014 Opacity (0-1) or variable name
428
- 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)
429
- effectStyleName (string, optional) \u2014 Effect style name (e.g. 'Shadow/Card') for shadows, blurs
430
- fills (array, optional) \u2014 Fill paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] for transparent. Primary way to set fills.
431
- fillColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)
432
- fillStyleName (string, optional) \u2014 Paint style name for fill
433
- fillVariableName (string, optional) \u2014 Color variable by name e.g. 'bg/primary'
434
- imageUrl (string, optional) \u2014 Image source \u2014 'pexel:<id>' for Pexels photos, a public URL, or a local file path. SVGs are inserted as vectors; raster images become IMAGE fills.
435
- imageScaleMode (FILL | FIT | CROP | TILE, optional) \u2014 How the image is scaled within the frame (default: FILL)
436
- strokes (array, optional) \u2014 Stroke paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] to clear. Primary way to set strokes.
437
- strokeColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)
438
- strokeStyleName (string, optional) \u2014 Paint style name for stroke
439
- strokeVariableName (string, optional) \u2014 Color variable by name for stroke
440
- strokeWeight (string, optional) \u2014 All sides (number) or variable name (string). Per-side: strokeTopWeight, strokeBottomWeight, strokeLeftWeight, strokeRightWeight.
441
- strokeTopWeight (string, optional)
442
- strokeBottomWeight (string, optional)
443
- strokeLeftWeight (string, optional)
444
- strokeRightWeight (string, optional)
445
- strokeAlign (INSIDE | OUTSIDE | CENTER, optional) \u2014 Stroke position (default: INSIDE)
446
- cornerRadius (string, optional) \u2014 All corners (number) or variable name (string). Per-corner: topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius.
447
- topLeftRadius (string, optional)
448
- topRightRadius (string, optional)
449
- bottomRightRadius (string, optional)
450
- bottomLeftRadius (string, optional)
451
- layoutMode (NONE | HORIZONTAL | VERTICAL, optional) \u2014 Layout direction (default: auto \u2014 NONE when width+height set, otherwise inferred from layout props)
452
- 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.
453
- padding (string, optional) \u2014 All edges (number) or variable name (string). Per-edge: paddingTop, paddingRight, paddingBottom, paddingLeft.
454
- paddingTop (string, optional)
455
- paddingRight (string, optional)
456
- paddingBottom (string, optional)
457
- paddingLeft (string, optional)
458
- primaryAxisAlignItems (MIN | MAX | CENTER | SPACE_BETWEEN, optional)
459
- counterAxisAlignItems (MIN | MAX | CENTER | BASELINE, optional)
460
- itemSpacing (string, optional) \u2014 Spacing between children (number or variable name string, default: 0)
461
- counterAxisSpacing (string, optional) \u2014 Gap between wrapped rows (requires layoutWrap: WRAP)
462
- strokesIncludedInLayout (boolean, optional) \u2014 Include stroke width in layout measurements (default: false)
463
- overflowDirection (NONE | HORIZONTAL | VERTICAL | BOTH, optional) \u2014 Scroll overflow in prototype (default: NONE)
464
- layoutPositioning (AUTO | ABSOLUTE, optional) \u2014 ABSOLUTE = floating inside auto-layout parent
465
- layoutSizingHorizontal (FIXED | HUG | FILL, optional)
466
- layoutSizingVertical (FIXED | HUG | FILL, optional)
467
- minWidth (number, optional) \u2014 Min width for responsive auto-layout
468
- maxWidth (number, optional) \u2014 Max width for responsive auto-layout
469
- minHeight (number, optional) \u2014 Min height for responsive auto-layout
470
- maxHeight (number, optional) \u2014 Max height for responsive auto-layout
471
- annotations (array, optional) \u2014 Set annotations \u2014 [{label?, labelMarkdown?, properties?, categoryId?}]. Properties validated per node type.
472
- clipsContent (boolean, optional)
473
- 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.
501
+ Example: frames(method:"create", type:"frame", items:[{name:"Dashboard Shell", x:0, y:0, width:1440, height:900, fillVariableName:"bg/canvas", children:[{type:"frame", name:"Content Area", x:80, y:80, width:640, height:360, layoutMode:"VERTICAL", padding:"space/24", itemSpacing:"space/12", fillVariableName:"bg/surface", cornerRadius:"radius/12", children:[{type:"text", name:"Dashboard overview", text:"Dashboard overview", textStyleName:"Heading/Medium", fontColorVariableName:"text/primary", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}]}]}])
502
+ Item fields for items[] when type:"frame":
503
+ name (string, optional) \u2014 Node name
504
+ parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
505
+ x (number, optional) \u2014 X position (default: 0)
506
+ y (number, optional) \u2014 Y position (default: 0)
507
+ width (number, optional) \u2014 Width in px (omit to shrink-to-content via HUG)
508
+ height (number, optional) \u2014 Height in px (omit to shrink-to-content via HUG)
509
+ rotation (number, optional) \u2014 Rotation in degrees (0-360)
510
+ visible (boolean, optional) \u2014 Show/hide (default true)
511
+ locked (boolean, optional) \u2014 Lock/unlock (default false)
512
+ opacity (string, optional) \u2014 Opacity (0-1) or variable name
513
+ 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)
514
+ effectStyleName (string, optional) \u2014 Effect style name (e.g. 'Shadow/Card') for shadows, blurs
515
+ fills (Paint[], optional) \u2014 Fill Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] for transparent. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables; use imageUrl/images for image authoring. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set non-image fills.
516
+ fillColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)
517
+ fillStyleName (string, optional) \u2014 Paint style name for fill
518
+ fillVariableName (string, optional) \u2014 Color variable by name e.g. 'bg/surface'
519
+ imageUrl (string, optional) \u2014 Image source \u2014 'pexel:<id>' for Pexels photos, a public URL, or a local file path. SVGs are inserted as vectors; raster images become IMAGE fills.
520
+ imageScaleMode (FILL | FIT | CROP | TILE, optional) \u2014 How the image is scaled within the frame (default: FILL)
521
+ strokes (Paint[], optional) \u2014 Stroke Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] to clear. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set strokes.
522
+ strokeColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)
523
+ strokeStyleName (string, optional) \u2014 Paint style name for stroke
524
+ strokeVariableName (string, optional) \u2014 Color variable by name for stroke
525
+ strokeWeight (string, optional) \u2014 All sides (number) or variable name (string). Per-side: strokeTopWeight, strokeBottomWeight, strokeLeftWeight, strokeRightWeight.
526
+ strokeTopWeight (string, optional)
527
+ strokeBottomWeight (string, optional)
528
+ strokeLeftWeight (string, optional)
529
+ strokeRightWeight (string, optional)
530
+ strokeAlign (INSIDE | OUTSIDE | CENTER, optional) \u2014 Stroke position (default: INSIDE)
531
+ cornerRadius (string, optional) \u2014 All corners (number) or variable name (string). Per-corner: topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius.
532
+ topLeftRadius (string, optional)
533
+ topRightRadius (string, optional)
534
+ bottomRightRadius (string, optional)
535
+ bottomLeftRadius (string, optional)
536
+ layoutMode (NONE | HORIZONTAL | VERTICAL, optional) \u2014 Layout direction (default: auto \u2014 NONE when width+height set, otherwise inferred from layout props)
537
+ 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.
538
+ padding (string, optional) \u2014 All edges (number) or variable name (string). Per-edge: paddingTop, paddingRight, paddingBottom, paddingLeft.
539
+ paddingTop (string, optional)
540
+ paddingRight (string, optional)
541
+ paddingBottom (string, optional)
542
+ paddingLeft (string, optional)
543
+ primaryAxisAlignItems (MIN | MAX | CENTER | SPACE_BETWEEN, optional)
544
+ counterAxisAlignItems (MIN | MAX | CENTER | BASELINE, optional)
545
+ itemSpacing (string, optional) \u2014 Spacing between children (number or variable name string, default: 0)
546
+ counterAxisSpacing (string, optional) \u2014 Gap between wrapped rows (requires layoutWrap: WRAP)
547
+ strokesIncludedInLayout (boolean, optional) \u2014 Include stroke width in layout measurements (default: false)
548
+ overflowDirection (NONE | HORIZONTAL | VERTICAL | BOTH, optional) \u2014 Scroll overflow in prototype (default: NONE)
549
+ layoutPositioning (AUTO | ABSOLUTE, optional) \u2014 ABSOLUTE = floating inside auto-layout parent
550
+ layoutSizingHorizontal (FIXED | HUG | FILL, optional)
551
+ layoutSizingVertical (FIXED | HUG | FILL, optional)
552
+ minWidth (number, optional) \u2014 Min width for responsive auto-layout
553
+ maxWidth (number, optional) \u2014 Max width for responsive auto-layout
554
+ minHeight (number, optional) \u2014 Min height for responsive auto-layout
555
+ maxHeight (number, optional) \u2014 Max height for responsive auto-layout
556
+ annotations (array, optional) \u2014 Set annotations \u2014 [{label?, labelMarkdown?, properties?, categoryId?}]. Properties validated per node type.
557
+ clipsContent (boolean, optional)
558
+ children (array, optional) \u2014 Inline child nodes \u2014 build nested trees in one call. Types: text: {type:"text", text, textStyleName?, fontColorVariableName?, layoutSizingHorizontal?}. frame: {type:"frame", name?, layoutMode?, fillVariableName?, itemSpacing?, layoutSizingHorizontal?, children?}. instance: {type:"instance", componentId, variantProperties?, properties?}. component: {type:"component", name, children?}. rectangle / ellipse / line: same params as the corresponding frames(method:"create", type:"rectangle"|"ellipse"|"line") branch. All params from text/frame endpoints are supported on their respective types. Inline fills/strokes accept Paint[] authoring input: SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. Do not use CSS gradients, REST gradientHandlePositions, or IMAGE/VIDEO/PATTERN in Paint[] authoring. Always set layoutSizingHorizontal + layoutSizingVertical on children inside auto-layout parents (FILL, HUG, or FIXED). Example: children:[{type:"ellipse", name:"Dot", width:6, height:6, fillVariableName:"status/active"}, {type:"text", name:"Title", text:"Title", textStyleName:"Heading/Medium", fontColorVariableName:"text/primary", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}, {type:"frame", name:"Row", layoutMode:"HORIZONTAL", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG", itemSpacing:"space/8", children:[{type:"instance", componentId:"1:2", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}]}] Inside components: add componentPropertyName to auto-bind TEXT or INSTANCE_SWAP properties.
474
559
 
475
560
 
476
561
  ## auto_layout \u2014 Auto-layout frame that arranges children automatically
477
- name (string, optional) \u2014 Node name
478
- parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
479
- x (number, optional) \u2014 X position (default: 0)
480
- y (number, optional) \u2014 Y position (default: 0)
481
- width (number, optional) \u2014 Width in px (omit to shrink-to-content via HUG)
482
- height (number, optional) \u2014 Height in px (omit to shrink-to-content via HUG)
483
- rotation (number, optional) \u2014 Rotation in degrees (0-360)
484
- visible (boolean, optional) \u2014 Show/hide (default true)
485
- locked (boolean, optional) \u2014 Lock/unlock (default false)
486
- opacity (string, optional) \u2014 Opacity (0-1) or variable name
487
- 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)
488
- effectStyleName (string, optional) \u2014 Effect style name (e.g. 'Shadow/Card') for shadows, blurs
489
- fills (array, optional) \u2014 Fill paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] for transparent. Primary way to set fills.
490
- fillColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)
491
- fillStyleName (string, optional) \u2014 Paint style name for fill
492
- fillVariableName (string, optional) \u2014 Color variable by name e.g. 'bg/primary'
493
- imageUrl (string, optional) \u2014 Image source \u2014 'pexel:<id>' for Pexels photos, a public URL, or a local file path. SVGs are inserted as vectors; raster images become IMAGE fills.
494
- imageScaleMode (FILL | FIT | CROP | TILE, optional) \u2014 How the image is scaled within the frame (default: FILL)
495
- strokes (array, optional) \u2014 Stroke paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] to clear. Primary way to set strokes.
496
- strokeColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)
497
- strokeStyleName (string, optional) \u2014 Paint style name for stroke
498
- strokeVariableName (string, optional) \u2014 Color variable by name for stroke
499
- strokeWeight (string, optional) \u2014 All sides (number) or variable name (string). Per-side: strokeTopWeight, strokeBottomWeight, strokeLeftWeight, strokeRightWeight.
500
- strokeTopWeight (string, optional)
501
- strokeBottomWeight (string, optional)
502
- strokeLeftWeight (string, optional)
503
- strokeRightWeight (string, optional)
504
- strokeAlign (INSIDE | OUTSIDE | CENTER, optional) \u2014 Stroke position (default: INSIDE)
505
- cornerRadius (string, optional) \u2014 All corners (number) or variable name (string). Per-corner: topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius.
506
- topLeftRadius (string, optional)
507
- topRightRadius (string, optional)
508
- bottomRightRadius (string, optional)
509
- bottomLeftRadius (string, optional)
510
- layoutMode (HORIZONTAL | VERTICAL, required) \u2014 Primary axis direction
511
- 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.
512
- padding (string, optional) \u2014 All edges (number) or variable name (string). Per-edge: paddingTop, paddingRight, paddingBottom, paddingLeft.
513
- paddingTop (string, optional)
514
- paddingRight (string, optional)
515
- paddingBottom (string, optional)
516
- paddingLeft (string, optional)
517
- primaryAxisAlignItems (MIN | MAX | CENTER | SPACE_BETWEEN, optional)
518
- counterAxisAlignItems (MIN | MAX | CENTER | BASELINE, optional)
519
- itemSpacing (string, optional) \u2014 Spacing between children (number or variable name string, default: 0)
520
- counterAxisSpacing (string, optional) \u2014 Gap between wrapped rows (requires layoutWrap: WRAP)
521
- strokesIncludedInLayout (boolean, optional) \u2014 Include stroke width in layout measurements (default: false)
522
- overflowDirection (NONE | HORIZONTAL | VERTICAL | BOTH, optional) \u2014 Scroll overflow in prototype (default: NONE)
523
- layoutPositioning (AUTO | ABSOLUTE, optional) \u2014 ABSOLUTE = floating inside auto-layout parent
524
- layoutSizingHorizontal (FIXED | HUG | FILL, optional)
525
- layoutSizingVertical (FIXED | HUG | FILL, optional)
526
- minWidth (number, optional) \u2014 Min width for responsive auto-layout
527
- maxWidth (number, optional) \u2014 Max width for responsive auto-layout
528
- minHeight (number, optional) \u2014 Min height for responsive auto-layout
529
- maxHeight (number, optional) \u2014 Max height for responsive auto-layout
530
- annotations (array, optional) \u2014 Set annotations \u2014 [{label?, labelMarkdown?, properties?, categoryId?}]. Properties validated per node type.
531
- clipsContent (boolean, optional)
532
- nodeIds (string[], optional) \u2014 Existing node IDs to wrap into auto-layout
533
- 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.
562
+ Example: frames(method:"create", type:"auto_layout", items:[{name:"Settings Card", width:360, height:180, layoutMode:"VERTICAL", padding:"space/24", itemSpacing:"space/12", fillVariableName:"bg/surface", strokeVariableName:"border/subtle", strokeWeight:"stroke/1", cornerRadius:"radius/12", children:[{type:"text", name:"Team settings", text:"Team settings", textStyleName:"Heading/Medium", fontColorVariableName:"text/primary", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}, {type:"text", name:"Manage workspace preferences.", text:"Manage workspace preferences.", textStyleName:"Body/Regular", fontColorVariableName:"text/secondary", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}]}])
563
+ Item fields for items[] when type:"auto_layout":
564
+ name (string, optional) \u2014 Node name
565
+ parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
566
+ x (number, optional) \u2014 X position (default: 0)
567
+ y (number, optional) \u2014 Y position (default: 0)
568
+ width (number, optional) \u2014 Width in px (omit to shrink-to-content via HUG)
569
+ height (number, optional) \u2014 Height in px (omit to shrink-to-content via HUG)
570
+ rotation (number, optional) \u2014 Rotation in degrees (0-360)
571
+ visible (boolean, optional) \u2014 Show/hide (default true)
572
+ locked (boolean, optional) \u2014 Lock/unlock (default false)
573
+ opacity (string, optional) \u2014 Opacity (0-1) or variable name
574
+ 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)
575
+ effectStyleName (string, optional) \u2014 Effect style name (e.g. 'Shadow/Card') for shadows, blurs
576
+ fills (Paint[], optional) \u2014 Fill Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] for transparent. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables; use imageUrl/images for image authoring. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set non-image fills.
577
+ fillColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)
578
+ fillStyleName (string, optional) \u2014 Paint style name for fill
579
+ fillVariableName (string, optional) \u2014 Color variable by name e.g. 'bg/surface'
580
+ imageUrl (string, optional) \u2014 Image source \u2014 'pexel:<id>' for Pexels photos, a public URL, or a local file path. SVGs are inserted as vectors; raster images become IMAGE fills.
581
+ imageScaleMode (FILL | FIT | CROP | TILE, optional) \u2014 How the image is scaled within the frame (default: FILL)
582
+ strokes (Paint[], optional) \u2014 Stroke Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] to clear. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set strokes.
583
+ strokeColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)
584
+ strokeStyleName (string, optional) \u2014 Paint style name for stroke
585
+ strokeVariableName (string, optional) \u2014 Color variable by name for stroke
586
+ strokeWeight (string, optional) \u2014 All sides (number) or variable name (string). Per-side: strokeTopWeight, strokeBottomWeight, strokeLeftWeight, strokeRightWeight.
587
+ strokeTopWeight (string, optional)
588
+ strokeBottomWeight (string, optional)
589
+ strokeLeftWeight (string, optional)
590
+ strokeRightWeight (string, optional)
591
+ strokeAlign (INSIDE | OUTSIDE | CENTER, optional) \u2014 Stroke position (default: INSIDE)
592
+ cornerRadius (string, optional) \u2014 All corners (number) or variable name (string). Per-corner: topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius.
593
+ topLeftRadius (string, optional)
594
+ topRightRadius (string, optional)
595
+ bottomRightRadius (string, optional)
596
+ bottomLeftRadius (string, optional)
597
+ layoutMode (HORIZONTAL | VERTICAL, required) \u2014 Primary axis direction
598
+ 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.
599
+ padding (string, optional) \u2014 All edges (number) or variable name (string). Per-edge: paddingTop, paddingRight, paddingBottom, paddingLeft.
600
+ paddingTop (string, optional)
601
+ paddingRight (string, optional)
602
+ paddingBottom (string, optional)
603
+ paddingLeft (string, optional)
604
+ primaryAxisAlignItems (MIN | MAX | CENTER | SPACE_BETWEEN, optional)
605
+ counterAxisAlignItems (MIN | MAX | CENTER | BASELINE, optional)
606
+ itemSpacing (string, optional) \u2014 Spacing between children (number or variable name string, default: 0)
607
+ counterAxisSpacing (string, optional) \u2014 Gap between wrapped rows (requires layoutWrap: WRAP)
608
+ strokesIncludedInLayout (boolean, optional) \u2014 Include stroke width in layout measurements (default: false)
609
+ overflowDirection (NONE | HORIZONTAL | VERTICAL | BOTH, optional) \u2014 Scroll overflow in prototype (default: NONE)
610
+ layoutPositioning (AUTO | ABSOLUTE, optional) \u2014 ABSOLUTE = floating inside auto-layout parent
611
+ layoutSizingHorizontal (FIXED | HUG | FILL, optional)
612
+ layoutSizingVertical (FIXED | HUG | FILL, optional)
613
+ minWidth (number, optional) \u2014 Min width for responsive auto-layout
614
+ maxWidth (number, optional) \u2014 Max width for responsive auto-layout
615
+ minHeight (number, optional) \u2014 Min height for responsive auto-layout
616
+ maxHeight (number, optional) \u2014 Max height for responsive auto-layout
617
+ annotations (array, optional) \u2014 Set annotations \u2014 [{label?, labelMarkdown?, properties?, categoryId?}]. Properties validated per node type.
618
+ clipsContent (boolean, optional)
619
+ nodeIds (string[], optional) \u2014 Existing node IDs to wrap into auto-layout
620
+ children (array, optional) \u2014 Inline child nodes \u2014 build nested trees in one call. Types: text: {type:"text", text, textStyleName?, fontColorVariableName?, layoutSizingHorizontal?}. frame: {type:"frame", name?, layoutMode?, fillVariableName?, itemSpacing?, layoutSizingHorizontal?, children?}. instance: {type:"instance", componentId, variantProperties?, properties?}. component: {type:"component", name, children?}. rectangle / ellipse / line: same params as the corresponding frames(method:"create", type:"rectangle"|"ellipse"|"line") branch. All params from text/frame endpoints are supported on their respective types. Inline fills/strokes accept Paint[] authoring input: SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. Do not use CSS gradients, REST gradientHandlePositions, or IMAGE/VIDEO/PATTERN in Paint[] authoring. Always set layoutSizingHorizontal + layoutSizingVertical on children inside auto-layout parents (FILL, HUG, or FIXED). Example: children:[{type:"ellipse", name:"Dot", width:6, height:6, fillVariableName:"status/active"}, {type:"text", name:"Title", text:"Title", textStyleName:"Heading/Medium", fontColorVariableName:"text/primary", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}, {type:"frame", name:"Row", layoutMode:"HORIZONTAL", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG", itemSpacing:"space/8", children:[{type:"instance", componentId:"1:2", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}]}] Inside components: add componentPropertyName to auto-bind TEXT or INSTANCE_SWAP properties.
534
621
 
535
622
 
536
623
  ## section \u2014 Figma section (top-level organizer)
537
- name (string, required) \u2014 Section name
538
- parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
539
- x (number, optional) \u2014 X position (default: 0)
540
- y (number, optional) \u2014 Y position (default: 0)
541
- width (number, optional) \u2014 Width (default: 500)
542
- height (number, optional) \u2014 Height (default: 500)
543
- fills (array, optional) \u2014 Fill paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] for transparent
544
- fillColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)
545
- fillStyleName (string, optional) \u2014 Paint style name for fill
546
- fillVariableName (string, optional) \u2014 Color variable by name e.g. 'bg/primary'
547
- imageUrl (string, optional) \u2014 Image source \u2014 'pexel:<id>', public URL, or local file path
548
- imageScaleMode (FILL | FIT | CROP | TILE, optional) \u2014 How the image is scaled (default: FILL)
624
+ Example: frames(method:"create", type:"section", items:[{name:"Components", x:0, y:0, width:1200, height:800, fillVariableName:"bg/canvas"}])
625
+ Item fields for items[] when type:"section":
626
+ name (string, required) \u2014 Section name
627
+ parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
628
+ x (number, optional) \u2014 X position (default: 0)
629
+ y (number, optional) \u2014 Y position (default: 0)
630
+ width (number, optional) \u2014 Width (default: 500)
631
+ height (number, optional) \u2014 Height (default: 500)
632
+ fills (Paint[], optional) \u2014 Fill Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] for transparent. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables; use imageUrl/images for image authoring. IMAGE/VIDEO/PATTERN may appear in readback metadata only
633
+ fillColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)
634
+ fillStyleName (string, optional) \u2014 Paint style name for fill
635
+ fillVariableName (string, optional) \u2014 Color variable by name e.g. 'bg/surface'
636
+ imageUrl (string, optional) \u2014 Image source \u2014 'pexel:<id>', public URL, or local file path
637
+ imageScaleMode (FILL | FIT | CROP | TILE, optional) \u2014 How the image is scaled (default: FILL)
549
638
 
550
639
  ## rectangle \u2014 Rectangle shape node
551
- name (string, optional) \u2014 Layer name (default: 'Rectangle')
552
- parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
553
- x (number, optional) \u2014 X position (default: 0)
554
- y (number, optional) \u2014 Y position (default: 0)
555
- width (number, optional) \u2014 Width in px (default: 100)
556
- height (number, optional) \u2014 Height in px (default: 100)
557
- fills (array, optional) \u2014 Fill paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] for transparent
558
- fillColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)
559
- fillStyleName (string, optional) \u2014 Paint style name for fill
560
- fillVariableName (string, optional) \u2014 Color variable by name e.g. 'bg/primary'
561
- imageUrl (string, optional) \u2014 Image source \u2014 'pexel:<id>', public URL, or local file path
562
- imageScaleMode (FILL | FIT | CROP | TILE, optional) \u2014 How the image is scaled (default: FILL)
563
- strokes (array, optional) \u2014 Stroke paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] to clear
564
- strokeColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)
565
- strokeVariableName (string, optional) \u2014 Color variable by name for stroke
566
- strokeWeight (string, optional)
567
- cornerRadius (string, optional) \u2014 All corners (number) or variable name (string). Per-corner: topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius.
568
- topLeftRadius (string, optional)
569
- topRightRadius (string, optional)
570
- bottomRightRadius (string, optional)
571
- bottomLeftRadius (string, optional)
572
- opacity (string, optional)
573
- layoutSizingHorizontal (FIXED | FILL, optional) \u2014 Horizontal sizing in auto-layout parent
574
- layoutSizingVertical (FIXED | FILL, optional) \u2014 Vertical sizing in auto-layout parent
575
- annotations (array, optional) \u2014 Annotations \u2014 [{label?, labelMarkdown?, properties?, categoryId?}]
640
+ Example: frames(method:"create", type:"rectangle", items:[{name:"Avatar Placeholder", width:64, height:64, cornerRadius:"radius/16", fillVariableName:"bg/muted"}])
641
+ Item fields for items[] when type:"rectangle":
642
+ name (string, optional) \u2014 Layer name (default: 'Rectangle')
643
+ parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
644
+ x (number, optional) \u2014 X position (default: 0)
645
+ y (number, optional) \u2014 Y position (default: 0)
646
+ width (number, optional) \u2014 Width in px (default: 100)
647
+ height (number, optional) \u2014 Height in px (default: 100)
648
+ fills (Paint[], optional) \u2014 Fill Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] for transparent. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables; use imageUrl/images for image authoring. IMAGE/VIDEO/PATTERN may appear in readback metadata only
649
+ fillColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)
650
+ fillStyleName (string, optional) \u2014 Paint style name for fill
651
+ fillVariableName (string, optional) \u2014 Color variable by name e.g. 'bg/surface'
652
+ imageUrl (string, optional) \u2014 Image source \u2014 'pexel:<id>', public URL, or local file path
653
+ imageScaleMode (FILL | FIT | CROP | TILE, optional) \u2014 How the image is scaled (default: FILL)
654
+ strokes (Paint[], optional) \u2014 Stroke Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] to clear. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables. IMAGE/VIDEO/PATTERN may appear in readback metadata only
655
+ strokeColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)
656
+ strokeVariableName (string, optional) \u2014 Color variable by name for stroke
657
+ strokeWeight (string, optional)
658
+ cornerRadius (string, optional) \u2014 All corners (number) or variable name (string). Per-corner: topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius.
659
+ topLeftRadius (string, optional)
660
+ topRightRadius (string, optional)
661
+ bottomRightRadius (string, optional)
662
+ bottomLeftRadius (string, optional)
663
+ opacity (string, optional)
664
+ layoutSizingHorizontal (FIXED | FILL, optional) \u2014 Horizontal sizing in auto-layout parent
665
+ layoutSizingVertical (FIXED | FILL, optional) \u2014 Vertical sizing in auto-layout parent
666
+ annotations (array, optional) \u2014 Annotations \u2014 [{label?, labelMarkdown?, properties?, categoryId?}]
576
667
 
577
668
  ## ellipse \u2014 Ellipse/circle shape node
578
- name (string, optional) \u2014 Layer name (default: 'Ellipse')
579
- parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
580
- x (number, optional) \u2014 X position (default: 0)
581
- y (number, optional) \u2014 Y position (default: 0)
582
- width (number, optional) \u2014 Width in px (default: 100)
583
- height (number, optional) \u2014 Height in px (default: 100, same as width for circle)
584
- fills (array, optional) \u2014 Fill paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] for transparent
585
- fillColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)
586
- fillStyleName (string, optional) \u2014 Paint style name for fill
587
- fillVariableName (string, optional) \u2014 Color variable by name e.g. 'bg/primary'
588
- imageUrl (string, optional) \u2014 Image source \u2014 'pexel:<id>', public URL, or local file path
589
- imageScaleMode (FILL | FIT | CROP | TILE, optional) \u2014 How the image is scaled (default: FILL)
590
- strokes (array, optional) \u2014 Stroke paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] to clear
591
- strokeColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)
592
- strokeVariableName (string, optional) \u2014 Color variable by name for stroke
593
- strokeWeight (string, optional)
594
- opacity (string, optional)
595
- layoutSizingHorizontal (FIXED | FILL, optional) \u2014 Horizontal sizing in auto-layout parent
596
- layoutSizingVertical (FIXED | FILL, optional) \u2014 Vertical sizing in auto-layout parent
597
- annotations (array, optional) \u2014 Annotations \u2014 [{label?, labelMarkdown?, properties?, categoryId?}]
669
+ Example: frames(method:"create", type:"ellipse", items:[{name:"Status Dot", width:12, height:12, fillVariableName:"status/success"}])
670
+ Item fields for items[] when type:"ellipse":
671
+ name (string, optional) \u2014 Layer name (default: 'Ellipse')
672
+ parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
673
+ x (number, optional) \u2014 X position (default: 0)
674
+ y (number, optional) \u2014 Y position (default: 0)
675
+ width (number, optional) \u2014 Width in px (default: 100)
676
+ height (number, optional) \u2014 Height in px (default: 100, same as width for circle)
677
+ fills (Paint[], optional) \u2014 Fill Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] for transparent. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables; use imageUrl/images for image authoring. IMAGE/VIDEO/PATTERN may appear in readback metadata only
678
+ fillColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)
679
+ fillStyleName (string, optional) \u2014 Paint style name for fill
680
+ fillVariableName (string, optional) \u2014 Color variable by name e.g. 'bg/surface'
681
+ imageUrl (string, optional) \u2014 Image source \u2014 'pexel:<id>', public URL, or local file path
682
+ imageScaleMode (FILL | FIT | CROP | TILE, optional) \u2014 How the image is scaled (default: FILL)
683
+ strokes (Paint[], optional) \u2014 Stroke Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] to clear. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables. IMAGE/VIDEO/PATTERN may appear in readback metadata only
684
+ strokeColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)
685
+ strokeVariableName (string, optional) \u2014 Color variable by name for stroke
686
+ strokeWeight (string, optional)
687
+ opacity (string, optional)
688
+ layoutSizingHorizontal (FIXED | FILL, optional) \u2014 Horizontal sizing in auto-layout parent
689
+ layoutSizingVertical (FIXED | FILL, optional) \u2014 Vertical sizing in auto-layout parent
690
+ annotations (array, optional) \u2014 Annotations \u2014 [{label?, labelMarkdown?, properties?, categoryId?}]
598
691
 
599
692
  ## line \u2014 Line shape node
600
- name (string, optional) \u2014 Layer name (default: 'Line')
601
- parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
602
- x (number, optional) \u2014 X position (default: 0)
603
- y (number, optional) \u2014 Y position (default: 0)
604
- length (number, optional) \u2014 Line length in px (default: 100)
605
- rotation (number, optional) \u2014 Rotation in degrees (default: 0 = horizontal)
606
- strokes (array, optional) \u2014 Stroke paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] to clear
607
- strokeColor (Color, optional) \u2014 Line color (default: black, auto-binds to matching variable/style)
608
- strokeVariableName (string, optional) \u2014 Color variable by name for stroke
609
- strokeWeight (string, optional) \u2014 Line thickness (default: 1)
610
- opacity (string, optional)
611
- layoutSizingHorizontal (FIXED | FILL, optional) \u2014 Horizontal sizing in auto-layout parent (defaults to FILL in vertical auto-layout)
612
- annotations (array, optional) \u2014 Annotations \u2014 [{label?, labelMarkdown?, properties?, categoryId?}]
693
+ Example: frames(method:"create", type:"line", items:[{name:"Divider", length:320, strokeVariableName:"border/subtle", strokeWeight:"stroke/1"}])
694
+ Item fields for items[] when type:"line":
695
+ name (string, optional) \u2014 Layer name (default: 'Line')
696
+ parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
697
+ x (number, optional) \u2014 X position (default: 0)
698
+ y (number, optional) \u2014 Y position (default: 0)
699
+ length (number, optional) \u2014 Line length in px (default: 100)
700
+ rotation (number, optional) \u2014 Rotation in degrees (default: 0 = horizontal)
701
+ strokes (Paint[], optional) \u2014 Stroke Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] to clear. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables. IMAGE/VIDEO/PATTERN may appear in readback metadata only
702
+ strokeColor (Color, optional) \u2014 Line color (default: black, auto-binds to matching variable/style)
703
+ strokeVariableName (string, optional) \u2014 Color variable by name for stroke
704
+ strokeWeight (string, optional) \u2014 Line thickness (default: 1)
705
+ opacity (string, optional)
706
+ layoutSizingHorizontal (FIXED | FILL, optional) \u2014 Horizontal sizing in auto-layout parent (defaults to FILL in vertical auto-layout)
707
+ annotations (array, optional) \u2014 Annotations \u2014 [{label?, labelMarkdown?, properties?, categoryId?}]
613
708
 
614
709
  ## group \u2014 Group existing nodes together
615
- nodeIds (string[], required) \u2014 Node IDs to group (min 1)
616
- name (string, optional) \u2014 Group name
617
- parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
710
+ Example: frames(method:"create", type:"group", items:[{nodeIds:["1:2","1:3"], name:"Icon Group"}])
711
+ Item fields for items[] when type:"group":
712
+ nodeIds (string[], required) \u2014 Node IDs to group (min 1)
713
+ name (string, optional) \u2014 Group name
714
+ parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
618
715
 
619
716
  ## boolean_operation \u2014 Combine shapes with boolean operations (union, subtract, intersect, exclude)
620
- operation (UNION | SUBTRACT | INTERSECT | EXCLUDE, required) \u2014 Boolean operation type
621
- nodeIds (string[], required) \u2014 Node IDs to combine (min 2, first node is the base for SUBTRACT)
622
- name (string, optional) \u2014 Result node name
623
- parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
717
+ Example: frames(method:"create", type:"boolean_operation", items:[{operation:"UNION", nodeIds:["1:2","1:3"], name:"Combined Shape", fillVariableName:"bg/accent"}])
718
+ Item fields for items[] when type:"boolean_operation":
719
+ fillStyleName (string, optional) \u2014 Paint style to apply to vector fills
720
+ fillVariableName (string, optional) \u2014 Color variable by name for vector fills
721
+ strokeStyleName (string, optional) \u2014 Paint style to apply to vector strokes
722
+ strokeVariableName (string, optional) \u2014 Color variable by name for vector strokes
723
+ operation (UNION | SUBTRACT | INTERSECT | EXCLUDE, required) \u2014 Boolean operation type
724
+ nodeIds (string[], required) \u2014 Node IDs to combine (min 2, first node is the base for SUBTRACT)
725
+ name (string, optional) \u2014 Result node name
726
+ parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
624
727
 
625
728
  ## svg \u2014 Create node from SVG markup
626
- fillStyleName (string, optional) \u2014 Paint style to apply to vector fills
627
- fillVariableName (string, optional) \u2014 Color variable by name for vector fills
628
- strokeStyleName (string, optional) \u2014 Paint style to apply to vector strokes
629
- strokeVariableName (string, optional) \u2014 Color variable by name for vector strokes
630
- svg (string, required) \u2014 SVG markup string
631
- name (string, optional) \u2014 Layer name (default: 'SVG')
632
- parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
633
- x (number, optional) \u2014 X position (default: 0)
634
- y (number, optional) \u2014 Y position (default: 0)
729
+ Example: frames(method:"create", type:"svg", items:[{name:"Logo Mark", svg:"<svg width=\\"24\\" height=\\"24\\"><path d=\\"M4 4h16v16H4z\\" fill=\\"currentColor\\"/></svg>", fillVariableName:"icon/primary"}])
730
+ Item fields for items[] when type:"svg":
731
+ fillStyleName (string, optional) \u2014 Paint style to apply to vector fills
732
+ fillVariableName (string, optional) \u2014 Color variable by name for vector fills
733
+ strokeStyleName (string, optional) \u2014 Paint style to apply to vector strokes
734
+ strokeVariableName (string, optional) \u2014 Color variable by name for vector strokes
735
+ svg (string, required) \u2014 SVG markup string
736
+ name (string, optional) \u2014 Layer name (default: 'SVG')
737
+ parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
738
+ x (number, optional) \u2014 X position (default: 0)
739
+ y (number, optional) \u2014 Y position (default: 0)
635
740
 
636
741
  ## slot \u2014 Create a slot inside a component. Slots are placeholder containers that instance users fill with content. Defaults to VERTICAL auto-layout with FILL/HUG sizing \u2014 ready to receive children. Accepts all frame layout properties.
637
- name (string, optional) \u2014 Node name
638
- parentId (string, optional) \u2014 Parent node ID inside the owning component. Required unless componentId is provided.
639
- x (number, optional) \u2014 X position (default: 0)
640
- y (number, optional) \u2014 Y position (default: 0)
641
- width (number, optional) \u2014 Width in px (omit to shrink-to-content via HUG)
642
- height (number, optional) \u2014 Height in px (omit to shrink-to-content via HUG)
643
- rotation (number, optional) \u2014 Rotation in degrees (0-360)
644
- visible (boolean, optional) \u2014 Show/hide (default true)
645
- locked (boolean, optional) \u2014 Lock/unlock (default false)
646
- opacity (string, optional) \u2014 Opacity (0-1) or variable name
647
- 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)
648
- effectStyleName (string, optional) \u2014 Effect style name (e.g. 'Shadow/Card') for shadows, blurs
649
- fills (array, optional) \u2014 Fill paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] for transparent. Primary way to set fills.
650
- fillColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)
651
- fillStyleName (string, optional) \u2014 Paint style name for fill
652
- fillVariableName (string, optional) \u2014 Color variable by name e.g. 'bg/primary'
653
- imageUrl (string, optional) \u2014 Image source \u2014 'pexel:<id>' for Pexels photos, a public URL, or a local file path. SVGs are inserted as vectors; raster images become IMAGE fills.
654
- imageScaleMode (FILL | FIT | CROP | TILE, optional) \u2014 How the image is scaled within the frame (default: FILL)
655
- strokes (array, optional) \u2014 Stroke paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] to clear. Primary way to set strokes.
656
- strokeColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)
657
- strokeStyleName (string, optional) \u2014 Paint style name for stroke
658
- strokeVariableName (string, optional) \u2014 Color variable by name for stroke
659
- strokeWeight (string, optional) \u2014 All sides (number) or variable name (string). Per-side: strokeTopWeight, strokeBottomWeight, strokeLeftWeight, strokeRightWeight.
660
- strokeTopWeight (string, optional)
661
- strokeBottomWeight (string, optional)
662
- strokeLeftWeight (string, optional)
663
- strokeRightWeight (string, optional)
664
- strokeAlign (INSIDE | OUTSIDE | CENTER, optional) \u2014 Stroke position (default: INSIDE)
665
- cornerRadius (string, optional) \u2014 All corners (number) or variable name (string). Per-corner: topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius.
666
- topLeftRadius (string, optional)
667
- topRightRadius (string, optional)
668
- bottomRightRadius (string, optional)
669
- bottomLeftRadius (string, optional)
670
- layoutMode (NONE | HORIZONTAL | VERTICAL, optional) \u2014 Layout direction (default: auto \u2014 NONE when width+height set, otherwise inferred from layout props)
671
- 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.
672
- padding (string, optional) \u2014 All edges (number) or variable name (string). Per-edge: paddingTop, paddingRight, paddingBottom, paddingLeft.
673
- paddingTop (string, optional)
674
- paddingRight (string, optional)
675
- paddingBottom (string, optional)
676
- paddingLeft (string, optional)
677
- primaryAxisAlignItems (MIN | MAX | CENTER | SPACE_BETWEEN, optional)
678
- counterAxisAlignItems (MIN | MAX | CENTER | BASELINE, optional)
679
- itemSpacing (string, optional) \u2014 Spacing between children (number or variable name string, default: 0)
680
- counterAxisSpacing (string, optional) \u2014 Gap between wrapped rows (requires layoutWrap: WRAP)
681
- strokesIncludedInLayout (boolean, optional) \u2014 Include stroke width in layout measurements (default: false)
682
- overflowDirection (NONE | HORIZONTAL | VERTICAL | BOTH, optional) \u2014 Scroll overflow in prototype (default: NONE)
683
- layoutPositioning (AUTO | ABSOLUTE, optional) \u2014 ABSOLUTE = floating inside auto-layout parent
684
- layoutSizingHorizontal (FIXED | HUG | FILL, optional)
685
- layoutSizingVertical (FIXED | HUG | FILL, optional)
686
- minWidth (number, optional) \u2014 Min width for responsive auto-layout
687
- maxWidth (number, optional) \u2014 Max width for responsive auto-layout
688
- minHeight (number, optional) \u2014 Min height for responsive auto-layout
689
- maxHeight (number, optional) \u2014 Max height for responsive auto-layout
690
- annotations (array, optional) \u2014 Set annotations \u2014 [{label?, labelMarkdown?, properties?, categoryId?}]. Properties validated per node type.
691
- componentId (string, optional) \u2014 Owning component ID. Optional \u2014 auto-resolved from parentId by walking up ancestors.`,
692
- "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',
693
- "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)"
742
+ Example: frames(method:"create", type:"slot", items:[{componentId:"1:23", name:"Content Slot", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}])
743
+ Item fields for items[] when type:"slot":
744
+ name (string, optional) \u2014 Node name
745
+ parentId (string, optional) \u2014 Parent node ID inside the owning component. Required unless componentId is provided.
746
+ x (number, optional) \u2014 X position (default: 0)
747
+ y (number, optional) \u2014 Y position (default: 0)
748
+ width (number, optional) \u2014 Width in px (omit to shrink-to-content via HUG)
749
+ height (number, optional) \u2014 Height in px (omit to shrink-to-content via HUG)
750
+ rotation (number, optional) \u2014 Rotation in degrees (0-360)
751
+ visible (boolean, optional) \u2014 Show/hide (default true)
752
+ locked (boolean, optional) \u2014 Lock/unlock (default false)
753
+ opacity (string, optional) \u2014 Opacity (0-1) or variable name
754
+ 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)
755
+ effectStyleName (string, optional) \u2014 Effect style name (e.g. 'Shadow/Card') for shadows, blurs
756
+ fills (Paint[], optional) \u2014 Fill Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] for transparent. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables; use imageUrl/images for image authoring. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set non-image fills.
757
+ fillColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)
758
+ fillStyleName (string, optional) \u2014 Paint style name for fill
759
+ fillVariableName (string, optional) \u2014 Color variable by name e.g. 'bg/surface'
760
+ imageUrl (string, optional) \u2014 Image source \u2014 'pexel:<id>' for Pexels photos, a public URL, or a local file path. SVGs are inserted as vectors; raster images become IMAGE fills.
761
+ imageScaleMode (FILL | FIT | CROP | TILE, optional) \u2014 How the image is scaled within the frame (default: FILL)
762
+ strokes (Paint[], optional) \u2014 Stroke Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] to clear. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set strokes.
763
+ strokeColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)
764
+ strokeStyleName (string, optional) \u2014 Paint style name for stroke
765
+ strokeVariableName (string, optional) \u2014 Color variable by name for stroke
766
+ strokeWeight (string, optional) \u2014 All sides (number) or variable name (string). Per-side: strokeTopWeight, strokeBottomWeight, strokeLeftWeight, strokeRightWeight.
767
+ strokeTopWeight (string, optional)
768
+ strokeBottomWeight (string, optional)
769
+ strokeLeftWeight (string, optional)
770
+ strokeRightWeight (string, optional)
771
+ strokeAlign (INSIDE | OUTSIDE | CENTER, optional) \u2014 Stroke position (default: INSIDE)
772
+ cornerRadius (string, optional) \u2014 All corners (number) or variable name (string). Per-corner: topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius.
773
+ topLeftRadius (string, optional)
774
+ topRightRadius (string, optional)
775
+ bottomRightRadius (string, optional)
776
+ bottomLeftRadius (string, optional)
777
+ layoutMode (NONE | HORIZONTAL | VERTICAL, optional) \u2014 Layout direction (default: auto \u2014 NONE when width+height set, otherwise inferred from layout props)
778
+ 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.
779
+ padding (string, optional) \u2014 All edges (number) or variable name (string). Per-edge: paddingTop, paddingRight, paddingBottom, paddingLeft.
780
+ paddingTop (string, optional)
781
+ paddingRight (string, optional)
782
+ paddingBottom (string, optional)
783
+ paddingLeft (string, optional)
784
+ primaryAxisAlignItems (MIN | MAX | CENTER | SPACE_BETWEEN, optional)
785
+ counterAxisAlignItems (MIN | MAX | CENTER | BASELINE, optional)
786
+ itemSpacing (string, optional) \u2014 Spacing between children (number or variable name string, default: 0)
787
+ counterAxisSpacing (string, optional) \u2014 Gap between wrapped rows (requires layoutWrap: WRAP)
788
+ strokesIncludedInLayout (boolean, optional) \u2014 Include stroke width in layout measurements (default: false)
789
+ overflowDirection (NONE | HORIZONTAL | VERTICAL | BOTH, optional) \u2014 Scroll overflow in prototype (default: NONE)
790
+ layoutPositioning (AUTO | ABSOLUTE, optional) \u2014 ABSOLUTE = floating inside auto-layout parent
791
+ layoutSizingHorizontal (FIXED | HUG | FILL, optional)
792
+ layoutSizingVertical (FIXED | HUG | FILL, optional)
793
+ minWidth (number, optional) \u2014 Min width for responsive auto-layout
794
+ maxWidth (number, optional) \u2014 Max width for responsive auto-layout
795
+ minHeight (number, optional) \u2014 Min height for responsive auto-layout
796
+ maxHeight (number, optional) \u2014 Max height for responsive auto-layout
797
+ annotations (array, optional) \u2014 Set annotations \u2014 [{label?, labelMarkdown?, properties?, categoryId?}]. Properties validated per node type.
798
+ componentId (string, optional) \u2014 Owning component ID. Optional \u2014 auto-resolved from parentId by walking up ancestors.
799
+
800
+ Response:
801
+ { results: ({id} | {error})[] }
802
+ // Shared types:
803
+ // Color: hex "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}
804
+ // VariableAlias: {type: "VARIABLE_ALIAS", id: string}. The id must be a Figma VariableID; discover it via variables.get/list or variable_collections.get. Prefer colorVariableName/fillVariableName/strokeVariableName when available; Paint[] VariableAlias is mainly for precise Paint[] round-trips and gradient stop bindings.
805
+ // Transform: [[number, number, number], [number, number, number]] (Figma Plugin API 2\xD73 matrix)
806
+ // 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"
807
+ // ColorStop: {position: 0-1, color: Color, boundVariables?: {color?: VariableAlias}}
808
+ // GradientPaint: {type: "GRADIENT_LINEAR"|"GRADIENT_RADIAL"|"GRADIENT_ANGULAR"|"GRADIENT_DIAMOND", gradientTransform: Transform, gradientStops: ColorStop[], visible?: boolean, opacity?: number, blendMode?: BlendMode}. Use gradientTransform + gradientStops (basic left-to-right: [[1,0,0],[0,1,0]]); do not use CSS gradients or REST gradientHandlePositions.
809
+ // Effect: {type: "DROP_SHADOW"|"INNER_SHADOW"|"LAYER_BLUR"|"BACKGROUND_BLUR", radius: number, color?: {r,g,b,a} (0-1), offset?: {x, y}, spread?: number, visible?: boolean}
810
+ // Paint: Paint[] authoring accepts only SOLID and GRADIENT_LINEAR/GRADIENT_RADIAL/GRADIENT_ANGULAR/GRADIENT_DIAMOND. SolidPaint: {type: "SOLID", color: Color, visible?: boolean, opacity?: number, blendMode?: BlendMode, boundVariables?: {color?: VariableAlias}}. GradientPaint authoring: {type: GRADIENT_*, gradientTransform: Transform, gradientStops: ColorStop[], visible?, opacity?, blendMode?}; bind variables on gradientStops[].boundVariables.color, not top-level gradient boundVariables. Do not pass IMAGE/VIDEO/PATTERN to create/update Paint[]; those may appear only in readback metadata from existing Figma content. Use imageUrl/images for image authoring. VIDEO/PATTERN authoring is not supported here. Do not use CSS gradients or REST gradientHandlePositions.`,
811
+ "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\n\nResponse:\n { results: ({id} | {error})[] }',
812
+ "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)\n\nResponse:\n Binary image data returned as MCP image content (SVG_STRING returns text)\n imageData (string, optional)\n mimeType (string, optional)"
694
813
  }
695
814
  },
696
815
  "icons": {
697
816
  "summary": '# icons\nSearch and create icons from 200k+ open-source icons via Iconify.\n\nMethods:\n search Search icons by keyword across all Iconify sets [read]\n collections List available Iconify icon sets [read]\n create Create an icon node in Figma from an Iconify icon name [create]\n\n// Icons are fetched from the Iconify API (iconify.design) and inserted as SVG vector nodes.\n// Icon names use "prefix:name" format. Common sets: lucide, mdi, tabler, heroicons, ph.\n// Examples: "lucide:home", "mdi:account-circle", "tabler:arrow-right", "ph:gear-bold"\n// Use search to discover icons by keyword. Use collections to list available icon sets.\n// create fetches the SVG and inserts it via frames.create \u2014 auto-detects fill vs stroke icons.\n// Use colorVariableName (not fillVariableName/strokeVariableName) \u2014 the handler applies to whichever channel has paint.\n// Fetched icons are cached in memory for the session (same icon+size is fetched once).\n// Powered by Iconify (iconify.design) \u2014 open-source icon framework.\n\nUse icons(method: "help", topic: "<method>") for method details.',
698
817
  "methods": {
699
- "search": '# icons.search\nSearch icons by keyword across all Iconify sets\n\nExample: icons(method:"search", query:"arrow right", prefix:"lucide")\n\nParams:\n query (string, required) \u2014 Search keyword (e.g. "home", "arrow", "user")\n prefix (string, optional) \u2014 Restrict to one icon set (e.g. "lucide", "mdi")\n limit (number, optional) \u2014 Max results (default 64)',
700
- "collections": '# icons.collections\nList available Iconify icon sets\n\nExample: icons(method:"collections", category:"UI 24px", limit:10)\n\nParams:\n query (string, optional) \u2014 Filter by name or prefix (e.g. "lucide", "material")\n category (string, optional) \u2014 Filter by category (e.g. "UI 24px", "Logos", "Emoji")\n limit (number, optional) \u2014 Max results (default: all)',
818
+ "search": '# icons.search\nSearch icons by keyword across all Iconify sets\n\nExample: icons(method:"search", query:"arrow right", prefix:"lucide")\n\nParams:\n query (string, required) \u2014 Search keyword (e.g. "home", "arrow", "user")\n prefix (string, optional) \u2014 Restrict to one icon set (e.g. "lucide", "mdi")\n limit (number, optional) \u2014 Max results (default 64)\n\nResponse:\n icons (string[], optional) \u2014 Icon names (e.g. ["lucide:home", "mdi:home"])\n total (number, optional) \u2014 Total matching icons',
819
+ "collections": '# icons.collections\nList available Iconify icon sets\n\nExample: icons(method:"collections", category:"UI 24px", limit:10)\n\nParams:\n query (string, optional) \u2014 Filter by name or prefix (e.g. "lucide", "material")\n category (string, optional) \u2014 Filter by category (e.g. "UI 24px", "Logos", "Emoji")\n limit (number, optional) \u2014 Max results (default: all)\n\nResponse:\n Array of icon set metadata\n collections (array, optional) \u2014 [{ prefix, name, total, category, license }]\n total (number, optional) \u2014 Total matching collections (before limit)',
701
820
  "create": `# icons.create
702
821
  Create an icon node in Figma from an Iconify icon name
703
822
 
@@ -711,7 +830,18 @@ Params:
711
830
  x (number, optional) \u2014 X position (default: 0)
712
831
  y (number, optional) \u2014 Y position (default: 0)
713
832
  colorVariableName (string, optional) \u2014 Color variable for the icon \u2014 auto-detects fill vs stroke (e.g. 'text/primary')
714
- colorStyleName (string, optional) \u2014 Paint style for the icon \u2014 auto-detects fill vs stroke (e.g. 'Icon/Primary')`
833
+ colorStyleName (string, optional) \u2014 Paint style for the icon \u2014 auto-detects fill vs stroke (e.g. 'Icon/Primary')
834
+
835
+ Response:
836
+ { results: ({id} | {error})[] }
837
+ // Shared types:
838
+ // Color: hex "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}
839
+ // VariableAlias: {type: "VARIABLE_ALIAS", id: string}. The id must be a Figma VariableID; discover it via variables.get/list or variable_collections.get. Prefer colorVariableName/fillVariableName/strokeVariableName when available; Paint[] VariableAlias is mainly for precise Paint[] round-trips and gradient stop bindings.
840
+ // Transform: [[number, number, number], [number, number, number]] (Figma Plugin API 2\xD73 matrix)
841
+ // 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"
842
+ // ColorStop: {position: 0-1, color: Color, boundVariables?: {color?: VariableAlias}}
843
+ // GradientPaint: {type: "GRADIENT_LINEAR"|"GRADIENT_RADIAL"|"GRADIENT_ANGULAR"|"GRADIENT_DIAMOND", gradientTransform: Transform, gradientStops: ColorStop[], visible?: boolean, opacity?: number, blendMode?: BlendMode}. Use gradientTransform + gradientStops (basic left-to-right: [[1,0,0],[0,1,0]]); do not use CSS gradients or REST gradientHandlePositions.
844
+ // Paint: Paint[] authoring accepts only SOLID and GRADIENT_LINEAR/GRADIENT_RADIAL/GRADIENT_ANGULAR/GRADIENT_DIAMOND. SolidPaint: {type: "SOLID", color: Color, visible?: boolean, opacity?: number, blendMode?: BlendMode, boundVariables?: {color?: VariableAlias}}. GradientPaint authoring: {type: GRADIENT_*, gradientTransform: Transform, gradientStops: ColorStop[], visible?, opacity?, blendMode?}; bind variables on gradientStops[].boundVariables.color, not top-level gradient boundVariables. Do not pass IMAGE/VIDEO/PATTERN to create/update Paint[]; those may appear only in readback metadata from existing Figma content. Use imageUrl/images for image authoring. VIDEO/PATTERN authoring is not supported here. Do not use CSS gradients or REST gradientHandlePositions.`
715
845
  }
716
846
  },
717
847
  "images": {
@@ -729,16 +859,36 @@ Params:
729
859
  color (string, optional) \u2014 Filter by color \u2014 hex (e.g. '#FF0000') or named: red, orange, yellow, green, turquoise, blue, violet, pink, brown, black, gray, white
730
860
  locale (string, optional) \u2014 Locale for search (e.g. 'en-US', 'ja-JP'). Default: en-US
731
861
  page (number, optional) \u2014 Page number for pagination (default: 1)
732
- per_page (number, optional) \u2014 Results per page (default: 15, max: 80)`,
733
- "preview": '# images.preview\nPreview a photo by ID \u2014 returns the image so you can see it before placing\n\nExample: images(method:"preview", id:12345)\n\nParams:\n id (number, required) \u2014 Photo ID from search results\n size (small | medium | large, optional) \u2014 Preview size (default: medium). small\u2248130px, medium\u2248350px, large\u2248940px height'
862
+ per_page (number, optional) \u2014 Results per page (default: 15, max: 80)
863
+
864
+ Response:
865
+ photos (array, optional) \u2014 [{ id, alt, avg_color, width, height }]
866
+ total_results (number, optional) \u2014 Total matching photos
867
+ page (number, optional)
868
+ per_page (number, optional)`,
869
+ "preview": '# images.preview\nPreview a photo by ID \u2014 returns the image so you can see it before placing\n\nExample: images(method:"preview", id:12345)\n\nParams:\n id (number, required) \u2014 Photo ID from search results\n size (small | medium | large, optional) \u2014 Preview size (default: medium). small\u2248130px, medium\u2248350px, large\u2248940px height\n\nResponse:\n The photo as a visual image preview\n image'
734
870
  }
735
871
  },
736
872
  "instances": {
737
- "summary": '# instances\nCreate and manage component instances.\n\nMethods:\n list Search for nodes (returns stubs only \u2014 use get with depth for full properties) [read]\n delete Delete nodes [edit]\n clone Duplicate nodes \u2014 produces a same-type copy (frame\u2192frame, instance\u2192instance, component\u2192component). Instance clones reference the same source component; they do not duplicate the component definition. [create]\n audit Run lint on a node \u2014 returns severity-ranked findings [read]\n reparent Move nodes into a new parent [edit]\n get Get instance detail with component properties and overrides [read]\n create Create component instances [create]\n update Set instance properties [edit]\n swap Swap instance component (preserves overrides) [edit]\n detach Detach instances from their component (converts to frame) [edit]\n reset_overrides Reset all overrides on instances to match their main component [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// Instances are linked copies of components. Changes to the component propagate to all instances.\n// Overrides: instance-level changes (text, fills, visibility) that differ from the component. Shown in overrides array.\n// variantProperties: when creating from a component set, pick which variant e.g. {"Style":"Secondary","Size":"Large"}.\n// ---\n// Property keys: read returns clean names ("Label"), write requires the #suffix ("Label#1:0"). Call instances.get(id) to discover exact keys before update.\n// swap: change which component an instance points to while preserving compatible overrides.\n// detach: permanently converts an instance to a regular frame, breaking the component link.\n// reset_overrides: reverts all instance overrides to match the main component.\n// Workflow (local components): components.list \u2192 instances.create with componentId + properties (one call).\n// Workflow (external/published libraries): library(method:"components", query:"...") \u2192 instances.create with componentName + properties. The MCP resolves componentName \u2192 key and imports via figma.importComponentByKeyAsync \u2014 the raw key never enters agent context.\n// Instances support frame-level overrides: layoutSizingHorizontal/Vertical (FIXED, FILL, HUG), opacity, width/height, min/max.\n// Use layoutSizingHorizontal: "FILL" to make instances stretch in auto-layout parents.\n\nUse instances(method: "help", topic: "<method>") for method details.',
873
+ "summary": '# instances\nCreate and manage component instances.\n\nMethods:\n list Search for nodes (returns stubs only \u2014 use get with depth for full properties) [read]\n delete Delete nodes [edit]\n clone Duplicate nodes \u2014 produces a same-type copy (frame\u2192frame, instance\u2192instance, component\u2192component). Instance clones reference the same source component; they do not duplicate the component definition. [create]\n scale Proportionally rescale a node subtree using Figma\'s visual Scale tool behavior. This is for visual/artifact scaling, not responsive layout resizing. [edit]\n audit Run lint on a node \u2014 returns severity-ranked findings [read]\n reparent Move nodes into a new parent [edit]\n get Get instance detail with component properties and overrides [read]\n create Create component instances [create]\n update Set instance properties [edit]\n swap Swap instance component (preserves overrides) [edit]\n detach Detach instances from their component (converts to frame) [edit]\n reset_overrides Reset all overrides on instances to match their main component [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// clipsContent: clip children to the node bounds where supported (frames/components/instances). Set false for overflow-visible layouts.\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[]; // readback Paint[]; authoring supports SOLID + gradients via gradientTransform + gradientStops\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. Paint[] authoring supports SOLID + gradients only; IMAGE/VIDEO/PATTERN are readback-only metadata.\n// Unknown keys produce a warning, preventing silent failures.\n// Instances are linked copies of components. Changes to the component propagate to all instances.\n// Overrides: instance-level changes (text, fills, visibility) that differ from the component. Shown in overrides array.\n// variantProperties: when creating from a component set, pick which variant e.g. {"Style":"Secondary","Size":"Large"}.\n// ---\n// Property keys: read returns clean names ("Label"), write requires the #suffix ("Label#1:0"). Call instances.get(id) to discover exact keys before update.\n// swap: change which component an instance points to while preserving compatible overrides.\n// detach: permanently converts an instance to a regular frame, breaking the component link.\n// reset_overrides: reverts all instance overrides to match the main component.\n// Workflow (local components): components.list \u2192 instances.create with componentId + properties (one call).\n// Workflow (external/published libraries): library(method:"components", query:"...") \u2192 instances.create with componentName + properties. The MCP resolves componentName \u2192 key and imports via figma.importComponentByKeyAsync \u2014 the raw key never enters agent context.\n// Instances support frame-level overrides: layoutSizingHorizontal/Vertical (FIXED, FILL, HUG), opacity, width/height, min/max.\n// Use layoutSizingHorizontal: "FILL" to make instances stretch in auto-layout parents.\n\nUse instances(method: "help", topic: "<method>") for method details.\n// Shared types:\n// Color: hex "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}\n// VariableAlias: {type: "VARIABLE_ALIAS", id: string}. The id must be a Figma VariableID; discover it via variables.get/list or variable_collections.get. Prefer colorVariableName/fillVariableName/strokeVariableName when available; Paint[] VariableAlias is mainly for precise Paint[] round-trips and gradient stop bindings.\n// Transform: [[number, number, number], [number, number, number]] (Figma Plugin API 2\xD73 matrix)\n// 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"\n// ColorStop: {position: 0-1, color: Color, boundVariables?: {color?: VariableAlias}}\n// GradientPaint: {type: "GRADIENT_LINEAR"|"GRADIENT_RADIAL"|"GRADIENT_ANGULAR"|"GRADIENT_DIAMOND", gradientTransform: Transform, gradientStops: ColorStop[], visible?: boolean, opacity?: number, blendMode?: BlendMode}. Use gradientTransform + gradientStops (basic left-to-right: [[1,0,0],[0,1,0]]); do not use CSS gradients or REST gradientHandlePositions.\n// Effect: {type: "DROP_SHADOW"|"INNER_SHADOW"|"LAYER_BLUR"|"BACKGROUND_BLUR", radius: number, color?: {r,g,b,a} (0-1), offset?: {x, y}, spread?: number, visible?: boolean}\n// Paint: Paint[] authoring accepts only SOLID and GRADIENT_LINEAR/GRADIENT_RADIAL/GRADIENT_ANGULAR/GRADIENT_DIAMOND. SolidPaint: {type: "SOLID", color: Color, visible?: boolean, opacity?: number, blendMode?: BlendMode, boundVariables?: {color?: VariableAlias}}. GradientPaint authoring: {type: GRADIENT_*, gradientTransform: Transform, gradientStops: ColorStop[], visible?, opacity?, blendMode?}; bind variables on gradientStops[].boundVariables.color, not top-level gradient boundVariables. Do not pass IMAGE/VIDEO/PATTERN to create/update Paint[]; those may appear only in readback metadata from existing Figma content. Use imageUrl/images for image authoring. VIDEO/PATTERN authoring is not supported here. Do not use CSS gradients or REST gradientHandlePositions.\n// NodeStub: {id: string, name: string, type: string}',
738
874
  "methods": {
739
- "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)',
740
- "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)",
741
- "clone": "# instances.clone\nDuplicate nodes \u2014 produces a same-type copy (frame\u2192frame, instance\u2192instance, component\u2192component). Instance clones reference the same source component; they do not duplicate the component definition.\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.",
875
+ "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)\n\nResponse:\n Paginated node search results (uses `results` not `items`)\n totalCount (number, required) \u2014 Total matching nodes\n returned (number, required) \u2014 Nodes in this page\n offset (number, optional)\n limit (number, optional)\n results (array, required) \u2014 Matching node stubs\n id (string, required)\n name (string, required)\n type (string, required)\n parentId (string, required)\n parentName (string, optional)\n bounds (object, optional)',
876
+ "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)\n\nResponse:\n { results: ("ok" | {error})[] }',
877
+ "clone": "# instances.clone\nDuplicate nodes \u2014 produces a same-type copy (frame\u2192frame, instance\u2192instance, component\u2192component). Instance clones reference the same source component; they do not duplicate the component definition.\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.\n\nResponse:\n { results: ({id} | {error})[] }",
878
+ "scale": `# instances.scale
879
+ Proportionally rescale a node subtree using Figma's visual Scale tool behavior. This is for visual/artifact scaling, not responsive layout resizing.
880
+
881
+ Example: instances(method:"scale", id:"1:23", factor:0.5)
882
+
883
+ Params:
884
+ id (string, optional) \u2014 Node ID to scale
885
+ factor (number, optional) \u2014 Scale factor, >= 0.01. 0.5 = 50%, 2 = 200%. Scales children, text, strokes, effects, and layout geometry from the node's top-left. On auto-layout or HUG/FILL nodes, Figma may resolve responsive sizing to fixed width/height.
886
+ items (array, optional) \u2014 Batch: [{id, factor}, ...]. Alternative to single-item params.
887
+ id (string, required) \u2014 Node ID to scale
888
+ factor (number, required) \u2014 Scale factor, >= 0.01. 0.5 = 50%, 2 = 200%.
889
+
890
+ Response:
891
+ { results: ("ok" | {error})[] }`,
742
892
  "audit": `# instances.audit
743
893
  Run lint on a node \u2014 returns severity-ranked findings
744
894
 
@@ -748,13 +898,18 @@ Params:
748
898
  maxDepth (number, optional) \u2014 Max tree depth (default: 10)
749
899
  maxFindings (number, optional) \u2014 Max findings (default: 50)
750
900
  minSeverity (error | unsafe | heuristic | style | verbose, optional) \u2014 Minimum severity to report (default: style). Set to 'verbose' to include AAA contrast and line-height checks.
751
- skipInstances (boolean, optional) \u2014 Skip instance internals \u2014 findings inside instances are owned by the component (default: true)`,
752
- "reparent": "# instances.reparent\nMove nodes into a new parent\n\nParams:\n items (array, required) \u2014 Array of {id, parentId, index?}\n id (string, required)\n parentId (string, required)\n index (number, optional)",
753
- "get": '# instances.get\nGet instance detail with component properties and overrides\n\nParams:\n id (string, required) \u2014 Instance 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.',
901
+ skipInstances (boolean, optional) \u2014 Skip instance internals \u2014 findings inside instances are owned by the component (default: true)
902
+
903
+ Response:
904
+ nodeId (string, optional)
905
+ nodeName (string, optional)
906
+ categories (array, optional) \u2014 Sorted by severity (error > unsafe > heuristic > style)`,
907
+ "reparent": '# instances.reparent\nMove nodes into a new parent\n\nParams:\n items (array, required) \u2014 Array of {id, parentId, index?}\n id (string, required)\n parentId (string, required)\n index (number, optional)\n\nResponse:\n { results: ("ok" | {error})[] }',
908
+ "get": '# instances.get\nGet instance detail with component properties and overrides\n\nParams:\n id (string, required) \u2014 Instance 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.\n\nResponse:\n results (array, required) \u2014 Serialized node(s) with componentProperties, overrides\n _truncated (boolean, optional)',
754
909
  "create": `# instances.create
755
910
  Create component instances
756
911
 
757
- Example: instances(method:"create", items:[{componentName:"Button", variantProperties:{"Size":"Large"}, properties:{"Label":"Click me"}, parentId:"2:45", layoutSizingHorizontal:"FILL"}]) // or componentId:"1:23" for a local component
912
+ Example: instances(method:"create", items:[{componentId:"1:23", variantProperties:{"Style":"Primary"}, properties:{"Button":"Click me"}, x:320, y:0}])
758
913
 
759
914
  Params:
760
915
  items (InstanceCreateItem[], required) \u2014 Array of {componentId, variantProperties?, x?, y?, parentId?, layoutSizingHorizontal?, ...}
@@ -783,19 +938,25 @@ Params:
783
938
  height (number, optional) \u2014 Override height (resize)
784
939
  explicitMode (object, optional) \u2014 Pin variable mode at creation \u2014 use { collectionName, modeName } (preferred) or { collectionId, modeId }. Useful for library components with Light/Dark modes.
785
940
  parentId (string, optional) \u2014 Parent node ID. Omit to place at current page root.
786
- depth (number, optional) \u2014 Response detail: omit for id+name only. 0=properties + child stubs. N=recurse N levels. -1=unlimited.`,
941
+ depth (number, optional) \u2014 Response detail: omit for id+name only. 0=properties + child stubs. N=recurse N levels. -1=unlimited.
942
+
943
+ Response:
944
+ { results: ({id} | {error})[] }
945
+ // Shared types:
946
+ // Color: hex "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}
947
+ // Effect: {type: "DROP_SHADOW"|"INNER_SHADOW"|"LAYER_BLUR"|"BACKGROUND_BLUR", radius: number, color?: {r,g,b,a} (0-1), offset?: {x, y}, spread?: number, visible?: boolean}`,
787
948
  "update": `# instances.update
788
949
  Set instance properties
789
950
 
790
- Example: instances(method:"update", items:[{id:"1:23", properties:{"Label#4:0":"Submit"}, fillColor:"#3B82F6", layoutSizingHorizontal:"FILL"}])
951
+ Example: instances(method:"update", items:[{id:"1:23", properties:{"Button#4:0":"Submit"}, fillVariableName:"bg/accent"}])
791
952
 
792
953
  Params:
793
- items (InstanceUpdateItem[], required) \u2014 Array of {id, properties: {"Label#1:0":"text"}, fillColor?: ...}
794
- fills (array, optional) \u2014 Fill paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] for transparent. Primary way to set fills.
954
+ items (InstanceUpdateItem[], required) \u2014 Array of {id, properties: {"Property#1:0":"text"}, fillVariableName?: ...}. Use components.get on the source component to discover exact property keys.
955
+ fills (Paint[], optional) \u2014 Fill Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] for transparent. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables; use imageUrl/images for image authoring. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set non-image fills.
795
956
  fillColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)
796
957
  fillStyleName (string, optional) \u2014 Paint style name for fill
797
- fillVariableName (string, optional) \u2014 Color variable by name e.g. 'bg/primary'
798
- strokes (array, optional) \u2014 Stroke paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] to clear. Primary way to set strokes.
958
+ fillVariableName (string, optional) \u2014 Color variable by name e.g. 'bg/surface'
959
+ strokes (Paint[], optional) \u2014 Stroke Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] to clear. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set strokes.
799
960
  strokeColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)
800
961
  strokeStyleName (string, optional) \u2014 Paint style name for stroke
801
962
  strokeVariableName (string, optional) \u2014 Color variable by name for stroke
@@ -867,10 +1028,22 @@ Params:
867
1028
  variableName (string, optional)
868
1029
  variableId (string, optional)
869
1030
  explicitMode (object, optional) \u2014 Pin variable mode \u2014 use { collectionName, modeName } (preferred) or { collectionId, modeId }
870
- exportSettings (array, optional) \u2014 Export settings`,
871
- "swap": "# instances.swap\nSwap instance component (preserves overrides)\n\nParams:\n items (array, required) \u2014 Array of {id, componentId}\n id (string, required) \u2014 Instance node ID\n componentId (string, required) \u2014 New component or component set ID",
872
- "detach": "# instances.detach\nDetach instances from their component (converts to frame)\n\nParams:\n items (array, required) \u2014 Array of {id}\n id (string, required) \u2014 Instance node ID",
873
- "reset_overrides": "# instances.reset_overrides\nReset all overrides on instances to match their main component\n\nParams:\n items (array, required) \u2014 Array of {id}\n id (string, required) \u2014 Instance node ID"
1031
+ exportSettings (array, optional) \u2014 Export settings
1032
+
1033
+ Response:
1034
+ { results: ("ok" | {error} | object)[] }
1035
+ // Shared types:
1036
+ // Color: hex "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}
1037
+ // VariableAlias: {type: "VARIABLE_ALIAS", id: string}. The id must be a Figma VariableID; discover it via variables.get/list or variable_collections.get. Prefer colorVariableName/fillVariableName/strokeVariableName when available; Paint[] VariableAlias is mainly for precise Paint[] round-trips and gradient stop bindings.
1038
+ // Transform: [[number, number, number], [number, number, number]] (Figma Plugin API 2\xD73 matrix)
1039
+ // 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"
1040
+ // ColorStop: {position: 0-1, color: Color, boundVariables?: {color?: VariableAlias}}
1041
+ // GradientPaint: {type: "GRADIENT_LINEAR"|"GRADIENT_RADIAL"|"GRADIENT_ANGULAR"|"GRADIENT_DIAMOND", gradientTransform: Transform, gradientStops: ColorStop[], visible?: boolean, opacity?: number, blendMode?: BlendMode}. Use gradientTransform + gradientStops (basic left-to-right: [[1,0,0],[0,1,0]]); do not use CSS gradients or REST gradientHandlePositions.
1042
+ // Effect: {type: "DROP_SHADOW"|"INNER_SHADOW"|"LAYER_BLUR"|"BACKGROUND_BLUR", radius: number, color?: {r,g,b,a} (0-1), offset?: {x, y}, spread?: number, visible?: boolean}
1043
+ // Paint: Paint[] authoring accepts only SOLID and GRADIENT_LINEAR/GRADIENT_RADIAL/GRADIENT_ANGULAR/GRADIENT_DIAMOND. SolidPaint: {type: "SOLID", color: Color, visible?: boolean, opacity?: number, blendMode?: BlendMode, boundVariables?: {color?: VariableAlias}}. GradientPaint authoring: {type: GRADIENT_*, gradientTransform: Transform, gradientStops: ColorStop[], visible?, opacity?, blendMode?}; bind variables on gradientStops[].boundVariables.color, not top-level gradient boundVariables. Do not pass IMAGE/VIDEO/PATTERN to create/update Paint[]; those may appear only in readback metadata from existing Figma content. Use imageUrl/images for image authoring. VIDEO/PATTERN authoring is not supported here. Do not use CSS gradients or REST gradientHandlePositions.`,
1044
+ "swap": '# instances.swap\nSwap instance component (preserves overrides)\n\nParams:\n items (array, required) \u2014 Array of {id, componentId}\n id (string, required) \u2014 Instance node ID\n componentId (string, required) \u2014 New component or component set ID\n\nResponse:\n { results: ("ok" | {error} | object)[] }',
1045
+ "detach": "# instances.detach\nDetach instances from their component (converts to frame)\n\nParams:\n items (array, required) \u2014 Array of {id}\n id (string, required) \u2014 Instance node ID\n\nResponse:\n { results: ({id} | {error})[] }",
1046
+ "reset_overrides": '# instances.reset_overrides\nReset all overrides on instances to match their main component\n\nParams:\n items (array, required) \u2014 Array of {id}\n id (string, required) \u2014 Instance node ID\n\nResponse:\n { results: ("ok" | {error} | object)[] }'
874
1047
  }
875
1048
  },
876
1049
  "library": {
@@ -920,7 +1093,16 @@ Example: library(method:"list") // uses FIGMA_TEAM_ID env var; or pass file/tea
920
1093
 
921
1094
  Params:
922
1095
  file (string, optional) \u2014 File URL or file key \u2014 e.g. 'https://www.figma.com/design/abc123/MyDS' or 'abc123'
923
- team (string, optional) \u2014 Team URL or team ID. Falls back to FIGMA_TEAM_ID env var if omitted.`,
1096
+ team (string, optional) \u2014 Team URL or team ID. Falls back to FIGMA_TEAM_ID env var if omitted.
1097
+
1098
+ Response:
1099
+ libraries (array, optional) \u2014 Components, sets, and styles grouped by source Figma file (library) and then by section \u2014 the same hierarchy designers see in Figma's Libraries browser. Use the library name to pick the intended kit when multiple libraries expose overlapping names (e.g. two files both defining 'Item' or 'Header'), and use section names to locate components semantically (e.g. the 'Sidebars' section contains the proper sidebar Item and Section Header, distinct from a List 'Item' row).
1100
+ name (string, optional) \u2014 Display name of the source Figma file.
1101
+ sections (array, optional) \u2014 Sections within the library, mirroring the headings designers see in Figma's Libraries panel. Usually correspond to containing frames or pages in the source file.
1102
+ name (string, optional) \u2014 Section heading \u2014 e.g. 'Sidebars', 'Windows', 'Buttons'. '(unsectioned)' when the source component is not inside a named frame.
1103
+ components (array, optional) \u2014 Non-variant component names in this section. Reference by name in instances.create via componentName.
1104
+ componentSets (array, optional) \u2014 Variant set names in this section. Use with variantProperties in instances.create.
1105
+ styles (object, optional) \u2014 Published styles in this section, grouped by type.`,
924
1106
  "get": `# library.get
925
1107
  Get rich details for components matching one or more queries. Returns nested libraries \u2192 sections \u2192 entries (same hierarchy as list) with properties, variant options, defaults, and a copy-pasteable usage hint at each leaf.
926
1108
 
@@ -931,7 +1113,16 @@ Params:
931
1113
  library (string, optional) \u2014 Optional source library (Figma file) name filter \u2014 case-insensitive substring. Use when multiple imported libraries expose overlapping component names (e.g. two files both defining 'Item'). Match the name returned under list \u2192 libraries[].name.
932
1114
  section (string, optional) \u2014 Optional section name filter \u2014 case-insensitive substring. Matches the containing frame / section headers returned under list \u2192 libraries[].sections[].name (e.g. 'Sidebars', 'Windows', 'List'). Combine with library for maximum precision.
933
1115
  file (string, optional) \u2014 Only used if the registry is empty \u2014 convenience to run list+get in one step.
934
- team (string, optional) \u2014 Only used if the registry is empty \u2014 convenience to run list+get in one step.`
1116
+ team (string, optional) \u2014 Only used if the registry is empty \u2014 convenience to run list+get in one step.
1117
+
1118
+ Response:
1119
+ libraries (array, optional) \u2014 Matching entries nested by source library and section \u2014 same hierarchy as list, but each leaf is a full detail object (properties, variant options, defaults, usage hint) instead of a bare name.
1120
+ name (string, optional) \u2014 Source Figma file name.
1121
+ sections (array, optional)
1122
+ name (string, optional) \u2014 Section heading (containing frame). '(unsectioned)' when absent.
1123
+ components (array, optional) \u2014 Non-variant components in this section with full detail. Each entry: { name, kind, description?, properties?, usage? } \u2014 properties is { [propName]: { type: VARIANT|TEXT|BOOLEAN|INSTANCE_SWAP, defaultValue?, options? } } matching components.get. usage is a copy-pasteable instances.create snippet.
1124
+ componentSets (array, optional) \u2014 Variant component sets in this section with full detail, same shape as components above. VARIANT properties carry options; pair with TEXT/BOOLEAN properties via instances.create.
1125
+ styles (object, optional) \u2014 Published styles in this section, grouped by type. Each entry: { name, kind: 'style', styleType, description? } (no properties/usage \u2014 styles have no variants).`
935
1126
  }
936
1127
  },
937
1128
  "lint": {
@@ -970,6 +1161,7 @@ Methods:
970
1161
  // "shape-instead-of-frame" \u2014 shapes used as containers [style]
971
1162
  // "fixed-in-autolayout" \u2014 FIXED-size children in auto-layout parents [heuristic]
972
1163
  // "unbounded-hug" \u2014 HUG on both axes [unsafe; short leaf text\u2192style]
1164
+ // "fill-in-hug" \u2014 collapsed FILL on the same axis inside a HUG parent (existing anchored states may be valid) [unsafe]
973
1165
  // "hug-cross-axis" \u2014 HUG on cross-axis of constrained parent [heuristic; leaf nodes\u2192style]
974
1166
  // "empty-container" \u2014 empty frames, excludes SLOT nodes [style]
975
1167
  // Token rules [token]:
@@ -1003,51 +1195,90 @@ Params:
1003
1195
  maxDepth (number, optional) \u2014 Max tree depth (default: 10)
1004
1196
  maxFindings (number, optional) \u2014 Max findings (default: 50)
1005
1197
  minSeverity (error | unsafe | heuristic | style | verbose, optional) \u2014 Minimum severity to report (default: style). Set to 'verbose' to include AAA contrast and line-height checks.
1006
- skipInstances (boolean, optional) \u2014 Skip instance internals \u2014 findings inside instances are owned by the component (default: true)`,
1007
- "fix": "# lint.fix\nAuto-fix frames to auto-layout\n\nParams:\n items (array, required) \u2014 Array of {nodeId, layoutMode?, itemSpacing?}\n nodeId (string, required) \u2014 Frame node ID\n layoutMode (VERTICAL | HORIZONTAL, optional) \u2014 Direction (default: auto-detected)\n itemSpacing (number, optional) \u2014 Spacing between children\n depth (number, optional) \u2014 Response detail for fixed nodes: omit for stubs, 0=properties, -1=full tree"
1198
+ skipInstances (boolean, optional) \u2014 Skip instance internals \u2014 findings inside instances are owned by the component (default: true)
1199
+
1200
+ Response:
1201
+ nodeId (string, required)
1202
+ nodeName (string, required)
1203
+ categories (array, required) \u2014 Sorted by severity (error > unsafe > heuristic > style)
1204
+ rule (string, required)
1205
+ severity (string, required) \u2014 error | unsafe | heuristic | style
1206
+ category (string, required) \u2014 component | composition | token | accessibility | naming
1207
+ count (number, required)
1208
+ fix (string, required)
1209
+ nodes (array, required)
1210
+ id (string, required)
1211
+ name (string, required)
1212
+ severity (string, optional) \u2014 Per-finding override when context changes the default
1213
+ warning (string, optional)`,
1214
+ "fix": '# lint.fix\nAuto-fix frames to auto-layout\n\nParams:\n items (array, required) \u2014 Array of {nodeId, layoutMode?, itemSpacing?}\n nodeId (string, required) \u2014 Frame node ID\n layoutMode (VERTICAL | HORIZONTAL, optional) \u2014 Direction (default: auto-detected)\n itemSpacing (number, optional) \u2014 Spacing between children\n depth (number, optional) \u2014 Response detail for fixed nodes: omit for stubs, 0=properties, -1=full tree\n\nResponse:\n { results: ("ok" | {error} | object)[] }'
1008
1215
  }
1009
1216
  },
1010
1217
  "prototyping": {
1011
1218
  "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.',
1012
1219
  "methods": {
1013
- "get": "# prototyping.get\nGet reactions and overflow direction on a node\n\nParams:\n id (string, required) \u2014 Node ID",
1014
- "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)',
1015
- "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}]}]",
1016
- "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)"
1220
+ "get": "# prototyping.get\nGet reactions and overflow direction on a node\n\nParams:\n id (string, required) \u2014 Node ID\n\nResponse:\n reactions (array, optional) \u2014 Reactions on this node\n overflowDirection (string, optional) \u2014 Overflow scroll direction (NONE, HORIZONTAL, VERTICAL, BOTH)",
1221
+ "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)\n\nResponse:\n { results: ("ok" | {error})[] }',
1222
+ "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}]}]\n\nResponse:\n { results: ("ok" | {error})[] }',
1223
+ "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)\n\nResponse:\n { results: ("ok" | {error})[] }'
1017
1224
  }
1018
1225
  },
1019
1226
  "selection": {
1020
1227
  "summary": '# selection\nRead and set the current Figma selection.\n\nMethods:\n get Get the current selection [read]\n set Set selection to nodes and scroll viewport to show them [read]\n\n// Selection is the set of nodes currently highlighted in the Figma canvas.\n// get returns the current selection. Without depth, returns stubs ({id, name, type}). With depth=0, returns full properties.\n// _truncated: true when the response was cut short due to node budget limits. Use depth=0 or specific fields to reduce payload.\n// set replaces the entire selection AND scrolls the viewport to show the selected nodes.\n\nUse selection(method: "help", topic: "<method>") for method details.',
1021
1228
  "methods": {
1022
- "get": "# selection.get\nGet the current selection\n\nParams:\n depth (number, optional) \u2014 Child recursion depth. Omit for stubs only, 0=selected nodes' properties, -1=unlimited.\n verbose (boolean, optional) \u2014 Include all properties (bounding box, constraints, text style details). Default false \u2014 returns slim, actionable output.",
1023
- "set": '# selection.set\nSet selection to nodes and scroll viewport to show them\n\nParams:\n nodeIds (string[], required) \u2014 Array of node IDs to select. Example: ["1:2","1:3"]'
1229
+ "get": "# selection.get\nGet the current selection\n\nParams:\n depth (number, optional) \u2014 Child recursion depth. Omit for stubs only, 0=selected nodes' properties, -1=unlimited.\n verbose (boolean, optional) \u2014 Include all properties (bounding box, constraints, text style details). Default false \u2014 returns slim, actionable output.\n\nResponse:\n results (array, required)\n id (string, required)\n name (string, required)\n type (string, required)\n _truncated (boolean, optional)\n _notice (string, optional)",
1230
+ "set": '# selection.set\nSet selection to nodes and scroll viewport to show them\n\nParams:\n nodeIds (string[], required) \u2014 Array of node IDs to select. Example: ["1:2","1:3"]\n\nResponse:\n count (number, required) \u2014 Number of nodes selected\n selectedNodes (array, required)\n name (string, required)\n id (string, required)\n notFoundIds (array, optional) \u2014 IDs that could not be found'
1024
1231
  }
1025
1232
  },
1026
1233
  "styles": {
1027
- "summary": '# styles\nCRUD for local paint, text, effect, and grid styles.\n\nMethods:\n list List local styles with optional type filter [read]\n get Get full style detail by ID [read]\n create Create local styles [create]\n update Update styles by ID or name [edit]\n delete Delete styles [edit]\n\n// Styles are named, reusable design properties that can be applied to nodes. Four types:\n// paint: a named color (applied to fills/strokes), text: typography settings, effect: shadows/blurs, grid: layout grids.\n// All ID params accept both IDs and display names (case-insensitive). Use whichever you have.\n// ---\n// leadingTrim: "CAP_HEIGHT" trims line-height to cap height (tighter text boxes), "NONE" is default.\n// fontStyle: font variant name like "Bold", "Italic", "Bold Italic". Use fonts.list to find available styles.\n//\n// Effect object shape (for effect styles):\n// { type: "DROP_SHADOW"|"INNER_SHADOW"|"LAYER_BLUR"|"BACKGROUND_BLUR",\n// color?: Color, offset?: {x, y}, radius: number, spread?: number,\n// visible?: boolean, blendMode?: string }\n// DROP_SHADOW/INNER_SHADOW require color, offset, radius. LAYER_BLUR/BACKGROUND_BLUR require radius only.\n// Example: { type: "DROP_SHADOW", color: "#00000040", offset: {x:0,y:4}, radius: 8 }\n//\n// LayoutGrid object shape (for grid styles):\n// Rows/Columns: { pattern: "ROWS"|"COLUMNS", alignment: "MIN"|"MAX"|"STRETCH"|"CENTER",\n// gutterSize: number, count: number, sectionSize?: number, offset?: number, visible?: boolean, color?: Color }\n// Grid: { pattern: "GRID", sectionSize: number, visible?: boolean, color?: Color }\n// Example: { pattern: "COLUMNS", alignment: "STRETCH", gutterSize: 20, count: 12, offset: 40 }\n\nUse styles(method: "help", topic: "<method>") for method details.',
1234
+ "summary": '# styles\nCRUD for local paint, text, effect, and grid styles.\n\nMethods:\n list List local styles with optional type filter [read]\n get Get full style detail by ID [read]\n create Create local styles [create]\n update Update styles by ID or name [edit]\n delete Delete styles [edit]\n\n// Styles are named, reusable design properties that can be applied to nodes. Four types:\n// paint: named PaintStyle.paints (applied to fills/strokes), text: typography settings, effect: shadows/blurs, grid: layout grids.\n// All ID params accept both IDs and display names (case-insensitive). Use whichever you have.\n// ---\n// leadingTrim: "CAP_HEIGHT" trims line-height to cap height (tighter text boxes), "NONE" is default.\n// fontStyle: font variant name like "Bold", "Italic", "Bold Italic". Use fonts.list to find available styles.\n// Paint styles: create/update paints: Paint[] authoring accepts only SOLID and gradients (GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND).\n// Use gradientTransform + gradientStops; for a basic left-to-right gradient use gradientTransform:[[1,0,0],[0,1,0]]. Do not use CSS gradients, REST gradientHandlePositions, or top-level gradient boundVariables.\n// styles.get/list readback may include IMAGE/VIDEO/PATTERN metadata from existing Figma content, but those are readback-only and cannot be passed back to create/update Paint[] authoring. Use imageUrl/images for image authoring on nodes; VIDEO/PATTERN authoring is not supported here.\n// For VariableAlias ids in Paint[] (SOLID boundVariables.color or gradientStops[].boundVariables.color), inspect variables.get/list or variable_collections.get. Prefer colorVariableName/fillVariableName where available.\n// Backward-compatible color/colorVariableName create/update shorthands still create a single SOLID paint.\n//\n// Effect object shape (for effect styles):\n// { type: "DROP_SHADOW"|"INNER_SHADOW"|"LAYER_BLUR"|"BACKGROUND_BLUR",\n// color?: Color, offset?: {x, y}, radius: number, spread?: number,\n// visible?: boolean, blendMode?: string }\n// DROP_SHADOW/INNER_SHADOW require color, offset, radius. LAYER_BLUR/BACKGROUND_BLUR require radius only.\n// Example: { type: "DROP_SHADOW", color: "#00000040", offset: {x:0,y:4}, radius: 8 }\n//\n// LayoutGrid object shape (for grid styles) follows Figma Plugin API conditional shapes:\n// Grid: { pattern:"GRID", sectionSize:number, visible?:boolean, color?:Color }\n// Rows/Columns: { pattern:"ROWS"|"COLUMNS", alignment?:"MIN"|"MAX"|"STRETCH"|"CENTER", gutterSize?:number, count?:number, offset?:number, sectionSize?:number, visible?:boolean, color?:Color }\n// Important: alignment:"STRETCH" must omit sectionSize because Figma computes stretched row/column sizes. Use sectionSize only with fixed rows/columns (MIN/MAX/CENTER) or GRID.\n// Examples: stretch columns {pattern:"COLUMNS", alignment:"STRETCH", count:12, gutterSize:24, offset:80}; fixed columns {pattern:"COLUMNS", alignment:"MIN", count:12, gutterSize:24, offset:80, sectionSize:72}; square grid {pattern:"GRID", sectionSize:8}.\n\nUse styles(method: "help", topic: "<method>") for method details.\n// Shared types:\n// Color: hex "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}\n// VariableAlias: {type: "VARIABLE_ALIAS", id: string}. The id must be a Figma VariableID; discover it via variables.get/list or variable_collections.get. Prefer colorVariableName/fillVariableName/strokeVariableName when available; Paint[] VariableAlias is mainly for precise Paint[] round-trips and gradient stop bindings.\n// Transform: [[number, number, number], [number, number, number]] (Figma Plugin API 2\xD73 matrix)\n// 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"\n// ColorStop: {position: 0-1, color: Color, boundVariables?: {color?: VariableAlias}}\n// GradientPaint: {type: "GRADIENT_LINEAR"|"GRADIENT_RADIAL"|"GRADIENT_ANGULAR"|"GRADIENT_DIAMOND", gradientTransform: Transform, gradientStops: ColorStop[], visible?: boolean, opacity?: number, blendMode?: BlendMode}. Use gradientTransform + gradientStops (basic left-to-right: [[1,0,0],[0,1,0]]); do not use CSS gradients or REST gradientHandlePositions.\n// Effect: {type: "DROP_SHADOW"|"INNER_SHADOW"|"LAYER_BLUR"|"BACKGROUND_BLUR", radius: number, color?: {r,g,b,a} (0-1), offset?: {x, y}, spread?: number, visible?: boolean}\n// Paint: Paint[] authoring accepts only SOLID and GRADIENT_LINEAR/GRADIENT_RADIAL/GRADIENT_ANGULAR/GRADIENT_DIAMOND. SolidPaint: {type: "SOLID", color: Color, visible?: boolean, opacity?: number, blendMode?: BlendMode, boundVariables?: {color?: VariableAlias}}. GradientPaint authoring: {type: GRADIENT_*, gradientTransform: Transform, gradientStops: ColorStop[], visible?, opacity?, blendMode?}; bind variables on gradientStops[].boundVariables.color, not top-level gradient boundVariables. Do not pass IMAGE/VIDEO/PATTERN to create/update Paint[]; those may appear only in readback metadata from existing Figma content. Use imageUrl/images for image authoring. VIDEO/PATTERN authoring is not supported here. Do not use CSS gradients or REST gradientHandlePositions.\n// LayoutGrid is conditional: GridLayoutGrid {pattern:"GRID", sectionSize:number, visible?:boolean, color?:Color}; RowsColsLayoutGrid {pattern:"ROWS"|"COLUMNS", alignment?:"MIN"|"MAX"|"CENTER"|"STRETCH", gutterSize?:number, count?:number, offset?:number, sectionSize?:number, visible?:boolean, color?:Color}. For alignment:"STRETCH", omit sectionSize; Figma computes stretched row/column sizes. Use sectionSize only with fixed rows/columns (MIN/MAX/CENTER) or GRID.',
1028
1235
  "methods": {
1029
- "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)',
1030
- "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.',
1031
- "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',
1032
- "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)',
1033
- "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"
1236
+ "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)\n\nResponse:\n totalCount (number, required)\n returned (number, optional)\n offset (number, optional)\n limit (number, optional)\n items (array, required)\n id (string, required)\n name (string, required)\n type (string, required)',
1237
+ "get": `# styles.get
1238
+ Get full style detail by ID
1239
+
1240
+ Params:
1241
+ id (string, required) \u2014 Style ID or name
1242
+ fields (string[], optional) \u2014 Property whitelist. Identity fields (id, name, type) always included. Omit for stubs on list, full on get. Pass ["*"] for all.
1243
+
1244
+ Response:
1245
+ id (string, required)
1246
+ name (string, required)
1247
+ type (string, required) \u2014 PAINT | TEXT | EFFECT | GRID
1248
+ paints (Paint[], optional) \u2014 PaintStyle.paints for PAINT styles. Readback returns Figma Plugin API Paint[]; gradients include gradientTransform, gradientStops, opacity/blendMode, and stop boundVariables. Existing Figma content may return IMAGE/VIDEO/PATTERN metadata, but those are readback-only and cannot be passed to create/update Paint[] authoring, which accepts only SOLID and gradients.
1249
+ boundVariables (object, optional) \u2014 PaintStyle.boundVariables, e.g. {paints:[{type:'VARIABLE_ALIAS', id:'...'}]}
1250
+ fontFamily (string, optional) \u2014 Font family (TEXT styles)
1251
+ fontSize (number, optional) \u2014 Font size (TEXT styles)
1252
+ effects (array, optional) \u2014 Effects array (EFFECT styles)
1253
+ layoutGrids (array, optional) \u2014 Layout grids (GRID styles)
1254
+ // Shared types:
1255
+ // Color: hex "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}
1256
+ // VariableAlias: {type: "VARIABLE_ALIAS", id: string}. The id must be a Figma VariableID; discover it via variables.get/list or variable_collections.get. Prefer colorVariableName/fillVariableName/strokeVariableName when available; Paint[] VariableAlias is mainly for precise Paint[] round-trips and gradient stop bindings.
1257
+ // Transform: [[number, number, number], [number, number, number]] (Figma Plugin API 2\xD73 matrix)
1258
+ // 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"
1259
+ // ColorStop: {position: 0-1, color: Color, boundVariables?: {color?: VariableAlias}}
1260
+ // GradientPaint: {type: "GRADIENT_LINEAR"|"GRADIENT_RADIAL"|"GRADIENT_ANGULAR"|"GRADIENT_DIAMOND", gradientTransform: Transform, gradientStops: ColorStop[], visible?: boolean, opacity?: number, blendMode?: BlendMode}. Use gradientTransform + gradientStops (basic left-to-right: [[1,0,0],[0,1,0]]); do not use CSS gradients or REST gradientHandlePositions.
1261
+ // Paint: Paint[] authoring accepts only SOLID and GRADIENT_LINEAR/GRADIENT_RADIAL/GRADIENT_ANGULAR/GRADIENT_DIAMOND. SolidPaint: {type: "SOLID", color: Color, visible?: boolean, opacity?: number, blendMode?: BlendMode, boundVariables?: {color?: VariableAlias}}. GradientPaint authoring: {type: GRADIENT_*, gradientTransform: Transform, gradientStops: ColorStop[], visible?, opacity?, blendMode?}; bind variables on gradientStops[].boundVariables.color, not top-level gradient boundVariables. Do not pass IMAGE/VIDEO/PATTERN to create/update Paint[]; those may appear only in readback metadata from existing Figma content. Use imageUrl/images for image authoring. VIDEO/PATTERN authoring is not supported here. Do not use CSS gradients or REST gradientHandlePositions.`,
1262
+ "create": '# styles.create\nCreate local styles\n\nExample: styles(method:"create", type:"paint", items:[{name:"Gradient/Primary", paints:[{type:"GRADIENT_LINEAR", gradientTransform:[[1,0,0],[0,1,0]], gradientStops:[{position:0,color:"#7D58ED"},{position:1,color:"#207CE5"}]}]}])\n\nCall shape: styles(method:"create", type:"<type>", items:[{...type-specific fields...}])\nDo not pass type-specific item fields at the top level; put them inside items[].\n\nDiscriminant: type (paint | text | effect | grid)\nTop-level params:\n type (paint | text | effect | grid, required) \u2014 Selects which item shape to use\n items (array, required) \u2014 One or more type-specific item objects\n\n ## paint \u2014 Paint/color style\n Example: styles(method:"create", type:"paint", items:[{name:"Surface/Primary", colorVariableName:"bg/surface"}])\n Item fields for items[] when type:"paint":\n name (string, required) \u2014 Style name\n paints (Paint[], optional) \u2014 PaintStyle.paints authoring array. Accepts only SOLID and GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND, using gradientTransform + gradientStops, opacity/blendMode, and gradientStops[].boundVariables.color. Mutually exclusive with color/colorVariableName shorthands. Do not pass IMAGE/VIDEO/PATTERN, CSS gradients, REST gradientHandlePositions, or top-level gradient boundVariables. Use imageUrl/images for image authoring on nodes; VIDEO/PATTERN authoring is not supported here. For examples call styles(method:"help", topic:"create").\n color (Color, optional) \u2014 Single-solid shorthand color. Optional when colorVariableName or paints is provided.\n colorVariableName (string, optional) \u2014 Single-solid shorthand: 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 Example: styles(method:"create", type:"text", items:[{name:"Heading/Medium", fontFamily:"Inter", fontStyle:"Medium", fontSize:20, lineHeight:{value:28, unit:"PIXELS"}}, {name:"Body/Regular", fontFamily:"Inter", fontSize:14, lineHeight:{value:20, unit:"PIXELS"}}, {name:"Body/Medium", fontFamily:"Inter", fontStyle:"Medium", fontSize:14, lineHeight:{value:20, unit:"PIXELS"}}])\n Item fields for items[] when type:"text":\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 Example: styles(method:"create", type:"effect", items:[{name:"Shadow/Medium", effects:[{type:"DROP_SHADOW", color:"#00000040", offset:{x:0,y:4}, radius:8}]}])\n Item fields for items[] when type:"effect":\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 Example: styles(method:"create", type:"grid", items:[{name:"Grid/Desktop 12", layoutGrids:[{pattern:"COLUMNS", alignment:"STRETCH", count:12, gutterSize:24, offset:80}]}])\n Item fields for items[] when type:"grid":\n name (string, required) \u2014 Style name\n layoutGrids (array, required) \u2014 Array of LayoutGrid objects. Conditional shapes: GRID requires sectionSize and does not use alignment/count/gutterSize/offset; ROWS/COLUMNS use alignment/count/gutterSize/offset, and sectionSize only for fixed alignments MIN/MAX/CENTER. For alignment:STRETCH, omit sectionSize.\n description (string, optional) \u2014 Style description\n\nResponse:\n { results: ({id} | {error})[] }\n// Shared types:\n// Color: hex "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}\n// VariableAlias: {type: "VARIABLE_ALIAS", id: string}. The id must be a Figma VariableID; discover it via variables.get/list or variable_collections.get. Prefer colorVariableName/fillVariableName/strokeVariableName when available; Paint[] VariableAlias is mainly for precise Paint[] round-trips and gradient stop bindings.\n// Transform: [[number, number, number], [number, number, number]] (Figma Plugin API 2\xD73 matrix)\n// 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"\n// ColorStop: {position: 0-1, color: Color, boundVariables?: {color?: VariableAlias}}\n// GradientPaint: {type: "GRADIENT_LINEAR"|"GRADIENT_RADIAL"|"GRADIENT_ANGULAR"|"GRADIENT_DIAMOND", gradientTransform: Transform, gradientStops: ColorStop[], visible?: boolean, opacity?: number, blendMode?: BlendMode}. Use gradientTransform + gradientStops (basic left-to-right: [[1,0,0],[0,1,0]]); do not use CSS gradients or REST gradientHandlePositions.\n// Effect: {type: "DROP_SHADOW"|"INNER_SHADOW"|"LAYER_BLUR"|"BACKGROUND_BLUR", radius: number, color?: {r,g,b,a} (0-1), offset?: {x, y}, spread?: number, visible?: boolean}\n// Paint: Paint[] authoring accepts only SOLID and GRADIENT_LINEAR/GRADIENT_RADIAL/GRADIENT_ANGULAR/GRADIENT_DIAMOND. SolidPaint: {type: "SOLID", color: Color, visible?: boolean, opacity?: number, blendMode?: BlendMode, boundVariables?: {color?: VariableAlias}}. GradientPaint authoring: {type: GRADIENT_*, gradientTransform: Transform, gradientStops: ColorStop[], visible?, opacity?, blendMode?}; bind variables on gradientStops[].boundVariables.color, not top-level gradient boundVariables. Do not pass IMAGE/VIDEO/PATTERN to create/update Paint[]; those may appear only in readback metadata from existing Figma content. Use imageUrl/images for image authoring. VIDEO/PATTERN authoring is not supported here. Do not use CSS gradients or REST gradientHandlePositions.\n// LayoutGrid is conditional: GridLayoutGrid {pattern:"GRID", sectionSize:number, visible?:boolean, color?:Color}; RowsColsLayoutGrid {pattern:"ROWS"|"COLUMNS", alignment?:"MIN"|"MAX"|"CENTER"|"STRETCH", gutterSize?:number, count?:number, offset?:number, sectionSize?:number, visible?:boolean, color?:Color}. For alignment:"STRETCH", omit sectionSize; Figma computes stretched row/column sizes. Use sectionSize only with fixed rows/columns (MIN/MAX/CENTER) or GRID.',
1263
+ "update": '# styles.update\nUpdate styles by ID or name\n\nExample: styles(method:"update", items:[{id:"Gradient/Primary", paints:[{type:"GRADIENT_LINEAR", gradientTransform:[[1,0,0],[0,1,0]], gradientStops:[{position:0,color:"#7D58ED"},{position:1,color:"#207CE5"}]}]}])\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 paints (Paint[], optional) \u2014 Replace PaintStyle.paints. Accepts only SOLID and GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND, using gradientTransform + gradientStops, opacity/blendMode, and gradientStops[].boundVariables.color. Mutually exclusive with color/colorVariableName. Do not pass IMAGE/VIDEO/PATTERN, CSS gradients, REST gradientHandlePositions, or top-level gradient boundVariables. Use imageUrl/images for image authoring on nodes; VIDEO/PATTERN authoring is not supported here. For examples call styles(method:"help", topic:"update").\n color (Color, optional) \u2014 New single-solid color shorthand (paint styles)\n colorVariableName (string, optional) \u2014 Bind to a COLOR variable by name using single-solid shorthand (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). Conditional shapes: GRID requires sectionSize and does not use alignment/count/gutterSize/offset; ROWS/COLUMNS use alignment/count/gutterSize/offset, and sectionSize only for fixed alignments MIN/MAX/CENTER. For alignment:STRETCH, omit sectionSize.\n\nResponse:\n { results: ("ok" | {error} | object)[] }\n// Shared types:\n// Color: hex "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}\n// VariableAlias: {type: "VARIABLE_ALIAS", id: string}. The id must be a Figma VariableID; discover it via variables.get/list or variable_collections.get. Prefer colorVariableName/fillVariableName/strokeVariableName when available; Paint[] VariableAlias is mainly for precise Paint[] round-trips and gradient stop bindings.\n// Transform: [[number, number, number], [number, number, number]] (Figma Plugin API 2\xD73 matrix)\n// 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"\n// ColorStop: {position: 0-1, color: Color, boundVariables?: {color?: VariableAlias}}\n// GradientPaint: {type: "GRADIENT_LINEAR"|"GRADIENT_RADIAL"|"GRADIENT_ANGULAR"|"GRADIENT_DIAMOND", gradientTransform: Transform, gradientStops: ColorStop[], visible?: boolean, opacity?: number, blendMode?: BlendMode}. Use gradientTransform + gradientStops (basic left-to-right: [[1,0,0],[0,1,0]]); do not use CSS gradients or REST gradientHandlePositions.\n// Effect: {type: "DROP_SHADOW"|"INNER_SHADOW"|"LAYER_BLUR"|"BACKGROUND_BLUR", radius: number, color?: {r,g,b,a} (0-1), offset?: {x, y}, spread?: number, visible?: boolean}\n// Paint: Paint[] authoring accepts only SOLID and GRADIENT_LINEAR/GRADIENT_RADIAL/GRADIENT_ANGULAR/GRADIENT_DIAMOND. SolidPaint: {type: "SOLID", color: Color, visible?: boolean, opacity?: number, blendMode?: BlendMode, boundVariables?: {color?: VariableAlias}}. GradientPaint authoring: {type: GRADIENT_*, gradientTransform: Transform, gradientStops: ColorStop[], visible?, opacity?, blendMode?}; bind variables on gradientStops[].boundVariables.color, not top-level gradient boundVariables. Do not pass IMAGE/VIDEO/PATTERN to create/update Paint[]; those may appear only in readback metadata from existing Figma content. Use imageUrl/images for image authoring. VIDEO/PATTERN authoring is not supported here. Do not use CSS gradients or REST gradientHandlePositions.\n// LayoutGrid is conditional: GridLayoutGrid {pattern:"GRID", sectionSize:number, visible?:boolean, color?:Color}; RowsColsLayoutGrid {pattern:"ROWS"|"COLUMNS", alignment?:"MIN"|"MAX"|"CENTER"|"STRETCH", gutterSize?:number, count?:number, offset?:number, sectionSize?:number, visible?:boolean, color?:Color}. For alignment:"STRETCH", omit sectionSize; Figma computes stretched row/column sizes. Use sectionSize only with fixed rows/columns (MIN/MAX/CENTER) or GRID.',
1264
+ "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\n\nResponse:\n { results: ("ok" | {error})[] }'
1034
1265
  }
1035
1266
  },
1036
1267
  "text": {
1037
- "summary": '# text\nCreate and manage text 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 \u2014 produces a same-type copy (frame\u2192frame, instance\u2192instance, component\u2192component). Instance clones reference the same source component; they do not duplicate the component definition. [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 text nodes [create]\n set_content Replace text content on existing text nodes [edit]\n scan Scan all text nodes within a subtree [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// Text nodes display text content with typography styling. They inherit node methods (get, list, update, delete, clone, reparent).\n// textAutoResize: NONE (fixed box), WIDTH_AND_HEIGHT (grow both), HEIGHT (fixed width, auto height), TRUNCATE (fixed + ellipsis).\n// Prefer textStyleName for typography, fontColorVariableName/fontColorStyleName for color.\n// Aliases: fillColor \u2192 fontColor, fillVariableName \u2192 fontColorVariableName, fillStyleName \u2192 fontColorStyleName (consistent with frames API).\n// ---\n// Smart defaults inside auto-layout parent: layoutSizingHorizontal defaults to FILL, layoutSizingVertical to HUG, textAutoResize to HEIGHT.\n// Text fills parent width and wraps automatically. Override with explicit values if needed.\n// fontStyle vs fontWeight: fontStyle is a named variant like "Bold", "Italic", "SemiBold". When set, fontWeight is ignored.\n// Use fonts.list to find available fontFamily + fontStyle combinations.\n// scan: finds all text nodes in a subtree. path (when includePath:true) shows the layer hierarchy e.g. "Frame > Card > Label".\n// ScanResult (per-item): { nodeId, count, truncated, textNodes: [{ id, name, characters, fontSize, fontFamily, fontStyle, path?, depth?, absoluteX?, absoluteY?, width?, height? }] }\n\nUse text(method: "help", topic: "<method>") for method details.',
1268
+ "summary": '# text\nCreate and manage text 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 \u2014 produces a same-type copy (frame\u2192frame, instance\u2192instance, component\u2192component). Instance clones reference the same source component; they do not duplicate the component definition. [create]\n scale Proportionally rescale a node subtree using Figma\'s visual Scale tool behavior. This is for visual/artifact scaling, not responsive layout resizing. [edit]\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 text nodes [create]\n set_content Replace text content on existing text nodes [edit]\n scan Scan all text nodes within a subtree [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// clipsContent: clip children to the node bounds where supported (frames/components/instances). Set false for overflow-visible layouts.\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[]; // readback Paint[]; authoring supports SOLID + gradients via gradientTransform + gradientStops\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. Paint[] authoring supports SOLID + gradients only; IMAGE/VIDEO/PATTERN are readback-only metadata.\n// Unknown keys produce a warning, preventing silent failures.\n// Text nodes display text content with typography styling. They inherit node methods (get, list, update, delete, clone, reparent).\n// textAutoResize: NONE (fixed box), WIDTH_AND_HEIGHT (grow both), HEIGHT (fixed width, auto height), TRUNCATE (fixed + ellipsis).\n// Prefer textStyleName for typography, fontColorVariableName/fontColorStyleName for color.\n// Aliases: fillColor \u2192 fontColor, fillVariableName \u2192 fontColorVariableName, fillStyleName \u2192 fontColorStyleName (consistent with frames API).\n// ---\n// Smart defaults inside auto-layout parent: layoutSizingHorizontal defaults to FILL, layoutSizingVertical to HUG, textAutoResize to HEIGHT.\n// Text fills parent width and wraps automatically. Override with explicit values if needed.\n// fontStyle vs fontWeight: fontStyle is a named variant like "Bold", "Italic", "SemiBold". When set, fontWeight is ignored.\n// Use fonts.list to find available fontFamily + fontStyle combinations.\n// scan: finds all text nodes in a subtree. path (when includePath:true) shows the layer hierarchy e.g. "Frame > Card > Label".\n// ScanResult (per-item): { nodeId, count, truncated, textNodes: [{ id, name, characters, fontSize, fontFamily, fontStyle, path?, depth?, absoluteX?, absoluteY?, width?, height? }] }\n\nUse text(method: "help", topic: "<method>") for method details.\n// Shared types:\n// Color: hex "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}\n// VariableAlias: {type: "VARIABLE_ALIAS", id: string}. The id must be a Figma VariableID; discover it via variables.get/list or variable_collections.get. Prefer colorVariableName/fillVariableName/strokeVariableName when available; Paint[] VariableAlias is mainly for precise Paint[] round-trips and gradient stop bindings.\n// Transform: [[number, number, number], [number, number, number]] (Figma Plugin API 2\xD73 matrix)\n// 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"\n// ColorStop: {position: 0-1, color: Color, boundVariables?: {color?: VariableAlias}}\n// GradientPaint: {type: "GRADIENT_LINEAR"|"GRADIENT_RADIAL"|"GRADIENT_ANGULAR"|"GRADIENT_DIAMOND", gradientTransform: Transform, gradientStops: ColorStop[], visible?: boolean, opacity?: number, blendMode?: BlendMode}. Use gradientTransform + gradientStops (basic left-to-right: [[1,0,0],[0,1,0]]); do not use CSS gradients or REST gradientHandlePositions.\n// Effect: {type: "DROP_SHADOW"|"INNER_SHADOW"|"LAYER_BLUR"|"BACKGROUND_BLUR", radius: number, color?: {r,g,b,a} (0-1), offset?: {x, y}, spread?: number, visible?: boolean}\n// Paint: Paint[] authoring accepts only SOLID and GRADIENT_LINEAR/GRADIENT_RADIAL/GRADIENT_ANGULAR/GRADIENT_DIAMOND. SolidPaint: {type: "SOLID", color: Color, visible?: boolean, opacity?: number, blendMode?: BlendMode, boundVariables?: {color?: VariableAlias}}. GradientPaint authoring: {type: GRADIENT_*, gradientTransform: Transform, gradientStops: ColorStop[], visible?, opacity?, blendMode?}; bind variables on gradientStops[].boundVariables.color, not top-level gradient boundVariables. Do not pass IMAGE/VIDEO/PATTERN to create/update Paint[]; those may appear only in readback metadata from existing Figma content. Use imageUrl/images for image authoring. VIDEO/PATTERN authoring is not supported here. Do not use CSS gradients or REST gradientHandlePositions.\n// NodeStub: {id: string, name: string, type: string}',
1038
1269
  "methods": {
1039
- "get": '# text.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.',
1040
- "list": '# text.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)',
1270
+ "get": '# text.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.\n\nResponse:\n Serialized node tree. Shape depends on depth parameter.\n results (Node[], required) \u2014 Serialized node trees\n _truncated (boolean, optional) \u2014 True when node budget exceeded\n _notice (string, optional) \u2014 Human-readable truncation notice',
1271
+ "list": '# text.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)\n\nResponse:\n Paginated node search results (uses `results` not `items`)\n totalCount (number, required) \u2014 Total matching nodes\n returned (number, required) \u2014 Nodes in this page\n offset (number, optional)\n limit (number, optional)\n results (array, required) \u2014 Matching node stubs\n id (string, required)\n name (string, required)\n type (string, required)\n parentId (string, required)\n parentName (string, optional)\n bounds (object, optional)',
1041
1272
  "update": `# text.update
1042
1273
  Patch node properties
1043
1274
 
1044
1275
  Params:
1045
- items (PatchItem[], required) \u2014 Array of {id, ...properties} to patch
1046
- fills (array, optional) \u2014 Fill paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] for transparent. Primary way to set fills.
1276
+ items (PatchItem[], required) \u2014 Array of {id, ...fields} to patch
1277
+ fills (Paint[], optional) \u2014 Fill Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] for transparent. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables; use imageUrl/images for image authoring. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set non-image fills.
1047
1278
  fillColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)
1048
1279
  fillStyleName (string, optional) \u2014 Paint style name for fill
1049
- fillVariableName (string, optional) \u2014 Color variable by name e.g. 'bg/primary'
1050
- strokes (array, optional) \u2014 Stroke paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] to clear. Primary way to set strokes.
1280
+ fillVariableName (string, optional) \u2014 Color variable by name e.g. 'bg/surface'
1281
+ strokes (Paint[], optional) \u2014 Stroke Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] to clear. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set strokes.
1051
1282
  strokeColor (Color, optional) \u2014 Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)
1052
1283
  strokeStyleName (string, optional) \u2014 Paint style name for stroke
1053
1284
  strokeVariableName (string, optional) \u2014 Color variable by name for stroke
@@ -1122,9 +1353,35 @@ Params:
1122
1353
  explicitMode (object, optional) \u2014 Pin variable mode \u2014 use { collectionName, modeName } (preferred) or { collectionId, modeId }
1123
1354
  exportSettings (array, optional) \u2014 Export settings
1124
1355
  annotations (array, optional) \u2014 Set annotations \u2014 [{label?, labelMarkdown?, properties?, categoryId?}]. Properties are validated per node type.
1125
- properties (object, optional) \u2014 Direct Figma API props (escape hatch)`,
1126
- "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)",
1127
- "clone": "# text.clone\nDuplicate nodes \u2014 produces a same-type copy (frame\u2192frame, instance\u2192instance, component\u2192component). Instance clones reference the same source component; they do not duplicate the component definition.\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.",
1356
+ clipsContent (boolean, optional) \u2014 Clip children to bounds where supported (frames/components/instances).
1357
+
1358
+ Response:
1359
+ { results: ("ok" | {error} | object)[] }
1360
+ // Shared types:
1361
+ // Color: hex "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}
1362
+ // VariableAlias: {type: "VARIABLE_ALIAS", id: string}. The id must be a Figma VariableID; discover it via variables.get/list or variable_collections.get. Prefer colorVariableName/fillVariableName/strokeVariableName when available; Paint[] VariableAlias is mainly for precise Paint[] round-trips and gradient stop bindings.
1363
+ // Transform: [[number, number, number], [number, number, number]] (Figma Plugin API 2\xD73 matrix)
1364
+ // 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"
1365
+ // ColorStop: {position: 0-1, color: Color, boundVariables?: {color?: VariableAlias}}
1366
+ // GradientPaint: {type: "GRADIENT_LINEAR"|"GRADIENT_RADIAL"|"GRADIENT_ANGULAR"|"GRADIENT_DIAMOND", gradientTransform: Transform, gradientStops: ColorStop[], visible?: boolean, opacity?: number, blendMode?: BlendMode}. Use gradientTransform + gradientStops (basic left-to-right: [[1,0,0],[0,1,0]]); do not use CSS gradients or REST gradientHandlePositions.
1367
+ // Effect: {type: "DROP_SHADOW"|"INNER_SHADOW"|"LAYER_BLUR"|"BACKGROUND_BLUR", radius: number, color?: {r,g,b,a} (0-1), offset?: {x, y}, spread?: number, visible?: boolean}
1368
+ // Paint: Paint[] authoring accepts only SOLID and GRADIENT_LINEAR/GRADIENT_RADIAL/GRADIENT_ANGULAR/GRADIENT_DIAMOND. SolidPaint: {type: "SOLID", color: Color, visible?: boolean, opacity?: number, blendMode?: BlendMode, boundVariables?: {color?: VariableAlias}}. GradientPaint authoring: {type: GRADIENT_*, gradientTransform: Transform, gradientStops: ColorStop[], visible?, opacity?, blendMode?}; bind variables on gradientStops[].boundVariables.color, not top-level gradient boundVariables. Do not pass IMAGE/VIDEO/PATTERN to create/update Paint[]; those may appear only in readback metadata from existing Figma content. Use imageUrl/images for image authoring. VIDEO/PATTERN authoring is not supported here. Do not use CSS gradients or REST gradientHandlePositions.`,
1369
+ "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)\n\nResponse:\n { results: ("ok" | {error})[] }',
1370
+ "clone": "# text.clone\nDuplicate nodes \u2014 produces a same-type copy (frame\u2192frame, instance\u2192instance, component\u2192component). Instance clones reference the same source component; they do not duplicate the component definition.\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.\n\nResponse:\n { results: ({id} | {error})[] }",
1371
+ "scale": `# text.scale
1372
+ Proportionally rescale a node subtree using Figma's visual Scale tool behavior. This is for visual/artifact scaling, not responsive layout resizing.
1373
+
1374
+ Example: text(method:"scale", id:"1:23", factor:0.5)
1375
+
1376
+ Params:
1377
+ id (string, optional) \u2014 Node ID to scale
1378
+ factor (number, optional) \u2014 Scale factor, >= 0.01. 0.5 = 50%, 2 = 200%. Scales children, text, strokes, effects, and layout geometry from the node's top-left. On auto-layout or HUG/FILL nodes, Figma may resolve responsive sizing to fixed width/height.
1379
+ items (array, optional) \u2014 Batch: [{id, factor}, ...]. Alternative to single-item params.
1380
+ id (string, required) \u2014 Node ID to scale
1381
+ factor (number, required) \u2014 Scale factor, >= 0.01. 0.5 = 50%, 2 = 200%.
1382
+
1383
+ Response:
1384
+ { results: ("ok" | {error})[] }`,
1128
1385
  "audit": `# text.audit
1129
1386
  Run lint on a node \u2014 returns severity-ranked findings
1130
1387
 
@@ -1134,12 +1391,17 @@ Params:
1134
1391
  maxDepth (number, optional) \u2014 Max tree depth (default: 10)
1135
1392
  maxFindings (number, optional) \u2014 Max findings (default: 50)
1136
1393
  minSeverity (error | unsafe | heuristic | style | verbose, optional) \u2014 Minimum severity to report (default: style). Set to 'verbose' to include AAA contrast and line-height checks.
1137
- skipInstances (boolean, optional) \u2014 Skip instance internals \u2014 findings inside instances are owned by the component (default: true)`,
1138
- "reparent": "# text.reparent\nMove nodes into a new parent\n\nParams:\n items (array, required) \u2014 Array of {id, parentId, index?}\n id (string, required)\n parentId (string, required)\n index (number, optional)",
1394
+ skipInstances (boolean, optional) \u2014 Skip instance internals \u2014 findings inside instances are owned by the component (default: true)
1395
+
1396
+ Response:
1397
+ nodeId (string, optional)
1398
+ nodeName (string, optional)
1399
+ categories (array, optional) \u2014 Sorted by severity (error > unsafe > heuristic > style)`,
1400
+ "reparent": '# text.reparent\nMove nodes into a new parent\n\nParams:\n items (array, required) \u2014 Array of {id, parentId, index?}\n id (string, required)\n parentId (string, required)\n index (number, optional)\n\nResponse:\n { results: ("ok" | {error})[] }',
1139
1401
  "create": `# text.create
1140
1402
  Create text nodes
1141
1403
 
1142
- Example: text(method:"create", items:[{text:"Hello", fontFamily:"Inter", fontSize:16, textStyleName:"body/medium"}])
1404
+ Example: text(method:"create", items:[{text:"Hello", textStyleName:"Body/Regular", fontColorVariableName:"text/primary"}])
1143
1405
 
1144
1406
  Params:
1145
1407
  items (TextItem[], required) \u2014 Array of text items to create
@@ -1157,7 +1419,7 @@ Params:
1157
1419
  letterSpacing (number | {value, unit: "PIXELS"|"PERCENT"}, optional)
1158
1420
  textCase (ORIGINAL | UPPER | LOWER | TITLE | SMALL_CAPS | SMALL_CAPS_FORCED, optional)
1159
1421
  textDecoration (NONE | UNDERLINE | STRIKETHROUGH, optional)
1160
- fills (array, optional) \u2014 Text color paints \u2014 e.g. [{type: 'SOLID', color: '#hex'}]. Same as node fills.
1422
+ fills (Paint[], optional) \u2014 Text Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. Same as node fills. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables. IMAGE/VIDEO/PATTERN may appear in readback metadata only.
1161
1423
  fontColor (Color, optional) \u2014 Shorthand \u2014 sets text color (auto-binds to matching variable/style)
1162
1424
  fontColorVariableName (string, optional) \u2014 Bind color variable by name e.g. 'text/primary'
1163
1425
  fontColorStyleName (string, optional) \u2014 Apply paint style \u2014 overrides fontColor
@@ -1171,20 +1433,56 @@ Params:
1171
1433
  componentPropertyName (string, optional) \u2014 Bind to a component TEXT property by name. Walks up ancestors to find the nearest component, or targets the component specified by componentId. For deeply nested text, consider using components(method:'create', type:'from_node') with exposeText:true instead \u2014 it auto-discovers and binds all text nodes.
1172
1434
  componentId (string, optional) \u2014 Target component ID for componentPropertyName binding. When omitted, walks up ancestors to find the nearest COMPONENT or COMPONENT_SET.
1173
1435
  annotations (array, optional) \u2014 Annotations \u2014 [{label?, labelMarkdown?, properties?, categoryId?}]
1174
- depth (number, optional) \u2014 Response detail: omit for id+name only. 0=properties + child stubs. N=recurse N levels. -1=unlimited.`,
1175
- "set_content": "# text.set_content\nReplace text content on existing text nodes\n\nParams:\n items (array, required) \u2014 Array of {nodeId, text}\n nodeId (string, required) \u2014 Text node ID\n text (string, required) \u2014 New text content\n depth (number, optional) \u2014 Response detail: omit for id+name only. 0=properties + child stubs. N=recurse N levels. -1=unlimited.",
1176
- "scan": "# text.scan\nScan all text nodes within a subtree\n\nParams:\n items ({ nodeId: string; limit?: number; includePath?: boolean; includeGeometry?: boolean }[], required) \u2014 Array of subtrees to scan"
1436
+ depth (number, optional) \u2014 Response detail: omit for id+name only. 0=properties + child stubs. N=recurse N levels. -1=unlimited.
1437
+
1438
+ Response:
1439
+ { results: ({id} | {error})[] }
1440
+ // Shared types:
1441
+ // Color: hex "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}
1442
+ // VariableAlias: {type: "VARIABLE_ALIAS", id: string}. The id must be a Figma VariableID; discover it via variables.get/list or variable_collections.get. Prefer colorVariableName/fillVariableName/strokeVariableName when available; Paint[] VariableAlias is mainly for precise Paint[] round-trips and gradient stop bindings.
1443
+ // Transform: [[number, number, number], [number, number, number]] (Figma Plugin API 2\xD73 matrix)
1444
+ // 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"
1445
+ // ColorStop: {position: 0-1, color: Color, boundVariables?: {color?: VariableAlias}}
1446
+ // GradientPaint: {type: "GRADIENT_LINEAR"|"GRADIENT_RADIAL"|"GRADIENT_ANGULAR"|"GRADIENT_DIAMOND", gradientTransform: Transform, gradientStops: ColorStop[], visible?: boolean, opacity?: number, blendMode?: BlendMode}. Use gradientTransform + gradientStops (basic left-to-right: [[1,0,0],[0,1,0]]); do not use CSS gradients or REST gradientHandlePositions.
1447
+ // Paint: Paint[] authoring accepts only SOLID and GRADIENT_LINEAR/GRADIENT_RADIAL/GRADIENT_ANGULAR/GRADIENT_DIAMOND. SolidPaint: {type: "SOLID", color: Color, visible?: boolean, opacity?: number, blendMode?: BlendMode, boundVariables?: {color?: VariableAlias}}. GradientPaint authoring: {type: GRADIENT_*, gradientTransform: Transform, gradientStops: ColorStop[], visible?, opacity?, blendMode?}; bind variables on gradientStops[].boundVariables.color, not top-level gradient boundVariables. Do not pass IMAGE/VIDEO/PATTERN to create/update Paint[]; those may appear only in readback metadata from existing Figma content. Use imageUrl/images for image authoring. VIDEO/PATTERN authoring is not supported here. Do not use CSS gradients or REST gradientHandlePositions.`,
1448
+ "set_content": '# text.set_content\nReplace text content on existing text nodes\n\nParams:\n items (array, required) \u2014 Array of {nodeId, text}\n nodeId (string, required) \u2014 Text node ID\n text (string, required) \u2014 New text content\n depth (number, optional) \u2014 Response detail: omit for id+name only. 0=properties + child stubs. N=recurse N levels. -1=unlimited.\n\nResponse:\n { results: ("ok" | {error})[] }',
1449
+ "scan": '# text.scan\nScan all text nodes within a subtree\n\nParams:\n items ({ nodeId: string; limit?: number; includePath?: boolean; includeGeometry?: boolean }[], required) \u2014 Array of subtrees to scan\n\nResponse:\n { results: ("ok" | {error} | object)[] }'
1177
1450
  }
1178
1451
  },
1179
1452
  "variable_collections": {
1180
- "summary": '# variable_collections\nCRUD for variable collections \u2014 the document-level API for design tokens.\n\nMethods:\n list List variable collections [read]\n get Get collection with all variables and values (full document) [read]\n create Create a collection with modes and variables in one call [create]\n update Rename collections [edit]\n delete Delete collections [edit]\n add_mode Add a mode to a collection [create]\n rename_mode Rename a mode [edit]\n remove_mode Remove a mode from a collection [edit]\n\n// Variable collections group design tokens and define their modes (e.g. Light/Dark, Desktop/Mobile).\n// All ID params accept both IDs and display names.\n// ---\n// valuesByMode: values keyed by mode name, e.g. {"Light": "#FFF", "Dark": "#111"}.\n// Aliases: {type: "VARIABLE_ALIAS", name: "other/variable"}.\n// scopes: see variables endpoint for full list.\n// Deleting a collection deletes all variables inside it.\n// The default mode cannot be removed. Use add_mode/remove_mode for additional modes.\n\nUse variable_collections(method: "help", topic: "<method>") for method details.',
1453
+ "summary": '# variable_collections\nCRUD for variable collections \u2014 the document-level API for design tokens.\n\nMethods:\n list List variable collections [read]\n get Get collection with all variables and values (full document) [read]\n create Create a collection with modes and variables in one call [create]\n update Rename collections [edit]\n delete Delete collections [edit]\n add_mode Add a mode to a collection [create]\n rename_mode Rename a mode [edit]\n remove_mode Remove a mode from a collection [edit]\n\n// Variable collections group design tokens and define their modes (e.g. Light/Dark, Desktop/Mobile).\n// All ID params accept both IDs and display names.\n// ---\n// valuesByMode: values keyed by mode name, e.g. {"Light": "#FFF", "Dark": "#111"}.\n// Aliases in variable values use {type: "VARIABLE_ALIAS", name: "other/variable"}.\n// Paint[] VariableAlias uses {type:"VARIABLE_ALIAS", id:"<VariableID>"}; variable_collections.get includes each variable id. Prefer *VariableName helpers when available.\n// scopes: see variables endpoint for full list.\n// Deleting a collection deletes all variables inside it.\n// The default mode cannot be removed. Use add_mode/remove_mode for additional modes.\n\nUse variable_collections(method: "help", topic: "<method>") for method details.\n// Shared types:\n// Color: hex "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}\n// VariableAlias: {type: "VARIABLE_ALIAS", id: string}. The id must be a Figma VariableID; discover it via variables.get/list or variable_collections.get. Prefer colorVariableName/fillVariableName/strokeVariableName when available; Paint[] VariableAlias is mainly for precise Paint[] round-trips and gradient stop bindings.\n// Transform: [[number, number, number], [number, number, number]] (Figma Plugin API 2\xD73 matrix)\n// 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"\n// ColorStop: {position: 0-1, color: Color, boundVariables?: {color?: VariableAlias}}\n// GradientPaint: {type: "GRADIENT_LINEAR"|"GRADIENT_RADIAL"|"GRADIENT_ANGULAR"|"GRADIENT_DIAMOND", gradientTransform: Transform, gradientStops: ColorStop[], visible?: boolean, opacity?: number, blendMode?: BlendMode}. Use gradientTransform + gradientStops (basic left-to-right: [[1,0,0],[0,1,0]]); do not use CSS gradients or REST gradientHandlePositions.\n// Paint: Paint[] authoring accepts only SOLID and GRADIENT_LINEAR/GRADIENT_RADIAL/GRADIENT_ANGULAR/GRADIENT_DIAMOND. SolidPaint: {type: "SOLID", color: Color, visible?: boolean, opacity?: number, blendMode?: BlendMode, boundVariables?: {color?: VariableAlias}}. GradientPaint authoring: {type: GRADIENT_*, gradientTransform: Transform, gradientStops: ColorStop[], visible?, opacity?, blendMode?}; bind variables on gradientStops[].boundVariables.color, not top-level gradient boundVariables. Do not pass IMAGE/VIDEO/PATTERN to create/update Paint[]; those may appear only in readback metadata from existing Figma content. Use imageUrl/images for image authoring. VIDEO/PATTERN authoring is not supported here. Do not use CSS gradients or REST gradientHandlePositions.',
1181
1454
  "methods": {
1182
- "list": '# variable_collections.list\nList variable collections\n\nParams:\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)',
1183
- "get": '# variable_collections.get\nGet collection with all variables and values (full document)\n\nParams:\n id (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.',
1455
+ "list": '# variable_collections.list\nList variable collections\n\nParams:\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)\n\nResponse:\n totalCount (number, required)\n returned (number, optional)\n offset (number, optional)\n limit (number, optional)\n items (array, required)\n id (string, required)\n name (string, required)\n modes (string[], optional) \u2014 Mode names\n variableCount (number, optional) \u2014 Number of variables',
1456
+ "get": `# variable_collections.get
1457
+ Get collection with all variables and values (full document)
1458
+
1459
+ Params:
1460
+ id (string, required) \u2014 Collection ID or name
1461
+ fields (string[], optional) \u2014 Property whitelist. Identity fields (id, name, type) always included. Omit for stubs on list, full on get. Pass ["*"] for all.
1462
+
1463
+ Response:
1464
+ id (string, required)
1465
+ name (string, required)
1466
+ modes (string[], required) \u2014 Mode names (e.g. ['Light', 'Dark'])
1467
+ variables (array, required) \u2014 All variables in this collection
1468
+ id (string, required) \u2014 Figma VariableID. Use as VariableAlias.id in Paint[] when needed.
1469
+ name (string, required)
1470
+ type (string, required) \u2014 COLOR | FLOAT | STRING | BOOLEAN
1471
+ valuesByMode (object, required) \u2014 Values keyed by mode name
1472
+ scopes (string[], optional)
1473
+ description (string, optional)
1474
+ // Shared types:
1475
+ // Color: hex "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}
1476
+ // VariableAlias: {type: "VARIABLE_ALIAS", id: string}. The id must be a Figma VariableID; discover it via variables.get/list or variable_collections.get. Prefer colorVariableName/fillVariableName/strokeVariableName when available; Paint[] VariableAlias is mainly for precise Paint[] round-trips and gradient stop bindings.
1477
+ // Transform: [[number, number, number], [number, number, number]] (Figma Plugin API 2\xD73 matrix)
1478
+ // 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"
1479
+ // ColorStop: {position: 0-1, color: Color, boundVariables?: {color?: VariableAlias}}
1480
+ // GradientPaint: {type: "GRADIENT_LINEAR"|"GRADIENT_RADIAL"|"GRADIENT_ANGULAR"|"GRADIENT_DIAMOND", gradientTransform: Transform, gradientStops: ColorStop[], visible?: boolean, opacity?: number, blendMode?: BlendMode}. Use gradientTransform + gradientStops (basic left-to-right: [[1,0,0],[0,1,0]]); do not use CSS gradients or REST gradientHandlePositions.
1481
+ // Paint: Paint[] authoring accepts only SOLID and GRADIENT_LINEAR/GRADIENT_RADIAL/GRADIENT_ANGULAR/GRADIENT_DIAMOND. SolidPaint: {type: "SOLID", color: Color, visible?: boolean, opacity?: number, blendMode?: BlendMode, boundVariables?: {color?: VariableAlias}}. GradientPaint authoring: {type: GRADIENT_*, gradientTransform: Transform, gradientStops: ColorStop[], visible?, opacity?, blendMode?}; bind variables on gradientStops[].boundVariables.color, not top-level gradient boundVariables. Do not pass IMAGE/VIDEO/PATTERN to create/update Paint[]; those may appear only in readback metadata from existing Figma content. Use imageUrl/images for image authoring. VIDEO/PATTERN authoring is not supported here. Do not use CSS gradients or REST gradientHandlePositions.`,
1184
1482
  "create": `# variable_collections.create
1185
1483
  Create a collection with modes and variables in one call
1186
1484
 
1187
- Example: variable_collections(method:"create", items:[{name:"Tokens", modes:["Light","Dark"], variables:[{name:"bg/primary", type:"COLOR", valuesByMode:{"Light":"#FFF","Dark":"#111"}, scopes:["ALL_FILLS"]}, {name:"text/primary", type:"COLOR", valuesByMode:{"Light":"#111","Dark":"#F0F0F0"}, scopes:["TEXT_FILL"]}, {name:"space/16", type:"FLOAT", value:16, scopes:["GAP","WIDTH_HEIGHT"]}, {name:"radius/8", type:"FLOAT", value:8, scopes:["CORNER_RADIUS"]}]}])
1485
+ Example: variable_collections(method:"create", items:[{name:"Tokens", variables:[{name:"bg/canvas", type:"COLOR", value:"#F7F8FA", scopes:["ALL_FILLS"]}, {name:"bg/surface", type:"COLOR", value:"#FFFFFF", scopes:["ALL_FILLS"]}, {name:"bg/accent", type:"COLOR", value:"#2563EB", scopes:["ALL_FILLS"]}, {name:"bg/muted", type:"COLOR", value:"#E5E7EB", scopes:["ALL_FILLS"]}, {name:"text/primary", type:"COLOR", value:"#111827", scopes:["TEXT_FILL"]}, {name:"text/secondary", type:"COLOR", value:"#4B5563", scopes:["TEXT_FILL"]}, {name:"text/inverse", type:"COLOR", value:"#FFFFFF", scopes:["TEXT_FILL"]}, {name:"border/subtle", type:"COLOR", value:"#D1D5DB", scopes:["STROKE_COLOR"]}, {name:"icon/primary", type:"COLOR", value:{type:"VARIABLE_ALIAS", name:"text/primary"}, scopes:["ALL_FILLS","STROKE_COLOR"]}, {name:"status/success", type:"COLOR", value:"#16A34A", scopes:["ALL_FILLS"]}, {name:"space/8", type:"FLOAT", value:8, scopes:["GAP"]}, {name:"space/12", type:"FLOAT", value:12, scopes:["GAP"]}, {name:"space/16", type:"FLOAT", value:16, scopes:["GAP"]}, {name:"space/24", type:"FLOAT", value:24, scopes:["GAP"]}, {name:"radius/8", type:"FLOAT", value:8, scopes:["CORNER_RADIUS"]}, {name:"radius/12", type:"FLOAT", value:12, scopes:["CORNER_RADIUS"]}, {name:"radius/16", type:"FLOAT", value:16, scopes:["CORNER_RADIUS"]}, {name:"stroke/1", type:"FLOAT", value:1, scopes:["STROKE_FLOAT"]}]}])
1188
1486
 
1189
1487
  Params:
1190
1488
  items (array, required) \u2014 Array of collection documents
@@ -1196,22 +1494,25 @@ Params:
1196
1494
  value (variable_value, optional) \u2014 Sets all modes to this value. Use valuesByMode for per-mode control.
1197
1495
  valuesByMode (object, optional) \u2014 Values keyed by mode name (e.g. {"Light": "#FFF", "Dark": "#111"})
1198
1496
  description (string, optional)
1199
- scopes (string[], optional) \u2014 Restrict where variable can be applied (default: ALL_SCOPES)`,
1200
- "update": "# variable_collections.update\nRename collections\n\nParams:\n items (array, required) \u2014 Array of {id, name}\n id (string, required) \u2014 Collection ID or name\n name (string, required) \u2014 New name",
1201
- "delete": "# variable_collections.delete\nDelete collections\n\nParams:\n id (string, optional) \u2014 Collection ID or name\n items (array, optional) \u2014 Batch: [{id}, ...]\n id (string, required)",
1202
- "add_mode": "# variable_collections.add_mode\nAdd a mode to a collection\n\nParams:\n items (array, required) \u2014 Array of {collectionId, name}\n collectionId (string, required) \u2014 Collection ID or name\n name (string, required) \u2014 Mode name",
1203
- "rename_mode": '# variable_collections.rename_mode\nRename a mode\n\nParams:\n items (array, required) \u2014 Array of {collectionId, modeId, name}\n collectionId (string, required) \u2014 Collection ID or name\n modeId (string, required) \u2014 Mode ID or name (e.g. "Dark")\n name (string, required) \u2014 New name',
1204
- "remove_mode": '# variable_collections.remove_mode\nRemove a mode from a collection\n\nParams:\n items (array, required) \u2014 Array of {collectionId, modeId}\n collectionId (string, required) \u2014 Collection ID or name\n modeId (string, required) \u2014 Mode ID or name (e.g. "Dark")'
1497
+ scopes (string[], optional) \u2014 Restrict where variable can be applied (default: ALL_SCOPES)
1498
+
1499
+ Response:
1500
+ { results: ({id} | {error})[] }`,
1501
+ "update": '# variable_collections.update\nRename collections\n\nParams:\n items (array, required) \u2014 Array of {id, name}\n id (string, required) \u2014 Collection ID or name\n name (string, required) \u2014 New name\n\nResponse:\n { results: ("ok" | {error} | object)[] }',
1502
+ "delete": '# variable_collections.delete\nDelete collections\n\nParams:\n id (string, optional) \u2014 Collection ID or name\n items (array, optional) \u2014 Batch: [{id}, ...]\n id (string, required)\n\nResponse:\n { results: ("ok" | {error})[] }',
1503
+ "add_mode": "# variable_collections.add_mode\nAdd a mode to a collection\n\nParams:\n items (array, required) \u2014 Array of {collectionId, name}\n collectionId (string, required) \u2014 Collection ID or name\n name (string, required) \u2014 Mode name\n\nResponse:\n { results: ({id} | {error})[] }",
1504
+ "rename_mode": '# variable_collections.rename_mode\nRename a mode\n\nParams:\n items (array, required) \u2014 Array of {collectionId, modeId, name}\n collectionId (string, required) \u2014 Collection ID or name\n modeId (string, required) \u2014 Mode ID or name (e.g. "Dark")\n name (string, required) \u2014 New name\n\nResponse:\n { results: ("ok" | {error} | object)[] }',
1505
+ "remove_mode": '# variable_collections.remove_mode\nRemove a mode from a collection\n\nParams:\n items (array, required) \u2014 Array of {collectionId, modeId}\n collectionId (string, required) \u2014 Collection ID or name\n modeId (string, required) \u2014 Mode ID or name (e.g. "Dark")\n\nResponse:\n { results: ("ok" | {error})[] }'
1205
1506
  }
1206
1507
  },
1207
1508
  "variables": {
1208
- "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.',
1509
+ "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 in variable values use {type: "VARIABLE_ALIAS", name: "other/variable"}.\n// Paint[] VariableAlias uses {type:"VARIABLE_ALIAS", id:"<VariableID>"}; get IDs from variables.get/list or variable_collections.get. Prefer *VariableName helpers when available.\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.\n// Shared types:\n// Color: hex "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}\n// VariableAlias: {type: "VARIABLE_ALIAS", id: string}. The id must be a Figma VariableID; discover it via variables.get/list or variable_collections.get. Prefer colorVariableName/fillVariableName/strokeVariableName when available; Paint[] VariableAlias is mainly for precise Paint[] round-trips and gradient stop bindings.\n// Transform: [[number, number, number], [number, number, number]] (Figma Plugin API 2\xD73 matrix)\n// 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"\n// ColorStop: {position: 0-1, color: Color, boundVariables?: {color?: VariableAlias}}\n// GradientPaint: {type: "GRADIENT_LINEAR"|"GRADIENT_RADIAL"|"GRADIENT_ANGULAR"|"GRADIENT_DIAMOND", gradientTransform: Transform, gradientStops: ColorStop[], visible?: boolean, opacity?: number, blendMode?: BlendMode}. Use gradientTransform + gradientStops (basic left-to-right: [[1,0,0],[0,1,0]]); do not use CSS gradients or REST gradientHandlePositions.\n// Paint: Paint[] authoring accepts only SOLID and GRADIENT_LINEAR/GRADIENT_RADIAL/GRADIENT_ANGULAR/GRADIENT_DIAMOND. SolidPaint: {type: "SOLID", color: Color, visible?: boolean, opacity?: number, blendMode?: BlendMode, boundVariables?: {color?: VariableAlias}}. GradientPaint authoring: {type: GRADIENT_*, gradientTransform: Transform, gradientStops: ColorStop[], visible?, opacity?, blendMode?}; bind variables on gradientStops[].boundVariables.color, not top-level gradient boundVariables. Do not pass IMAGE/VIDEO/PATTERN to create/update Paint[]; those may appear only in readback metadata from existing Figma content. Use imageUrl/images for image authoring. VIDEO/PATTERN authoring is not supported here. Do not use CSS gradients or REST gradientHandlePositions.',
1209
1510
  "methods": {
1210
- "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)',
1211
- "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.',
1212
- "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)',
1213
- "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.',
1214
- "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)"
1511
+ "list": '# variables.list\nSearch variables within a collection\n\nExample: variables(method:"list", collectionId:"Tokens", 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)\n\nResponse:\n totalCount (number, required)\n returned (number, optional)\n offset (number, optional)\n limit (number, optional)\n items (array, required)\n id (string, required) \u2014 Figma VariableID. Use as VariableAlias.id in Paint[] when needed.\n name (string, required)\n type (string, optional) \u2014 COLOR | FLOAT | STRING | BOOLEAN\n valuesByMode (object, optional) \u2014 Values keyed by mode name\n scopes (string[], optional)\n description (string, optional)\n// Shared types:\n// Color: hex "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}\n// VariableAlias: {type: "VARIABLE_ALIAS", id: string}. The id must be a Figma VariableID; discover it via variables.get/list or variable_collections.get. Prefer colorVariableName/fillVariableName/strokeVariableName when available; Paint[] VariableAlias is mainly for precise Paint[] round-trips and gradient stop bindings.\n// Transform: [[number, number, number], [number, number, number]] (Figma Plugin API 2\xD73 matrix)\n// 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"\n// ColorStop: {position: 0-1, color: Color, boundVariables?: {color?: VariableAlias}}\n// GradientPaint: {type: "GRADIENT_LINEAR"|"GRADIENT_RADIAL"|"GRADIENT_ANGULAR"|"GRADIENT_DIAMOND", gradientTransform: Transform, gradientStops: ColorStop[], visible?: boolean, opacity?: number, blendMode?: BlendMode}. Use gradientTransform + gradientStops (basic left-to-right: [[1,0,0],[0,1,0]]); do not use CSS gradients or REST gradientHandlePositions.\n// Paint: Paint[] authoring accepts only SOLID and GRADIENT_LINEAR/GRADIENT_RADIAL/GRADIENT_ANGULAR/GRADIENT_DIAMOND. SolidPaint: {type: "SOLID", color: Color, visible?: boolean, opacity?: number, blendMode?: BlendMode, boundVariables?: {color?: VariableAlias}}. GradientPaint authoring: {type: GRADIENT_*, gradientTransform: Transform, gradientStops: ColorStop[], visible?, opacity?, blendMode?}; bind variables on gradientStops[].boundVariables.color, not top-level gradient boundVariables. Do not pass IMAGE/VIDEO/PATTERN to create/update Paint[]; those may appear only in readback metadata from existing Figma content. Use imageUrl/images for image authoring. VIDEO/PATTERN authoring is not supported here. Do not use CSS gradients or REST gradientHandlePositions.',
1512
+ "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.\n\nResponse:\n id (string, required) \u2014 Figma VariableID. Use as VariableAlias.id in Paint[] when needed.\n name (string, required)\n type (COLOR | FLOAT | STRING | BOOLEAN, required)\n collectionId (string, required) \u2014 Collection display name\n valuesByMode (Record<string, number | boolean | string | Color | {type: "VARIABLE_ALIAS", name: string}>, required) \u2014 Values keyed by mode name (e.g. "Light", "Dark")\n description (string, optional) \u2014 Variable description\n scopes (string[], optional) \u2014 Where this variable can be applied\n// Shared types:\n// Color: hex "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}\n// VariableAlias: {type: "VARIABLE_ALIAS", id: string}. The id must be a Figma VariableID; discover it via variables.get/list or variable_collections.get. Prefer colorVariableName/fillVariableName/strokeVariableName when available; Paint[] VariableAlias is mainly for precise Paint[] round-trips and gradient stop bindings.\n// Transform: [[number, number, number], [number, number, number]] (Figma Plugin API 2\xD73 matrix)\n// 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"\n// ColorStop: {position: 0-1, color: Color, boundVariables?: {color?: VariableAlias}}\n// GradientPaint: {type: "GRADIENT_LINEAR"|"GRADIENT_RADIAL"|"GRADIENT_ANGULAR"|"GRADIENT_DIAMOND", gradientTransform: Transform, gradientStops: ColorStop[], visible?: boolean, opacity?: number, blendMode?: BlendMode}. Use gradientTransform + gradientStops (basic left-to-right: [[1,0,0],[0,1,0]]); do not use CSS gradients or REST gradientHandlePositions.\n// Paint: Paint[] authoring accepts only SOLID and GRADIENT_LINEAR/GRADIENT_RADIAL/GRADIENT_ANGULAR/GRADIENT_DIAMOND. SolidPaint: {type: "SOLID", color: Color, visible?: boolean, opacity?: number, blendMode?: BlendMode, boundVariables?: {color?: VariableAlias}}. GradientPaint authoring: {type: GRADIENT_*, gradientTransform: Transform, gradientStops: ColorStop[], visible?, opacity?, blendMode?}; bind variables on gradientStops[].boundVariables.color, not top-level gradient boundVariables. Do not pass IMAGE/VIDEO/PATTERN to create/update Paint[]; those may appear only in readback metadata from existing Figma content. Use imageUrl/images for image authoring. VIDEO/PATTERN authoring is not supported here. Do not use CSS gradients or REST gradientHandlePositions.',
1513
+ "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:"Tokens", items:[{name:"bg/warning", type:"COLOR", value:"#F59E0B", 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)\n\nResponse:\n { results: ({id} | {error})[] }',
1514
+ "update": '# variables.update\nUpdate variable metadata and/or set values\n\nExample: variables(method:"update", collectionId:"Tokens", items:[{name:"bg/accent", value:"#1D4ED8"}])\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.\n\nResponse:\n { results: ("ok" | {error} | object)[] }',
1515
+ "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)\n\nResponse:\n { results: ("ok" | {error})[] }'
1215
1516
  }
1216
1517
  },
1217
1518
  "version_history": {
@@ -1232,7 +1533,10 @@ Save a named version to the file's version history
1232
1533
 
1233
1534
  Params:
1234
1535
  title (string, required) \u2014 Version title (e.g., "Added hero sections with website copy")
1235
- description (string, optional) \u2014 Optional longer description of what changed`
1536
+ description (string, optional) \u2014 Optional longer description of what changed
1537
+
1538
+ Response:
1539
+ id (string, required) \u2014 Version ID returned by Figma`
1236
1540
  }
1237
1541
  }
1238
1542
  };
@@ -1383,6 +1687,113 @@ var colorRgba = import_zod3.z.preprocess((v) => {
1383
1687
  import_zod3.z.string()
1384
1688
  // Non-hex strings pass through for handler-level style/variable resolution
1385
1689
  ])).describe('Hex "#FF0000", {r,g,b,a?} 0-1, or style/variable name.');
1690
+ var variableAlias = import_zod3.z.object({
1691
+ type: import_zod3.z.literal("VARIABLE_ALIAS"),
1692
+ id: import_zod3.z.string()
1693
+ }).strict().describe('{type:"VARIABLE_ALIAS", id:string}. Discover VariableIDs via variables.get/list or variable_collections.get; prefer *VariableName helpers when available.');
1694
+ var transform = import_zod3.z.tuple([
1695
+ import_zod3.z.tuple([import_zod3.z.coerce.number(), import_zod3.z.coerce.number(), import_zod3.z.coerce.number()]),
1696
+ import_zod3.z.tuple([import_zod3.z.coerce.number(), import_zod3.z.coerce.number(), import_zod3.z.coerce.number()])
1697
+ ]).describe("Figma Plugin API Transform: [[number,number,number],[number,number,number]]");
1698
+ var blendMode = import_zod3.z.enum([
1699
+ "PASS_THROUGH",
1700
+ "NORMAL",
1701
+ "DARKEN",
1702
+ "MULTIPLY",
1703
+ "LINEAR_BURN",
1704
+ "COLOR_BURN",
1705
+ "LIGHTEN",
1706
+ "SCREEN",
1707
+ "LINEAR_DODGE",
1708
+ "COLOR_DODGE",
1709
+ "OVERLAY",
1710
+ "SOFT_LIGHT",
1711
+ "HARD_LIGHT",
1712
+ "DIFFERENCE",
1713
+ "EXCLUSION",
1714
+ "HUE",
1715
+ "SATURATION",
1716
+ "COLOR",
1717
+ "LUMINOSITY"
1718
+ ]);
1719
+ var paintColor = import_zod3.z.preprocess((v) => {
1720
+ if (typeof v === "string") return parseHex(v) ?? v;
1721
+ return v;
1722
+ }, import_zod3.z.object({
1723
+ r: import_zod3.z.coerce.number().min(0).max(1),
1724
+ g: import_zod3.z.coerce.number().min(0).max(1),
1725
+ b: import_zod3.z.coerce.number().min(0).max(1),
1726
+ a: import_zod3.z.coerce.number().min(0).max(1).optional()
1727
+ }).strict()).describe('Paint color: hex "#FF0000"/"#FF000080" or {r,g,b,a?} 0-1. Non-hex strings are not valid inside Paint[].');
1728
+ var paintBoundVariables = import_zod3.z.object({
1729
+ color: variableAlias.optional()
1730
+ }).strict();
1731
+ var commonPaintFields = {
1732
+ visible: flexBool(import_zod3.z.boolean()).optional(),
1733
+ opacity: import_zod3.z.coerce.number().min(0).max(1).optional(),
1734
+ blendMode: blendMode.optional()
1735
+ };
1736
+ var colorStop = import_zod3.z.object({
1737
+ position: import_zod3.z.coerce.number().min(0).max(1),
1738
+ color: paintColor,
1739
+ boundVariables: paintBoundVariables.optional()
1740
+ }).strict().describe("ColorStop: {position:0..1, color: Color, boundVariables?: {color: VariableAlias}}");
1741
+ var solidPaint = import_zod3.z.object({
1742
+ type: import_zod3.z.literal("SOLID"),
1743
+ color: paintColor,
1744
+ boundVariables: paintBoundVariables.optional(),
1745
+ ...commonPaintFields
1746
+ }).strict();
1747
+ var gradientPaint = import_zod3.z.object({
1748
+ type: import_zod3.z.enum(["GRADIENT_LINEAR", "GRADIENT_RADIAL", "GRADIENT_ANGULAR", "GRADIENT_DIAMOND"]),
1749
+ gradientTransform: transform,
1750
+ gradientStops: import_zod3.z.array(colorStop),
1751
+ ...commonPaintFields
1752
+ }).strict().describe("GradientPaint: use gradientTransform + gradientStops. Do not use REST gradientHandlePositions.");
1753
+ var imageFilters = import_zod3.z.object({
1754
+ exposure: import_zod3.z.coerce.number().optional(),
1755
+ contrast: import_zod3.z.coerce.number().optional(),
1756
+ saturation: import_zod3.z.coerce.number().optional(),
1757
+ temperature: import_zod3.z.coerce.number().optional(),
1758
+ tint: import_zod3.z.coerce.number().optional(),
1759
+ highlights: import_zod3.z.coerce.number().optional(),
1760
+ shadows: import_zod3.z.coerce.number().optional()
1761
+ }).strict();
1762
+ var imagePaint = import_zod3.z.object({
1763
+ type: import_zod3.z.literal("IMAGE"),
1764
+ scaleMode: import_zod3.z.enum(["FILL", "FIT", "CROP", "TILE"]),
1765
+ imageHash: import_zod3.z.string().nullable(),
1766
+ imageTransform: transform.optional(),
1767
+ scalingFactor: import_zod3.z.coerce.number().optional(),
1768
+ rotation: import_zod3.z.coerce.number().optional(),
1769
+ filters: imageFilters.optional(),
1770
+ ...commonPaintFields
1771
+ }).strict();
1772
+ var videoPaint = import_zod3.z.object({
1773
+ type: import_zod3.z.literal("VIDEO"),
1774
+ scaleMode: import_zod3.z.enum(["FILL", "FIT", "CROP", "TILE"]),
1775
+ videoHash: import_zod3.z.string().nullable(),
1776
+ videoTransform: transform.optional(),
1777
+ scalingFactor: import_zod3.z.coerce.number().optional(),
1778
+ rotation: import_zod3.z.coerce.number().optional(),
1779
+ filters: imageFilters.optional(),
1780
+ ...commonPaintFields
1781
+ }).strict();
1782
+ var patternPaint = import_zod3.z.object({
1783
+ type: import_zod3.z.literal("PATTERN"),
1784
+ sourceNodeId: import_zod3.z.string(),
1785
+ tileType: import_zod3.z.enum(["RECTANGULAR", "HORIZONTAL_HEXAGONAL", "VERTICAL_HEXAGONAL"]),
1786
+ scalingFactor: import_zod3.z.coerce.number(),
1787
+ spacing: import_zod3.z.object({ x: import_zod3.z.coerce.number(), y: import_zod3.z.coerce.number() }).strict(),
1788
+ horizontalAlignment: import_zod3.z.enum(["START", "CENTER", "END"]),
1789
+ ...commonPaintFields
1790
+ }).strict();
1791
+ var paintInput = import_zod3.z.union([solidPaint, gradientPaint], {
1792
+ error: "Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients, REST gradientHandlePositions, IMAGE, VIDEO, or PATTERN."
1793
+ }).describe("Paint[] authoring input supports SOLID and Figma gradient paints only. Images use imageUrl/images endpoint; VIDEO and PATTERN authoring are not supported here.");
1794
+ var paint = paintInput.describe("Paint[] authoring input. Supports SOLID and gradients: GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; REST gradientHandlePositions is not accepted. IMAGE/VIDEO/PATTERN are readback-only metadata, not authoring input.");
1795
+ var paintArray = flexJson(import_zod3.z.array(paintInput)).describe("Paint[] input array. Authoring accepts only SOLID and gradients: GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use imageUrl/images for images; VIDEO/PATTERN authoring is not supported here.");
1796
+ var paintArrayLoose = flexJson(import_zod3.z.array(import_zod3.z.unknown())).describe("Paint[] input array. Authoring accepts only SOLID and gradients. Adapter validates details and returns guidance; CSS gradients, REST gradientHandlePositions, IMAGE, VIDEO, and PATTERN are not supported as authoring input. Use imageUrl/images for images.");
1386
1797
  var variableValue = import_zod3.z.preprocess((v) => {
1387
1798
  if (typeof v === "string") return parseHex(v) ?? v;
1388
1799
  return v;
@@ -1460,6 +1871,7 @@ var tools = [
1460
1871
  if (params.id === void 0) throw new Error('delete_category requires "id"');
1461
1872
  }
1462
1873
  if (!params.items) return;
1874
+ if (Array.isArray(params.items) && params.items.length === 0) throw new Error('items: [] is a no-op. Batch calls need at least one item. Omit items to use single-item params, or pass one or more item objects. Use annotations(method: "help", topic: "' + m + '") to see valid item shapes.');
1463
1875
  if (m === "get") {
1464
1876
  const itemSchema = import_zod4.z.object({
1465
1877
  id: import_zod4.z.string(),
@@ -1472,8 +1884,11 @@ var tools = [
1472
1884
  throw new Error(e.issues.map((i) => {
1473
1885
  const path = i.path.join(".");
1474
1886
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
1475
- const desc = shape?.[i.path[1]]?.description;
1476
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
1887
+ const field = String(i.path[1] ?? i.path[0] ?? "");
1888
+ const desc = shape?.[field]?.description;
1889
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
1890
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call annotations(method:"help", topic:"get").' : "";
1891
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
1477
1892
  }).join("; "));
1478
1893
  }
1479
1894
  throw e;
@@ -1491,8 +1906,11 @@ var tools = [
1491
1906
  throw new Error(e.issues.map((i) => {
1492
1907
  const path = i.path.join(".");
1493
1908
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
1494
- const desc = shape?.[i.path[1]]?.description;
1495
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
1909
+ const field = String(i.path[1] ?? i.path[0] ?? "");
1910
+ const desc = shape?.[field]?.description;
1911
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
1912
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call annotations(method:"help", topic:"set").' : "";
1913
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
1496
1914
  }).join("; "));
1497
1915
  }
1498
1916
  throw e;
@@ -1513,8 +1931,11 @@ var tools = [
1513
1931
  throw new Error(e.issues.map((i) => {
1514
1932
  const path = i.path.join(".");
1515
1933
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
1516
- const desc = shape?.[i.path[1]]?.description;
1517
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
1934
+ const field = String(i.path[1] ?? i.path[0] ?? "");
1935
+ const desc = shape?.[field]?.description;
1936
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
1937
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call annotations(method:"help", topic:"add").' : "";
1938
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
1518
1939
  }).join("; "));
1519
1940
  }
1520
1941
  throw e;
@@ -1532,8 +1953,11 @@ var tools = [
1532
1953
  throw new Error(e.issues.map((i) => {
1533
1954
  const path = i.path.join(".");
1534
1955
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
1535
- const desc = shape?.[i.path[1]]?.description;
1536
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
1956
+ const field = String(i.path[1] ?? i.path[0] ?? "");
1957
+ const desc = shape?.[field]?.description;
1958
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
1959
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call annotations(method:"help", topic:"remove").' : "";
1960
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
1537
1961
  }).join("; "));
1538
1962
  }
1539
1963
  throw e;
@@ -1544,16 +1968,17 @@ var tools = [
1544
1968
  },
1545
1969
  {
1546
1970
  name: "components",
1547
- 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 \u2014 produces a same-type copy (frame\u2192frame, instance\u2192instance, component\u2192component). Instance clones reference the same source component; they do not duplicate the component definition.\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).',
1971
+ 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 \u2014 produces a same-type copy (frame\u2192frame, instance\u2192instance, component\u2192component). Instance clones reference the same source component; they do not duplicate the component definition.\n scale (id?, factor?, items?: { id: string; factor: number }[]) \u2192 { results: "ok"[] } // Proportionally rescale a node subtree using Figma\'s visual Scale tool behavior. This is for visual/artifact scaling, not responsive layout resizing.\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).',
1548
1972
  schema: (caps2) => filterMethodsByTier({
1549
- method: import_zod4.z.enum(["clone", "audit", "reparent", "list", "get", "create", "commit", "update", "delete", "help"]),
1973
+ method: import_zod4.z.enum(["clone", "scale", "audit", "reparent", "list", "get", "create", "commit", "update", "delete", "help"]),
1550
1974
  id: import_zod4.z.string().optional().describe("Node ID"),
1551
1975
  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)"),
1552
1976
  parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place at current page root."),
1553
1977
  x: import_zod4.z.coerce.number().optional().describe("X position (default: 0)"),
1554
1978
  y: import_zod4.z.coerce.number().optional().describe("Y position (default: 0)"),
1555
- 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"),
1979
+ 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/scale/reparent/update"),
1556
1980
  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."),
1981
+ factor: import_zod4.z.coerce.number().optional().describe("Scale factor, >= 0.01. 0.5 = 50%, 2 = 200%. Scales children, text, strokes, effects, and layout geometry from the node's top-left. On auto-layout or HUG/FILL nodes, Figma may resolve responsive sizing to fixed width/height."),
1557
1982
  rules: flexStringList(import_zod4.z.array(import_zod4.z.string())).optional().describe('Rules to check. Default: ["all"]. Categories: "component", "composition", "token", "naming", "wcag".'),
1558
1983
  maxDepth: import_zod4.z.coerce.number().optional().describe("Max tree depth (default: 10)"),
1559
1984
  maxFindings: import_zod4.z.coerce.number().optional().describe("Max findings (default: 50)"),
@@ -1566,10 +1991,16 @@ var tools = [
1566
1991
  verbose: import_zod4.z.boolean().optional().describe("Include all properties (bounding box, constraints, text style details). Default false \u2014 returns slim, actionable output."),
1567
1992
  type: import_zod4.z.enum(["component", "from_node", "variant_set"]).optional().describe("Discriminant for create method"),
1568
1993
  topic: import_zod4.z.string().optional().describe('Help topic \u2014 method name for endpoint help, e.g. "create"')
1569
- }, caps2, { "clone": "create", "audit": "read", "reparent": "edit", "list": "read", "get": "read", "create": "create", "commit": "edit", "update": "edit", "delete": "edit", "help": "read" }),
1994
+ }, caps2, { "clone": "create", "scale": "edit", "audit": "read", "reparent": "edit", "list": "read", "get": "read", "create": "create", "commit": "edit", "update": "edit", "delete": "edit", "help": "read" }),
1570
1995
  tier: "read",
1571
1996
  validate: (params) => {
1572
1997
  const m = params.method;
1998
+ if (m === "create") {
1999
+ const itemDiscriminant = Array.isArray(params.items) ? params.items.find((it) => it && typeof it === "object" && typeof it.type === "string")?.type : void 0;
2000
+ if (params.type === void 0) {
2001
+ throw new Error(itemDiscriminant ? 'components.create uses top-level "type", not "type" inside items. Move the item value to the top level and use help for valid item shapes.' : 'components.create requires top-level "type" (component, from_node, variant_set). Use components(method: "help", topic: "create") for valid item shapes.');
2002
+ }
2003
+ }
1573
2004
  if (m === "commit") {
1574
2005
  if (params.id === void 0) throw new Error('commit requires "id"');
1575
2006
  }
@@ -1577,6 +2008,7 @@ var tools = [
1577
2008
  if (params.id === void 0) throw new Error('delete requires "id"');
1578
2009
  }
1579
2010
  if (!params.items) return;
2011
+ if (Array.isArray(params.items) && params.items.length === 0) throw new Error('items: [] is a no-op. Batch calls need at least one item. Omit items to use single-item params, or pass one or more item objects. Use components(method: "help", topic: "' + m + '") to see valid item shapes.');
1580
2012
  if (m === "create") {
1581
2013
  if (params.items) {
1582
2014
  if (params.type === "variant_set") for (const it of params.items) {
@@ -1600,13 +2032,13 @@ var tools = [
1600
2032
  opacity: token.optional().describe("Opacity (0-1) or variable name"),
1601
2033
  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(),
1602
2034
  effectStyleName: import_zod4.z.string().optional().describe("Effect style name (e.g. 'Shadow/Card') for shadows, blurs"),
1603
- fills: import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown())).optional().describe("Fill paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] for transparent. Primary way to set fills."),
2035
+ fills: paintArrayLoose.optional().describe("Fill Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] for transparent. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables; use imageUrl/images for image authoring. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set non-image fills."),
1604
2036
  fillColor: colorRgba.optional().describe("Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)"),
1605
2037
  fillStyleName: import_zod4.z.string().optional().describe("Paint style name for fill"),
1606
- fillVariableName: import_zod4.z.string().optional().describe("Color variable by name e.g. 'bg/primary'"),
2038
+ fillVariableName: import_zod4.z.string().optional().describe("Color variable by name e.g. 'bg/surface'"),
1607
2039
  imageUrl: import_zod4.z.string().optional().describe("Image source \u2014 'pexel:<id>' for Pexels photos, a public URL, or a local file path. SVGs are inserted as vectors; raster images become IMAGE fills."),
1608
2040
  imageScaleMode: import_zod4.z.enum(["FILL", "FIT", "CROP", "TILE"]).optional().describe("How the image is scaled within the frame (default: FILL)"),
1609
- strokes: import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown())).optional().describe("Stroke paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] to clear. Primary way to set strokes."),
2041
+ strokes: paintArrayLoose.optional().describe("Stroke Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] to clear. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set strokes."),
1610
2042
  strokeColor: colorRgba.optional().describe("Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)"),
1611
2043
  strokeStyleName: import_zod4.z.string().optional().describe("Paint style name for stroke"),
1612
2044
  strokeVariableName: import_zod4.z.string().optional().describe("Color variable by name for stroke"),
@@ -1643,7 +2075,7 @@ var tools = [
1643
2075
  maxHeight: import_zod4.z.coerce.number().optional().describe("Max height for responsive auto-layout"),
1644
2076
  annotations: flexJson(import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()))).optional().describe("Set annotations \u2014 [{label?, labelMarkdown?, properties?, categoryId?}]. Properties validated per node type."),
1645
2077
  description: import_zod4.z.string().optional().describe("Component description (shown in Figma's component panel)"),
1646
- 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'),
2078
+ 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?, textStyleName?, fontColorVariableName?, layoutSizingHorizontal?}. frame: {type:"frame", name?, layoutMode?, fillVariableName?, itemSpacing?, layoutSizingHorizontal?, children?}. instance: {type:"instance", componentId, componentPropertyName?, variantProperties?, properties?}. component: {type:"component", name, children?}. rectangle / ellipse / line: same params as the corresponding frames(method:"create", type:"rectangle"|"ellipse"|"line") branch. All params from text/frame endpoints are supported on their respective types. Inline fills/strokes accept Paint[] authoring input: SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. Do not use CSS gradients, REST gradientHandlePositions, or IMAGE/VIDEO/PATTERN in Paint[] authoring. 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:"ellipse", name:"Dot", width:6, height:6, fillVariableName:"status/active"}, {type:"text", name:"Label", text:"Button", componentPropertyName:"Label", textStyleName:"Body/Medium", fontColorVariableName:"text/primary", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}, {type:"frame", name:"Actions", layoutMode:"HORIZONTAL", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG", itemSpacing:"space/8", children:[{type:"instance", componentId:"1:2", componentPropertyName:"Action", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}]}]\n'),
1647
2079
  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.")
1648
2080
  }).passthrough(),
1649
2081
  "from_node": import_zod4.z.object({
@@ -1664,13 +2096,13 @@ var tools = [
1664
2096
  opacity: token.optional().describe("Opacity (0-1) or variable name"),
1665
2097
  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(),
1666
2098
  effectStyleName: import_zod4.z.string().optional().describe("Effect style name (e.g. 'Shadow/Card') for shadows, blurs"),
1667
- fills: import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown())).optional().describe("Fill paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] for transparent. Primary way to set fills."),
2099
+ fills: paintArrayLoose.optional().describe("Fill Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] for transparent. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables; use imageUrl/images for image authoring. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set non-image fills."),
1668
2100
  fillColor: colorRgba.optional().describe("Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)"),
1669
2101
  fillStyleName: import_zod4.z.string().optional().describe("Paint style name for fill"),
1670
- fillVariableName: import_zod4.z.string().optional().describe("Color variable by name e.g. 'bg/primary'"),
2102
+ fillVariableName: import_zod4.z.string().optional().describe("Color variable by name e.g. 'bg/surface'"),
1671
2103
  imageUrl: import_zod4.z.string().optional().describe("Image source \u2014 'pexel:<id>' for Pexels photos, a public URL, or a local file path. SVGs are inserted as vectors; raster images become IMAGE fills."),
1672
2104
  imageScaleMode: import_zod4.z.enum(["FILL", "FIT", "CROP", "TILE"]).optional().describe("How the image is scaled within the frame (default: FILL)"),
1673
- strokes: import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown())).optional().describe("Stroke paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] to clear. Primary way to set strokes."),
2105
+ strokes: paintArrayLoose.optional().describe("Stroke Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] to clear. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set strokes."),
1674
2106
  strokeColor: colorRgba.optional().describe("Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)"),
1675
2107
  strokeStyleName: import_zod4.z.string().optional().describe("Paint style name for stroke"),
1676
2108
  strokeVariableName: import_zod4.z.string().optional().describe("Color variable by name for stroke"),
@@ -1708,24 +2140,26 @@ var tools = [
1708
2140
  annotations: flexJson(import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()))).optional().describe("Set annotations \u2014 [{label?, labelMarkdown?, properties?, categoryId?}]. Properties validated per node type."),
1709
2141
  componentIds: flexStringList(import_zod4.z.array(import_zod4.z.string())).optional().describe("Existing component IDs to combine (min 2). Alternative to children."),
1710
2142
  variantPropertyName: import_zod4.z.string().optional().describe("Rename the auto-generated variant property (default: 'Property 1')"),
1711
- 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.')
2143
+ 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}. Variant children use the same inline child types as components.create, including rectangle / ellipse / line. All variants must share the same child structure. Alternative to componentIds \u2014 do not combine both.')
1712
2144
  }).passthrough()
1713
2145
  };
1714
2146
  const s = params.type && schemas[params.type];
1715
- if (s) {
1716
- try {
1717
- params.items = import_zod4.z.array(s).parse(params.items);
1718
- } catch (e) {
1719
- if (e instanceof import_zod4.z.ZodError) {
1720
- throw new Error(e.issues.map((i) => {
1721
- const path = i.path.join(".");
1722
- const shape = s instanceof import_zod4.z.ZodObject ? s.shape : null;
1723
- const desc = shape?.[i.path[1]]?.description;
1724
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
1725
- }).join("; "));
1726
- }
1727
- throw e;
2147
+ if (!s) throw new Error('components.create: unknown type. Use components(method: "help", topic: "create") for valid types and item shapes.');
2148
+ try {
2149
+ params.items = import_zod4.z.array(s).parse(params.items);
2150
+ } catch (e) {
2151
+ if (e instanceof import_zod4.z.ZodError) {
2152
+ throw new Error(e.issues.map((i) => {
2153
+ const path = i.path.join(".");
2154
+ const shape = s instanceof import_zod4.z.ZodObject ? s.shape : null;
2155
+ const field = String(i.path[1] ?? i.path[0] ?? "");
2156
+ const desc = shape?.[field]?.description;
2157
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
2158
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call components(method:"help", topic:"create").' : "";
2159
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
2160
+ }).join("; "));
1728
2161
  }
2162
+ throw e;
1729
2163
  }
1730
2164
  }
1731
2165
  if (m === "update") {
@@ -1745,15 +2179,18 @@ var tools = [
1745
2179
  throw new Error(e.issues.map((i) => {
1746
2180
  const path = i.path.join(".");
1747
2181
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
1748
- const desc = shape?.[i.path[1]]?.description;
1749
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
2182
+ const field = String(i.path[1] ?? i.path[0] ?? "");
2183
+ const desc = shape?.[field]?.description;
2184
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
2185
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call components(method:"help", topic:"update").' : "";
2186
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
1750
2187
  }).join("; "));
1751
2188
  }
1752
2189
  throw e;
1753
2190
  }
1754
2191
  }
1755
2192
  },
1756
- 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" }
2193
+ commandMap: { "clone": "components.clone", "scale": "components.scale", "audit": "components.audit", "reparent": "components.reparent", "list": "components.list", "get": "components.get", "create": "components.create", "commit": "components.commit", "update": "components.update", "delete": "components.delete" }
1757
2194
  },
1758
2195
  {
1759
2196
  name: "connection",
@@ -1803,9 +2240,9 @@ var tools = [
1803
2240
  },
1804
2241
  {
1805
2242
  name: "frames",
1806
- 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 \u2014 produces a same-type copy (frame\u2192frame, instance\u2192instance, component\u2192component). Instance clones reference the same source component; they do not duplicate the component definition.\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|slot, items: (FrameItem | AutoLayoutItem | SectionItem | RectangleItem | EllipseItem | LineItem | GroupItem | BooleanOperationItem | SvgItem | SlotItem)[]) \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).',
2243
+ 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 \u2014 produces a same-type copy (frame\u2192frame, instance\u2192instance, component\u2192component). Instance clones reference the same source component; they do not duplicate the component definition.\n scale (id?, factor?, items?: { id: string; factor: number }[]) \u2192 { results: "ok"[] } // Proportionally rescale a node subtree using Figma\'s visual Scale tool behavior. This is for visual/artifact scaling, not responsive layout resizing.\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|slot, items: (FrameItem | AutoLayoutItem | SectionItem | RectangleItem | EllipseItem | LineItem | GroupItem | BooleanOperationItem | SvgItem | SlotItem)[]) \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).',
1807
2244
  schema: (caps2) => filterMethodsByTier({
1808
- method: import_zod4.z.enum(["get", "list", "update", "delete", "clone", "audit", "reparent", "create", "commit", "export", "help"]),
2245
+ method: import_zod4.z.enum(["get", "list", "update", "delete", "clone", "scale", "audit", "reparent", "create", "commit", "export", "help"]),
1809
2246
  id: import_zod4.z.string().optional().describe("Node ID"),
1810
2247
  fields: flexStringList(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.'),
1811
2248
  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."),
@@ -1815,10 +2252,11 @@ var tools = [
1815
2252
  parentId: import_zod4.z.string().optional().describe("Search only within this subtree"),
1816
2253
  offset: import_zod4.z.coerce.number().optional().default(0).describe("Skip N items for pagination (default 0)"),
1817
2254
  limit: import_zod4.z.coerce.number().optional().default(100).describe("Max items per page (default 100)"),
1818
- 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 update/delete/clone/reparent"),
2255
+ 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 update/delete/clone/scale/reparent"),
1819
2256
  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)"),
1820
2257
  x: import_zod4.z.coerce.number().optional().describe("X position (default: 0)"),
1821
2258
  y: import_zod4.z.coerce.number().optional().describe("Y position (default: 0)"),
2259
+ factor: import_zod4.z.coerce.number().optional().describe("Scale factor, >= 0.01. 0.5 = 50%, 2 = 200%. Scales children, text, strokes, effects, and layout geometry from the node's top-left. On auto-layout or HUG/FILL nodes, Figma may resolve responsive sizing to fixed width/height."),
1822
2260
  rules: flexStringList(import_zod4.z.array(import_zod4.z.string())).optional().describe('Rules to check. Default: ["all"]. Categories: "component", "composition", "token", "naming", "wcag".'),
1823
2261
  maxDepth: import_zod4.z.coerce.number().optional().describe("Max tree depth (default: 10)"),
1824
2262
  maxFindings: import_zod4.z.coerce.number().optional().describe("Max findings (default: 50)"),
@@ -1828,10 +2266,16 @@ var tools = [
1828
2266
  format: import_zod4.z.enum(["PNG", "JPG", "SVG", "SVG_STRING", "PDF"]).optional().describe("Export format (default: PNG). SVG_STRING returns raw SVG text."),
1829
2267
  scale: import_zod4.z.coerce.number().optional().describe("Export scale (default: 1, only for PNG/JPG)"),
1830
2268
  topic: import_zod4.z.string().optional().describe('Help topic \u2014 method name for endpoint help, e.g. "create"')
1831
- }, caps2, { "get": "read", "list": "read", "update": "edit", "delete": "edit", "clone": "create", "audit": "read", "reparent": "edit", "create": "create", "commit": "edit", "export": "read", "help": "read" }),
2269
+ }, caps2, { "get": "read", "list": "read", "update": "edit", "delete": "edit", "clone": "create", "scale": "edit", "audit": "read", "reparent": "edit", "create": "create", "commit": "edit", "export": "read", "help": "read" }),
1832
2270
  tier: "read",
1833
2271
  validate: (params) => {
1834
2272
  const m = params.method;
2273
+ if (m === "create") {
2274
+ const itemDiscriminant = Array.isArray(params.items) ? params.items.find((it) => it && typeof it === "object" && typeof it.type === "string")?.type : void 0;
2275
+ if (params.type === void 0) {
2276
+ throw new Error(itemDiscriminant ? 'frames.create uses top-level "type", not "type" inside items. Move the item value to the top level and use help for valid item shapes.' : 'frames.create requires top-level "type" (frame, auto_layout, section, rectangle, ellipse, line, group, boolean_operation, svg, slot). Use frames(method: "help", topic: "create") for valid item shapes.');
2277
+ }
2278
+ }
1835
2279
  if (m === "commit") {
1836
2280
  if (params.id === void 0) throw new Error('commit requires "id"');
1837
2281
  }
@@ -1839,6 +2283,7 @@ var tools = [
1839
2283
  if (params.id === void 0) throw new Error('export requires "id"');
1840
2284
  }
1841
2285
  if (!params.items) return;
2286
+ if (Array.isArray(params.items) && params.items.length === 0) throw new Error('items: [] is a no-op. Batch calls need at least one item. Omit items to use single-item params, or pass one or more item objects. Use frames(method: "help", topic: "' + m + '") to see valid item shapes.');
1842
2287
  if (m === "create") {
1843
2288
  const schemas = {
1844
2289
  "frame": import_zod4.z.object({
@@ -1854,13 +2299,13 @@ var tools = [
1854
2299
  opacity: token.optional().describe("Opacity (0-1) or variable name"),
1855
2300
  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(),
1856
2301
  effectStyleName: import_zod4.z.string().optional().describe("Effect style name (e.g. 'Shadow/Card') for shadows, blurs"),
1857
- fills: import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown())).optional().describe("Fill paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] for transparent. Primary way to set fills."),
2302
+ fills: paintArrayLoose.optional().describe("Fill Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] for transparent. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables; use imageUrl/images for image authoring. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set non-image fills."),
1858
2303
  fillColor: colorRgba.optional().describe("Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)"),
1859
2304
  fillStyleName: import_zod4.z.string().optional().describe("Paint style name for fill"),
1860
- fillVariableName: import_zod4.z.string().optional().describe("Color variable by name e.g. 'bg/primary'"),
2305
+ fillVariableName: import_zod4.z.string().optional().describe("Color variable by name e.g. 'bg/surface'"),
1861
2306
  imageUrl: import_zod4.z.string().optional().describe("Image source \u2014 'pexel:<id>' for Pexels photos, a public URL, or a local file path. SVGs are inserted as vectors; raster images become IMAGE fills."),
1862
2307
  imageScaleMode: import_zod4.z.enum(["FILL", "FIT", "CROP", "TILE"]).optional().describe("How the image is scaled within the frame (default: FILL)"),
1863
- strokes: import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown())).optional().describe("Stroke paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] to clear. Primary way to set strokes."),
2308
+ strokes: paintArrayLoose.optional().describe("Stroke Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] to clear. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set strokes."),
1864
2309
  strokeColor: colorRgba.optional().describe("Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)"),
1865
2310
  strokeStyleName: import_zod4.z.string().optional().describe("Paint style name for stroke"),
1866
2311
  strokeVariableName: import_zod4.z.string().optional().describe("Color variable by name for stroke"),
@@ -1897,7 +2342,7 @@ var tools = [
1897
2342
  maxHeight: import_zod4.z.coerce.number().optional().describe("Max height for responsive auto-layout"),
1898
2343
  annotations: flexJson(import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()))).optional().describe("Set annotations \u2014 [{label?, labelMarkdown?, properties?, categoryId?}]. Properties validated per node type."),
1899
2344
  clipsContent: flexBool(import_zod4.z.boolean()).optional(),
1900
- 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')
2345
+ 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, textStyleName?, fontColorVariableName?, layoutSizingHorizontal?}. frame: {type:"frame", name?, layoutMode?, fillVariableName?, itemSpacing?, layoutSizingHorizontal?, children?}. instance: {type:"instance", componentId, variantProperties?, properties?}. component: {type:"component", name, children?}. rectangle / ellipse / line: same params as the corresponding frames(method:"create", type:"rectangle"|"ellipse"|"line") branch. All params from text/frame endpoints are supported on their respective types. Inline fills/strokes accept Paint[] authoring input: SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. Do not use CSS gradients, REST gradientHandlePositions, or IMAGE/VIDEO/PATTERN in Paint[] authoring. Always set layoutSizingHorizontal + layoutSizingVertical on children inside auto-layout parents (FILL, HUG, or FIXED). Example: children:[{type:"ellipse", name:"Dot", width:6, height:6, fillVariableName:"status/active"}, {type:"text", name:"Title", text:"Title", textStyleName:"Heading/Medium", fontColorVariableName:"text/primary", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}, {type:"frame", name:"Row", layoutMode:"HORIZONTAL", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG", itemSpacing:"space/8", children:[{type:"instance", componentId:"1:2", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}]}] Inside components: add componentPropertyName to auto-bind TEXT or INSTANCE_SWAP properties.\n')
1901
2346
  }).passthrough(),
1902
2347
  "auto_layout": import_zod4.z.object({
1903
2348
  name: import_zod4.z.string().optional().describe("Node name"),
@@ -1912,13 +2357,13 @@ var tools = [
1912
2357
  opacity: token.optional().describe("Opacity (0-1) or variable name"),
1913
2358
  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(),
1914
2359
  effectStyleName: import_zod4.z.string().optional().describe("Effect style name (e.g. 'Shadow/Card') for shadows, blurs"),
1915
- fills: import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown())).optional().describe("Fill paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] for transparent. Primary way to set fills."),
2360
+ fills: paintArrayLoose.optional().describe("Fill Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] for transparent. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables; use imageUrl/images for image authoring. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set non-image fills."),
1916
2361
  fillColor: colorRgba.optional().describe("Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)"),
1917
2362
  fillStyleName: import_zod4.z.string().optional().describe("Paint style name for fill"),
1918
- fillVariableName: import_zod4.z.string().optional().describe("Color variable by name e.g. 'bg/primary'"),
2363
+ fillVariableName: import_zod4.z.string().optional().describe("Color variable by name e.g. 'bg/surface'"),
1919
2364
  imageUrl: import_zod4.z.string().optional().describe("Image source \u2014 'pexel:<id>' for Pexels photos, a public URL, or a local file path. SVGs are inserted as vectors; raster images become IMAGE fills."),
1920
2365
  imageScaleMode: import_zod4.z.enum(["FILL", "FIT", "CROP", "TILE"]).optional().describe("How the image is scaled within the frame (default: FILL)"),
1921
- strokes: import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown())).optional().describe("Stroke paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] to clear. Primary way to set strokes."),
2366
+ strokes: paintArrayLoose.optional().describe("Stroke Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] to clear. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set strokes."),
1922
2367
  strokeColor: colorRgba.optional().describe("Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)"),
1923
2368
  strokeStyleName: import_zod4.z.string().optional().describe("Paint style name for stroke"),
1924
2369
  strokeVariableName: import_zod4.z.string().optional().describe("Color variable by name for stroke"),
@@ -1956,7 +2401,7 @@ var tools = [
1956
2401
  annotations: flexJson(import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()))).optional().describe("Set annotations \u2014 [{label?, labelMarkdown?, properties?, categoryId?}]. Properties validated per node type."),
1957
2402
  clipsContent: flexBool(import_zod4.z.boolean()).optional(),
1958
2403
  nodeIds: flexStringList(import_zod4.z.array(import_zod4.z.string())).optional().describe("Existing node IDs to wrap into auto-layout"),
1959
- 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')
2404
+ 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, textStyleName?, fontColorVariableName?, layoutSizingHorizontal?}. frame: {type:"frame", name?, layoutMode?, fillVariableName?, itemSpacing?, layoutSizingHorizontal?, children?}. instance: {type:"instance", componentId, variantProperties?, properties?}. component: {type:"component", name, children?}. rectangle / ellipse / line: same params as the corresponding frames(method:"create", type:"rectangle"|"ellipse"|"line") branch. All params from text/frame endpoints are supported on their respective types. Inline fills/strokes accept Paint[] authoring input: SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. Do not use CSS gradients, REST gradientHandlePositions, or IMAGE/VIDEO/PATTERN in Paint[] authoring. Always set layoutSizingHorizontal + layoutSizingVertical on children inside auto-layout parents (FILL, HUG, or FIXED). Example: children:[{type:"ellipse", name:"Dot", width:6, height:6, fillVariableName:"status/active"}, {type:"text", name:"Title", text:"Title", textStyleName:"Heading/Medium", fontColorVariableName:"text/primary", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}, {type:"frame", name:"Row", layoutMode:"HORIZONTAL", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG", itemSpacing:"space/8", children:[{type:"instance", componentId:"1:2", layoutSizingHorizontal:"FILL", layoutSizingVertical:"HUG"}]}] Inside components: add componentPropertyName to auto-bind TEXT or INSTANCE_SWAP properties.\n')
1960
2405
  }).passthrough(),
1961
2406
  "section": import_zod4.z.object({
1962
2407
  name: import_zod4.z.string().describe("Section name"),
@@ -1965,10 +2410,10 @@ var tools = [
1965
2410
  y: import_zod4.z.coerce.number().optional().describe("Y position (default: 0)"),
1966
2411
  width: import_zod4.z.coerce.number().optional().describe("Width (default: 500)"),
1967
2412
  height: import_zod4.z.coerce.number().optional().describe("Height (default: 500)"),
1968
- fills: import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown())).optional().describe("Fill paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] for transparent"),
2413
+ fills: paintArrayLoose.optional().describe("Fill Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] for transparent. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables; use imageUrl/images for image authoring. IMAGE/VIDEO/PATTERN may appear in readback metadata only"),
1969
2414
  fillColor: colorRgba.optional().describe("Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)"),
1970
2415
  fillStyleName: import_zod4.z.string().optional().describe("Paint style name for fill"),
1971
- fillVariableName: import_zod4.z.string().optional().describe("Color variable by name e.g. 'bg/primary'"),
2416
+ fillVariableName: import_zod4.z.string().optional().describe("Color variable by name e.g. 'bg/surface'"),
1972
2417
  imageUrl: import_zod4.z.string().optional().describe("Image source \u2014 'pexel:<id>', public URL, or local file path"),
1973
2418
  imageScaleMode: import_zod4.z.enum(["FILL", "FIT", "CROP", "TILE"]).optional().describe("How the image is scaled (default: FILL)")
1974
2419
  }).passthrough(),
@@ -1979,13 +2424,13 @@ var tools = [
1979
2424
  y: import_zod4.z.coerce.number().optional().describe("Y position (default: 0)"),
1980
2425
  width: import_zod4.z.coerce.number().optional().describe("Width in px (default: 100)"),
1981
2426
  height: import_zod4.z.coerce.number().optional().describe("Height in px (default: 100)"),
1982
- fills: import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown())).optional().describe("Fill paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] for transparent"),
2427
+ fills: paintArrayLoose.optional().describe("Fill Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] for transparent. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables; use imageUrl/images for image authoring. IMAGE/VIDEO/PATTERN may appear in readback metadata only"),
1983
2428
  fillColor: colorRgba.optional().describe("Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)"),
1984
2429
  fillStyleName: import_zod4.z.string().optional().describe("Paint style name for fill"),
1985
- fillVariableName: import_zod4.z.string().optional().describe("Color variable by name e.g. 'bg/primary'"),
2430
+ fillVariableName: import_zod4.z.string().optional().describe("Color variable by name e.g. 'bg/surface'"),
1986
2431
  imageUrl: import_zod4.z.string().optional().describe("Image source \u2014 'pexel:<id>', public URL, or local file path"),
1987
2432
  imageScaleMode: import_zod4.z.enum(["FILL", "FIT", "CROP", "TILE"]).optional().describe("How the image is scaled (default: FILL)"),
1988
- strokes: import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown())).optional().describe("Stroke paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] to clear"),
2433
+ strokes: paintArrayLoose.optional().describe("Stroke Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] to clear. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables. IMAGE/VIDEO/PATTERN may appear in readback metadata only"),
1989
2434
  strokeColor: colorRgba.optional().describe("Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)"),
1990
2435
  strokeVariableName: import_zod4.z.string().optional().describe("Color variable by name for stroke"),
1991
2436
  strokeWeight: token.optional(),
@@ -2006,13 +2451,13 @@ var tools = [
2006
2451
  y: import_zod4.z.coerce.number().optional().describe("Y position (default: 0)"),
2007
2452
  width: import_zod4.z.coerce.number().optional().describe("Width in px (default: 100)"),
2008
2453
  height: import_zod4.z.coerce.number().optional().describe("Height in px (default: 100, same as width for circle)"),
2009
- fills: import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown())).optional().describe("Fill paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] for transparent"),
2454
+ fills: paintArrayLoose.optional().describe("Fill Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] for transparent. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables; use imageUrl/images for image authoring. IMAGE/VIDEO/PATTERN may appear in readback metadata only"),
2010
2455
  fillColor: colorRgba.optional().describe("Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)"),
2011
2456
  fillStyleName: import_zod4.z.string().optional().describe("Paint style name for fill"),
2012
- fillVariableName: import_zod4.z.string().optional().describe("Color variable by name e.g. 'bg/primary'"),
2457
+ fillVariableName: import_zod4.z.string().optional().describe("Color variable by name e.g. 'bg/surface'"),
2013
2458
  imageUrl: import_zod4.z.string().optional().describe("Image source \u2014 'pexel:<id>', public URL, or local file path"),
2014
2459
  imageScaleMode: import_zod4.z.enum(["FILL", "FIT", "CROP", "TILE"]).optional().describe("How the image is scaled (default: FILL)"),
2015
- strokes: import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown())).optional().describe("Stroke paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] to clear"),
2460
+ strokes: paintArrayLoose.optional().describe("Stroke Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] to clear. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables. IMAGE/VIDEO/PATTERN may appear in readback metadata only"),
2016
2461
  strokeColor: colorRgba.optional().describe("Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)"),
2017
2462
  strokeVariableName: import_zod4.z.string().optional().describe("Color variable by name for stroke"),
2018
2463
  strokeWeight: token.optional(),
@@ -2028,7 +2473,7 @@ var tools = [
2028
2473
  y: import_zod4.z.coerce.number().optional().describe("Y position (default: 0)"),
2029
2474
  length: import_zod4.z.coerce.number().optional().describe("Line length in px (default: 100)"),
2030
2475
  rotation: import_zod4.z.coerce.number().optional().describe("Rotation in degrees (default: 0 = horizontal)"),
2031
- strokes: import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown())).optional().describe("Stroke paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] to clear"),
2476
+ strokes: paintArrayLoose.optional().describe("Stroke Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] to clear. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables. IMAGE/VIDEO/PATTERN may appear in readback metadata only"),
2032
2477
  strokeColor: colorRgba.optional().describe("Line color (default: black, auto-binds to matching variable/style)"),
2033
2478
  strokeVariableName: import_zod4.z.string().optional().describe("Color variable by name for stroke"),
2034
2479
  strokeWeight: token.optional().describe("Line thickness (default: 1)"),
@@ -2042,6 +2487,10 @@ var tools = [
2042
2487
  parentId: import_zod4.z.string().optional().describe("Parent node ID. Omit to place at current page root.")
2043
2488
  }).passthrough(),
2044
2489
  "boolean_operation": import_zod4.z.object({
2490
+ fillStyleName: import_zod4.z.string().optional().describe("Paint style to apply to vector fills"),
2491
+ fillVariableName: import_zod4.z.string().optional().describe("Color variable by name for vector fills"),
2492
+ strokeStyleName: import_zod4.z.string().optional().describe("Paint style to apply to vector strokes"),
2493
+ strokeVariableName: import_zod4.z.string().optional().describe("Color variable by name for vector strokes"),
2045
2494
  operation: import_zod4.z.enum(["UNION", "SUBTRACT", "INTERSECT", "EXCLUDE"]).describe("Boolean operation type"),
2046
2495
  nodeIds: import_zod4.z.array(import_zod4.z.string()).describe("Node IDs to combine (min 2, first node is the base for SUBTRACT)"),
2047
2496
  name: import_zod4.z.string().optional().describe("Result node name"),
@@ -2071,13 +2520,13 @@ var tools = [
2071
2520
  opacity: token.optional().describe("Opacity (0-1) or variable name"),
2072
2521
  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(),
2073
2522
  effectStyleName: import_zod4.z.string().optional().describe("Effect style name (e.g. 'Shadow/Card') for shadows, blurs"),
2074
- fills: import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown())).optional().describe("Fill paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] for transparent. Primary way to set fills."),
2523
+ fills: paintArrayLoose.optional().describe("Fill Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] for transparent. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables; use imageUrl/images for image authoring. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set non-image fills."),
2075
2524
  fillColor: colorRgba.optional().describe("Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)"),
2076
2525
  fillStyleName: import_zod4.z.string().optional().describe("Paint style name for fill"),
2077
- fillVariableName: import_zod4.z.string().optional().describe("Color variable by name e.g. 'bg/primary'"),
2526
+ fillVariableName: import_zod4.z.string().optional().describe("Color variable by name e.g. 'bg/surface'"),
2078
2527
  imageUrl: import_zod4.z.string().optional().describe("Image source \u2014 'pexel:<id>' for Pexels photos, a public URL, or a local file path. SVGs are inserted as vectors; raster images become IMAGE fills."),
2079
2528
  imageScaleMode: import_zod4.z.enum(["FILL", "FIT", "CROP", "TILE"]).optional().describe("How the image is scaled within the frame (default: FILL)"),
2080
- strokes: import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown())).optional().describe("Stroke paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] to clear. Primary way to set strokes."),
2529
+ strokes: paintArrayLoose.optional().describe("Stroke Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] to clear. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set strokes."),
2081
2530
  strokeColor: colorRgba.optional().describe("Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)"),
2082
2531
  strokeStyleName: import_zod4.z.string().optional().describe("Paint style name for stroke"),
2083
2532
  strokeVariableName: import_zod4.z.string().optional().describe("Color variable by name for stroke"),
@@ -2117,24 +2566,26 @@ var tools = [
2117
2566
  }).passthrough()
2118
2567
  };
2119
2568
  const s = params.type && schemas[params.type];
2120
- if (s) {
2121
- try {
2122
- params.items = import_zod4.z.array(s).parse(params.items);
2123
- } catch (e) {
2124
- if (e instanceof import_zod4.z.ZodError) {
2125
- throw new Error(e.issues.map((i) => {
2126
- const path = i.path.join(".");
2127
- const shape = s instanceof import_zod4.z.ZodObject ? s.shape : null;
2128
- const desc = shape?.[i.path[1]]?.description;
2129
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
2130
- }).join("; "));
2131
- }
2132
- throw e;
2569
+ if (!s) throw new Error('frames.create: unknown type. Use frames(method: "help", topic: "create") for valid types and item shapes.');
2570
+ try {
2571
+ params.items = import_zod4.z.array(s).parse(params.items);
2572
+ } catch (e) {
2573
+ if (e instanceof import_zod4.z.ZodError) {
2574
+ throw new Error(e.issues.map((i) => {
2575
+ const path = i.path.join(".");
2576
+ const shape = s instanceof import_zod4.z.ZodObject ? s.shape : null;
2577
+ const field = String(i.path[1] ?? i.path[0] ?? "");
2578
+ const desc = shape?.[field]?.description;
2579
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
2580
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call frames(method:"help", topic:"create").' : "";
2581
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
2582
+ }).join("; "));
2133
2583
  }
2584
+ throw e;
2134
2585
  }
2135
2586
  }
2136
2587
  },
2137
- 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" }
2588
+ commandMap: { "get": "frames.get", "list": "frames.list", "update": "frames.update", "delete": "frames.delete", "clone": "frames.clone", "scale": "frames.scale", "audit": "frames.audit", "reparent": "frames.reparent", "create": "frames.create", "commit": "frames.commit", "export": "frames.export" }
2138
2589
  },
2139
2590
  {
2140
2591
  name: "icons",
@@ -2196,9 +2647,9 @@ var tools = [
2196
2647
  },
2197
2648
  {
2198
2649
  name: "instances",
2199
- description: '/** Create and manage component instances. Use method "help" for detailed parameter docs. */\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 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 \u2014 produces a same-type copy (frame\u2192frame, instance\u2192instance, component\u2192component). Instance clones reference the same source component; they do not duplicate the component definition.\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 get (id, fields?, depth?, verbose?) \u2192 { results, _truncated? } // Get instance detail with component properties and overrides\n create (items: InstanceCreateItem[], depth?) \u2192 { results: {id}[] } // Create component instances\n update (items: InstanceUpdateItem[]) \u2192 { results: ("ok" | {error})[] } // Set instance properties\n swap (items: { id: string; componentId: string }[]) \u2192 { results: ("ok" | {error})[] } // Swap instance component (preserves overrides)\n detach (items: { id: string }[]) \u2192 { results: {id}[] } // Detach instances from their component (converts to frame)\n reset_overrides(items: { id: string }[]) \u2192 { results: ("ok" | {error})[] } // Reset all overrides on instances to match their main component\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).',
2650
+ description: '/** Create and manage component instances. Use method "help" for detailed parameter docs. */\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 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 \u2014 produces a same-type copy (frame\u2192frame, instance\u2192instance, component\u2192component). Instance clones reference the same source component; they do not duplicate the component definition.\n scale (id?, factor?, items?: { id: string; factor: number }[]) \u2192 { results: "ok"[] } // Proportionally rescale a node subtree using Figma\'s visual Scale tool behavior. This is for visual/artifact scaling, not responsive layout resizing.\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 get (id, fields?, depth?, verbose?) \u2192 { results, _truncated? } // Get instance detail with component properties and overrides\n create (items: InstanceCreateItem[], depth?) \u2192 { results: {id}[] } // Create component instances\n update (items: InstanceUpdateItem[]) \u2192 { results: ("ok" | {error})[] } // Set instance properties\n swap (items: { id: string; componentId: string }[]) \u2192 { results: ("ok" | {error})[] } // Swap instance component (preserves overrides)\n detach (items: { id: string }[]) \u2192 { results: {id}[] } // Detach instances from their component (converts to frame)\n reset_overrides(items: { id: string }[]) \u2192 { results: ("ok" | {error})[] } // Reset all overrides on instances to match their main component\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).',
2200
2651
  schema: (caps2) => filterMethodsByTier({
2201
- method: import_zod4.z.enum(["list", "delete", "clone", "audit", "reparent", "get", "create", "update", "swap", "detach", "reset_overrides", "help"]),
2652
+ method: import_zod4.z.enum(["list", "delete", "clone", "scale", "audit", "reparent", "get", "create", "update", "swap", "detach", "reset_overrides", "help"]),
2202
2653
  query: import_zod4.z.string().optional().describe("Name search query (case-insensitive substring match)"),
2203
2654
  types: flexStringList(import_zod4.z.array(import_zod4.z.string())).optional().describe('Filter by node types (e.g. ["FRAME", "TEXT"])'),
2204
2655
  parentId: import_zod4.z.string().optional().describe("Search only within this subtree"),
@@ -2206,11 +2657,12 @@ var tools = [
2206
2657
  offset: import_zod4.z.coerce.number().optional().default(0).describe("Skip N items for pagination (default 0)"),
2207
2658
  limit: import_zod4.z.coerce.number().optional().default(100).describe("Max items per page (default 100)"),
2208
2659
  id: import_zod4.z.string().optional().describe("Single node ID"),
2209
- 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 delete/clone/reparent/create/update/swap/detach/reset_overrides"),
2660
+ 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 delete/clone/scale/reparent/create/update/swap/detach/reset_overrides"),
2210
2661
  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)"),
2211
2662
  x: import_zod4.z.coerce.number().optional().describe("X position (default: 0)"),
2212
2663
  y: import_zod4.z.coerce.number().optional().describe("Y position (default: 0)"),
2213
2664
  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."),
2665
+ factor: import_zod4.z.coerce.number().optional().describe("Scale factor, >= 0.01. 0.5 = 50%, 2 = 200%. Scales children, text, strokes, effects, and layout geometry from the node's top-left. On auto-layout or HUG/FILL nodes, Figma may resolve responsive sizing to fixed width/height."),
2214
2666
  rules: flexStringList(import_zod4.z.array(import_zod4.z.string())).optional().describe('Rules to check. Default: ["all"]. Categories: "component", "composition", "token", "naming", "wcag".'),
2215
2667
  maxDepth: import_zod4.z.coerce.number().optional().describe("Max tree depth (default: 10)"),
2216
2668
  maxFindings: import_zod4.z.coerce.number().optional().describe("Max findings (default: 50)"),
@@ -2218,7 +2670,7 @@ var tools = [
2218
2670
  skipInstances: flexBool(import_zod4.z.boolean()).optional().describe("Skip instance internals \u2014 findings inside instances are owned by the component (default: true)"),
2219
2671
  verbose: import_zod4.z.boolean().optional().describe("Include all properties (bounding box, constraints, text style details). Default false \u2014 returns slim, actionable output."),
2220
2672
  topic: import_zod4.z.string().optional().describe('Help topic \u2014 method name for endpoint help, e.g. "create"')
2221
- }, caps2, { "list": "read", "delete": "edit", "clone": "create", "audit": "read", "reparent": "edit", "get": "read", "create": "create", "update": "edit", "swap": "edit", "detach": "edit", "reset_overrides": "edit", "help": "read" }),
2673
+ }, caps2, { "list": "read", "delete": "edit", "clone": "create", "scale": "edit", "audit": "read", "reparent": "edit", "get": "read", "create": "create", "update": "edit", "swap": "edit", "detach": "edit", "reset_overrides": "edit", "help": "read" }),
2222
2674
  tier: "read",
2223
2675
  validate: (params) => {
2224
2676
  const m = params.method;
@@ -2226,6 +2678,7 @@ var tools = [
2226
2678
  if (params.id === void 0) throw new Error('get requires "id"');
2227
2679
  }
2228
2680
  if (!params.items) return;
2681
+ if (Array.isArray(params.items) && params.items.length === 0) throw new Error('items: [] is a no-op. Batch calls need at least one item. Omit items to use single-item params, or pass one or more item objects. Use instances(method: "help", topic: "' + m + '") to see valid item shapes.');
2229
2682
  if (m === "create") {
2230
2683
  for (const it of params.items) {
2231
2684
  if (it.id !== void 0 && it.componentId === void 0) {
@@ -2267,8 +2720,11 @@ var tools = [
2267
2720
  throw new Error(e.issues.map((i) => {
2268
2721
  const path = i.path.join(".");
2269
2722
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
2270
- const desc = shape?.[i.path[1]]?.description;
2271
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
2723
+ const field = String(i.path[1] ?? i.path[0] ?? "");
2724
+ const desc = shape?.[field]?.description;
2725
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
2726
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call instances(method:"help", topic:"create").' : "";
2727
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
2272
2728
  }).join("; "));
2273
2729
  }
2274
2730
  throw e;
@@ -2276,11 +2732,11 @@ var tools = [
2276
2732
  }
2277
2733
  if (m === "update") {
2278
2734
  const itemSchema = import_zod4.z.object({
2279
- fills: import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown())).optional().describe("Fill paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] for transparent. Primary way to set fills."),
2735
+ fills: paintArrayLoose.optional().describe("Fill Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] for transparent. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables; use imageUrl/images for image authoring. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set non-image fills."),
2280
2736
  fillColor: colorRgba.optional().describe("Shorthand \u2014 sets a single solid fill (auto-binds to matching variable/style)"),
2281
2737
  fillStyleName: import_zod4.z.string().optional().describe("Paint style name for fill"),
2282
- fillVariableName: import_zod4.z.string().optional().describe("Color variable by name e.g. 'bg/primary'"),
2283
- strokes: import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown())).optional().describe("Stroke paints array \u2014 e.g. [{type: 'SOLID', color: '#hex'}] or [] to clear. Primary way to set strokes."),
2738
+ fillVariableName: import_zod4.z.string().optional().describe("Color variable by name e.g. 'bg/surface'"),
2739
+ strokes: paintArrayLoose.optional().describe("Stroke Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. [] to clear. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables. IMAGE/VIDEO/PATTERN may appear in readback metadata only. Primary way to set strokes."),
2284
2740
  strokeColor: colorRgba.optional().describe("Shorthand \u2014 sets a single solid stroke (auto-binds to matching variable/style)"),
2285
2741
  strokeStyleName: import_zod4.z.string().optional().describe("Paint style name for stroke"),
2286
2742
  strokeVariableName: import_zod4.z.string().optional().describe("Color variable by name for stroke"),
@@ -2361,8 +2817,11 @@ var tools = [
2361
2817
  throw new Error(e.issues.map((i) => {
2362
2818
  const path = i.path.join(".");
2363
2819
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
2364
- const desc = shape?.[i.path[1]]?.description;
2365
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
2820
+ const field = String(i.path[1] ?? i.path[0] ?? "");
2821
+ const desc = shape?.[field]?.description;
2822
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
2823
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call instances(method:"help", topic:"update").' : "";
2824
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
2366
2825
  }).join("; "));
2367
2826
  }
2368
2827
  throw e;
@@ -2380,8 +2839,11 @@ var tools = [
2380
2839
  throw new Error(e.issues.map((i) => {
2381
2840
  const path = i.path.join(".");
2382
2841
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
2383
- const desc = shape?.[i.path[1]]?.description;
2384
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
2842
+ const field = String(i.path[1] ?? i.path[0] ?? "");
2843
+ const desc = shape?.[field]?.description;
2844
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
2845
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call instances(method:"help", topic:"swap").' : "";
2846
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
2385
2847
  }).join("; "));
2386
2848
  }
2387
2849
  throw e;
@@ -2398,8 +2860,11 @@ var tools = [
2398
2860
  throw new Error(e.issues.map((i) => {
2399
2861
  const path = i.path.join(".");
2400
2862
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
2401
- const desc = shape?.[i.path[1]]?.description;
2402
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
2863
+ const field = String(i.path[1] ?? i.path[0] ?? "");
2864
+ const desc = shape?.[field]?.description;
2865
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
2866
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call instances(method:"help", topic:"detach").' : "";
2867
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
2403
2868
  }).join("; "));
2404
2869
  }
2405
2870
  throw e;
@@ -2416,15 +2881,18 @@ var tools = [
2416
2881
  throw new Error(e.issues.map((i) => {
2417
2882
  const path = i.path.join(".");
2418
2883
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
2419
- const desc = shape?.[i.path[1]]?.description;
2420
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
2884
+ const field = String(i.path[1] ?? i.path[0] ?? "");
2885
+ const desc = shape?.[field]?.description;
2886
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
2887
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call instances(method:"help", topic:"reset_overrides").' : "";
2888
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
2421
2889
  }).join("; "));
2422
2890
  }
2423
2891
  throw e;
2424
2892
  }
2425
2893
  }
2426
2894
  },
2427
- commandMap: { "list": "instances.list", "delete": "instances.delete", "clone": "instances.clone", "audit": "instances.audit", "reparent": "instances.reparent", "get": "instances.get", "create": "instances.create", "update": "instances.update", "swap": "instances.swap", "detach": "instances.detach", "reset_overrides": "instances.reset_overrides" }
2895
+ commandMap: { "list": "instances.list", "delete": "instances.delete", "clone": "instances.clone", "scale": "instances.scale", "audit": "instances.audit", "reparent": "instances.reparent", "get": "instances.get", "create": "instances.create", "update": "instances.update", "swap": "instances.swap", "detach": "instances.detach", "reset_overrides": "instances.reset_overrides" }
2428
2896
  },
2429
2897
  {
2430
2898
  name: "library",
@@ -2497,6 +2965,7 @@ var tools = [
2497
2965
  validate: (params) => {
2498
2966
  const m = params.method;
2499
2967
  if (!params.items) return;
2968
+ if (Array.isArray(params.items) && params.items.length === 0) throw new Error('items: [] is a no-op. Batch calls need at least one item. Omit items to use single-item params, or pass one or more item objects. Use lint(method: "help", topic: "' + m + '") to see valid item shapes.');
2500
2969
  if (m === "fix") {
2501
2970
  for (const it of params.items) {
2502
2971
  if (it.id !== void 0 && it.nodeId === void 0) {
@@ -2516,8 +2985,11 @@ var tools = [
2516
2985
  throw new Error(e.issues.map((i) => {
2517
2986
  const path = i.path.join(".");
2518
2987
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
2519
- const desc = shape?.[i.path[1]]?.description;
2520
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
2988
+ const field = String(i.path[1] ?? i.path[0] ?? "");
2989
+ const desc = shape?.[field]?.description;
2990
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
2991
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call lint(method:"help", topic:"fix").' : "";
2992
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
2521
2993
  }).join("; "));
2522
2994
  }
2523
2995
  throw e;
@@ -2568,6 +3040,7 @@ var tools = [
2568
3040
  if (params.index === void 0) throw new Error('remove requires "index"');
2569
3041
  }
2570
3042
  if (!params.items) return;
3043
+ if (Array.isArray(params.items) && params.items.length === 0) throw new Error('items: [] is a no-op. Batch calls need at least one item. Omit items to use single-item params, or pass one or more item objects. Use prototyping(method: "help", topic: "' + m + '") to see valid item shapes.');
2571
3044
  if (m === "add") {
2572
3045
  const itemSchema = import_zod4.z.object({
2573
3046
  id: import_zod4.z.string().describe("Node ID"),
@@ -2593,8 +3066,11 @@ var tools = [
2593
3066
  throw new Error(e.issues.map((i) => {
2594
3067
  const path = i.path.join(".");
2595
3068
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
2596
- const desc = shape?.[i.path[1]]?.description;
2597
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
3069
+ const field = String(i.path[1] ?? i.path[0] ?? "");
3070
+ const desc = shape?.[field]?.description;
3071
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
3072
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call prototyping(method:"help", topic:"add").' : "";
3073
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
2598
3074
  }).join("; "));
2599
3075
  }
2600
3076
  throw e;
@@ -2624,7 +3100,7 @@ var tools = [
2624
3100
  },
2625
3101
  {
2626
3102
  name: "styles",
2627
- description: '/** CRUD for local paint, text, effect, and grid styles. Use method "help" for detailed parameter docs. */\n list (type?: paint|text|effect|grid, fields?, offset?, limit?) \u2192 { totalCount, items } // List local styles with optional type filter\n get (id, fields?) \u2192 { id, name, type, paints?, fontFamily?, fontSize?, effects?, layoutGrids? } // Get full style detail by ID\n create (type: paint|text|effect|grid, items: (PaintItem | TextItem | EffectItem | GridItem)[]) \u2192 { results: {id}[] } // Create local styles\n update (type?: paint|text|effect|grid, items: PatchStyleItem[]) \u2192 { results: ("ok" | {error})[] } // Update styles by ID or name\n delete (id?, items?: { id: string }[]) \u2192 { results: "ok"[] } // Delete styles\n// Styles are named, reusable design properties that can be applied to nodes. Four types:\n// paint: a named color (applied to fills/strokes), text: typography settings, effect: shadows/blurs, grid: layout grids.\n// All ID params accept both IDs and display names (case-insensitive). Use whichever you have.',
3103
+ description: '/** CRUD for local paint, text, effect, and grid styles. Use method "help" for detailed parameter docs. */\n list (type?: paint|text|effect|grid, fields?, offset?, limit?) \u2192 { totalCount, items } // List local styles with optional type filter\n get (id, fields?) \u2192 { id, name, type, paints?: Paint[], boundVariables?, fontFamily?, fontSize?, effects?, layoutGrids? } // Get full style detail by ID\n create (type: paint|text|effect|grid, items: (PaintItem | TextItem | EffectItem | GridItem)[]) \u2192 { results: {id}[] } // Create local styles\n update (type?: paint|text|effect|grid, items: PatchStyleItem[]) \u2192 { results: ("ok" | {error})[] } // Update styles by ID or name\n delete (id?, items?: { id: string }[]) \u2192 { results: "ok"[] } // Delete styles\n// Styles are named, reusable design properties that can be applied to nodes. Four types:\n// paint: named PaintStyle.paints (applied to fills/strokes), text: typography settings, effect: shadows/blurs, grid: layout grids.\n// All ID params accept both IDs and display names (case-insensitive). Use whichever you have.\n// Shared types:\n// Color: hex "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}\n// VariableAlias: {type: "VARIABLE_ALIAS", id: string}. The id must be a Figma VariableID; discover it via variables.get/list or variable_collections.get. Prefer colorVariableName/fillVariableName/strokeVariableName when available; Paint[] VariableAlias is mainly for precise Paint[] round-trips and gradient stop bindings.\n// Transform: [[number, number, number], [number, number, number]] (Figma Plugin API 2\xD73 matrix)\n// 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"\n// ColorStop: {position: 0-1, color: Color, boundVariables?: {color?: VariableAlias}}\n// GradientPaint: {type: "GRADIENT_LINEAR"|"GRADIENT_RADIAL"|"GRADIENT_ANGULAR"|"GRADIENT_DIAMOND", gradientTransform: Transform, gradientStops: ColorStop[], visible?: boolean, opacity?: number, blendMode?: BlendMode}. Use gradientTransform + gradientStops (basic left-to-right: [[1,0,0],[0,1,0]]); do not use CSS gradients or REST gradientHandlePositions.\n// Paint: Paint[] authoring accepts only SOLID and GRADIENT_LINEAR/GRADIENT_RADIAL/GRADIENT_ANGULAR/GRADIENT_DIAMOND. SolidPaint: {type: "SOLID", color: Color, visible?: boolean, opacity?: number, blendMode?: BlendMode, boundVariables?: {color?: VariableAlias}}. GradientPaint authoring: {type: GRADIENT_*, gradientTransform: Transform, gradientStops: ColorStop[], visible?, opacity?, blendMode?}; bind variables on gradientStops[].boundVariables.color, not top-level gradient boundVariables. Do not pass IMAGE/VIDEO/PATTERN to create/update Paint[]; those may appear only in readback metadata from existing Figma content. Use imageUrl/images for image authoring. VIDEO/PATTERN authoring is not supported here. Do not use CSS gradients or REST gradientHandlePositions.',
2628
3104
  schema: (caps2) => filterMethodsByTier({
2629
3105
  method: import_zod4.z.enum(["list", "get", "create", "update", "delete", "help"]),
2630
3106
  type: import_zod4.z.enum(["paint", "text", "effect", "grid"]).optional().describe("Filter by style type"),
@@ -2641,13 +3117,21 @@ var tools = [
2641
3117
  if (m === "get") {
2642
3118
  if (params.id === void 0) throw new Error('get requires "id"');
2643
3119
  }
3120
+ if (m === "create") {
3121
+ const itemDiscriminant = Array.isArray(params.items) ? params.items.find((it) => it && typeof it === "object" && typeof it.type === "string")?.type : void 0;
3122
+ if (params.type === void 0) {
3123
+ throw new Error(itemDiscriminant ? 'styles.create uses top-level "type", not "type" inside items. Move the item value to the top level and use help for valid item shapes.' : 'styles.create requires top-level "type" (paint, text, effect, grid). Use styles(method: "help", topic: "create") for valid item shapes.');
3124
+ }
3125
+ }
2644
3126
  if (!params.items) return;
3127
+ if (Array.isArray(params.items) && params.items.length === 0) throw new Error('items: [] is a no-op. Batch calls need at least one item. Omit items to use single-item params, or pass one or more item objects. Use styles(method: "help", topic: "' + m + '") to see valid item shapes.');
2645
3128
  if (m === "create") {
2646
3129
  const schemas = {
2647
3130
  "paint": import_zod4.z.object({
2648
3131
  name: import_zod4.z.string().describe("Style name"),
2649
- color: colorRgba.optional().describe("Color value. Optional when colorVariableName is provided."),
2650
- colorVariableName: import_zod4.z.string().optional().describe("Bind to a COLOR variable by name (style tracks the variable). Can be used alone \u2014 color is resolved from the variable."),
3132
+ paints: paintArrayLoose.optional().describe('PaintStyle.paints authoring array. Accepts only SOLID and GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND, using gradientTransform + gradientStops, opacity/blendMode, and gradientStops[].boundVariables.color. Mutually exclusive with color/colorVariableName shorthands. Do not pass IMAGE/VIDEO/PATTERN, CSS gradients, REST gradientHandlePositions, or top-level gradient boundVariables. Use imageUrl/images for image authoring on nodes; VIDEO/PATTERN authoring is not supported here. For examples call styles(method:"help", topic:"create").'),
3133
+ color: colorRgba.optional().describe("Single-solid shorthand color. Optional when colorVariableName or paints is provided."),
3134
+ colorVariableName: import_zod4.z.string().optional().describe("Single-solid shorthand: bind to a COLOR variable by name (style tracks the variable). Can be used alone \u2014 color is resolved from the variable."),
2651
3135
  description: import_zod4.z.string().optional().describe("Style description")
2652
3136
  }).passthrough(),
2653
3137
  "text": import_zod4.z.object({
@@ -2671,25 +3155,27 @@ var tools = [
2671
3155
  }).passthrough(),
2672
3156
  "grid": import_zod4.z.object({
2673
3157
  name: import_zod4.z.string().describe("Style name"),
2674
- layoutGrids: flexJson(import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()))).describe("Array of LayoutGrid objects"),
3158
+ layoutGrids: flexJson(import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()))).describe("Array of LayoutGrid objects. Conditional shapes: GRID requires sectionSize and does not use alignment/count/gutterSize/offset; ROWS/COLUMNS use alignment/count/gutterSize/offset, and sectionSize only for fixed alignments MIN/MAX/CENTER. For alignment:STRETCH, omit sectionSize."),
2675
3159
  description: import_zod4.z.string().optional().describe("Style description")
2676
3160
  }).passthrough()
2677
3161
  };
2678
3162
  const s = params.type && schemas[params.type];
2679
- if (s) {
2680
- try {
2681
- params.items = import_zod4.z.array(s).parse(params.items);
2682
- } catch (e) {
2683
- if (e instanceof import_zod4.z.ZodError) {
2684
- throw new Error(e.issues.map((i) => {
2685
- const path = i.path.join(".");
2686
- const shape = s instanceof import_zod4.z.ZodObject ? s.shape : null;
2687
- const desc = shape?.[i.path[1]]?.description;
2688
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
2689
- }).join("; "));
2690
- }
2691
- throw e;
3163
+ if (!s) throw new Error('styles.create: unknown type. Use styles(method: "help", topic: "create") for valid types and item shapes.');
3164
+ try {
3165
+ params.items = import_zod4.z.array(s).parse(params.items);
3166
+ } catch (e) {
3167
+ if (e instanceof import_zod4.z.ZodError) {
3168
+ throw new Error(e.issues.map((i) => {
3169
+ const path = i.path.join(".");
3170
+ const shape = s instanceof import_zod4.z.ZodObject ? s.shape : null;
3171
+ const field = String(i.path[1] ?? i.path[0] ?? "");
3172
+ const desc = shape?.[field]?.description;
3173
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
3174
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call styles(method:"help", topic:"create").' : "";
3175
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
3176
+ }).join("; "));
2692
3177
  }
3178
+ throw e;
2693
3179
  }
2694
3180
  }
2695
3181
  if (m === "update") {
@@ -2697,8 +3183,9 @@ var tools = [
2697
3183
  id: import_zod4.z.string().describe("Style ID or name"),
2698
3184
  name: import_zod4.z.string().optional().describe("Rename the style"),
2699
3185
  description: import_zod4.z.string().optional().describe("Style description"),
2700
- color: colorRgba.optional().describe("New color (paint styles)"),
2701
- colorVariableName: import_zod4.z.string().optional().describe("Bind to a COLOR variable by name (paint styles)"),
3186
+ paints: paintArrayLoose.optional().describe('Replace PaintStyle.paints. Accepts only SOLID and GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND, using gradientTransform + gradientStops, opacity/blendMode, and gradientStops[].boundVariables.color. Mutually exclusive with color/colorVariableName. Do not pass IMAGE/VIDEO/PATTERN, CSS gradients, REST gradientHandlePositions, or top-level gradient boundVariables. Use imageUrl/images for image authoring on nodes; VIDEO/PATTERN authoring is not supported here. For examples call styles(method:"help", topic:"update").'),
3187
+ color: colorRgba.optional().describe("New single-solid color shorthand (paint styles)"),
3188
+ colorVariableName: import_zod4.z.string().optional().describe("Bind to a COLOR variable by name using single-solid shorthand (paint styles)"),
2702
3189
  fontFamily: import_zod4.z.string().optional(),
2703
3190
  fontStyle: import_zod4.z.string().optional(),
2704
3191
  fontSize: import_zod4.z.coerce.number().optional(),
@@ -2710,7 +3197,7 @@ var tools = [
2710
3197
  paragraphSpacing: import_zod4.z.coerce.number().optional().describe("Paragraph spacing (px)"),
2711
3198
  leadingTrim: import_zod4.z.enum(["CAP_HEIGHT", "NONE"]).optional(),
2712
3199
  effects: flexJson(import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()))).optional().describe("Array of Effect objects"),
2713
- layoutGrids: flexJson(import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()))).optional().describe("Array of LayoutGrid objects (grid styles)")
3200
+ layoutGrids: flexJson(import_zod4.z.array(import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()))).optional().describe("Array of LayoutGrid objects (grid styles). Conditional shapes: GRID requires sectionSize and does not use alignment/count/gutterSize/offset; ROWS/COLUMNS use alignment/count/gutterSize/offset, and sectionSize only for fixed alignments MIN/MAX/CENTER. For alignment:STRETCH, omit sectionSize.")
2714
3201
  }).passthrough();
2715
3202
  try {
2716
3203
  params.items = import_zod4.z.array(itemSchema).parse(params.items);
@@ -2719,8 +3206,11 @@ var tools = [
2719
3206
  throw new Error(e.issues.map((i) => {
2720
3207
  const path = i.path.join(".");
2721
3208
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
2722
- const desc = shape?.[i.path[1]]?.description;
2723
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
3209
+ const field = String(i.path[1] ?? i.path[0] ?? "");
3210
+ const desc = shape?.[field]?.description;
3211
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
3212
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call styles(method:"help", topic:"update").' : "";
3213
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
2724
3214
  }).join("; "));
2725
3215
  }
2726
3216
  throw e;
@@ -2737,8 +3227,11 @@ var tools = [
2737
3227
  throw new Error(e.issues.map((i) => {
2738
3228
  const path = i.path.join(".");
2739
3229
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
2740
- const desc = shape?.[i.path[1]]?.description;
2741
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
3230
+ const field = String(i.path[1] ?? i.path[0] ?? "");
3231
+ const desc = shape?.[field]?.description;
3232
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
3233
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call styles(method:"help", topic:"delete").' : "";
3234
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
2742
3235
  }).join("; "));
2743
3236
  }
2744
3237
  throw e;
@@ -2749,9 +3242,9 @@ var tools = [
2749
3242
  },
2750
3243
  {
2751
3244
  name: "text",
2752
- description: '/** Create and manage text 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 \u2014 produces a same-type copy (frame\u2192frame, instance\u2192instance, component\u2192component). Instance clones reference the same source component; they do not duplicate the component definition.\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 (items: TextItem[], depth?) \u2192 { results: {id}[] } // Create text nodes\n set_content(items: { nodeId: string; text: string }[], depth?) \u2192 { results: "ok"[] } // Replace text content on existing text nodes\n scan (items: { nodeId: string; limit?: number; includePath?: boolean; includeGeometry?: boolean }[]) \u2192 { results: ("ok" | {error})[] } // Scan all text nodes within a subtree\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).',
3245
+ description: '/** Create and manage text 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 \u2014 produces a same-type copy (frame\u2192frame, instance\u2192instance, component\u2192component). Instance clones reference the same source component; they do not duplicate the component definition.\n scale (id?, factor?, items?: { id: string; factor: number }[]) \u2192 { results: "ok"[] } // Proportionally rescale a node subtree using Figma\'s visual Scale tool behavior. This is for visual/artifact scaling, not responsive layout resizing.\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 (items: TextItem[], depth?) \u2192 { results: {id}[] } // Create text nodes\n set_content(items: { nodeId: string; text: string }[], depth?) \u2192 { results: "ok"[] } // Replace text content on existing text nodes\n scan (items: { nodeId: string; limit?: number; includePath?: boolean; includeGeometry?: boolean }[]) \u2192 { results: ("ok" | {error})[] } // Scan all text nodes within a subtree\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).',
2753
3246
  schema: (caps2) => filterMethodsByTier({
2754
- method: import_zod4.z.enum(["get", "list", "update", "delete", "clone", "audit", "reparent", "create", "set_content", "scan", "help"]),
3247
+ method: import_zod4.z.enum(["get", "list", "update", "delete", "clone", "scale", "audit", "reparent", "create", "set_content", "scan", "help"]),
2755
3248
  id: import_zod4.z.string().optional().describe("Node ID"),
2756
3249
  fields: flexStringList(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.'),
2757
3250
  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."),
@@ -2761,21 +3254,23 @@ var tools = [
2761
3254
  parentId: import_zod4.z.string().optional().describe("Search only within this subtree"),
2762
3255
  offset: import_zod4.z.coerce.number().optional().default(0).describe("Skip N items for pagination (default 0)"),
2763
3256
  limit: import_zod4.z.coerce.number().optional().default(100).describe("Max items per page (default 100)"),
2764
- 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 update/delete/clone/reparent/create/set_content/scan"),
3257
+ 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 update/delete/clone/scale/reparent/create/set_content/scan"),
2765
3258
  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)"),
2766
3259
  x: import_zod4.z.coerce.number().optional().describe("X position (default: 0)"),
2767
3260
  y: import_zod4.z.coerce.number().optional().describe("Y position (default: 0)"),
3261
+ factor: import_zod4.z.coerce.number().optional().describe("Scale factor, >= 0.01. 0.5 = 50%, 2 = 200%. Scales children, text, strokes, effects, and layout geometry from the node's top-left. On auto-layout or HUG/FILL nodes, Figma may resolve responsive sizing to fixed width/height."),
2768
3262
  rules: flexStringList(import_zod4.z.array(import_zod4.z.string())).optional().describe('Rules to check. Default: ["all"]. Categories: "component", "composition", "token", "naming", "wcag".'),
2769
3263
  maxDepth: import_zod4.z.coerce.number().optional().describe("Max tree depth (default: 10)"),
2770
3264
  maxFindings: import_zod4.z.coerce.number().optional().describe("Max findings (default: 50)"),
2771
3265
  minSeverity: import_zod4.z.enum(["error", "unsafe", "heuristic", "style", "verbose"]).optional().describe("Minimum severity to report (default: style). Set to 'verbose' to include AAA contrast and line-height checks."),
2772
3266
  skipInstances: flexBool(import_zod4.z.boolean()).optional().describe("Skip instance internals \u2014 findings inside instances are owned by the component (default: true)"),
2773
3267
  topic: import_zod4.z.string().optional().describe('Help topic \u2014 method name for endpoint help, e.g. "create"')
2774
- }, caps2, { "get": "read", "list": "read", "update": "edit", "delete": "edit", "clone": "create", "audit": "read", "reparent": "edit", "create": "create", "set_content": "edit", "scan": "read", "help": "read" }),
3268
+ }, caps2, { "get": "read", "list": "read", "update": "edit", "delete": "edit", "clone": "create", "scale": "edit", "audit": "read", "reparent": "edit", "create": "create", "set_content": "edit", "scan": "read", "help": "read" }),
2775
3269
  tier: "read",
2776
3270
  validate: (params) => {
2777
3271
  const m = params.method;
2778
3272
  if (!params.items) return;
3273
+ if (Array.isArray(params.items) && params.items.length === 0) throw new Error('items: [] is a no-op. Batch calls need at least one item. Omit items to use single-item params, or pass one or more item objects. Use text(method: "help", topic: "' + m + '") to see valid item shapes.');
2779
3274
  if (m === "create") {
2780
3275
  for (const it of params.items) {
2781
3276
  if (it.characters !== void 0 && it.text === void 0) {
@@ -2798,7 +3293,7 @@ var tools = [
2798
3293
  letterSpacing: letterSpacing.optional(),
2799
3294
  textCase: import_zod4.z.enum(["ORIGINAL", "UPPER", "LOWER", "TITLE", "SMALL_CAPS", "SMALL_CAPS_FORCED"]).optional(),
2800
3295
  textDecoration: import_zod4.z.enum(["NONE", "UNDERLINE", "STRIKETHROUGH"]).optional(),
2801
- 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."),
3296
+ fills: paintArrayLoose.optional().describe("Text Paint[] authoring \u2014 accepts only SOLID or GRADIENT_LINEAR/RADIAL/ANGULAR/DIAMOND with gradientTransform + gradientStops. Same as node fills. Do not use CSS gradients, REST gradientHandlePositions, IMAGE/VIDEO/PATTERN, or top-level gradient boundVariables. IMAGE/VIDEO/PATTERN may appear in readback metadata only."),
2802
3297
  fontColor: colorRgba.optional().describe("Shorthand \u2014 sets text color (auto-binds to matching variable/style)"),
2803
3298
  fontColorVariableName: import_zod4.z.string().optional().describe("Bind color variable by name e.g. 'text/primary'"),
2804
3299
  fontColorStyleName: import_zod4.z.string().optional().describe("Apply paint style \u2014 overrides fontColor"),
@@ -2820,8 +3315,11 @@ var tools = [
2820
3315
  throw new Error(e.issues.map((i) => {
2821
3316
  const path = i.path.join(".");
2822
3317
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
2823
- const desc = shape?.[i.path[1]]?.description;
2824
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
3318
+ const field = String(i.path[1] ?? i.path[0] ?? "");
3319
+ const desc = shape?.[field]?.description;
3320
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
3321
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call text(method:"help", topic:"create").' : "";
3322
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
2825
3323
  }).join("; "));
2826
3324
  }
2827
3325
  throw e;
@@ -2849,19 +3347,22 @@ var tools = [
2849
3347
  throw new Error(e.issues.map((i) => {
2850
3348
  const path = i.path.join(".");
2851
3349
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
2852
- const desc = shape?.[i.path[1]]?.description;
2853
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
3350
+ const field = String(i.path[1] ?? i.path[0] ?? "");
3351
+ const desc = shape?.[field]?.description;
3352
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
3353
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call text(method:"help", topic:"set_content").' : "";
3354
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
2854
3355
  }).join("; "));
2855
3356
  }
2856
3357
  throw e;
2857
3358
  }
2858
3359
  }
2859
3360
  },
2860
- commandMap: { "get": "text.get", "list": "text.list", "update": "text.update", "delete": "text.delete", "clone": "text.clone", "audit": "text.audit", "reparent": "text.reparent", "create": "text.create", "set_content": "text.set_content", "scan": "text.scan" }
3361
+ commandMap: { "get": "text.get", "list": "text.list", "update": "text.update", "delete": "text.delete", "clone": "text.clone", "scale": "text.scale", "audit": "text.audit", "reparent": "text.reparent", "create": "text.create", "set_content": "text.set_content", "scan": "text.scan" }
2861
3362
  },
2862
3363
  {
2863
3364
  name: "variable_collections",
2864
- description: '/** CRUD for variable collections \u2014 the document-level API for design tokens. Use method "help" for detailed parameter docs. */\n list (fields?, offset?, limit?) \u2192 { totalCount, items } // List variable collections\n get (id, fields?) \u2192 { id?, name?, modes?, variables? } // Get collection with all variables and values (full document)\n create (items: { name: string; modes?: string[]; variables?: { name: string; type: "COLOR" | "FLOAT" | "STRING" | "BOOLEAN"; value?: number | boolean | string | Color | {type: "VARIABLE_ALIAS", name: string}; valuesByMode?: Record<string, unknown>; description?: string; scopes?: string[] }[] }[]) \u2192 { results: {id}[] } // Create a collection with modes and variables in one call\n update (items: { id: string; name: string }[]) \u2192 { results: ("ok" | {error})[] } // Rename collections\n delete (id?, items?: { id: string }[]) \u2192 { results: "ok"[] } // Delete collections\n add_mode (items: { collectionId: string; name: string }[]) \u2192 { results: {modeId}[] } // Add a mode to a collection\n rename_mode(items: { collectionId: string; modeId: string; name: string }[]) \u2192 { results: ("ok" | {error})[] } // Rename a mode\n remove_mode(items: { collectionId: string; modeId: string }[]) \u2192 { results: "ok"[] } // Remove a mode from a collection\n// Variable collections group design tokens and define their modes (e.g. Light/Dark, Desktop/Mobile).\n// All ID params accept both IDs and display names.\n// Shared types:\n// Color: hex "#FF0000" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}',
3365
+ description: '/** CRUD for variable collections \u2014 the document-level API for design tokens. Use method "help" for detailed parameter docs. */\n list (fields?, offset?, limit?) \u2192 { totalCount, items } // List variable collections\n get (id, fields?) \u2192 { id?, name?, modes?, variables? } // Get collection with all variables and values (full document)\n create (items: { name: string; modes?: string[]; variables?: { name: string; type: "COLOR" | "FLOAT" | "STRING" | "BOOLEAN"; value?: number | boolean | string | Color | {type: "VARIABLE_ALIAS", name: string}; valuesByMode?: Record<string, unknown>; description?: string; scopes?: string[] }[] }[]) \u2192 { results: {id}[] } // Create a collection with modes and variables in one call\n update (items: { id: string; name: string }[]) \u2192 { results: ("ok" | {error})[] } // Rename collections\n delete (id?, items?: { id: string }[]) \u2192 { results: "ok"[] } // Delete collections\n add_mode (items: { collectionId: string; name: string }[]) \u2192 { results: {modeId}[] } // Add a mode to a collection\n rename_mode(items: { collectionId: string; modeId: string; name: string }[]) \u2192 { results: ("ok" | {error})[] } // Rename a mode\n remove_mode(items: { collectionId: string; modeId: string }[]) \u2192 { results: "ok"[] } // Remove a mode from a collection\n// Variable collections group design tokens and define their modes (e.g. Light/Dark, Desktop/Mobile).\n// All ID params accept both IDs and display names.\n// Shared types:\n// Color: hex "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}',
2865
3366
  schema: (caps2) => filterMethodsByTier({
2866
3367
  method: import_zod4.z.enum(["list", "get", "create", "update", "delete", "add_mode", "rename_mode", "remove_mode", "help"]),
2867
3368
  fields: flexStringList(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.'),
@@ -2878,6 +3379,7 @@ var tools = [
2878
3379
  if (params.id === void 0) throw new Error('get requires "id"');
2879
3380
  }
2880
3381
  if (!params.items) return;
3382
+ if (Array.isArray(params.items) && params.items.length === 0) throw new Error('items: [] is a no-op. Batch calls need at least one item. Omit items to use single-item params, or pass one or more item objects. Use variable_collections(method: "help", topic: "' + m + '") to see valid item shapes.');
2881
3383
  if (m === "create") {
2882
3384
  const itemSchema = import_zod4.z.object({
2883
3385
  name: import_zod4.z.string().describe("Collection name"),
@@ -2891,8 +3393,11 @@ var tools = [
2891
3393
  throw new Error(e.issues.map((i) => {
2892
3394
  const path = i.path.join(".");
2893
3395
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
2894
- const desc = shape?.[i.path[1]]?.description;
2895
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
3396
+ const field = String(i.path[1] ?? i.path[0] ?? "");
3397
+ const desc = shape?.[field]?.description;
3398
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
3399
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call variable_collections(method:"help", topic:"create").' : "";
3400
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
2896
3401
  }).join("; "));
2897
3402
  }
2898
3403
  throw e;
@@ -2910,8 +3415,11 @@ var tools = [
2910
3415
  throw new Error(e.issues.map((i) => {
2911
3416
  const path = i.path.join(".");
2912
3417
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
2913
- const desc = shape?.[i.path[1]]?.description;
2914
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
3418
+ const field = String(i.path[1] ?? i.path[0] ?? "");
3419
+ const desc = shape?.[field]?.description;
3420
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
3421
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call variable_collections(method:"help", topic:"update").' : "";
3422
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
2915
3423
  }).join("; "));
2916
3424
  }
2917
3425
  throw e;
@@ -2928,8 +3436,11 @@ var tools = [
2928
3436
  throw new Error(e.issues.map((i) => {
2929
3437
  const path = i.path.join(".");
2930
3438
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
2931
- const desc = shape?.[i.path[1]]?.description;
2932
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
3439
+ const field = String(i.path[1] ?? i.path[0] ?? "");
3440
+ const desc = shape?.[field]?.description;
3441
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
3442
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call variable_collections(method:"help", topic:"delete").' : "";
3443
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
2933
3444
  }).join("; "));
2934
3445
  }
2935
3446
  throw e;
@@ -2947,8 +3458,11 @@ var tools = [
2947
3458
  throw new Error(e.issues.map((i) => {
2948
3459
  const path = i.path.join(".");
2949
3460
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
2950
- const desc = shape?.[i.path[1]]?.description;
2951
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
3461
+ const field = String(i.path[1] ?? i.path[0] ?? "");
3462
+ const desc = shape?.[field]?.description;
3463
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
3464
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call variable_collections(method:"help", topic:"add_mode").' : "";
3465
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
2952
3466
  }).join("; "));
2953
3467
  }
2954
3468
  throw e;
@@ -2967,8 +3481,11 @@ var tools = [
2967
3481
  throw new Error(e.issues.map((i) => {
2968
3482
  const path = i.path.join(".");
2969
3483
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
2970
- const desc = shape?.[i.path[1]]?.description;
2971
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
3484
+ const field = String(i.path[1] ?? i.path[0] ?? "");
3485
+ const desc = shape?.[field]?.description;
3486
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
3487
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call variable_collections(method:"help", topic:"rename_mode").' : "";
3488
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
2972
3489
  }).join("; "));
2973
3490
  }
2974
3491
  throw e;
@@ -2986,8 +3503,11 @@ var tools = [
2986
3503
  throw new Error(e.issues.map((i) => {
2987
3504
  const path = i.path.join(".");
2988
3505
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
2989
- const desc = shape?.[i.path[1]]?.description;
2990
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
3506
+ const field = String(i.path[1] ?? i.path[0] ?? "");
3507
+ const desc = shape?.[field]?.description;
3508
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
3509
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call variable_collections(method:"help", topic:"remove_mode").' : "";
3510
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
2991
3511
  }).join("; "));
2992
3512
  }
2993
3513
  throw e;
@@ -2998,7 +3518,7 @@ var tools = [
2998
3518
  },
2999
3519
  {
3000
3520
  name: "variables",
3001
- 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}',
3521
+ 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 { id, 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: {id, 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 "#RGB"|"#RGBA"|"#RRGGBB"|"#RRGGBBAA" or {r: 0-1, g: 0-1, b: 0-1, a?: 0-1}',
3002
3522
  schema: (caps2) => filterMethodsByTier({
3003
3523
  method: import_zod4.z.enum(["list", "get", "create", "update", "delete", "help"]),
3004
3524
  collectionId: import_zod4.z.string().optional().describe("Collection ID or name"),
@@ -3031,6 +3551,7 @@ var tools = [
3031
3551
  if (params.collectionId === void 0) throw new Error('delete requires "collectionId"');
3032
3552
  }
3033
3553
  if (!params.items) return;
3554
+ if (Array.isArray(params.items) && params.items.length === 0) throw new Error('items: [] is a no-op. Batch calls need at least one item. Omit items to use single-item params, or pass one or more item objects. Use variables(method: "help", topic: "' + m + '") to see valid item shapes.');
3034
3555
  if (m === "create") {
3035
3556
  const itemSchema = import_zod4.z.object({
3036
3557
  name: import_zod4.z.string().describe("Variable name (must be unique within collection)"),
@@ -3047,8 +3568,11 @@ var tools = [
3047
3568
  throw new Error(e.issues.map((i) => {
3048
3569
  const path = i.path.join(".");
3049
3570
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
3050
- const desc = shape?.[i.path[1]]?.description;
3051
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
3571
+ const field = String(i.path[1] ?? i.path[0] ?? "");
3572
+ const desc = shape?.[field]?.description;
3573
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
3574
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call variables(method:"help", topic:"create").' : "";
3575
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
3052
3576
  }).join("; "));
3053
3577
  }
3054
3578
  throw e;
@@ -3070,8 +3594,11 @@ var tools = [
3070
3594
  throw new Error(e.issues.map((i) => {
3071
3595
  const path = i.path.join(".");
3072
3596
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
3073
- const desc = shape?.[i.path[1]]?.description;
3074
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
3597
+ const field = String(i.path[1] ?? i.path[0] ?? "");
3598
+ const desc = shape?.[field]?.description;
3599
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
3600
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call variables(method:"help", topic:"update").' : "";
3601
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
3075
3602
  }).join("; "));
3076
3603
  }
3077
3604
  throw e;
@@ -3088,8 +3615,11 @@ var tools = [
3088
3615
  throw new Error(e.issues.map((i) => {
3089
3616
  const path = i.path.join(".");
3090
3617
  const shape = itemSchema instanceof import_zod4.z.ZodObject ? itemSchema.shape : null;
3091
- const desc = shape?.[i.path[1]]?.description;
3092
- return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "");
3618
+ const field = String(i.path[1] ?? i.path[0] ?? "");
3619
+ const desc = shape?.[field]?.description;
3620
+ const paintField = field === "paints" || field === "fills" || field === "strokes";
3621
+ const paintHelp = paintField ? ' Invalid Paint[] payload. Supported Paint[] authoring types: SOLID, GRADIENT_LINEAR, GRADIENT_RADIAL, GRADIENT_ANGULAR, GRADIENT_DIAMOND. Use gradientTransform + gradientStops; do not use CSS gradients or REST gradientHandlePositions. IMAGE/VIDEO/PATTERN are readback-only metadata, not Paint[] authoring input; use imageUrl/images for images. For examples call variables(method:"help", topic:"delete").' : "";
3622
+ return path + ": " + i.message + (desc ? " (expected: " + desc + ")" : "") + paintHelp;
3093
3623
  }).join("; "));
3094
3624
  }
3095
3625
  throw e;
@@ -3146,10 +3676,10 @@ var guidelinesList = [
3146
3676
  }
3147
3677
  ];
3148
3678
  var guidelinesContent = {
3149
- "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## Slots\n\nSlots are placeholder containers inside components that instance users can fill with custom content.\n\n- Create at component root: `frames(method:"create", type:"slot", items:[{parentId:"<comp_id>", name:"Content"}])`\n- Create nested inside a frame within a component: `frames(method:"create", type:"slot", items:[{parentId:"<frame_id>", name:"Content"}])`\n- In instances, add content by using the slot\'s ID as `parentId` on any create/reparent call\n- Empty slots are normal \u2014 they don\'t trigger lint warnings\n\n## Checking\n\nRun `components(method:"audit", id)` \u2014 checks both lint rules and property bindings in one call.',
3679
+ "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:"space/8"}])`\n\nProperty bindings (TEXT, INSTANCE_SWAP) are preserved on cloned variants.\n\n## Slots\n\nSlots are placeholder containers inside components that instance users can fill with custom content.\n\n- Create at component root: `frames(method:"create", type:"slot", items:[{parentId:"<comp_id>", name:"Content"}])`\n- Create nested inside a frame within a component: `frames(method:"create", type:"slot", items:[{parentId:"<frame_id>", name:"Content"}])`\n- In instances, add content by using the slot\'s ID as `parentId` on any create/reparent call\n- Empty slots are normal \u2014 they don\'t trigger lint warnings\n\n## Checking\n\nRun `components(method:"audit", id)` \u2014 checks both lint rules and property bindings in one call.',
3150
3680
  "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).',
3151
3681
  "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',
3152
- "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.',
3682
+ "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/surface"` or `fillStyleName:"Surface/Primary"`\n- Stroke: `strokeVariableName:"border/subtle"`\n- Text color: `fontColorVariableName:"text/primary"`\n\nIf no matching variable exists, create one first:\n```\nvariables(method:"create", collectionId:"Tokens", items:[{name:"bg/warning", type:"COLOR", value:"#F59E0B", 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:"Tokens", items:[{name:"space/32", type:"FLOAT", value:32, scopes:["GAP"]}])\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.',
3153
3683
  "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.'
3154
3684
  };
3155
3685
  function resolveGuideline(topic) {
@@ -4086,7 +4616,8 @@ async function registerAllTools(server2, sendCommand, caps2) {
4086
4616
  return { content: [{ type: "text", text }] };
4087
4617
  }
4088
4618
  const teamFromEnv = process.env.FIGMA_TEAM_ID;
4089
- let { file, team } = params;
4619
+ const { file } = params;
4620
+ let { team } = params;
4090
4621
  const needsTarget = (m) => m === "list" || m === "get" && filterRegistryByQuery("").length === 0;
4091
4622
  if (!file && !team && needsTarget(method) && teamFromEnv) team = teamFromEnv;
4092
4623
  if (method === "list") {
@@ -4517,9 +5048,9 @@ See "Version mismatch" in CARRYME.md or DRAGME.md for update steps.`;
4517
5048
  type: "text",
4518
5049
  text: connected ? `Tunnel reset: ${body.message}. Reconnected on port ${activePort}.
4519
5050
 
4520
- IMPORTANT: The Figma plugin was also disconnected. Ask the user to reopen the Vibma plugin, then call connection(method: "create") followed by connection(method: "get").` : `Tunnel reset: ${body.message}. Reconnection in progress.
5051
+ IMPORTANT: The Figma plugin was also disconnected from the tunnel. Ask the user to use the existing Vibma plugin window and click Connect again if needed, then call connection(method: "create") followed by connection(method: "get").` : `Tunnel reset: ${body.message}. Reconnection in progress.
4521
5052
 
4522
- IMPORTANT: The Figma plugin was also disconnected. Ask the user to reopen the Vibma plugin, then call connection(method: "create") to retry.`
5053
+ IMPORTANT: The Figma plugin was also disconnected from the tunnel. Ask the user to use the existing Vibma plugin window and click Connect again if needed, then call connection(method: "create") to retry.`
4523
5054
  }]
4524
5055
  };
4525
5056
  }