Imported from 2233admin/design-pipeline (
skill/references/prism-system/upstream/skills/figma-integration/figma-use/SKILL.md). Install upstream withnpx skills add 2233admin/design-pipeline --skill figma-use. Copyright stays with the author (MIT).
figma-use — Figma Plugin API Skill
Use figma_execute (Figma Console MCP) or use_figma (Figma Desktop Bridge MCP) to execute JavaScript in Figma files via the Plugin API. All detailed reference docs live in references/.
Design System note: This repo uses the Figma Console MCP (figma_execute) as the primary execution tool. The Figma Desktop Bridge MCP (use_figma) is a fallback when Console MCP is unavailable. All API patterns below apply to both tools identically — only the tool name differs.
If the task involves building or updating a full page, screen, or multi-section layout, also load figma-integration/figma-make-workflow.md. Both skills work together: this one covers the Plugin API rules; that one covers the screen-building workflow.
Before writing any Plugin API code, load references/plugin-api-standalone.index.md to understand what is possible. For exact type signatures, grep references/plugin-api-standalone.d.ts for relevant symbols — never load it all at once.
Always start with references/working-with-design-systems/wwds.md when working with design systems: understanding components, variables, text styles, and effect styles.
1. Critical Rules
- Use
returnto send data back. The return value is JSON-serialized automatically. Do NOT callfigma.closePlugin()or wrap code in an async IIFE. - Write plain JavaScript with top-level
awaitandreturn. Code is automatically wrapped in an async context. Do NOT wrap in(async () => { ... })(). figma.notify()throws "not implemented" — never use it.getPluginData()/setPluginData()are not supported — usegetSharedPluginData()/setSharedPluginData()instead, or track node IDs by returning them.- Work incrementally in small steps. Break large operations into multiple calls. Validate after each step. This is the most important practice for avoiding bugs.
- Colors are 0–1 range (not 0–255):
{r: 1, g: 0, b: 0}= red. - Fills/strokes are read-only arrays — clone, modify, reassign.
- Font MUST be loaded before any text operation:
await figma.loadFontAsync({family, style}). - Pages load incrementally — use
await figma.setCurrentPageAsync(page)to switch pages and load their content. setBoundVariableForPaintreturns a NEW paint — must capture and reassign.createVariableaccepts collection object or ID string (object preferred).layoutSizingHorizontal/Vertical = 'FILL'MUST be set AFTERparent.appendChild(child)— setting before append throws. Same applies to'HUG'on non-auto-layout nodes.- Position new top-level nodes away from (0,0). Scan
figma.currentPage.childrento find a clear position to the right of the rightmost node. Only applies to page-level nodes — nested nodes are positioned by their parent. - On error, STOP. Do NOT immediately retry. Failed scripts are atomic — no changes are made. Read the error carefully, fix the script, then retry.
- MUST
returnALL created/mutated node IDs. Collect every affected node ID and return them:return { createdNodeIds: [...], mutatedNodeIds: [...] }. - Always set
variable.scopesexplicitly. The defaultALL_SCOPESpollutes every property picker. Use specific scopes:["FRAME_FILL", "SHAPE_FILL"]for backgrounds,["TEXT_FILL"]for text colors,["GAP"]for spacing. awaitevery Promise. Never leave a Promise unawaited — unawaited async calls cause silent failures and race conditions.
For detailed WRONG/CORRECT examples of each rule, see references/gotchas.md.
2. Page Rules (Critical)
Page context resets between calls — figma.currentPage starts on the first page each time.
Switching pages
Use await figma.setCurrentPageAsync(page) to switch pages and load content. The sync setter figma.currentPage = page throws in use_figma/figma_execute runtimes.
// Switch to a specific page
const targetPage = figma.root.children.find((p) => p.name === 'My Page');
await figma.setCurrentPageAsync(targetPage);
// targetPage.children is now populated
// Iterate over all pages
for (const page of figma.root.children) {
await figma.setCurrentPageAsync(page);
// page.children is now loaded
}
Across script runs
figma.currentPage resets to the first page at the start of each call. If your workflow spans multiple calls and targets a non-default page, call await figma.setCurrentPageAsync(page) at the start of each invocation.
3. return Is Your Output Channel
The agent sees ONLY the value you return. Everything else is invisible.
- Returning IDs (CRITICAL): Every script that creates or mutates canvas nodes MUST return all affected node IDs.
- Progress reporting:
return { createdNodeIds: [...], count: 5, errors: [] } console.log()output is never returned to the agent.- Always return actionable data (IDs, counts, status) so subsequent calls can reference created objects.
4. Editor Mode
Scripts work in design mode (editorType "figma", the default). FigJam ("figjam") has a different set of available node types.
Available in design mode: Rectangle, Frame, Component, Text, Ellipse, Star, Line, Vector, Polygon, BooleanOperation, Slice, Page, Section, TextPath. Blocked in design mode: Sticky, Connector, ShapeWithText, CodeBlock, Slide, SlideRow, Webpage.
5. Incremental Workflow (How to Avoid Bugs)
The most common cause of bugs is trying to do too much in a single call. Work in small steps and validate after each one.
The pattern
- Inspect first. Run a read-only script to discover what already exists — pages, components, variables, naming conventions.
- Do one thing per call. Create variables in one call, components in the next, compose layouts in another.
- Return IDs from every call. Always
returncreated node IDs, variable IDs, collection IDs. - Validate after each step. Use
get_metadatato verify structure; useget_screenshotafter major milestones. - Fix before moving on. If validation reveals a problem, fix it before proceeding.
Suggested step order for complex tasks
Step 1: Inspect file — discover pages, components, variables, conventions
Step 2: Create tokens/variables (if needed) → validate with get_metadata
Step 3: Create individual components → validate with get_metadata + get_screenshot
Step 4: Compose layouts from component instances → validate with get_screenshot
Step 5: Final verification
What to validate at each step
| After... | Check with get_metadata |
Check with get_screenshot |
|---|---|---|
| Creating variables | Collection count, variable count, mode names | — |
| Creating components | Child count, variant names, property definitions | Variants visible, grid readable |
| Binding variables | Node properties reflect bindings | Colors/tokens resolved correctly |
| Composing layouts | Instance nodes have mainComponent, hierarchy correct | No cropped text, no overlaps, correct spacing |
6. Error Recovery & Self-Correction
Scripts are atomic — failed scripts do not execute. File remains unchanged on error.
When a script returns an error
- STOP. Do not immediately fix and retry.
- Read the error message carefully.
- If unclear, call
get_metadataorget_screenshotto understand file state. - Fix the script based on the error.
- Retry the corrected script.
Common self-correction patterns
| Error | Likely cause | Fix |
|---|---|---|
"not implemented" |
Used figma.notify() |
Remove it — use return |
"node must be an auto-layout frame..." |
Set FILL/HUG before appending |
Move appendChild before layoutSizingX = 'FILL' |
"Setting figma.currentPage is not supported" |
Used sync page setter | Use await figma.setCurrentPageAsync(page) |
| Property value out of range | Color channel > 1 | Divide by 255 |
"Cannot read properties of null" |
Node doesn't exist | Check page context, verify ID |
"The node with id X does not exist" |
Parent instance implicitly detached | Re-discover by traversal from a stable frame |
For the full validation workflow, see references/validation-and-recovery.md.
7. Pre-Flight Checklist
Before submitting ANY script call, verify:
- Code uses
returnto send data back (NOTfigma.closePlugin()) - Code is NOT wrapped in an async IIFE
-
returnvalue includes structured data with actionable info (IDs, counts) - NO usage of
figma.notify()anywhere - NO usage of
console.log()as output (usereturninstead) - All colors use 0–1 range (not 0–255)
- Fills/strokes are reassigned as new arrays (not mutated in place)
- Page switches use
await figma.setCurrentPageAsync(page)(sync setter throws) -
layoutSizingVertical/Horizontal = 'FILL'is set AFTERparent.appendChild(child) -
loadFontAsync()called BEFORE any text property changes -
lineHeight/letterSpacinguse{unit, value}format (not bare numbers) -
resize()is called BEFORE setting sizing modes (resize resets them to FIXED) - New top-level nodes are positioned away from (0,0)
- ALL created/mutated node IDs are collected and included in the
returnvalue - Every async call is
awaited — no fire-and-forget Promises
8. Discover Conventions Before Creating
Always inspect the Figma file before creating anything. Different files use different naming conventions, variable structures, and component patterns. Match what's already there.
Quick inspection scripts
List all pages and top-level nodes:
const pages = figma.root.children.map(
(p) => `${p.name} id=${p.id} children=${p.children.length}`
);
return pages.join('\n');
List existing components across all pages:
const results = [];
for (const page of figma.root.children) {
await figma.setCurrentPageAsync(page);
page.findAll((n) => {
if (n.type === 'COMPONENT' || n.type === 'COMPONENT_SET')
results.push(`[${page.name}] ${n.name} (${n.type}) id=${n.id}`);
return false;
});
}
return results.join('\n');
List existing variable collections:
const collections = await figma.variables.getLocalVariableCollectionsAsync();
const results = collections.map((c) => ({
name: c.name,
id: c.id,
varCount: c.variableIds.length,
modes: c.modes.map((m) => m.name)
}));
return results;
9. Design System Context
When working with Design System tokens in Figma:
- Token architecture: Foundation → Palette → Semantic (3-layer).
- Dark mode neutrals are reversed:
neutral.50= white in light mode, black in dark mode. Verify withhex_lookupMCP tool before setting variable values. - Variable naming follows token paths:
semantic/color/background/defaultmaps to the Figma variablecolor/background/default(collection prefix stripped). - Use Token MCP (
search_tokens,token_lookup,dependency_graph) for intent-first discovery before writing variables. - Scopes match token categories: color tokens →
["FRAME_FILL","SHAPE_FILL"]/["TEXT_FILL"]/["STROKE_COLOR"]; spacing tokens →["GAP"]/["WIDTH_HEIGHT"]; radius tokens →["CORNER_RADIUS"]. - Code syntax: set
WEBcode syntax to the CSS variable name from tokens (e.g.var(--color-bg-default)).
10. Reference Docs
Load these as needed based on what your task involves:
| Doc | When to load | What it covers |
|---|---|---|
| gotchas.md | Before any script | Every known pitfall with WRONG/CORRECT code examples |
| common-patterns.md | Need working code examples | Script scaffolds: shapes, text, auto-layout, variables, components, multi-step workflows |
| plugin-api-patterns.md | Creating/editing nodes | Fills, strokes, Auto Layout, effects, grouping, cloning, styles |
| api-reference.md | Need exact API surface | Node creation, variables API, core properties, what works and what doesn't |
| validation-and-recovery.md | Multi-step writes or error recovery | get_metadata vs get_screenshot workflow, mandatory error recovery steps |
| component-patterns.md | Creating components/variants | combineAsVariants, component properties, INSTANCE_SWAP, variant layout, metadata traversal |
| variable-patterns.md | Creating/binding variables | Collections, modes, scopes, aliasing, binding patterns, discovering existing variables |
| text-style-patterns.md | Creating/applying text styles | Type ramps, font probing, listing styles, applying styles to nodes |
| effect-style-patterns.md | Creating/applying effect styles | Drop shadows, listing styles, applying styles to nodes |
| working-with-design-systems/wwds.md | Working with design systems | Key concepts, processes, and guidelines for design systems in Figma |
| working-with-design-systems/wwds-variables.md | Design system variable context | Aliasing strategy, mode decisions, code syntax philosophy, grouping conventions |
11. Snippet Examples
Snippets throughout the reference docs contain useful Plugin API code. Use them as-is or as starter code. If a pattern recurs and isn't yet documented, write it to disk as a new reference snippet for future reuse.