### Install Dependencies Source: https://github.com/figma/plugin-samples/blob/main/README.md Install project dependencies for bundling with Webpack and React. ```bash $ npm install ``` ```bash $ npm run build ``` -------------------------------- ### Install Project Dependencies Source: https://github.com/figma/plugin-samples/blob/main/README.md Installs the necessary project dependencies, including Figma typings, for the sample plugins. ```bash $ npm install ``` -------------------------------- ### Install Dependencies and Compile Plugin (Bash) Source: https://context7.com/figma/plugin-samples/llms.txt Commands to install global TypeScript, repository dependencies, and compile a specific plugin. Also includes steps for plugins using bundlers like webpack. ```bash # Install global TypeScript compiler and shared typings npm install -g typescript npm install # installs @figma/plugin-typings at repo root # Compile a specific plugin (e.g. barchart) cd barchart tsc # For plugins using a bundler (webpack / esbuild / vite): cd webpack-react npm install npm run build ``` -------------------------------- ### Install TypeScript Compiler Source: https://github.com/figma/plugin-samples/blob/main/README.md Installs the TypeScript compiler globally using npm. This is a prerequisite for compiling the plugin code. ```bash $ npm install -g typescript ``` -------------------------------- ### W3C Design Tokens Spec Example Source: https://github.com/figma/plugin-samples/blob/main/variables-import-export/README.md Illustrates the expected JSON structure for defining design tokens according to the W3C Design Tokens specification, including basic value types and aliases. ```json { "group name": { "token name": { "$value": 1234, "$type": "number" } }, "alias name": { "$value": "{group name.token name}" } } ``` -------------------------------- ### Create Auto-Layout Frame Container (TypeScript) Source: https://context7.com/figma/plugin-samples/llms.txt Shows how to create a FrameNode, resize it, position it, and add child nodes. It also includes an example of configuring auto-layout properties like direction, padding, spacing, and sizing modes. ```typescript // Create an 800×600 frame centered in the viewport, with a solid border const frame = figma.createFrame(); frame.resizeWithoutConstraints(800, 600); frame.x = figma.viewport.center.x - 400; frame.y = figma.viewport.center.y - 300; const border = figma.createRectangle(); frame.appendChild(border); border.resizeWithoutConstraints(800, 600); border.strokeAlign = 'INSIDE'; border.strokeWeight = 3; border.fills = []; border.strokes = [{ type: 'SOLID', color: { r: 0, g: 0, b: 0 } }]; border.constraints = { horizontal: 'STRETCH', vertical: 'STRETCH' }; // Auto-layout tally card example const card = figma.createFrame(); card.cornerRadius = 8; card.layoutMode = 'VERTICAL'; card.paddingLeft = card.paddingRight = card.paddingTop = card.paddingBottom = 16; card.itemSpacing = 8; card.primaryAxisSizingMode = card.counterAxisSizingMode = 'AUTO'; card.fills = [{ type: 'SOLID', color: { r: 1, g: 1, b: 1 } }]; card.strokes = [{ type: 'SOLID', color: { r: 0, g: 0, b: 0 } }]; card.strokeWeight = 2; figma.currentPage.appendChild(card); ``` -------------------------------- ### Figma Plugin Manifest Structure (JSON) Source: https://context7.com/figma/plugin-samples/llms.txt Example of a manifest.json file required for every Figma plugin. It declares metadata, API version, entry points, editor type, network access, and document access. ```json { "id": "bar-chart-sample", "name": "Bar Chart Sample", "api": "1.0.0", "main": "code.js", "ui": "ui.html", "editorType": ["figma", "figjam"], "networkAccess": { "allowedDomains": ["https://fonts.googleapis.com"] }, "documentAccess": "dynamic-page" } ``` -------------------------------- ### Add Drag Start Listener to Icons Source: https://github.com/figma/plugin-samples/blob/main/icon-drag-and-drop-hosted/index.html Attaches a 'dragstart' event listener to all elements with the class 'icon'. This listener sets the dataTransfer object with the SVG content of the dragged icon, preparing it for drag and drop operations. ```javascript const icons = document.getElementsByClassName('icon'); for (const icon of icons) { icon.addEventListener('dragstart', (e) => { e.dataTransfer.setData("image/svg+xml", e.target.innerHTML); }) } ``` -------------------------------- ### Plugin Parameters and Quick Actions Source: https://context7.com/figma/plugin-samples/llms.txt Details how to handle user input for Quick Actions using `figma.parameters.on('input', ...)` for suggestions and `figma.on('run', ...)` for plugin execution. ```APIDOC ## Plugin Parameters ### `figma.parameters.on('input', ...)` / `figma.on('run', ...)` — Quick Actions with suggestions Register an `input` handler to provide autocomplete `setSuggestions()` or `setError()` on each keystroke. The `run` event fires when the user confirms all parameters and the plugin executes. ### Example Usage: ```typescript // Resizer plugin: accept width/height or a scale factor via Quick Actions figma.parameters.on('input', ({ query, key, result }: ParameterInputEvent) => { if (figma.currentPage.selection.length === 0) { result.setError('Please select one or more nodes first'); return; } switch (key) { case 'width': validateNumber(query, result, ['640', '800', '1024', '1280']); break; case 'height': validateNumber(query, result, ['480', '600', '720', '960']); break; case 'scale': validateNumber(query, result); break; } }); figma.on('run', ({ command, parameters }: RunEvent) => { if (!parameters) return; if (command === 'relative') { const scale = parseFloat(parameters.scale as string); for (const node of figma.currentPage.selection) { if ('rescale' in node) node.rescale(scale); } } else { const w = parseInt(parameters.width as string); const h = parseInt(parameters.height as string); for (const node of figma.currentPage.selection) { if ('resize' in node) node.resize(w, h); } } figma.closePlugin(); }); function validateNumber(query: string, result: SuggestionResults, completions?: string[]) { if (query === '') { result.setSuggestions(completions ?? []); return; } if (!Number.isFinite(Number(query))) { result.setError('Please enter a numeric value'); return; } if (Number(query) <= 0) { result.setError('Must be larger than 0'); return; } result.setSuggestions([query, ...(completions ?? []).filter(s => s.includes(query) && s !== query)]); } ``` ``` -------------------------------- ### Serve HTML Locally with Python Source: https://github.com/figma/plugin-samples/blob/main/icon-drag-and-drop-hosted/README.md Use this command to serve the index.html file locally on port 4004 for development. ```bash python3 -m http.server 4004 ``` -------------------------------- ### Create and Style Rectangles (TypeScript) Source: https://context7.com/figma/plugin-samples/llms.txt Demonstrates creating multiple rectangle nodes, styling them with solid fills, positioning them, appending them to the current page, selecting them, and zooming the viewport to fit. ```typescript // Create 5 orange rectangles spaced 150px apart, select them, and zoom to fit const nodes: SceneNode[] = []; for (let i = 0; i < 5; i++) { const rect = figma.createRectangle(); rect.x = i * 150; rect.fills = [{ type: 'SOLID', color: { r: 1, g: 0.5, b: 0 } }]; figma.currentPage.appendChild(rect); nodes.push(rect); } figma.currentPage.selection = nodes; figma.viewport.scrollAndZoomIntoView(nodes); figma.closePlugin(); ``` -------------------------------- ### Initialize and Handle Plugin Messages in JavaScript Source: https://github.com/figma/plugin-samples/blob/main/snippet-saver/ui.html Sets up event listeners for initializing the plugin and handling messages from the Figma plugin host. It parses incoming plugin data and updates the UI accordingly. ```javascript const LANGUAGES = [ "BASH", "CPP", "CSS", "GO", "GRAPHQL", "HTML", "JAVASCRIPT", "JSON", "KOTLIN", "PLAINTEXT", "PYTHON", "RUBY", "RUST", "SQL", "SWIFT", "TYPESCRIPT", ]; const LANGUAGE_OPTIONS = LANGUAGES.map( (l) => `` ).join(""); const main = document.querySelector("main"); let snippetList = []; parent.postMessage({ pluginMessage: { type: "INITIALIZE" } }, "*"); window.onmessage = (e) => { const data = e.data.pluginMessage; if (data.type === "SELECTION") { handleSelectionChange(data); } else { console.log(data); } }; ``` -------------------------------- ### Figma Plugin Parameters with Input Suggestions Source: https://context7.com/figma/plugin-samples/llms.txt Implement Quick Actions with `figma.parameters.on('input', ...)` for real-time suggestions and error handling. The `figma.on('run', ...)` event fires when the user confirms parameters. ```typescript figma.parameters.on('input', ({ query, key, result }: ParameterInputEvent) => { if (figma.currentPage.selection.length === 0) { result.setError('Please select one or more nodes first'); return; } switch (key) { case 'width': validateNumber(query, result, ['640', '800', '1024', '1280']); break; case 'height': validateNumber(query, result, ['480', '600', '720', '960']); break; case 'scale': validateNumber(query, result); break; } }); figma.on('run', ({ command, parameters }: RunEvent) => { if (!parameters) return; if (command === 'relative') { const scale = parseFloat(parameters.scale as string); for (const node of figma.currentPage.selection) { if ('rescale' in node) node.rescale(scale); } } else { const w = parseInt(parameters.width as string); const h = parseInt(parameters.height as string); for (const node of figma.currentPage.selection) { if ('resize' in node) node.resize(w, h); } } figma.closePlugin(); }); function validateNumber(query: string, result: SuggestionResults, completions?: string[]) { if (query === '') { result.setSuggestions(completions ?? []); return; } if (!Number.isFinite(Number(query))) { result.setError('Please enter a numeric value'); return; } if (Number(query) <= 0) { result.setError('Must be larger than 0'); return; } result.setSuggestions([query, ...(completions ?? []).filter(s => s.includes(query) && s !== query)]); } ``` -------------------------------- ### Node Search and Tree Traversal Source: https://context7.com/figma/plugin-samples/llms.txt Demonstrates how to find nodes on the current page using `findAll` and how to implement a non-blocking tree walker for large documents. ```APIDOC ## `figma.currentPage.findAll()` / `walkTree` generator — Node search patterns `findAll(predicate)` performs a depth-first search of the entire page sub-tree to return all matching nodes. For large documents that might block the UI thread, a generator-based walker with `setTimeout` can be used to yield control periodically. ### Example Usage: ```typescript // Find all STAMP nodes on the current page (FigJam vote-tally pattern) const stamps = figma.currentPage.findAll(node => node.type === 'STAMP'); const stickies = figma.currentPage.findChildren(node => node.type === 'STICKY'); // Non-blocking text search using a generator and setTimeout function* walkTree(node: BaseNode) { yield node; if ('children' in node) { for (const child of node.children) yield* walkTree(child); } } function searchFor(query: string) { const walker = walkTree(figma.currentPage); let timer: ReturnType; function processChunk() { const results: string[] = []; let count = 0; let done = true; let res: IteratorResult; while (!(res = walker.next()).done) { const node = res.value; if (node.type === 'TEXT' && node.characters.toLowerCase().includes(query)) { results.push(node.id); } if (++count === 1000) { // yield every 1000 nodes to keep UI responsive done = false; timer = setTimeout(processChunk, 20); break; } } figma.ui.postMessage({ query, results, done }); } processChunk(); } ``` ``` -------------------------------- ### Import W3C Design Tokens with `importJSONFile()` Source: https://context7.com/figma/plugin-samples/llms.txt Parses a token JSON file, creates a variable collection, and resolves alias references. Ensure `parseColor` is defined elsewhere. ```typescript // Trigger from the UI after the user selects a file figma.ui.onmessage = (e) => { if (e.type === 'IMPORT') { importJSONFile({ fileName: e.fileName, body: e.body }); } }; function importJSONFile({ fileName, body }: { fileName: string; body: string }) { const json = JSON.parse(body); const collection = figma.variables.createVariableCollection(fileName); const modeId = collection.modes[0].modeId; const tokens: Record = {}; const aliases: Record = {}; // Recursively walk the token tree; defer aliases for a second pass function traverse(key: string, obj: Record, type?: string) { type = type || (obj.$type as string); if (key.startsWith('$')) return; if (obj.$value !== undefined) { const val = String(obj.$value).trim(); if (val.startsWith('{')) { const valueKey = val.replace(/[{}]/g, '').replace(/\./g, '/'); aliases[key] = { key, valueKey }; } else if (type === 'color') { const token = figma.variables.createVariable(key, collection, 'COLOR'); token.setValueForMode(modeId, parseColor(val)); // parseColor not shown tokens[key] = token; } else if (type === 'number') { const token = figma.variables.createVariable(key, collection, 'FLOAT'); token.setValueForMode(modeId, obj.$value as number); tokens[key] = token; } } else { for (const [k, v] of Object.entries(obj)) { if (!k.startsWith('$')) traverse(`${key}/${k}`, v as Record, type); } } } for (const [key, val] of Object.entries(json)) traverse(key, val as Record); // Resolve aliases for (const { key, valueKey } of Object.values(aliases)) { if (tokens[valueKey]) { const alias = figma.variables.createVariable(key, collection, tokens[valueKey].resolvedType); alias.setValueForMode(modeId, { type: 'VARIABLE_ALIAS', id: tokens[valueKey].id }); } } } ``` -------------------------------- ### Build Plugin Files with TypeScript Source: https://github.com/figma/plugin-samples/blob/main/icon-drag-and-drop-hosted/README.md Compile TypeScript files to JavaScript for the plugin to function. ```bash tsc ``` -------------------------------- ### Basic CSS for Icon Grid and Icons Source: https://github.com/figma/plugin-samples/blob/main/icon-drag-and-drop-hosted/index.html Provides basic styling for the icon grid and individual icons, including layout, sizing, and hover effects. Ensures icons are draggable with a 'grab' cursor. ```css body { background-color: var(--figma-color-bg); color: var(--figma-color-text); } .icons-grid { display: flex; flex-wrap: wrap; } .icon { border-radius: 4px; cursor:grab; height:24px; margin: 4px; padding: 4px; width:24px; } .icon:hover { background-color: #ddd; } ``` -------------------------------- ### Listen for Document Changes with figma.on('documentchange', ...) Source: https://context7.com/figma/plugin-samples/llms.txt Observe real-time document mutations like creates, deletes, and property changes. The event provides details on the origin, type, and affected node. Ensure `figma.loadAllPagesAsync()` is called to monitor changes on all pages. ```typescript figma.showUI(__html__, { height: 600, width: 600 }); async function initialize() { await figma.loadAllPagesAsync(); // required to observe changes on non-current pages figma.on('documentchange', (event) => { const messages = event.documentChanges.map(change => { const { origin, type } = change; const parts = [origin, type]; if (type === 'PROPERTY_CHANGE') { parts.push(change.node.type, change.properties.join(', ')); } else if (type === 'STYLE_PROPERTY_CHANGE') { parts.push(change.style?.name ?? '', change.properties.join(', ')); } else if (type !== 'STYLE_CREATE' && type !== 'STYLE_DELETE') { parts.push(change.node.type); } return parts.join(' '); // Example output: "LOCAL PROPERTY_CHANGE RECTANGLE fills, opacity" }); figma.ui.postMessage(messages, { origin: '*' }); }); } void initialize(); ``` -------------------------------- ### Asynchronous Node and Page Navigation Source: https://context7.com/figma/plugin-samples/llms.txt Provides methods for asynchronously fetching nodes by ID and switching to different pages, enabling navigation within the Figma document. ```APIDOC ## `figma.getNodeByIdAsync()` / `figma.setCurrentPageAsync()` — Node and page navigation Asynchronously fetch any node by its stable ID string. Switch to a different page before zooming into a cross-page node. ### Example Usage: ```typescript // Navigate to a layer or page by ID (go-to plugin pattern) async function goToNode(nodeId: string) { const node = await figma.getNodeByIdAsync(nodeId); if (!node) { figma.notify('Node not found'); figma.closePlugin(); return; } if (node.type === 'PAGE') { await figma.setCurrentPageAsync(node as PageNode); } else { // Walk up the tree to find which page this node lives on let parent = node.parent; while (parent && parent.type !== 'PAGE') parent = parent.parent; if (parent) await figma.setCurrentPageAsync(parent as PageNode); figma.viewport.scrollAndZoomIntoView([node as SceneNode]); figma.currentPage.selection = [node as SceneNode]; } figma.closePlugin(); } ``` ``` -------------------------------- ### figma.on('documentchange', ...) Source: https://context7.com/figma/plugin-samples/llms.txt Listen for real-time document mutations in Figma. This event handler captures creates, deletes, and property changes, providing details about the origin and type of each change. ```APIDOC ## `figma.on('documentchange', ...)` — React to real-time document mutations ### Description Listen for all creates, deletes, and property changes on the document. The event delivers an array of `DocumentChange` objects describing what changed, which node was affected, and whether the change originated from the user, a remote collaborator, or a plugin. ### Usage ```typescript figma.showUI(__html__, { height: 600, width: 600 }); async function initialize() { await figma.loadAllPagesAsync(); // required to observe changes on non-current pages figma.on('documentchange', (event) => { const messages = event.documentChanges.map(change => { const { origin, type } = change; const parts = [origin, type]; if (type === 'PROPERTY_CHANGE') { parts.push(change.node.type, change.properties.join(', ')); } else if (type === 'STYLE_PROPERTY_CHANGE') { parts.push(change.style?.name ?? '', change.properties.join(', ')); } else if (type !== 'STYLE_CREATE' && type !== 'STYLE_DELETE') { parts.push(change.node.type); } return parts.join(' '); // Example output: "LOCAL PROPERTY_CHANGE RECTANGLE fills, opacity" }); figma.ui.postMessage(messages, { origin: '*' }); }); } void initialize(); ``` ``` -------------------------------- ### figma.getLocalPaintStylesAsync() Source: https://context7.com/figma/plugin-samples/llms.txt Convert local paint styles into variable tokens. This function reads all paint styles, deduplicates them by color and opacity, and creates corresponding variable collections. ```APIDOC ## `figma.getLocalPaintStylesAsync()` — Convert paint styles to variable tokens ### Description Reads all local paint styles, deduplicates by hex + opacity, and creates a `Style Tokens` variable collection. Styles that share a color value are aliased to a single parent variable in a companion `Style Tokens: Aliased` collection. ### Usage ```typescript async function initialize() { const styles = await figma.getLocalPaintStylesAsync(); // Build a map: hex-opacity → { color, tokens[] } const tokenDataMap: Record = {}; for (const style of styles) { const paints = style.paints.filter(p => p.visible && p.type === 'SOLID'); if (paints.length !== 1) continue; const { color, opacity = 1, blendMode } = paints[0] as SolidPaint; if (blendMode !== 'NORMAL') continue; const hex = rgbToHex(color); const id = `${hex}-${opacity}`; tokenDataMap[id] ??= { color, hex, opacity, tokens: [] }; tokenDataMap[id].tokens.push(style.name); } const collection = figma.variables.createVariableCollection('Style Tokens'); const modeId = collection.modes[0].modeId; for (const { color, opacity, tokens } of Object.values(tokenDataMap)) { for (const name of tokens) { const token = figma.variables.createVariable(name, collection, 'COLOR'); token.setValueForMode(modeId, { r: color.r, g: color.g, b: color.b, a: opacity }); } } figma.closePlugin(); } void initialize(); ``` ``` -------------------------------- ### Plugin: Draw Bar Chart from UI Input Source: https://context7.com/figma/plugin-samples/llms.txt This TypeScript code runs in the plugin sandbox. It receives an array of numbers from the UI, loads a font, creates a frame, and draws a bar chart based on the input numbers. The plugin closes after drawing. ```typescript figma.showUI(__html__); figma.ui.onmessage = async (numbers: number[]) => { await figma.loadFontAsync({ family: 'Inter', style: 'Regular' }); const frameWidth = 800, frameHeight = 600; const frame = figma.createFrame(); frame.resizeWithoutConstraints(frameWidth, frameHeight); frame.x = figma.viewport.center.x - frameWidth / 2; frame.y = figma.viewport.center.y - frameHeight / 2; const min = numbers.reduce((a, b) => Math.min(a, b), 0); const max = numbers.reduce((a, b) => Math.max(a, b), 0); for (let i = 0; i < numbers.length; i++) { const num = numbers[i]; const left = 25 + 750 * (i + 0.25) / numbers.length; const right = 25 + 750 * (i + 0.75) / numbers.length; const top = 50 + 550 - 550 * (Math.max(0, num) - min) / (max - min); const bottom = 50 + 550 - 550 * (Math.min(0, num) - min) / (max - min); const col = figma.createRectangle(); frame.appendChild(col); col.x = left; col.y = top; col.resizeWithoutConstraints(right - left, bottom - top); col.fills = [{ type: 'SOLID', color: { r: 1, g: 0, b: 0 } }]; } figma.closePlugin(); }; ``` -------------------------------- ### Fetch External Data for Parameter Suggestions Source: https://context7.com/figma/plugin-samples/llms.txt Use an invisible UI iframe to fetch data from external APIs for parameter suggestions. Network requests are not allowed directly in the plugin sandbox. ```typescript // manifest.json for a parameter plugin that queries an external API // { // "parameters": [{ "name": "Country", "key": "country", "description": "Country name" }], // "networkAccess": { "allowedDomains": ["https://restcountries.com"] } // } figma.parameters.on('input', ({ key, query, result }: ParameterInputEvent) => { if (key === 'country') { // Delegate the network call to the UI iframe figma.showUI(__html__, { visible: false }); figma.ui.postMessage({ type: 'FETCH_CAPITALS', query }); figma.ui.onmessage = (suggestions: Array<{ name: string; data: unknown }>) => { result.setSuggestions(suggestions); }; } }); figma.on('run', ({ parameters }: RunEvent) => { const capital = (parameters!['country'] as { capital: string }).capital; figma.notify(`Capital: ${capital}`); figma.closePlugin(); }); ``` -------------------------------- ### Handle Multi-Context Plugins with `figma.editorType` and `figma.mode` Source: https://context7.com/figma/plugin-samples/llms.txt Branches plugin behavior based on the current editor context (design, Dev Mode) and mode (inspect, codegen). ```typescript // dev-mode/code.js — handle all three contexts if (figma.editorType === 'dev') { if (figma.mode === 'inspect') { figma.showUI('

Dev Mode Inspect Panel

'); } else if (figma.mode === 'codegen') { figma.codegen.on('generate', () => [ { title: 'Component', code: 'export default Component;', language: 'TYPESCRIPT' }, ]); } } else if (figma.editorType === 'figma') { figma.showUI('

Design Mode Panel

'); } ``` -------------------------------- ### Find Nodes and Walk Tree Generator in Figma Source: https://context7.com/figma/plugin-samples/llms.txt Use `findAll` for direct node searching or a generator-based `walkTree` with `setTimeout` for non-blocking searches in large documents. The walker yields control periodically to keep the UI responsive. ```typescript const stamps = figma.currentPage.findAll(node => node.type === 'STAMP'); const stickies = figma.currentPage.findChildren(node => node.type === 'STICKY'); ``` ```typescript function* walkTree(node: BaseNode) { yield node; if ('children' in node) { for (const child of node.children) yield* walkTree(child); } } ``` ```typescript function searchFor(query: string) { const walker = walkTree(figma.currentPage); let timer: ReturnType; function processChunk() { const results: string[] = []; let count = 0; let done = true; let res: IteratorResult; while (!(res = walker.next()).done) { const node = res.value; if (node.type === 'TEXT' && node.characters.toLowerCase().includes(query)) { results.push(node.id); } if (++count === 1000) { // yield every 1000 nodes to keep UI responsive done = false; timer = setTimeout(processChunk, 20); break; } } figma.ui.postMessage({ query, results, done }); } processChunk(); } ``` -------------------------------- ### Compile Bar Chart Plugin Source: https://github.com/figma/plugin-samples/blob/main/README.md Compiles the TypeScript code for the Bar Chart sample plugin. Navigate to the plugin's directory and run 'tsc' to compile. ```bash cd barchart tsc ``` -------------------------------- ### Export Design Tokens as JSON Source: https://context7.com/figma/plugin-samples/llms.txt Iterate through local variable collections and modes to generate a W3C-style design token JSON file. The result is posted to the UI for download. ```typescript async function exportToJSON() { const collections = await figma.variables.getLocalVariableCollectionsAsync(); const files: Array<{ fileName: string; body: object }> = []; for (const collection of collections) { for (const mode of collection.modes) { const file = { fileName: `${collection.name}.${mode.name}.tokens.json`, body: {} as Record }; for (const varId of collection.variableIds) { const variable = await figma.variables.getVariableByIdAsync(varId); if (!variable) continue; const value = variable.valuesByMode[mode.modeId]; if (value === undefined) continue; // Build nested object from slash-separated name const parts = variable.name.split('/'); let obj: Record = file.body; parts.forEach((part, i) => { if (i < parts.length - 1) { obj[part] = obj[part] || {}; obj = obj[part] as Record; } }); const leaf = parts[parts.length - 1]; obj[leaf] = { $type: variable.resolvedType === 'COLOR' ? 'color' : 'number', $value: value, }; } files.push(file); } } figma.ui.postMessage({ type: 'EXPORT_RESULT', files }); } figma.ui.onmessage = async (e) => { if (e.type === 'EXPORT') await exportToJSON(); }; ``` -------------------------------- ### figma.createText() Source: https://context7.com/figma/plugin-samples/llms.txt Creates a text node and allows for its positioning and styling. Requires `figma.loadFontAsync` to be called before setting text content. ```APIDOC ## `figma.createText()` — Create and position a text node Must call `await figma.loadFontAsync(...)` before setting `characters`. Supports `fontSize`, `textAlignHorizontal`, `textAlignVertical`, `textAutoResize`, `relativeTransform` (for arbitrary rotation/placement), and `fontName`. ```typescript // Create a bar chart label above a column await figma.loadFontAsync({ family: 'Inter', style: 'Regular' }); const label = figma.createText(); frame.appendChild(label); label.x = 100; label.y = 20; label.resizeWithoutConstraints(120, 50); label.fills = [{ type: 'SOLID', color: { r: 0, g: 0, b: 0 } }]; label.characters = '42'; label.fontSize = 30; label.textAlignHorizontal = 'CENTER'; label.textAlignVertical = 'BOTTOM'; label.constraints = { horizontal: 'STRETCH', vertical: 'STRETCH' }; ``` ``` -------------------------------- ### Handle Plugin Messages and Fetch Data Source: https://github.com/figma/plugin-samples/blob/main/trivia/ui.html Listens for messages from the Figma plugin, fetches data from a provided URL, and posts the JSON response back. ```javascript window.onmessage = async (event) => { const msg = event.data.pluginMessage const url = event.data.pluginMessage.url const res = await fetch(url) const json = await res.json() postMessage(json, msg.type) }; function postMessage(response, type) { window.parent.postMessage( { pluginMessage: { response, type } }, "*" ); } ``` -------------------------------- ### Crop PNG into Ellipse on Drop Source: https://context7.com/figma/plugin-samples/llms.txt Handles image file drops to create an ellipse filled with the dropped PNG. Uses `figma.createImage()` and `figma.createEllipse()`. Returns `false` to prevent default drop behavior. ```typescript // Crop a dropped PNG into an ellipse (png-crop plugin pattern) figma.on('drop', (event) => { if (event.files && event.files.length > 0) { const file = event.files[0]; if (file.type === 'image/png') { file.getBytesAsync().then(bytes => { const image = figma.createImage(bytes); const ellipse = figma.createEllipse(); ellipse.x = event.x; ellipse.y = event.y; ellipse.resize(320, 320); ellipse.fills = [{ imageHash: image.hash, scaleMode: 'FILL', scalingFactor: 1, type: 'IMAGE', }]; }); return false; // prevent default drop behavior } } }); ``` -------------------------------- ### figma.createFrame() Source: https://context7.com/figma/plugin-samples/llms.txt Creates a FrameNode, which serves as a primary container. It can be configured for auto-layout and used to group other nodes. ```APIDOC ## figma.createFrame() ### Description `FrameNode` is the primary container type. Set `layoutMode` to `"VERTICAL"` or `"HORIZONTAL"` to enable auto layout, configure padding and spacing, and append child nodes with `appendChild`. ### Method ```typescript figma.createFrame() ``` ### Parameters None ### Request Example ```typescript // Create an 800×600 frame centered in the viewport, with a solid border const frame = figma.createFrame(); frame.resizeWithoutConstraints(800, 600); frame.x = figma.viewport.center.x - 400; frame.y = figma.viewport.center.y - 300; const border = figma.createRectangle(); frame.appendChild(border); border.resizeWithoutConstraints(800, 600); border.strokeAlign = 'INSIDE'; border.strokeWeight = 3; border.fills = []; border.strokes = [{ type: 'SOLID', color: { r: 0, g: 0, b: 0 } }]; border.constraints = { horizontal: 'STRETCH', vertical: 'STRETCH' }; // Auto-layout tally card example const card = figma.createFrame(); card.cornerRadius = 8; card.layoutMode = 'VERTICAL'; card.paddingLeft = card.paddingRight = card.paddingTop = card.paddingBottom = 16; card.itemSpacing = 8; card.primaryAxisSizingMode = card.counterAxisSizingMode = 'AUTO'; card.fills = [{ type: 'SOLID', color: { r: 1, g: 1, b: 1 } }]; card.strokes = [{ type: 'SOLID', color: { r: 0, g: 0, b: 0 } }]; card.strokeWeight = 2; figma.currentPage.appendChild(card); ``` ### Response #### Success Response Returns a `FrameNode` object. #### Response Example ```typescript // FrameNode object { // ... properties of FrameNode } ``` ``` -------------------------------- ### figma.createRectangle() Source: https://context7.com/figma/plugin-samples/llms.txt Creates a RectangleNode on the current page. You can then style it and append it to a parent container. ```APIDOC ## figma.createRectangle() ### Description Creates a `RectangleNode` on the current page. After creation, set `x`, `y`, resize with `resizeWithoutConstraints`, and assign `fills` / `strokes` using paint descriptors. Append to a parent container with `appendChild`. Constraints control how the node behaves when its parent is resized. ### Method ```typescript figma.createRectangle() ``` ### Parameters None ### Request Example ```typescript // Create 5 orange rectangles spaced 150px apart, select them, and zoom to fit const nodes: SceneNode[] = []; for (let i = 0; i < 5; i++) { const rect = figma.createRectangle(); rect.x = i * 150; rect.fills = [{ type: 'SOLID', color: { r: 1, g: 0.5, b: 0 } }]; figma.currentPage.appendChild(rect); nodes.push(rect); } figma.currentPage.selection = nodes; figma.viewport.scrollAndZoomIntoView(nodes); figma.closePlugin(); ``` ### Response #### Success Response Returns a `RectangleNode` object. #### Response Example ```typescript // RectangleNode object { // ... properties of RectangleNode } ``` ``` -------------------------------- ### UI: Collect Numbers and Send to Plugin Source: https://context7.com/figma/plugin-samples/llms.txt This HTML/JavaScript code runs in the UI iframe. It collects comma-separated numbers from an input field, converts them to an array of numbers, and sends them to the plugin via `parent.postMessage`. It also includes a listener for messages from the plugin. ```html ``` -------------------------------- ### figma.createShapeWithText() / figma.createConnector() Source: https://context7.com/figma/plugin-samples/llms.txt Creates FigJam-specific nodes: `ShapeWithTextNode` for sticky-like shapes and `ConnectorNode` for drawing arrows between nodes. Connectors can use automatic magnet attachment. ```APIDOC ## `figma.createShapeWithText()` / `figma.createConnector()` — FigJam nodes `ShapeWithTextNode` is a FigJam sticky-like shape. `ConnectorNode` draws an arrow between two endpoint nodes identified by their IDs. Set `magnet: 'AUTO'` for automatic attachment point selection. Only available when `figma.editorType === 'figjam'`. ```typescript // Create 5 rounded-rectangle shapes with connectors between them (FigJam) if (figma.editorType === 'figjam') { const nodes: SceneNode[] = []; for (let i = 0; i < 5; i++) { const shape = figma.createShapeWithText(); shape.shapeType = 'ROUNDED_RECTANGLE'; // Other shapeType values: 'SQUARE' | 'ELLIPSE' | 'DIAMOND' | // 'TRIANGLE_UP' | 'TRIANGLE_DOWN' | 'PARALLELOGRAM_RIGHT' | 'PARALLELOGRAM_LEFT' shape.x = i * 400; shape.fills = [{ type: 'SOLID', color: { r: 1, g: 0.5, b: 0 } }]; figma.currentPage.appendChild(shape); nodes.push(shape); } for (let i = 0; i < nodes.length - 1; i++) { const connector = figma.createConnector(); connector.strokeWeight = 8; connector.connectorStart = { endpointNodeId: nodes[i].id, magnet: 'AUTO' }; connector.connectorEnd = { endpointNodeId: nodes[i + 1].id, magnet: 'AUTO' }; } figma.currentPage.selection = nodes; figma.viewport.scrollAndZoomIntoView(nodes); figma.closePlugin(); } ``` ``` -------------------------------- ### Handle Figma Plugin Messages for Meta Tag Fetching Source: https://github.com/figma/plugin-samples/blob/main/metacards/ui.html This code handles messages received from the Figma plugin UI. It specifically listens for a 'fetchMetaTags' function call, retrieves the URL and node ID, calls the `fetchMetaTags` utility, and posts the results or errors back to the Figma plugin. ```javascript // Handle messages from figma plugin window.onmessage = async (event) => { if(event.data.pluginMessage){ let msg = event.data.pluginMessage; if(msg.function === "fetchMetaTags"){ let url = msg.data; let nodeId = msg.nodeId; fetchMetaTags(url) .then(metaTags => { parent.postMessage({ pluginMessage: { function: 'createMetaCard', data: metaTags, nodeId: nodeId } }, '*') }) .catch(err => { parent.postMessage({ pluginMessage: { function: 'fetchError', data: err } }, '*') }); } } } ``` -------------------------------- ### Convert Paint Styles to Variable Tokens with figma.getLocalPaintStylesAsync() Source: https://context7.com/figma/plugin-samples/llms.txt This function reads local paint styles, deduplicates them based on hex code and opacity, and creates corresponding variable tokens. Styles with identical color values are aliased to a single parent variable. ```typescript async function initialize() { const styles = await figma.getLocalPaintStylesAsync(); // Build a map: hex-opacity → { color, tokens[] } const tokenDataMap: Record = {}; for (const style of styles) { const paints = style.paints.filter(p => p.visible && p.type === 'SOLID'); if (paints.length !== 1) continue; const { color, opacity = 1, blendMode } = paints[0] as SolidPaint; if (blendMode !== 'NORMAL') continue; const hex = rgbToHex(color); const id = `${hex}-${opacity}`; tokenDataMap[id] ??= { color, hex, opacity, tokens: [] }; tokenDataMap[id].tokens.push(style.name); } const collection = figma.variables.createVariableCollection('Style Tokens'); const modeId = collection.modes[0].modeId; for (const { color, opacity, tokens } of Object.values(tokenDataMap)) { for (const name of tokens) { const token = figma.variables.createVariable(name, collection, 'COLOR'); token.setValueForMode(modeId, { r: color.r, g: color.g, b: color.b, a: opacity }); } } figma.closePlugin(); } void initialize(); ``` -------------------------------- ### Handle Form Submission for Variable Import Source: https://github.com/figma/plugin-samples/blob/main/variables-import-export/import.html This JavaScript code listens for form submissions to import variables. It validates the input and sends a message to the parent process. ```javascript document.querySelector("form").addEventListener("submit", (e) => { const fileName = document.querySelector("input").value.trim(); const body = document.querySelector("textarea").value.trim(); e.preventDefault(); if (isValidJSON(body) && fileName) { parent.postMessage( { pluginMessage: { fileName, body, type: "IMPORT" } }, "*" ); } else { alert("Invalid filename or JSON"); } }); ``` -------------------------------- ### Create and Manage Individual Snippet Items in JavaScript Source: https://github.com/figma/plugin-samples/blob/main/snippet-saver/ui.html Generates the HTML elements for a single snippet, including a title input, language select, code textarea, and a remove button. It also sets up event listeners to trigger saving changes. ```javascript function itemFromData( { language, code, title } = { language: "PLAINTEXT", code: "", title: "New Snippet" }, index ) { const article = document.createElement("article"); const textarea = document.createElement("textarea"); const select = document.createElement("select"); const input = document.createElement("input"); const remove = document.createElement("button"); remove.addEventListener("click", () => { snippetList.splice(index, 1); onChange(); render(); }); input.addEventListener("input", onChange); select.addEventListener("change", onChange); textarea.addEventListener("input", onChange); remove.innerHTML = "×"; select.innerHTML = LANGUAGE_OPTIONS; input.value = title; select.value = language; textarea.value = code; const div = document.createElement("div"); div.appendChild(input); div.appendChild(remove); article.appendChild(div); article.appendChild(textarea); article.appendChild(select); return { textarea, select, input, article }; } ``` -------------------------------- ### Load Image as ArrayBuffer from URL for Figma Source: https://github.com/figma/plugin-samples/blob/main/metacards/ui.html Use this function to load an image from a URL and convert it into an ArrayBuffer, suitable for passing back to Figma for asynchronous rendering. It handles cross-origin issues by attempting to use a CORS proxy if direct loading fails. ```javascript async function getEncodedImageFromURL(url) { return new Promise((resolve, reject) => { const img = new Image(); // Some websites will allow loading of images into a canvas if set to Anonymous img.crossOrigin = "Anonymous"; img.onload = () => { const canvas = document.createElement('canvas'); const ctx = canvas.getContext("2d"); canvas.width = img.naturalWidth; canvas.height = img.naturalHeight; ctx.drawImage(img, 0, 0); canvas.toBlob(async (blob) => { let blobBuffer = await blob.arrayBuffer(); resolve({ img: img, data: new Uint8Array(blobBuffer) }); }) } // If an Anonymous image does not load, attempt to load it // cross origin using cors-anywhere img.onerror = () => { if(img.src.indexOf("cors-anywhere") === -1){ img.src = `https://cors-anywhere.herokuapp.com/${url.replace(/http(s)?:\/\//,'')}`; } else { reject("Error fetching image"); } } img.src = url; }); } ``` -------------------------------- ### Create Variable Collections and Tokens Source: https://context7.com/figma/plugin-samples/llms.txt Create named variable collections with typed tokens (COLOR or FLOAT). Use `setValueForMode` to assign literal values or `VARIABLE_ALIAS` references. ```typescript // Create a "colors" collection with a primary token and an alias function createCollection(name: string) { const collection = figma.variables.createVariableCollection(name); const modeId = collection.modes[0].modeId; return { collection, modeId }; } const { collection, modeId } = createCollection('colors'); // Primitive token const primary = figma.variables.createVariable('primary', collection, 'COLOR'); primary.setValueForMode(modeId, { r: 0.2, g: 0.4, b: 1, a: 1 }); // Alias token pointing to primary const buttonBg = figma.variables.createVariable('button/background', collection, 'COLOR'); buttonBg.setValueForMode(modeId, { type: 'VARIABLE_ALIAS', id: primary.id }); figma.closePlugin(); ``` -------------------------------- ### Create and Position Text Node in Figma Source: https://context7.com/figma/plugin-samples/llms.txt Use `figma.createText()` to create a text node. Ensure `await figma.loadFontAsync()` is called before setting text content. Supports various text styling and positioning properties. ```typescript // Create a bar chart label above a column await figma.loadFontAsync({ family: 'Inter', style: 'Regular' }); const label = figma.createText(); frame.appendChild(label); label.x = 100; label.y = 20; label.resizeWithoutConstraints(120, 50); label.fills = [{ type: 'SOLID', color: { r: 0, g: 0, b: 0 } }]; label.characters = '42'; label.fontSize = 30; label.textAlignHorizontal = 'CENTER'; label.textAlignVertical = 'BOTTOM'; label.constraints = { horizontal: 'STRETCH', vertical: 'STRETCH' }; ``` -------------------------------- ### Create Rectangles in Figma Source: https://github.com/figma/plugin-samples/blob/main/README.md This code snippet demonstrates creating a specified number of rectangles in Figma after prompting the user for input. It's designed to run within the Figma desktop application. ```typescript const count = parseInt(prompt("How many rectangles?")); if (count && count > 0) { for (let i = 0; i < count; i++) { const rect = figma.createRectangle(); rect.x = i * 100; rect.fills = [{ type: 'SOLID', color: { r: 1, g: 0.5, b: 0 } }]; figma.closePlugin(); } } ```