All skills
figma avatar

/figma-use-figjam

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

This skill helps agents use Figma's use_figma MCP tool in the FigJam context. Can be used alongside figma-use which has foundational context for using the use_figma tool.

Use this Skill: https://skilld.dev/gh/figma/mcp-server-guide/figma-use-figjam

This session only. Nothing lands on disk.

referencesbatch-modify.md

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

Batch Operations Pattern

Part of the figma-use-figjam skill. Patterns for modifying many existing nodes at once.

Typical workflow:

  1. Find nodes using traversal APIs (findAll, findAllWithCriteria)
  2. Apply modifications using the patterns below

Performance Tips

1. Use findAllWithCriteria for Type-Based Searches

findAllWithCriteria is significantly faster than findAll when filtering by node type only.

// ✅ FAST - Use findAllWithCriteria for type filtering
const textNodes = figma.currentPage.findAllWithCriteria({ types: ['TEXT'] })
const shapes = figma.currentPage.findAllWithCriteria({
  types: ['RECTANGLE', 'ELLIPSE', 'POLYGON', 'STAR'],
})

// ❌ SLOWER - findAll with type check
const textNodesSlow = figma.currentPage.findAll((n) => n.type === 'TEXT')

figma.closePlugin()

2. Limit Search Scope

Search within a specific node rather than the entire page.

// ✅ FAST - Search within specific frame, using indexed type lookup
const frame = await figma.getNodeByIdAsync('123:456')
if (frame && 'findAllWithCriteria' in frame) {
  const textInFrame = frame.findAllWithCriteria({ types: ['TEXT'] })
}

// ❌ SLOWER - Whole-page predicate scan
const allText = figma.currentPage.findAll((n) => n.type === 'TEXT')

figma.closePlugin()

Batch Modify Pattern

Basic Batch Modification

const page = figma.currentPage

// Find all buttons
const buttons = page.findAll((n) => n.name.toLowerCase().includes('button'))
console.log(`Found ${buttons.length} buttons`)

// Modify each one
let modified = 0
for (const btn of buttons) {
  if ('fills' in btn) {
    btn.fills = [{ type: 'SOLID', color: { r: 0, g: 0.5, b: 1 } }]
    modified++
  }
}

console.log(`Modified ${modified} buttons`)
figma.closePlugin()

With Progress Logging

For long operations, log progress so you can track what's happening.

const nodes = figma.currentPage.findAllWithCriteria({ types: ['TEXT'] })
console.log(`Processing ${nodes.length} text nodes...`)

let processed = 0
for (const node of nodes) {
  // Load all fonts (handles mixed fonts via styled segments)
  const segments = node.getStyledTextSegments(['fontName'])
  await Promise.all(segments.map((s) => figma.loadFontAsync(s.fontName)))
  node.fontSize = 16

  processed++
  if (processed % 50 === 0) {
    console.log(`Processed ${processed}/${nodes.length}`)
  }
}

console.log(`Done! Processed ${processed} nodes`)
figma.closePlugin()

Chunked Processing

For very large operations, process in chunks to avoid timeouts.

async function processInChunks(nodes, chunkSize, processFn) {
  const results = []

  for (let i = 0; i < nodes.length; i += chunkSize) {
    const chunk = nodes.slice(i, i + chunkSize)
    console.log(
      `Processing chunk ${Math.floor(i / chunkSize) + 1}/${Math.ceil(nodes.length / chunkSize)}`,
    )

    for (const node of chunk) {
      const result = await processFn(node)
      results.push(result)
    }
  }

  return results
}

// Usage
const allText = figma.currentPage.findAllWithCriteria({ types: ['TEXT'] })

await processInChunks(allText, 100, async (node) => {
  // Load all fonts (handles mixed fonts via styled segments)
  const segments = node.getStyledTextSegments(['fontName'])
  await Promise.all(segments.map((s) => figma.loadFontAsync(s.fontName)))
  node.textCase = 'UPPER'
  return node.id
})

figma.closePlugin()

Collecting Results

Build Summary Object

const textNodes = figma.currentPage.findAllWithCriteria({ types: ['TEXT'] })

// Collect statistics
const fontUsage = {}
for (const node of textNodes) {
  if (node.fontName && node.fontName.family) {
    const key = `${node.fontName.family} ${node.fontName.style}`
    fontUsage[key] = (fontUsage[key] || 0) + 1
  }
}

console.log('Font usage:')
for (const [font, count] of Object.entries(fontUsage).sort((a, b) => b[1] - a[1])) {
  console.log(`  ${font}: ${count}`)
}

figma.closePlugin()

Group by Property

const nodes = figma.currentPage.findAll((n) => 'fills' in n)

// Group by fill color
const byColor = {}
for (const node of nodes) {
  if (Array.isArray(node.fills) && node.fills.length > 0) {
    const fill = node.fills[0]
    if (fill.type === 'SOLID') {
      const key = `rgb(${Math.round(fill.color.r * 255)}, ${Math.round(fill.color.g * 255)}, ${Math.round(fill.color.b * 255)})`
      if (!byColor[key]) byColor[key] = []
      byColor[key].push(node.name)
    }
  }
}

console.log('Nodes by color:', JSON.stringify(byColor, null, 2))
figma.closePlugin()

Safe Batch Updates

Check Before Modify

const nodes = figma.currentPage.findAll((n) => n.name.includes('Button'))

for (const node of nodes) {
  // Log before state
  console.log(`${node.name} before:`, 'fills' in node ? JSON.stringify(node.fills) : 'no fills')

  // Check if modification is possible
  if (!('fills' in node)) {
    console.log(`  Skipping ${node.name} - no fills property`)
    continue
  }

  // Modify
  node.fills = [{ type: 'SOLID', color: { r: 0, g: 0.5, b: 1 } }]

  // Log after state
  console.log(`${node.name} after:`, JSON.stringify(node.fills))
}

figma.closePlugin()

Common Patterns: Renaming Layers

Bulk Find-and-Replace in Names

const nodes = figma.currentPage.findAll((n) => n.name.includes('Button'))
console.log(`Found ${nodes.length} nodes to rename`)

for (const node of nodes) {
  const oldName = node.name
  node.name = node.name.replace('Button', 'Btn')
  console.log(`  "${oldName}" → "${node.name}"`)
}

figma.closePlugin()

Auto-Numbering Children

const frame = await figma.getNodeByIdAsync('123:456')

if ('children' in frame) {
  for (let i = 0; i < frame.children.length; i++) {
    frame.children[i].name = `Item ${i + 1}`
  }
  console.log(`Numbered ${frame.children.length} children`)
}

figma.closePlugin()

Content-Based Naming (Name from Text Content)

const frames = figma.currentPage.findAllWithCriteria({ types: ['FRAME'] })

let renamed = 0
for (const frame of frames) {
  // Use the type-indexed criteria for type-based searches; take the first match.
  const heading = frame.findAllWithCriteria({ types: ['TEXT'] })[0]
  if (heading) {
    frame.name = heading.characters.slice(0, 40)
    renamed++
  }
}

console.log(`Renamed ${renamed} frames from heading text`)
figma.closePlugin()

Strip Auto-Generated Names

const autoNamePattern = /^(Frame|Rectangle|Ellipse|Group|Vector|Line|Polygon|Star)\s+\d+$/
const nodes = figma.currentPage.findAll((n) => autoNamePattern.test(n.name))
console.log(`Found ${nodes.length} auto-named nodes`)

for (const node of nodes) {
  node.name = node.type.toLowerCase()
}

figma.closePlugin()

Add Prefix with / Separator (Layer Panel Grouping)

Figma groups layers in the panel by / in names (e.g., icons/arrow, icons/check).

// Use the type-indexed criteria for the type filter, then narrow by name.
const icons = figma.currentPage
  .findAllWithCriteria({ types: ['INSTANCE'] })
  .filter((n) => n.name.toLowerCase().includes('icon'))

for (const icon of icons) {
  if (!icon.name.startsWith('icons/')) {
    icon.name = `icons/${icon.name}`
  }
}

console.log(`Prefixed ${icons.length} icon layers`)
figma.closePlugin()

Source: SKILL.md on GitHub

No alerts16d3 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    This skill provides documentation and code patterns for using Figma's official MCP tools in FigJam files. It is safe and contains no malicious code or instructions.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

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

Last checked against GitHub 20 hours ago.

Activeupdated last month
disable-model-invocation
false
  • MCP
  • figma
  • figjam
  • plugin-api
  • board-creation
  • collaborative-design
  • javascript

README badge

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

Instructs the use_figma MCP tool for FigJam-specific operations: creating boards, sections, stickies, connectors, tables, and code blocks. Covers inspection via get_figjam, text mutations, image uploads, and positioning rules that differ from Figma Design files.

Generated from the current SKILL.md.

Do I call `figma.createPage()` in FigJam files?
No. FigJam files (figma.com/board/...) do not support `createPage()` and will throw a TypeError. FigJam has a single implicit page; use sections instead to organize content.
How do I inspect a FigJam file to get node IDs?
`get_figjam` is the inspection tool for FigJam files and returns the full node tree as XML with all IDs. Always call it upfront before writing `use_figma` code that references existing nodes, since `console.log` output from `use_figma` is not returned to the agent.
Can I use `get_metadata` on FigJam files?
No. `get_metadata` is design-mode only and will fail immediately on FigJam files with an 'unsupported for FigJam files' error.
How do I add images to a FigJam board?
`upload_assets` is the only supported way to add images to FigJam. Do not use `figma.createImage()` or `figma.createImageAsync()` from inside `use_figma`.
What is the canonical recipe for editing text in FigJam?
Load the font, await it, then mutate the text node, then return affected IDs. FigJam text nodes use varying default fonts (sticky/shape use Inter Medium, connector has no default), so always load the actual font from `node.text.fontName` rather than hardcoding a family.

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