Home › Figma plugins › Figma plugin CLAUDE.md

Figma plugin CLAUDE.md

CLAUDE.md for Figma plugins in TypeScript: main thread vs UI iframe, message passing, dynamic page loading with async APIs, fonts, manifest permissions, and testing.

Claude Code (CLAUDE.md)Figma plugins

How to use

Save this as CLAUDE.md in your repository root, commit it, and your agent will pick it up automatically. Edit the commands to match your project.

Note: Review and test before use. Provided as is, without warranty. See Terms.

CLAUDE.mdDownload  
# CLAUDE.md: Figma plugin

## Commands
- `npm run build` (bundles `code.ts` and the UI) · `npm run watch` · `npm run typecheck` · `npm run lint` if present.
- Test by importing `manifest.json` in the Figma desktop app (Plugins → Development). You can't run Figma here; say what needs a manual check.

## Architecture
- Two contexts: the main thread (`code.ts`) has the `figma` API but no DOM or browser APIs; the UI (`ui.html`/React in an iframe) has the DOM but no `figma` API. They talk only through `figma.ui.postMessage(msg)` ↔ `window.onmessage` and `parent.postMessage({ pluginMessage: msg }, '*')` ↔ `figma.ui.onmessage`.
- Define every message as a typed discriminated union in `src/messages.ts`, shared by both sides. Validate incoming messages; ignore unknown types.
- Keep `@figma/plugin-typings` current and typecheck both bundles.

## Figma API rules
- The manifest uses `"documentAccess": "dynamic-page"`: use async APIs (`figma.getNodeByIdAsync`, `page.loadAsync()`, `figma.loadAllPagesAsync()` only when truly needed). Don't touch other pages' nodes without loading them.
- Load fonts before changing text: `await figma.loadFontAsync(node.fontName as FontName)`; handle `figma.mixed` font names by loading each segment's font.
- Batch edits and keep them scoped to the selection or a known node; never iterate the whole document with `findAll` when `findAllWithCriteria` or the selection works.
- Wrap work in try/catch and finish with `figma.notify(...)` for success or failure and `figma.closePlugin()` for one-shot commands.
- Use `figma.clientStorage` for user preferences; use `setPluginData`/`setSharedPluginData` (with a namespace) for data attached to nodes. Never store secrets in plugin data.

## Manifest
Declare `networkAccess.allowedDomains` precisely (no `*` unless justified in `reasoning`), the `editorType` actually supported (`figma`, `figjam`, `dev`), and `capabilities` only when used. Don't change the plugin `id`.

More: all Figma plugins rules · all Claude Code (CLAUDE.md) rules

Related rules

Neovim Lua plugin CLAUDE.md

CLAUDE.md for Neovim plugins in Lua: setup(opts) config merging, autocommand groups, keymaps with desc, lazy loading, :checkhealth, and headless tests.

Claude Code (CLAUDE.md)Neovim plugins (Lua)

Electron app AGENTS.md

AGENTS.md for Electron desktop apps (Electron Forge or electron-vite): process layout, IPC contracts, and release safety.

AGENTS.mdElectron

Electron app Windsurf rules

Windsurf rules for secure Electron 44 apps: context isolation, preload bridges, typed IPC, and packaging.

WindsurfElectron

Obsidian plugin Cursor rules

Cursor rules for Obsidian community plugins in TypeScript: lifecycle and cleanup, Vault and MetadataCache APIs, settings, safe DOM, and release files.

CursorObsidian plugins

Raycast extension AGENTS.md

AGENTS.md for Raycast extensions in TypeScript and React: manifest commands and preferences, @raycast/api components, @raycast/utils hooks, error toasts, and store-ready linting.

AGENTS.mdRaycast extensions

Tauri 2 Rust backend rules

Cursor rules for the Rust side of Tauri 2 apps: commands, typed errors, state, plugins, and capability files.

CursorTauri

Get the best new AI prompts every week

One short email a week: the best new prompts and rules for ChatGPT, Claude, Gemini, Midjourney, Cursor and more, plus what changed in the tools. Free, unsubscribe anytime.

Finishes on our newsletter page at beehiiv (opens in a new tab). Or subscribe directly.