All skills
openai avatar

/figma-use

@0e7823c official
by openaiopenai/skills28k stars
1,891

**MANDATORY prerequisite** — you MUST invoke this skill BEFORE every `use_figma` tool call. NEVER call `use_figma` directly without loading this skill first. Skipping it causes common, hard-to-debug failures. Trigger whenever the user wants to perform a write action or a unique read action that requires JavaScript execution in the Figma file context — e.g. create/edit/delete nodes, set up variables or tokens, build components and variants, modify auto-layout or fills, bind variables to properties, or inspect file structure programmatically.

Use this Skill: https://skilld.dev/gh/openai/skills/figma-use

This session only. Nothing lands on disk.

referencestext-style-patterns.md

≈1.6k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Text Style API Patterns

Part of the use_figma skill. How to create, apply, and inspect text styles using the Plugin API.

For design system context (when to create text styles, how they relate to tokens, headless limitations), see wwds-text-styles.

Contents

  • Listing Text Styles
  • Creating a Text Style
  • Probing Font Styles
  • Creating a Type Ramp (Multi-Step)
  • Applying Text Styles to Nodes

Listing Text Styles

/**
 * Lists all local text styles with their key properties.
 *
 * @returns {Promise<Array<{id: string, name: string, key: string, fontSize: number, fontName: FontName, lineHeight: LineHeight, letterSpacing: LetterSpacing}>>}
 */
async function listTextStyles() {
  const styles = await figma.getLocalTextStylesAsync();
  return styles.map(s => ({
    id: s.id,
    name: s.name,
    key: s.key,
    fontSize: s.fontSize,
    fontName: s.fontName,
    lineHeight: s.lineHeight,
    letterSpacing: s.letterSpacing
  }));
}

Full runnable script:

(async () => {
  try {
    const results = await listTextStyles();
    figma.closePlugin(JSON.stringify(results));
  } catch(e) { figma.closePluginWithFailure(e.toString()); }
})()

Creating a Text Style

Font MUST be loaded before setting fontName. lineHeight and letterSpacing must be {value, unit} objects — bare numbers throw.

/**
 * Creates a text style with all typographic properties set.
 * Font MUST be loaded before calling.
 *
 * @param {string} name - Slash-delimited name, e.g. "body/base"
 * @param {{ family: string, style: string }} fontName
 * @param {number} fontSize - In pixels
 * @param {{ value: number, unit: 'PIXELS' | 'PERCENT' } | { unit: 'AUTO' }} lineHeight
 * @param {{ value: number, unit: 'PIXELS' | 'PERCENT' }} [letterSpacing]
 * @param {string} [description] - e.g. the CSS variable name "CSS: var(--font-body-base)"
 * @returns {TextStyle}
 */
function createTextStyleFull(name, fontName, fontSize, lineHeight, letterSpacing, description) {
  const style = figma.createTextStyle();
  style.name = name;
  style.fontName = fontName;
  style.fontSize = fontSize;
  style.lineHeight = lineHeight; // { unit: 'AUTO' } | { value, unit: 'PIXELS'|'PERCENT' }
  if (letterSpacing) style.letterSpacing = letterSpacing;
  if (description) style.description = description;
  return style;
}

Probing Font Styles

Font style names vary per provider and per file ("SemiBold" vs "Semi Bold"). Always probe before hardcoding:

/**
 * Probes available font styles for a given family.
 * Useful when font style names are unknown (e.g. "SemiBold" vs "Semi Bold").
 *
 * @param {string} family - Font family name, e.g. "Inter"
 * @param {string[]} stylesToTest - Candidate style names to probe
 * @returns {Promise<string[]>} - Style names that loaded successfully
 */
async function probeAvailableFontStyles(family, stylesToTest) {
  const available = [];
  for (const style of stylesToTest) {
    try {
      await figma.loadFontAsync({ family, style });
      available.push(style);
    } catch (_) {}
  }
  return available;
}

Creating a Type Ramp (Multi-Step)

Handles font loading, deduplication, and idempotency. Each entry: [name, fontFamily, fontStyle, fontSize_px, lineHeight, cssVar].

HEADLESS NOTE: setBoundVariable on TextStyle is not supported in use_figma. This function sets raw values. To bind variables, do it interactively in Figma after creation.

/**
 * Creates a full type ramp from a token definition array.
 * Handles font loading, deduplication, and idempotency.
 *
 * Each entry: [name, fontFamily, fontStyle, fontSize_px, lineHeight, cssVar]
 *   - lineHeight: { unit: 'AUTO' } or { value: number, unit: 'PIXELS' | 'PERCENT' }
 *
 * @param {Array} defs - Array of [name, fontFamily, fontStyle, fontSize, lineHeight, cssVar] tuples
 * @returns {Promise<{ created: string[], skipped: string[] }>}
 */
async function createTypeRamp(defs) {
  const uniqueFonts = new Set();
  for (const [, family, style] of defs) {
    uniqueFonts.add(JSON.stringify({ family, style }));
  }
  await Promise.all(
    [...uniqueFonts].map(f => figma.loadFontAsync(JSON.parse(f)))
  );

  const existing = new Set(
    (await figma.getLocalTextStylesAsync()).map(s => s.name)
  );

  const created = [];
  const skipped = [];

  for (const [name, family, style, fontSize, lineHeight, cssVar] of defs) {
    if (existing.has(name)) {
      skipped.push(name);
      continue;
    }
    const ts = figma.createTextStyle();
    ts.name = name;
    ts.fontName = { family, style };
    ts.fontSize = fontSize;
    ts.lineHeight = lineHeight ?? { unit: 'AUTO' };
    if (cssVar) ts.description = `CSS: var(${cssVar})`;
    created.push(name);
  }

  return { created, skipped };
}

Full runnable script:

(async () => {
  try {
    const defs = [
      ['heading/xl', 'Inter', 'Bold',      48, { unit: 'PIXELS', value: 56 }, '--font-heading-xl'],
      ['heading/lg', 'Inter', 'Bold',      36, { unit: 'PIXELS', value: 44 }, '--font-heading-lg'],
      ['body/base',  'Inter', 'Regular',   16, { unit: 'AUTO' },              '--font-body-base'],
      ['body/sm',    'Inter', 'Regular',   14, { unit: 'AUTO' },              '--font-body-sm'],
      ['code/base',  'Roboto Mono', 'Regular', 14, { unit: 'AUTO' },          '--font-code-base'],
    ];
    const result = await createTypeRamp(defs);
    figma.closePlugin(JSON.stringify(result));
  } catch(e) { figma.closePluginWithFailure(e.toString()); }
})()

Applying Text Styles to Nodes

/**
 * Applies a text style to all TEXT nodes on the current page that match a given name pattern.
 *
 * @param {string} styleId - The ID of a TextStyle.
 * @param {string} nodeNamePattern - Substring match against node names.
 * @returns {Promise<number>} - Number of nodes the style was applied to.
 */
async function applyTextStyleToMatchingNodes(styleId, nodeNamePattern) {
  const textNodes = figma.currentPage.findAllWithCriteria({ types: ['TEXT'] });
  let applied = 0;
  for (const node of textNodes) {
    if (node.name.includes(nodeNamePattern)) {
      await node.setTextStyleIdAsync(styleId);
      applied++;
    }
  }
  return applied;
}

Full runnable script:

(async () => {
  try {
    const applied = await applyTextStyleToMatchingNodes('STYLE_ID', 'Heading');
    figma.closePlugin(JSON.stringify({ applied }));
  } catch(e) { figma.closePluginWithFailure(e.toString()); }
})()

Source: SKILL.md on GitHub

No alerts17d4 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    This skill provides a robust framework for interacting with the Figma Plugin API via a Model Context Protocol (MCP) server. It includes comprehensive documentation, design system alignment guidelines, and architectural best practices. While the skill enables dynamic code execution and processes external document data, these are standard features of its intended use as a development tool for the Figma platform. The instructions emphasize validation and incremental workflows to manage these capabilities safely.

  • Socket17d

    No alerts

  • Snyk17d

    Risk: LOW · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 0e7823c. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Activeupdated 6 months ago
  • figma
  • plugin-api
  • javascript
  • design-automation
  • variables
  • components
  • design-systems

README badge

README badge for openai/skills/figma-use

This skill loads the Figma Plugin API ruleset and reference docs, making it a prerequisite for executing JavaScript in Figma files via the use_figma MCP tool. It covers critical constraints like async/await patterns, page switching, node ID tracking, and incremental workflow practices to avoid race conditions and atomicity failures.

Generated from the current SKILL.md.

Do I need to load this skill before every use_figma call?
Yes. You must pass `skillNames: "figma-use"` and load this skill before every `use_figma` tool call. Skipping it causes hard-to-debug failures.
Can I use figma.notify() to show messages in the plugin UI?
No. `figma.notify()` throws "not implemented". Use `return` to send data back to the agent instead.
What should I do if a use_figma call fails with an error?
Stop and read the error message carefully. `use_figma` is atomic — if a script errors, no changes are made to the file. Fix the script based on the error and retry.
How do I switch to a different page in a use_figma script?
Use `await figma.setCurrentPageAsync(page)` to switch pages and load their content. The sync setter `figma.currentPage = page` throws an error.
What should I return from a use_figma script that creates or modifies nodes?
Always return all affected node IDs in a structured object, e.g. `return { createdNodeIds: [...], mutatedNodeIds: [...] }`. This is required so subsequent calls can reference those nodes.

Generated from the current SKILL.md. These answers refresh after source changes.