# Plugin API Patterns > Part of the [use_figma skill](../SKILL.md). Quick reference for common Figma Plugin API operations. ## Contents - Execution Basics - Creating Nodes - Fills and Strokes - Auto Layout - Effects - Opacity and Blend Modes - Corner Radius and Clipping - Grouping and Organization - Components and Variants - Styles - Cloning, Finding Nodes, and Grids - Constraints and Viewport ## Execution Basics ### Page Context Page context resets between `use_figma` calls — `figma.currentPage` always starts on the first page. Use `await figma.setCurrentPageAsync(page)` at the start of each invocation to switch to the correct page. ```javascript const targetPage = figma.root.children.find(p => p.name === "My Page"); await figma.setCurrentPageAsync(targetPage); // targetPage.children is now populated ``` ### Returning Results Scripts are automatically wrapped in an async IIFE with error handling. Just write plain JS and use `return` to send data back to the agent: ```javascript // Return an object — auto-serialized to JSON return { nodeId: frame.id, count: 5 } // Return a string return "Created 3 components" ``` Errors are automatically captured — no try/catch needed. `figma.notify()` does **not** exist. Return all information via the `return` value. ### Working Incrementally Don't build an entire screen in one call. Break work into small steps: 1. Create tokens/variables 2. Create text styles 3. Build individual components 4. Compose sections 5. Assemble screens Verify structure with `get_metadata` between steps. Use `get_screenshot` after each major creation milestone to catch visual problems early. ## Creating Nodes ### Frames ```javascript const frame = figma.createFrame(); frame.name = "Container"; frame.resize(1440, 900); frame.x = 0; frame.y = 0; frame.fills = [{ type: "SOLID", color: { r: 0.98, g: 0.98, b: 0.99 } }]; ``` ### Text ```javascript // MUST load font before any text operations await figma.loadFontAsync({ family: "Inter", style: "Regular" }); const text = figma.createText(); text.fontName = { family: "Inter", style: "Regular" }; text.fontSize = 16; text.lineHeight = { value: 24, unit: "PIXELS" }; text.letterSpacing = { value: 0, unit: "PERCENT" }; text.characters = "Hello World"; text.fills = [{ type: "SOLID", color: { r: 0.1, g: 0.1, b: 0.12 } }]; ``` ### Rectangles ```javascript const rect = figma.createRectangle(); rect.name = "Background"; rect.resize(400, 300); rect.cornerRadius = 12; rect.fills = [{ type: "SOLID", color: { r: 0.95, g: 0.95, b: 0.96 } }]; ``` ### Ellipses ```javascript const circle = figma.createEllipse(); circle.name = "Avatar Circle"; circle.resize(48, 48); circle.fills = [{ type: "SOLID", color: { r: 0.85, g: 0.87, b: 0.90 } }]; ``` ### Lines ```javascript const line = figma.createLine(); line.name = "Divider"; line.resize(400, 0); line.strokes = [{ type: "SOLID", color: { r: 0, g: 0, b: 0 }, opacity: 0.08 }]; line.strokeWeight = 1; ``` ### SVG Import ```javascript const svgString = ` `; const node = figma.createNodeFromSvg(svgString); node.name = "Icon/Arrow Right"; node.resize(24, 24); ``` ## Fills & Strokes ### Solid Fill ```javascript node.fills = [{ type: "SOLID", color: { r: 0.2, g: 0.2, b: 0.25 } }]; ``` ### Fill with Opacity ```javascript node.fills = [{ type: "SOLID", color: { r: 0.2, g: 0.2, b: 0.25 }, opacity: 0.5 }]; ``` ### No Fill (Transparent) ```javascript node.fills = []; ``` ### Linear Gradient ```javascript node.fills = [{ type: "GRADIENT_LINEAR", gradientStops: [ { color: { r: 0.2, g: 0.36, b: 0.96, a: 1 }, position: 0 }, { color: { r: 0.56, g: 0.24, b: 0.88, a: 1 }, position: 1 } ], gradientTransform: [[1, 0, 0], [0, 1, 0]] }]; ``` ### Strokes ```javascript node.strokes = [{ type: "SOLID", color: { r: 0.85, g: 0.85, b: 0.87 } }]; node.strokeWeight = 1; node.strokeAlign = "INSIDE"; // "CENTER", "OUTSIDE" ``` ### Multiple Fills (Layered) ```javascript node.fills = [ { type: "SOLID", color: { r: 0.95, g: 0.95, b: 0.96 } }, { type: "SOLID", color: { r: 0.2, g: 0.36, b: 0.96 }, opacity: 0.05 } ]; ``` ## Auto Layout ### Setting Up Auto Layout ```javascript const frame = figma.createFrame(); frame.layoutMode = "VERTICAL"; // or "HORIZONTAL" frame.primaryAxisSizingMode = "AUTO"; // Hug main axis frame.counterAxisSizingMode = "FIXED"; // Fixed cross axis frame.resize(360, 1); // Width fixed, height auto frame.itemSpacing = 16; // Gap between children frame.paddingTop = 24; frame.paddingBottom = 24; frame.paddingLeft = 24; frame.paddingRight = 24; ``` ### Alignment ```javascript // Main axis (direction of layout) frame.primaryAxisAlignItems = "MIN"; // Start frame.primaryAxisAlignItems = "CENTER"; // Center frame.primaryAxisAlignItems = "MAX"; // End frame.primaryAxisAlignItems = "SPACE_BETWEEN"; // Distribute // Cross axis frame.counterAxisAlignItems = "MIN"; // Start frame.counterAxisAlignItems = "CENTER"; // Center frame.counterAxisAlignItems = "MAX"; // End // NOTE: 'STRETCH' is NOT valid — use 'MIN' + child.layoutSizingX = 'FILL' ``` ### Child Sizing ```javascript // IMPORTANT: FILL can only be set AFTER the child is appended to an auto-layout parent parent.appendChild(child) child.layoutSizingHorizontal = "FILL"; // Stretch to parent child.layoutSizingHorizontal = "HUG"; // Shrink to content child.layoutSizingHorizontal = "FIXED"; // Manual width child.layoutSizingVertical = "FILL"; child.layoutSizingVertical = "HUG"; child.layoutSizingVertical = "FIXED"; ``` ### Wrapping (Grid-like Layout) ```javascript frame.layoutMode = "HORIZONTAL"; frame.layoutWrap = "WRAP"; frame.itemSpacing = 24; // Horizontal gap frame.counterAxisSpacing = 24; // Vertical gap (between rows) ``` ### Absolute Positioning Within Auto Layout ```javascript child.layoutPositioning = "ABSOLUTE"; child.constraints = { horizontal: "MAX", vertical: "MIN" }; // Top-right child.x = parentWidth - childWidth - 8; child.y = 8; ``` ## Effects ### Drop Shadow ```javascript node.effects = [{ type: "DROP_SHADOW", color: { r: 0, g: 0, b: 0, a: 0.08 }, offset: { x: 0, y: 4 }, radius: 16, spread: -2, visible: true, blendMode: "NORMAL" }]; ``` ### Inner Shadow ```javascript node.effects = [{ type: "INNER_SHADOW", color: { r: 0, g: 0, b: 0, a: 0.05 }, offset: { x: 0, y: 1 }, radius: 2, spread: 0, visible: true, blendMode: "NORMAL" }]; ``` ### Background Blur ```javascript node.effects = [{ type: "BACKGROUND_BLUR", radius: 16, visible: true }]; ``` ### Layer Blur ```javascript node.effects = [{ type: "LAYER_BLUR", radius: 8, visible: true }]; ``` ### Multiple Effects ```javascript node.effects = [ { type: "DROP_SHADOW", color: { r: 0, g: 0, b: 0, a: 0.04 }, offset: { x: 0, y: 1 }, radius: 3, spread: 0, visible: true, blendMode: "NORMAL" }, { type: "DROP_SHADOW", color: { r: 0, g: 0, b: 0, a: 0.06 }, offset: { x: 0, y: 8 }, radius: 24, spread: -4, visible: true, blendMode: "NORMAL" } ]; ``` ## Opacity & Blend Modes ```javascript node.opacity = 0.5; node.blendMode = "NORMAL"; // "MULTIPLY", "SCREEN", "OVERLAY", "DARKEN", "LIGHTEN", etc. ``` ## Corner Radius ```javascript // Uniform node.cornerRadius = 12; // Per-corner node.topLeftRadius = 12; node.topRightRadius = 12; node.bottomLeftRadius = 0; node.bottomRightRadius = 0; ``` ## Clipping ```javascript frame.clipsContent = true; // Children clipped to frame bounds ``` ## Grouping & Organization ### Groups ```javascript const group = figma.group([node1, node2, node3], figma.currentPage); group.name = "Grouped Elements"; ``` ### Sections ```javascript const section = figma.createSection(); section.name = "My Section"; section.resizeWithoutConstraints(800, 600); section.x = 0; section.y = 0; // IMPORTANT: Sections don't auto-resize — always resize after adding content ``` ### Appending Children ```javascript parentFrame.appendChild(childNode); // Insert at a specific index parentFrame.insertChild(0, childNode); // Insert at beginning ``` ## Components & Variants ### Create Component ```javascript const component = figma.createComponent(); component.name = "Button/Primary"; component.description = "Primary action button."; ``` ### Create Instance ```javascript const instance = component.createInstance(); instance.x = 200; instance.y = 100; ``` ### Import Components by Key (Team Libraries) These methods import components from **team libraries** (not the same file). For components in the current file, use `figma.getNodeByIdAsync()` or `findOne()`/`findAll()`. ```javascript // Import a published component from a team library by its key const comp = await figma.importComponentByKeyAsync(componentKey) const instance = comp.createInstance() // Import a published component set from a team library by its key const set = await figma.importComponentSetByKeyAsync(componentSetKey) const variant = set.defaultVariant const variantInstance = variant.createInstance() ``` ### Combine as Variants ```javascript // IMPORTANT: Pass ComponentNodes (not frames) const componentSet = figma.combineAsVariants( [variantA, variantB, variantC], figma.currentPage ); componentSet.name = "Button"; componentSet.description = "Button component with multiple variants."; // CRITICAL: Layout variants in a grid after combining (they stack at 0,0) let maxX = 0, maxY = 0; componentSet.children.forEach((child, i) => { child.x = (i % numCols) * colWidth; child.y = Math.floor(i / numCols) * rowHeight; }); for (const child of componentSet.children) { maxX = Math.max(maxX, child.x + child.width); maxY = Math.max(maxY, child.y + child.height); } componentSet.resizeWithoutConstraints(maxX + 40, maxY + 40); ``` ### Component Properties ```javascript // addComponentProperty returns a STRING key — capture it! const labelKey = component.addComponentProperty("label", "TEXT", "Button"); const showIconKey = component.addComponentProperty("showIcon", "BOOLEAN", true); const iconSlotKey = component.addComponentProperty("iconSlot", "INSTANCE_SWAP", defaultIconId); // MUST link properties to child nodes via componentPropertyReferences labelNode.componentPropertyReferences = { characters: labelKey }; iconInstance.componentPropertyReferences = { visible: showIconKey, mainComponent: iconSlotKey }; ``` ## Styles ### Text Style ```javascript await figma.loadFontAsync({ family: "Inter", style: "Regular" }); const style = figma.createTextStyle(); style.name = "Body/Default"; style.fontName = { family: "Inter", style: "Regular" }; style.fontSize = 16; style.lineHeight = { value: 24, unit: "PIXELS" }; style.letterSpacing = { value: 0, unit: "PERCENT" }; // Apply to a text node textNode.textStyleId = style.id; ``` ### Effect Style ```javascript const shadowStyle = figma.createEffectStyle(); shadowStyle.name = "Shadow/Subtle"; shadowStyle.effects = [{ type: "DROP_SHADOW", color: { r: 0, g: 0, b: 0, a: 0.06 }, offset: { x: 0, y: 2 }, radius: 8, spread: 0, visible: true, blendMode: "NORMAL" }]; // Apply to a node frame.effectStyleId = shadowStyle.id; ``` ## Cloning & Duplication ```javascript const clone = originalNode.clone(); clone.x = originalNode.x + originalNode.width + 40; clone.name = "Copy of " + originalNode.name; ``` ## Finding Nodes ```javascript // Find by name on current page const node = figma.currentPage.findOne(n => n.name === "My Frame"); // Find all by type const allTexts = figma.currentPage.findAll(n => n.type === "TEXT"); // Find all by name pattern const allButtons = figma.currentPage.findAll(n => n.name.startsWith("Button/")); ``` ## Layout Grids ```javascript frame.layoutGrids = [ { pattern: "COLUMNS", alignment: "STRETCH", count: 12, gutterSize: 24, offset: 80, visible: true } ]; ``` ## Constraints (Non-Auto-Layout Frames) ```javascript child.constraints = { horizontal: "LEFT_RIGHT", // LEFT, RIGHT, CENTER, LEFT_RIGHT, SCALE vertical: "TOP" // TOP, BOTTOM, CENTER, TOP_BOTTOM, SCALE }; ``` ## Viewport & Zoom ```javascript // Zoom to fit specific nodes figma.viewport.scrollAndZoomIntoView([frame1, frame2]); ```