Skip to content

@tank/figma-plugin

1.2.0

Guidance for building Figma plugins. Covers architecture, Plugin API (nodes, styles, variables, components), UI development, Dev Mode codegen, widgets, publishing, and monetization. Triggers: figma plugin, figma API, plugin development, figma widget, Dev Mode, codegen, figma node, figma styles, figma variables, iframe, message passing, plugin UI, figma publish, figma marketplace.


name: "@tank/figma-plugin" description: "Guidance for building Figma plugins. Covers architecture, Plugin API (nodes, styles, variables, components), UI development, Dev Mode codegen, widgets, publishing, and monetization. Triggers: figma plugin, figma API, plugin development, figma widget, Dev Mode, codegen, figma node, figma styles, figma variables, iframe, message passing, plugin UI, figma publish, figma marketplace."

Figma Plugin Development

Expert guidance for building Figma plugins — from architecture and API usage to UI development, publishing, and monetization.

Synthesized from: Official Figma Plugin API Documentation, @figma/plugin-typings, figma/plugin-samples, Tokens Studio, FigmaToCode, Design Lint, Config talks, Evil Martians guides.

When to Use This Skill

Use when the task involves:

  • Creating a new Figma plugin (design mode, FigJam, Dev Mode, Slides)
  • Working with the Figma Plugin API (nodes, styles, variables, components)
  • Building plugin UI (iframe, React, message passing)
  • Generating code from Figma designs (codegen plugins)
  • Publishing or monetizing a Figma plugin
  • Debugging plugin issues (sandbox, font loading, network, performance)

Core Concepts

Dual-Context Architecture

┌──────────────────────┐     postMessage     ┌──────────────────────┐
│    MAIN THREAD       │ ◄──────────────────► │     UI THREAD        │
│    (Sandbox)         │                      │     (iframe)         │
│                      │                      │                      │
│  ✓ figma.* API       │                      │  ✓ DOM, fetch, canvas│
│  ✓ Read/write nodes  │                      │  ✓ React/HTML/CSS    │
│  ✗ No browser APIs   │                      │  ✗ No figma.* access │
└──────────────────────┘                      └──────────────────────┘

Plugin Types

Editor TypeManifest ValueRead/WriteKey Capability
Figma Design"figma"Read + WriteFull node manipulation
FigJam"figjam"Read + WriteStickies, connectors, stamps
Dev Mode"dev"Read OnlyInspection, codegen
Slides"slides"Read + WriteSlide manipulation
Buzz"buzz"Read + WriteBuzz-specific features

Critical Patterns (Memorize These)

1. Immutable arrays — fills, strokes, effects MUST be cloned and reassigned:

const fills = JSON.parse(JSON.stringify(node.fills))
fills[0] = { ...fills[0], color: { r: 1, g: 0, b: 0 } }
node.fills = fills
// OR use helper: node.fills = [figma.util.solidPaint('#FF0000')]

2. Font loading — MUST load before editing any text property:

if (textNode.hasMissingFont) return // Always check first
const fonts = textNode.getRangeAllFontNames(0, textNode.characters.length)
await Promise.all(fonts.map(figma.loadFontAsync))
textNode.characters = 'New text'

3. Message passing — syntax differs between main thread and UI:

// Main → UI:  figma.ui.postMessage(data)
// UI → Main:  parent.postMessage({ pluginMessage: data }, '*')

4. Close plugin — MUST call when done or plugin runs forever:

figma.closePlugin()           // Silent close
figma.closePlugin('Done!')    // Close with notification

Workflow

Creating a New Plugin

  1. Choose editor type → determines manifest editorType and capabilities
  2. Set up project → TypeScript + bundler (Vite recommended)
  3. Design architecture → decide if plugin needs UI or runs headless
  4. Implement → use reference files below for API details
  5. Test edge cases → no selection, wrong types, missing fonts, large docs
  6. Publish → first publish requires review, updates are instant

Decision: Plugin vs Widget

NeedChoose
One-time operation (export, transform, lint)Plugin
Complex UI with forms/inputsPlugin
External API integrationPlugin
Collaborative tool visible to all usersWidget
Persistent element on canvasWidget
Real-time multiplayer featuresWidget

Decision: Build Tool

SituationRecommended
New project, modern stackVite + esbuild
Large codebase, many depsWebpack + SWC
Simple plugin, no frameworkesbuild alone
Want batteries-includedCreate Figma Plugin (community)
Want hot reload dev serverPlugma (community)

Decision: Storage

Data TypeStore InScope
Per-document metadatanode.setPluginData()File (your plugin)
Cross-plugin document datanode.setSharedPluginData()File (all plugins)
User preferencesfigma.clientStorageLocal machine
Shared/synced dataExternal API via fetchServer

Anti-Patterns

Don'tDo Instead
Modify node.fills[0] directlyClone → modify → reassign entire array
Edit text without loading fontsAlways await figma.loadFontAsync() first
Use findAll() on huge docsUse findAllWithCriteria() (faster)
Load all pages at startupUse "documentAccess": "dynamic-page", load on demand
Send Node objects to UISerialize to plain objects first
Forget figma.closePlugin()Always close, even in error paths
Use getMainComponent() syncUse getMainComponentAsync() for remote components
Hardcode component/style IDsUse .key for imports, .id only within same session
Ignore networkAccess in manifestSpecify exact domains, not wildcards
Skip missing font checksAlways check textNode.hasMissingFont

Reference Files

FileWhen to Load
@references/plugin-architecture.mdSetting up a new plugin, manifest questions, build tooling
@references/scene-graph-and-nodes.mdWorking with nodes, traversal, creation, type checking
@references/styling-and-layout.mdFills, strokes, effects, auto-layout, constraints
@references/text-and-typography.mdText nodes, font loading, mixed styles, text manipulation
@references/components-and-variants.mdComponents, variants, instances, library operations, styles
@references/ui-development.mdPlugin UI, message passing, React, theming, drag-and-drop
@references/variables-and-storage.mdVariables API, design tokens, pluginData, clientStorage
@references/devmode-codegen-publishing.mdDev Mode, codegen, VS Code, testing, publishing, payments

Quick Reference: Common Operations

// Selection
const sel = figma.currentPage.selection
figma.currentPage.selection = [node]

// Viewport
figma.viewport.scrollAndZoomIntoView([node])
figma.viewport.center = { x: 0, y: 0 }
figma.viewport.zoom = 1

// Notifications
figma.notify('Message')
figma.notify('Error!', { error: true })

// Events
figma.on('selectionchange', () => {})
figma.on('currentpagechange', () => {})
figma.on('documentchange', (e) => {})
figma.on('close', () => {})
figma.on('drop', (e) => {})

// Export
const bytes = await node.exportAsync({ format: 'PNG', constraint: { type: 'SCALE', value: 2 } })
const svg = await node.exportAsync({ format: 'SVG' })

Command Palette

Search skills, docs, and navigate Tank