12 KiB
figma-plugin-api Specification
Purpose
Figma-compatible Plugin API for headless JavaScript execution. Provides figma global object (FigmaAPI class) that mirrors Figma's plugin surface for scripting .fig files. Enables eval command, AI tools, and automated batch operations without GUI.
Requirements
Requirement: Figma-compatible global object
The system SHALL provide a figma global object that mirrors Figma's Plugin API surface for headless JavaScript execution.
Scenario: Creating figma object
- WHEN
new FigmaAPI(sceneGraph)is instantiated - THEN the object provides methods matching Figma's plugin API (createFrame, createRectangle, createText, etc.)
Scenario: Accessing current page
- WHEN user accesses
figma.currentPage - THEN system returns a proxy for the active page with methods like
findAll,findOne,appendChild
Scenario: Accessing document root
- WHEN user accesses
figma.root - THEN system returns a proxy for the document root containing all pages
Requirement: Node creation methods
The system SHALL provide creation methods for all supported node types.
Scenario: Creating a frame
- WHEN user calls
figma.createFrame() - THEN system creates a FRAME node, adds it to current page, and returns a proxy
Scenario: Creating a rectangle
- WHEN user calls
figma.createRectangle() - THEN system creates a RECTANGLE node with default fill
Scenario: Creating text
- WHEN user calls
figma.createText() - THEN system creates a TEXT node with default font (Inter Regular 14px)
Scenario: Creating other shapes
- WHEN user calls
figma.createEllipse(),figma.createLine(),figma.createPolygon(),figma.createStar(),figma.createVector() - THEN system creates corresponding node types
Scenario: Creating component
- WHEN user calls
figma.createComponent() - THEN system creates a COMPONENT node
Scenario: Creating component set
- WHEN user calls
figma.createComponentSet() - THEN system creates a COMPONENT_SET node
Requirement: Node proxy with property access
The system SHALL wrap SceneNode objects in proxies that provide Figma-compatible property getters and setters.
Scenario: Reading node properties
- WHEN user accesses
node.id,node.type,node.name,node.x,node.y,node.width,node.height - THEN system returns current values from the underlying SceneNode
Scenario: Setting node properties
- WHEN user sets
node.name = "New Name"ornode.x = 100 - THEN system updates the SceneNode via SceneGraph.updateNode()
Scenario: Reading removed nodes
- WHEN user accesses a property on a removed node
- THEN system throws "Node has been removed"
Requirement: Geometry and transforms
The system SHALL provide geometry properties matching Figma's API.
Scenario: Basic dimensions
- WHEN user accesses
node.width,node.height,node.rotation - THEN system returns dimensions and rotation from SceneNode
Scenario: Absolute position
- WHEN user accesses
node.absoluteTransform - THEN system returns 2x3 matrix
[[a, b, tx], [c, d, ty]]
Scenario: Absolute bounding box
- WHEN user accesses
node.absoluteBoundingBoxornode.absoluteRenderBounds - THEN system returns
{x, y, width, height}in absolute coordinates
Scenario: Resizing nodes
- WHEN user calls
node.resize(200, 100) - THEN system updates node width and height
Requirement: Fill, stroke, and effects
The system SHALL provide Figma-compatible paint and effect properties.
Scenario: Reading fills
- WHEN user accesses
node.fills - THEN system returns frozen array of Fill objects
Scenario: Setting fills
- WHEN user sets
node.fills = [{ type: "SOLID", color: { r: 1, g: 0, b: 0 } }] - THEN system updates node fills
Scenario: Reading strokes
- WHEN user accesses
node.strokes,node.strokeWeight,node.strokeAlign - THEN system returns stroke configuration
Scenario: Reading effects
- WHEN user accesses
node.effects - THEN system returns frozen array of Effect objects
Requirement: Text node properties
The system SHALL provide text-specific properties for TEXT nodes.
Scenario: Reading text content
- WHEN user accesses
textNode.characters - THEN system returns text content string
Scenario: Setting text content
- WHEN user sets
textNode.characters = "Hello" - THEN system updates text content
Scenario: Font properties
- WHEN user accesses
textNode.fontName,textNode.fontSize,textNode.fontWeight - THEN system returns font configuration
Scenario: Setting font
- WHEN user sets
textNode.fontName = { family: "Inter", style: "Bold" } - THEN system converts style to weight (700) and updates font
Scenario: Text alignment
- WHEN user accesses
textNode.textAlignHorizontal - THEN system returns "LEFT", "CENTER", or "RIGHT"
Requirement: Auto-layout properties
The system SHALL provide auto-layout (flexbox) properties for frames.
Scenario: Reading layout mode
- WHEN user accesses
frame.layoutMode - THEN system returns "NONE", "HORIZONTAL", or "VERTICAL"
Scenario: Setting layout mode
- WHEN user sets
frame.layoutMode = "VERTICAL" - THEN system enables auto-layout with vertical direction
Scenario: Spacing and padding
- WHEN user accesses
frame.itemSpacing,frame.paddingLeft,frame.paddingTop, etc. - THEN system returns spacing values
Scenario: Layout sizing
- WHEN user accesses
node.layoutSizingHorizontal,node.layoutSizingVertical - THEN system returns "FIXED", "HUG", or "FILL"
Requirement: Tree operations
The system SHALL provide methods for manipulating the scene graph tree.
Scenario: Appending child
- WHEN user calls
parent.appendChild(child) - THEN system reparents child to parent
Scenario: Inserting child
- WHEN user calls
parent.insertChild(2, child) - THEN system inserts child at index 2 in parent's children
Scenario: Accessing children
- WHEN user accesses
parent.children - THEN system returns frozen array of child proxies
Scenario: Accessing parent
- WHEN user accesses
node.parent - THEN system returns parent proxy or null for root
Scenario: Removing node
- WHEN user calls
node.remove() - THEN system deletes node from scene graph
Requirement: Traversal and queries
The system SHALL provide methods for finding nodes in the scene graph.
Scenario: Finding all matching nodes
- WHEN user calls
figma.currentPage.findAll(n => n.type === "FRAME") - THEN system returns array of proxies for all frames in the page
Scenario: Finding first matching node
- WHEN user calls
figma.currentPage.findOne(n => n.name === "Button") - THEN system returns first matching proxy or null
Scenario: Finding by ID
- WHEN user calls
figma.getNodeById("node-123") - THEN system returns proxy for that node or null
Scenario: Finding with criteria object
- WHEN user calls
figma.currentPage.findAllWithCriteria({ types: ["FRAME", "GROUP"] }) - THEN system returns array of proxies matching type criteria
Requirement: Selection management
The system SHALL track and expose current selection.
Scenario: Reading selection
- WHEN user accesses
figma.currentPage.selection - THEN system returns array of selected node proxies
Scenario: Setting selection
- WHEN user sets
figma.currentPage.selection = [node1, node2] - THEN system updates editor selection state
Requirement: Component operations
The system SHALL provide component and instance methods.
Scenario: Creating component from node
- WHEN user calls
figma.createComponentFromNode(frame) - THEN system converts frame to COMPONENT and returns proxy
Scenario: Creating instance
- WHEN user calls
component.createInstance() - THEN system creates INSTANCE referencing the component
Scenario: Swapping instance
- WHEN user calls
instance.swapComponent(otherComponent) - THEN system updates instance's mainComponent reference
Requirement: Grouping operations
The system SHALL provide grouping methods.
Scenario: Grouping nodes
- WHEN user calls
figma.group([node1, node2], parent) - THEN system creates a GROUP containing the nodes
Scenario: Ungrouping
- WHEN user calls
figma.ungroup(group) - THEN system removes group and reparents children to group's parent
Requirement: Corner radius handling
The system SHALL handle both uniform and independent corner radii matching Figma's API.
Scenario: Uniform corner radius
- WHEN user accesses
rectangle.cornerRadiusand all corners have same radius - THEN system returns that radius value
Scenario: Mixed corner radius
- WHEN user accesses
rectangle.cornerRadiusand corners have different radii - THEN system returns the MIXED symbol
Scenario: Individual corners
- WHEN user accesses
rectangle.topLeftRadius,rectangle.topRightRadius, etc. - THEN system returns individual corner radius values
Requirement: Cloning nodes
The system SHALL support deep cloning of nodes.
Scenario: Cloning a node
- WHEN user calls
node.clone() - THEN system creates a deep copy with new GUID and returns proxy
Scenario: Cloning with children
- WHEN user calls
frame.clone()on a frame with children - THEN system recursively clones children
Requirement: JSON serialization
The system SHALL provide JSON export for AI tools and debugging.
Scenario: Exporting node to JSON
- WHEN user calls
figma.toJSON(node) - THEN system returns object with
type,name,id, geometry, fills, strokes, and recursive children
Scenario: Exporting with depth limit
- WHEN user calls
figma.toJSON(node, { maxDepth: 2 }) - THEN system includes children only 2 levels deep
Requirement: Frozen arrays for safety
The system SHALL return frozen arrays for multi-value properties to prevent accidental mutation.
Scenario: Fills array is frozen
- WHEN user accesses
node.fillsand triesfills.push(...) - THEN system throws error (array is frozen)
Scenario: Children array is frozen
- WHEN user accesses
parent.childrenand trieschildren[0] = other - THEN system throws error (array is frozen)
Requirement: Internal symbols hidden
The system SHALL hide internal implementation details using Symbol properties.
Scenario: Internals not enumerable
- WHEN user calls
Object.keys(nodeProxy)orfor (let k in nodeProxy) - THEN system does not expose INTERNAL_ID, INTERNAL_GRAPH, INTERNAL_API
Requirement: Variable support
The system SHALL provide access to design variables.
Scenario: Listing variables
- WHEN user calls
figma.variables.getLocalVariables() - THEN system returns array of Variable objects
Scenario: Listing variable collections
- WHEN user calls
figma.variables.getLocalVariableCollections() - THEN system returns array of VariableCollection objects
Scenario: Getting variable by ID
- WHEN user calls
figma.variables.getVariableById("var-123") - THEN system returns Variable object or undefined
Requirement: Type guards
The system SHALL provide type-checking methods matching Figma's API.
Scenario: Checking node type
- WHEN user checks
if (node.type === "FRAME") - THEN system allows type-based branching
Requirement: Stub methods for unimplemented features
The system SHALL provide stub methods for Figma API methods not yet implemented, throwing descriptive errors.
Scenario: Calling unimplemented method
- WHEN user calls
figma.createImage(data)orfigma.createShapeWithText() - THEN system throws "Not implemented: "
Scenario: Notifying user
- WHEN user calls
figma.notify("Hello") - THEN system logs to console (headless mode has no UI notifications)