All skills
figma avatar

/figma-use

@1729207 official
by figmafigma/mcp-server-guide2k stars
194

**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/figma/mcp-server-guide/figma-use

This session only. Nothing lands on disk.

referencestext-style-patterns.md

≈2.1k 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, use_figma limitations), see wwds-text-styles.

Prefer $fig for creation + binding

For new text styles + binding them to text nodes, reach for $fig first — fonts preload automatically, the style and the binding go in the same plan, and the binding uses the natural textStyle property (no *StyleId suffix to remember):

const heading = $fig.textStyle({
  name: "Heading/1",
  fontName: { family: "Inter", style: "Bold" },
  fontSize: 48,
})
$fig.text({ characters: "Title", textStyle: heading })

See fig-builder.md for the full surface (paintStyle / textStyle / effectStyle / gridStyle / getStyle, the FigPlanStyle handle methods, and the fills / strokes / effects / layoutGrids / textStyle property routing).

The raw Plugin API patterns below are the fallback for when you genuinely need to interleave style ops with mid-script async calls or read computed properties off the live TextStyle before deciding what to do next.

Contents

  • Listing Text Styles
  • Creating a Text Style
  • Discovering Available Font Styles
  • Creating a Type Ramp (Multi-Step)
  • Importing Library Text Styles
  • 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:

const results = await listTextStyles();
return results;

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;
}

Discovering Available Font Styles

Font style names vary per provider and per file. Use figma.listAvailableFontsAsync() to discover exact style strings — never guess or probe with try/catch:

/**
 * Discovers available font styles for a given family using listAvailableFontsAsync.
 *
 * @param {string} family - Font family name, e.g. "Inter"
 * @returns {Promise<string[]>} - All available style names for the family
 */
async function getAvailableFontStyles(family) {
  const allFonts = await figma.listAvailableFontsAsync();
  return allFonts
    .filter(f => f.fontName.family === family)
    .map(f => f.fontName.style);
}

Creating a Type Ramp (Multi-Step)

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

/**
 * 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:

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);
return result;

Using Library Text Styles by key (preferred)

A style found via a search_design_system queries entry with entity: "style" returns a key. Pass it directly into $fig.getStyle(styleKey) and apply via the textStyle property on any $fig.text(...) / $fig.query('TEXT').set(...) — the plan queues the library import automatically.

const heading = $fig.getStyle(HEADING_TEXT_STYLE_KEY)
$fig.text({ characters: 'Title', textStyle: heading })

// Bulk apply to existing text nodes
$fig.query('TEXT[name=Heading]').set({ textStyle: heading })

Prefer reusing library text styles over creating new ones.

Raw-API fallback

// If you need the imported TextStyle's metadata mid-script
const headingStyle = await figma.importStyleByKeyAsync("TEXT_STYLE_KEY");
await textNode.setTextStyleIdAsync(headingStyle.id);

Applying Text Styles to Nodes

Prefer $fig.query(...).set({ textStyle }) over findAllWithCriteria + a manual loop — the selector matches name patterns directly, and $fig batches the writes and resolves the style id at flush time. The textStyle property accepts a $fig.getStyle(...) handle (local id OR library key from search_design_system) or a raw style id string.

// Library style by key — $fig queues the import; no separate await needed.
const heading = $fig.getStyle(HEADING_TEXT_STYLE_KEY)

// Apply to every TEXT whose name contains 'Heading' on the current page
const result = $fig.query('TEXT[name*=Heading]').set({ textStyle: heading })
return { applied: result.length }

Scope to a subtree or another page via a second arg / a parent handle:

// Scoped to one frame
const card = $fig.get('1:42')
$fig.query('TEXT[name*=Heading]', card).set({ textStyle: heading })

// Across the whole document (all pages)
$fig.query('TEXT[name*=Heading]', figma.root).set({ textStyle: heading })

If you already have a local style id (not a key) and don't want a $fig.getStyle wrap, the raw setter still works:

$fig.query('TEXT[name*=Heading]').each(async (n) => {
  await n.node?.setTextStyleIdAsync('STYLE_ID')   // only after $fig.done() / auto-flush
})

Source: SKILL.md on GitHub

No alerts9d4 checks · Risk SAFE
  • Gen Agent Trust Hub9d

    The skill provides comprehensive instructions and reference material for interacting with the Figma Plugin API. No security issues were detected.

  • Socket9d

    No alerts

  • Snyk9d

    Risk: LOW · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

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

Last checked against GitHub yesterday.

Activeupdated 2 weeks ago
disable-model-invocation
false
  • figma
  • plugin-api
  • design-systems
  • javascript
  • components
  • variables
  • auto-layout
  • tokens

README badge

README badge for figma/mcp-server-guide/figma-use

Loads prerequisites for the `use_figma` tool, which executes JavaScript in Figma files via the Plugin API. This skill teaches critical rules for font loading, text editing, auto-layout, pagination, async operations, and incremental work patterns that prevent hard-to-debug failures. Install this before any Figma programmatic task—creating or editing nodes, binding variables, building components, or inspecting file structure.

Generated from the current SKILL.md.

Do I need to load this skill before calling use_figma?
Yes. This skill is a mandatory prerequisite. You must load figma-use before every use_figma tool call and include it in the skillNames parameter, or the call will fail with hard-to-debug errors.
What kind of operations does this skill cover?
Write actions and unique read actions that require JavaScript execution in Figma files: creating/editing/deleting nodes, setting up variables and tokens, building components and variants, modifying auto-layout or fills, binding variables to properties, and inspecting file structure programmatically.
Can I use console.log() to debug my code?
No. console.log() output is not returned. Use return statements to send data back instead — return values are automatically JSON-serialized.
How do I switch to a different page in Figma?
Use await figma.setCurrentPageAsync(page) to switch pages and load their content. The synchronous setter figma.currentPage = page does not work and will throw an error.
What should I do if a use_figma call fails?
Stop and do not retry immediately. Failed scripts are atomic — no changes are made to the file. Read the error message carefully, fix the script, and retry.

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