关于 figma-use
figma-use 是通过 Figma Plugin API 在 Figma 文件中执行 JavaScript 的技能,面向需要读取或修改 Figma 文件的 Agent。它提供 API 规则、设计系统操作指引和安全编辑要求。
主要功能
- 01在 Figma 文件中执行 JavaScript
- 02提供 Plugin API 操作规范
- 03指导设计系统相关操作
- 04涵盖页面、文本与变量规则
适用场景
- 01读取 Figma 文件内容
- 02按要求编辑画布节点
- 03在设计系统中查找和使用资产
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ figma/ mcp-server-guide --skill figma-use安装后在 Claude Code 中输入/figma-use确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/api-reference.mdcommon-patterns.mdcomponent-patterns.mdeffect-style-patterns.mdgotchas.mdplugin-api-patterns.mdplugin-api-standalone.d.tsplugin-api-standalone.index.mdtext-style-patterns.mdvalidation-and-recovery.mdvariable-patterns.mdreferences/working-with-design-systems/wwds-components--creating.mdwwds-components--using.mdwwds-components.mdwwds-effect-styles.mdwwds-text-styles.mdwwds-variables--creating.mdwwds-variables--using.mdwwds-variables.mdwwds.md详细介绍
use_figma — Figma 插件 API 技能
使用 use_figma 工具,通过插件 API 在 Figma 文件中执行 JavaScript。所有详细参考文档都位于 references/ 中。
如果可用,请在读取或编辑文件前,使用 fileKey 和 description 调用 create_session(如有需要,先创建文件),然后将返回的 sessionId 原样传递给所有接受该参数的调用,包括后续调用和跨文件操作。
调用 use_figma 时,始终在逗号分隔的 skillNames 参数中包含 figma-use。如果此技能是通过 MCP 资源加载的,则必须在名称前加上 resource:(例如 resource:figma-use)。 这是用于追踪技能使用情况的日志参数,不会影响执行。
如果 Figma MCP 工具显示为延迟加载工具,请使用 select: 语法,通过一次 ToolSearch 调用批量加载所有工具的架构,例如 ToolSearch query="select:use_figma,get_screenshot,get_metadata,create_new_file"。一次往返胜过六次。
对可见设计的更改为强制要求: 在首次调用会产生更改的 use_figma 之前,同时加载 figma-generate-design 和此技能,并在每次会产生更改的调用的 skillNames 中包含这两个名称。无论更改涉及单个可见属性或元素,还是完整页面、屏幕或组合的多分区视图,都适用此要求——即使用户将该视图称为组件。figma-use 提供插件 API 规则;figma-generate-design 提供通过 search_design_system 发现设计系统、导入资源和增量组装的能力。
可复用库例外: 如果主要交付内容是供复用或发布的可复用组件、组件集、变体系统、变量/令牌集合、样式基础,或其他库资源,请改为加载 figma-generate-library。它提供组件创建工作流,包括变量基础、变体集和设计令牌绑定;这些内容仅靠 figma-use 无法涵盖。如果任务同时包含库资源和使用这些资源的组合设计,请加载这两个配套技能。只读的 use_figma 调用无需加载这两个技能。
首先,加载 plugin-api-standalone.index.md,了解 API 的能力范围。收到编写插件 API 代码的要求时,请依据这些上下文,在 plugin-api-standalone.d.ts 中搜索相关类型、方法和属性。这是 API 范围的权威信息来源。该类型定义文件很大,因此不要一次性全部加载;请按需搜索相关部分。
重要:处理设计系统时,务必先查看 working-with-design-systems/wwds.md,了解在 Figma 中使用设计系统的关键概念、流程和指南。然后根据需要加载组件、变量、文本样式和效果样式的具体参考文档。
1. 关键规则
- 使用
return返回数据。 返回值会自动序列化为 JSON(对象、数组、字符串、数字)。不要调用figma.closePlugin(),也不要将代码包装在异步 IIFE 中——这些已由系统处理。 - 使用顶层
await和return编写纯 JavaScript。 代码会自动包装在异步上下文中。不要将代码包装在(async () => { ... })()中。 figma.notify()会抛出“not implemented”错误——切勿使用。 3a. 返回节点 ID,并将工作流状态保存在 Figma 文件之外。 仅在COMPONENT或COMPONENT_SET的node.description中设置易于理解的组件用途和用法——切勿在画框或实例上设置。 3b. 访问特定类型的属性前先缩小类型范围。 检查node.type,使用"characters" in node这样的能力检查,或使用findAllWithCriteria预筛选。characters要求节点支持文本;可选链无法避免访问不支持的属性时出错。console.log()的内容不会返回——使用return输出。- 构建操作时,应考虑安全重试,并根据实际证据进行验证。 不要仅为设置验证检查点而拆分可正常工作的操作。如果脚本在重试时仍然安全,可将相关工作批量处理;完整的章节或页面可在一次调用中构建。跨越页面上下文、部分执行难以恢复,或实际失败后需要定向重试时,再拆分操作。每次写入都返回受影响的 ID 及相关计数、名称或边界,这就算结构验证。只有在缺少必要证据或相关修改后,才运行单独的结构检查。通常在完成布局后截一次图,修正视觉问题后再截一次。最近一次通过检查的截图就是最终检查;没有相关改动时不要重复检查。要求通过后即停止。
- 颜色使用 0–1 范围(不是 0–255):
{r: 1, g: 0, b: 0}= 红色。Paint 的color对象只能使用{r, g, b},不能包含a字段;不透明度应设置在 paint 层级({ type: 'SOLID', color: {...}, opacity: 0.5 })。 - 填充和描边是 只读数组——克隆、修改后再重新赋值。
- 每次文本编辑都必须遵循标准流程:加载字体 →
await→ 修改 → 返回受影响节点 ID。 跳过加载会抛出Cannot write to node with unloaded font "<family> <style>"。此规则不仅适用于characters,还适用于对字体尚未加载的节点执行的任何操作(appendChild、insertChild、setBoundVariable、setExplicitVariableModeForCollection、setValueForMode、涉及文本的findAll回调)。修改现有文本时,使用getStyledTextSegments(['fontName'])加载节点当前使用的字体,不要硬编码默认字体。大多数环境会预加载 Inter,因此其他字体更容易暴露这个问题——但所有字体都必须遵循相同流程。如果样式字符串未经验证,先使用await figma.listAvailableFontsAsync()——绝不要猜测("SemiBold"和"Semi Bold"是常见易错点)。对于作用域为FONT_FAMILY的变量,在调用setBoundVariable("fontFamily", …)、setValueForMode或setExplicitVariableModeForCollection之前,先加载所有相关模式下的每个值。lineHeight/letterSpacing接受{unit, value},不能只传数字。参见 标准文本编辑流程。 - 页面会增量加载——使用
await figma.setCurrentPageAsync(page)切换页面并加载其内容。同步设置器figma.currentPage = page不起作用,并会抛出"Setting figma.currentPage is not supported"。每次use_figma调用开始时,页面上下文都会重置为第一页,因此每次调用都要重新切换;每次调用最多切换一次,并行分配多页面工作——参见 页面规则 和 gotchas.md。 setBoundVariableForPaint会返回一个新的 paint——必须接收并重新赋值。createVariable接受集合对象或 ID 字符串(优先使用对象)。layoutSizingHorizontal/Vertical的可用值受结构上下文限制——FIXED始终有效,HUG和FILL则不然。'HUG'仅适用于自动布局画框本身,或自动布局画框的 TEXT 子节点。'FILL'仅适用于自动布局画框的子节点,且该子节点不能是绝对定位、位于不可变画框内,或是画布网格子节点。实际操作中,应先将节点添加到自动布局父节点,再设置HUG/FILL——新建或未设置父节点的节点尚不满足此规则。此属性本身存在于每个SceneNode上;报错原因是值被拒绝,而不是“没有此属性”。参见 常见问题。 12a. 包含相关子节点的容器应使用自动布局。 当子节点之间存在结构关系——堆叠、并排、对齐、间隔或包裹——请使用figma.createAutoLayout()包裹它们,而不要使用带有绝对x/y的figma.createFrame()。绝对坐标控制容器在画布上的位置;自动布局控制容器内子节点之间的关系。省略容器会导致文本重排、内容变化或重叠时没有保护。 12b.layoutSizing*和*AxisSizingMode是不同的枚举,切勿混用。layoutSizingHorizontal/layoutSizingVertical(设置在子节点上)接受'FIXED'|'HUG'|'FILL';primaryAxisSizingMode/counterAxisSizingMode(设置在画框本身上)接受'FIXED'|'AUTO'。因此,layoutSizingVertical = 'AUTO'无效(应使用'HUG'),而counterAxisSizingMode = 'FILL'会抛出Expected 'FIXED' | 'AUTO', received 'FILL'(应使用'FIXED'/'AUTO')。同一设置器还可能引发另外两种错误——Error: in set_layoutSizingHorizontal: node must be an auto-layout frame or a child of an auto-layout frame和Error: in set_layoutSizingHorizontal: FILL can only be set on children of auto-layout frames——这表示节点尚未处于自动布局上下文中;建议:将父节点设为自动布局(figma.createAutoLayout()),并先用appendChild添加节点,再进行设置(参见规则 12)。参见 常见问题。 12c.resize()会将尺寸模式重置为FIXED,因此应先调用它,再设置layoutSizing*。 需要换行的 TEXT 块应设置textAutoResize = 'HEIGHT',并显式指定固定宽度(调用resize()),而不是只设置FILL——默认的WIDTH_AND_HEIGHT模式会忽略FILL,使节点宽度收缩至接近零。之后应确认node.width > 0。- 新建的顶层节点应放在远离 (0,0) 的位置。 直接添加到页面的节点默认位于 (0,0)。扫描
figma.currentPage.children,找到空闲位置(例如最右侧节点的右边)。此规则仅适用于页面级节点——嵌套在其他画框或自动布局容器中的节点由其父节点定位。参见 常见问题。 - 发生
use_figma错误时,遵守safeToRetryWithoutCanvasRead。 若值为true,修复错误后重试。若值为false,读取画布,确定发生了什么变化,然后再进行修改。参见 错误恢复。 - 必须通过
return返回所有已创建/修改节点的 ID。 每当脚本在画布上创建新节点或修改现有节点时,都要收集每个受影响节点的 ID,并在结构化对象中返回(例如return { createdNodeIds: [...], mutatedNodeIds: [...] })。后续调用需要依靠这些 ID 来引用、验证或清理节点。use_figma调用之间不会保留状态,因此应将前一次调用中的 ID 作为字符串字面量传入,而不是使用变量。多步骤示例参见 common-patterns.md。 - 创建变量时,始终显式设置
variable.scopes。 默认的ALL_SCOPES会污染每个属性选择器,几乎从来不是你想要的结果。背景等用途可使用["FRAME_FILL", "SHAPE_FILL"],文本颜色可使用["TEXT_FILL"],间距可使用["GAP"]等具体作用域。完整列表参见 variable-patterns.md。 - 为每个 Promise 添加
await。 切勿留下未等待的 Promise——未等待的异步调用(例如不带await的figma.loadFontAsync(...)或figma.setCurrentPageAsync(page))会以即发即弃的方式执行,造成静默失败或竞态条件。脚本可能在异步操作完成前就返回,导致数据缺失或修改只完成一部分。 - 切勿从变体组件读取
componentPropertyDefinitions。 先缩小所属节点的范围:节点本身是COMPONENT_SET时直接使用;仅当父节点不是COMPONENT_SET时才使用COMPONENT;否则将变体COMPONENT提升为其父级集合。可选链无法保证安全访问该 getter。参见 组件属性所属节点范围判断。
每条规则的错误/正确示例详见 常见问题与常见错误。
2. 页面规则(关键)
仅支持异步的 setter 和每次调用时的上下文重置见规则 9。本节将详细说明唯一需要通过示例讲解的规则:每个脚本最多切换一次页面;涉及多个页面的工作应并行拆分。
切勿遍历 figma.root.children 并在循环中切换页面——每次切换都会重新加载文件。如果工作涉及多个页面,应拆分为 N 个 use_figma 调用(每个目标页面一个),并并行发出——在一条助手消息中包含 N 个 use_figma 工具调用块。执行框架会并发运行这些调用;每个脚本只设置一次 currentPage。
明确指示: 扇出调用时,你 MUST 在一条消息中发出 N 个工具调用。不要分多轮发送。不要等一个调用完成后再发出下一个。按页面顺序逐个调用会完全抵消拆分带来的好处。
// AVOID — switches pages N times in one script, reloads the file each time
for (const page of figma.root.children) {
await figma.setCurrentPageAsync(page);
// ... touch this page ...
}
// PREFER — read-only discovery call to get page IDs, then in the NEXT message
// emit N parallel use_figma tool calls (one per page), each setting currentPage once.
涉及多个页面的工作,无论是读取还是写入,默认都应并行扇出。你也可以多次调用 use_figma,以逐步完成工作(例如,先 return 现有节点的元数据,再在后续脚本中修改它们)。完整说明请参阅 gotchas.md → 每次 use_figma 调用只设置一次当前页面。
3. return 是你的输出渠道
Agent 只能看到你 return 的值——console.log() 不可见(规则 4),抛出的错误会自动捕获(让错误继续传播,或显式 throw)。硬性要求见规则 15:每个创建或修改画布节点的脚本都 MUST 以结构化对象返回所有受影响的节点 ID,以及任何可执行的状态信息——例如 return { createdNodeIds: [...], mutatedNodeIds: [...], count: 5, errors: [] }——以便后续调用引用、验证或清理这些节点。
4. 编辑器模式
use_figma 在设计模式下工作(editorType 为 "figma",默认值)。FigJam("figjam")和 Slides("slides")可用的节点类型各不相同——大多数设计节点在 FigJam 中不可用,而仅限 FigJam 的节点在 Slides 中不可用。
根据 URL 判断编辑器: 设计 = figma.com/design/...,FigJam = figma.com/board/...,Slides = figma.com/slides/...。在假设某个 API 可用之前,请先确认。
设计模式下可用:Rectangle、Frame、Component、Text、Ellipse、Star、Line、Vector、Polygon、BooleanOperation、Slice、Page、Section、TextPath。
设计模式下不可用:Sticky、Connector、ShapeWithText、CodeBlock、Slide、SlideRow、SlideGrid、InteractiveSlideElement、Webpage。
Slides 模式下可用:Rectangle、Frame、Component、Text、Ellipse、Star、Line、Vector、Polygon、BooleanOperation、Slice、Section、TextPath、Slide、SlideRow、SlideGrid、InteractiveSlideElement。
Slides 模式下不可用:Sticky、Connector、ShapeWithText、CodeBlock、Webpage、Page。
仅限设计模式的 API(不只是节点类型): figma.createPage() 仅适用于设计文件(figma.com/design/...)。在 FigJam(figma.com/board/...)和 Slides(figma.com/slides/...)中调用会抛出 TypeError: figma.createPage no such property 'createPage' on the figma global object。在 FigJam 或 Slides 工作流中不要调用 figma.createPage()。
Slides 说明: 目前还没有专门用于读取 Slides 文件的工具。使用
use_figma搭配只读脚本进行检查(参见第 6 节的“先检查”模式),并使用get_screenshot/await node.screenshot()获取视觉上下文。如需 Slides 专属 API 指南,请加载 figma-use-slides 技能。
5. 高效 API——优先使用这些 API,而非冗长的替代方案
这些 API 可减少样板代码、避免顺序错误并压缩 token 输出。始终优先使用这些 API,而非冗长的替代方案。
node.query(selector) — 类 CSS 节点搜索
使用类 CSS 选择器在子树中查找节点。替代冗长的 findAll + 筛选循环。
// BEFORE — verbose traversal
const texts = frame.findAll(n => n.type === 'TEXT' && n.name === 'Title')
// AFTER — one-liner with query
const texts = frame.query('TEXT[name=Title]')
选择器语法:
- 类型:
FRAME、TEXT、RECTANGLE、ELLIPSE、COMPONENT、INSTANCE、SECTION(不区分大小写) - 属性精确匹配:
[name=Card]、[visible=true]、[opacity=0.5] - 属性子串匹配:
[name*=art](包含)、[name^=Header](以此开头)、[name$=Nav](以此结尾) - 点路径遍历:
[fills.0.type=SOLID]、[fills.*.type=SOLID](通配索引) - 实例匹配:
[mainComponent=nodeId]、[mainComponent.name=Button] - 组合符:
FRAME > TEXT(直接子节点)、FRAME TEXT(任意后代节点)、A + B(相邻兄弟节点)、A ~ B(一般兄弟节点) - 伪类:
:first-child、:last-child、:nth-child(2)、:not(TYPE)、:is(FRAME, RECTANGLE)、:where(TEXT, ELLIPSE) - 节点 ID:
#nodeId或不带前缀的 GUID - 逗号:
TEXT, RECTANGLE(并集) - 通配符:
*(任意类型)
QueryResult 方法:
| 方法 | 说明 |
|---|---|
.length | 匹配节点的数量 |
.first() | 第一个匹配节点(或 null) |
.last() | 最后一个匹配节点(或 null) |
.toArray() | 转换为普通数组 |
.each(fn) | 使用回调迭代,返回 this 以便链式调用 |
.map(fn) | 映射为新数组 |
.filter(fn) | 筛选并返回新的 QueryResult |
.values(keys) | 提取属性值:.values(['name', 'x', 'y']) → [{name, x, y}, ...] |
.set(props) | 为所有匹配节点设置属性(见下方的 node.set()) |
.query(selector) | 在匹配节点内进行子查询 |
for...of | 可迭代——可用于 for 循环 |
范围:node.query() 会在该节点的子树中搜索。要搜索整个页面,请使用 figma.currentPage.query('...')。不存在全局的 figma.query()。
示例:
// Recolor all text inside cards
figma.currentPage.query('FRAME[name^=Card] TEXT').set({
fills: [{type: 'SOLID', color: {r: 0.2, g: 0.2, b: 0.8}}]
})
// Get names and positions of all frames
return figma.currentPage.query('FRAME').values(['name', 'x', 'y'])
// Find the first component named "Button"
const btn = figma.currentPage.query('COMPONENT[name=Button]').first()
// Find all instances of a specific component
figma.currentPage.query(`INSTANCE[mainComponent=${compId}]`)
// Find nodes with solid fills using dot-path traversal
figma.currentPage.query('[fills.0.type=SOLID]')
node.set(props) — 批量更新属性
一次调用即可设置多个属性。返回 this 以便链式调用。
// BEFORE — one line per property
frame.opacity = 0.5
frame.cornerRadius = 8
frame.name = "Card"
// AFTER — single call
frame.set({ opacity: 0.5, cornerRadius: 8, name: "Card" })
**优先级键顺序:**无论对象键的顺序如何,layoutMode 总是在其他属性(如 width/height)之前应用。这可以避免一个常见问题:设置 layoutMode 与否会导致 resize() 的行为不同。
宽高处理:width 和 height 会自动通过 node.resize() 设置——设置 { width: 200 } 会调用 resize(200, currentHeight)。
与 query 链式调用:
// Find all rectangles named "Divider" and update them
figma.currentPage.query('RECTANGLE[name=Divider]').set({
fills: [{type: 'SOLID', color: {r: 0.9, g: 0.9, b: 0.9}}],
cornerRadius: 2
})
figma.createAutoLayout(direction?, props?) — 自动布局框架
创建一个已启用自动布局且两轴均贴合内容的框架。只要子节点之间存在结构关系,这就是默认容器(见规则 12a)。
// BEFORE — manual setup, easy to get ordering wrong
const frame = figma.createFrame()
frame.layoutMode = 'VERTICAL'
frame.primaryAxisSizingMode = 'AUTO'
frame.counterAxisSizingMode = 'AUTO'
frame.layoutSizingHorizontal = 'HUG'
frame.layoutSizingVertical = 'HUG'
// AFTER — one call, layout ready
const frame = figma.createAutoLayout('VERTICAL')
添加子节点后,可立即将 layoutSizingHorizontal/Vertical 设为 'FILL'——无需手动设置尺寸模式。
可将可选的 props 对象作为第一个或第二个参数传入:
figma.createAutoLayout({ name: 'Card', itemSpacing: 12 }) // HORIZONTAL + props
figma.createAutoLayout('VERTICAL', { name: 'Column', itemSpacing: 8 }) // VERTICAL + props
node.placeholder — 用于反馈 AI 正在处理的闪烁叠加效果
在节点上设置闪烁叠加效果,表示工作正在进行。完成后务必移除闪烁效果——残留的闪烁效果会让用户困惑,也表明工作尚未完成。
// Mark as in-progress
frame.placeholder = true
// ... build out the content ...
// MUST remove when done — never leave shimmers on finished nodes
frame.placeholder = false
构建复杂布局时,先在各个区块上设置 placeholder = true,再填充内容;每个区块完成后,将其 placeholder = false。
await node.screenshot(opts?) — 内嵌截图
将节点捕获为 PNG,并在响应中内嵌返回。无需单独调用 get_screenshot。
// Take a screenshot of a frame (returned inline in the tool response)
await frame.screenshot()
// Custom scale (default auto-scales: 0.5x or capped so max dimension ≤ 1024px)
await frame.screenshot({ scale: 2 })
// Include overlapping content from sibling nodes
await frame.screenshot({ contentsOnly: false })
使用时机: 遵循规则 5。需要视觉证据时,截取构图截图。如果之后进行了视觉修复,再截取一张修复后的截图;这张通过检查的截图就是最终截图。不要再额外截取一张没有变化的“最终”截图。
自动命名: 图片标题包含节点元数据——"Card (300x150 at 0,60).png"——无需解析图片即可了解空间上下文。
默认缩放: 使用 0.5x 缩放,但会自动限制最大输出尺寸不超过 1024px。显式指定 { scale: N } 时不受此限制。
6. 渐进式工作流(如何避免错误)
最常见的浪费原因是不必要的拆分、重复验证,以及无法安全重试的脚本。遵循规则 5 中的安全重试和基于证据的验证约定。
关键规则
- 根据可恢复性而非验证频率选择调用边界。 在安全的情况下,批量执行相关的创建、属性更新、父子关系设置和针对性诊断。完整页面可以通过一次调用完成;不要仅仅为了逐节验证,就把它拆分成页眉、内容和页脚等多个调用。Slides 例外: 在 Slides 文件中,幻灯片是彼此独立的子树——相关限制是每张幻灯片的复杂度,而不是跨幻灯片的节点总数。一次调用安全地创建 3–5 张新幻灯片,也可以在一次调用中对整个演示文稿的每张幻灯片应用相同编辑(例如添加页脚、为标题重新着色)。有关演示文稿的构建工作流,请参阅 figma-use-slides。
- 从上到下构建,先创建占位内容。 先创建外层结构,并在每个区块上设置
placeholder = true,然后在后续调用中逐步将占位内容替换为真实内容。
工作模式
- 先检查。 创建任何内容之前,先运行只读的
use_figma,了解文件中已有的内容——页面、组件、变量、命名约定。与现有内容保持一致。 - 构建骨架。 创建包含占位区块的顶层结构。在每个区块上设置
placeholder = true,以便用户看到进度。 - 分批填充内容,并确保可安全重试。 如果操作仍可安全重试,可以一起填充多个相关区块。完成后,将每个区块的
placeholder = false。 - 每次调用都返回 ID(规则 15)——后续调用需要使用已创建的节点、变量和集合 ID 作为输入。
- 写入后返回验证证据。 返回 ID 以及相关的数量、名称、层级或边界。仅在缺少证据或变更导致先前证据失效后,才进行单独审计。视觉检查请遵循规则 5。
- 修复后再继续。 如果验证发现问题,先修复再进行下一步。不要在有问题的基础上继续构建。
复杂任务的建议步骤顺序
Step 1: Inspect file — discover existing pages, components, variables, conventions
Step 2: Create tokens/variables (if needed)
→ return collection, variable, and mode counts
Step 3: Create individual components
→ return component IDs and relevant child/variant counts
Step 4: Compose layouts from component instances
→ return layout IDs/bounds + take a composition screenshot
Step 5: Apply a targeted visual fix only if needed
→ take one post-fix screenshot; this is final
Step 6: Stop if nothing relevant changed
每个步骤中需要验证的内容
| 完成操作后…… | 使用 get_metadata 检查 | 使用 get_screenshot 检查 |
|---|---|---|
| 创建变量 | 集合数量、变量数量、模式名称 | — |
| 创建组件 | 子节点数量、变体名称、属性定义 | 变体可见且未折叠,网格清晰可读 |
| 绑定变量 | 节点属性反映绑定情况 | 颜色/令牌正确解析 |
| 组合布局 | 实例节点具有 mainComponent,层级正确 | 没有裁切或截断的文本、没有重叠元素、间距正确 |
7. 错误恢复与自我纠正
任何 use_figma 调用出错时,都要遵守 safeToRetryWithoutCanvasRead(规则 14):值为 true → 修正已识别的错误并重试,不要额外读取画布进行诊断;值为 false → 读取画布,确定发生了什么变化,然后再进行修改。如果同一个 API 或属性错误出现两次,先检查其定义并修复根本原因,然后再重试;不要围绕同一个无效变更继续拆分操作。修复方法已列入关键规则的错误,应在相应规则中诊断——"not implemented"(figma.notify,规则 3)、layoutSizing* 的 HUG/FILL 拒绝(规则 12、12b)、"Setting figma.currentPage is not supported"(规则 9)、变体上的 componentPropertyDefinitions(规则 18),以及错误节点类型上的 characters/description(规则 3a、3b)。下表列出契约未涵盖的故障:
| 错误消息 | 可能原因 | 修复方法 |
|---|---|---|
| Property value out of range | 颜色通道 > 1(误用 0–255,而不是 0–1) | 除以 255 |
"Cannot read properties of null" | 节点不存在(ID 错误、页面错误) | 检查页面上下文并验证 ID |
| 脚本挂起 / 无响应 | 无限循环或未解决的 Promise | 检查是否有 while(true) 或缺少 await;确保代码能够结束 |
"The node with id X does not exist" | 父实例被子级 detachInstance() 隐式分离,导致 ID 发生变化 | 从稳定的(非实例)父级框架开始遍历,重新发现节点 |
脚本成功但结果看起来不对时
调用 get_metadata 检查结构是否正确(层级、数量、位置),并调用 get_screenshot 检查视觉效果是否正确——仔细查看是否有文字被裁切或截断(行高导致内容被切掉),以及元素是否重叠;这些问题很常见,也很容易被忽略。先确认差异属于结构问题还是视觉问题,再编写有针对性的修复脚本,只修改有问题的部分——不要全部重建。
完整的验证工作流请参阅 验证与错误恢复。
8. 提交前检查清单
提交任何 use_figma 调用前,都要根据 第 1 节中的操作契约重新检查脚本。过去在此处列出的所有检查项现在都归在该节中——违反其中任意一项的脚本都尚未准备好提交:
- 输出 — 使用
return(而不是figma.closePlugin()),不封装在异步 IIFE 中,不使用console.log()作为输出;return结构化数据,包含所有已创建/已修改节点的 ID(规则 1、2、4、15) - 颜色与填充 — 范围为 0–1;绘制对象的
color仅包含{r, g, b}(不含a);将填充/描边重新赋值为新数组(规则 6、7) - 类型收窄 — 访问
characters、description和componentPropertyDefinitions前,先进行保护检查/类型收窄(规则 3a、3b、18) - 页面 — 切换页面时使用
await figma.setCurrentPageAsync(page),每次调用最多一次(规则 9) - 布局与尺寸 — 相关子节点放在
figma.createAutoLayout()中;顶层节点的位置远离 (0,0);appendChild后设置HUG/FILL;设置尺寸模式前先调用resize();换行文本使用textAutoResize='HEIGHT'+ 固定宽度(规则 12、12a、12b、12c、13) - 文本 — 使用规范的字体设置流程,并通过
listAvailableFontsAsync()验证样式名称;lineHeight/letterSpacing使用{unit, value};FONT_FAMILY变量须先加载每种模式的值(规则 8) - 异步与状态 — 对每个 Promise 使用
await;将多步骤操作中的 ID 作为字符串字面量传递(规则 15、17)
9. 创建前先了解约定
创建任何内容前,务必检查 Figma 文件。 不同文件使用的命名约定、变量结构和组件模式各不相同。代码应遵循文件中已有的约定,而不是强加新的约定。
如果对任何约定(命名、作用域、结构)有疑问,先检查 Figma 文件,再检查用户的代码库。只有两者都没有相关约定时,才采用通用模式。
快速检查脚本
列出所有页面和顶层节点:
const pages = figma.root.children.map(p => `${p.name} id=${p.id} children=${p.children.length}`);
return pages.join('\n');
列出所有页面中的现有组件:
search_design_system 适用于已发布的组件。对于画布上的组件,请使用两步扇出方式——不要在一个脚本中循环遍历页面。
第 1 步:运行一次只读的 use_figma,获取页面 ID:
return figma.root.children.map(p => ({ id: p.id, name: p.name }));
第 2 步:在下一轮助手回复中,并行针对每个页面各发出一次 use_figma(在一条消息中包含 N 个工具调用块)。每次运行:
const page = await figma.getNodeByIdAsync(PAGE_ID);
await figma.setCurrentPageAsync(page);
// findAllWithCriteria uses an indexed type lookup — hundreds of times faster
// than the findAll(n => n.type === '…') side-effect-in-predicate antipattern.
const matches = page.findAllWithCriteria({ types: ['COMPONENT', 'COMPONENT_SET'] });
return matches.map(n => ({ page: page.name, name: n.name, type: n.type, id: n.id }));
列出现有变量集合及其约定:
const collections = await figma.variables.getLocalVariableCollectionsAsync();
const results = collections.map(c => ({
name: c.name, id: c.id,
varCount: c.variableIds.length,
modes: c.modes.map(m => m.name)
}));
return results;
10. 参考文档
根据任务需要加载以下文档:
| 文档 | 加载时机 | 内容 |
|---|---|---|
| gotchas.md | 调用任何 use_figma 之前 | 所有已知陷阱及其错误/正确代码示例——从规范的文本编辑流程开始 |
| common-patterns.md | 需要可运行的代码示例时 | 脚本框架:形状、文本、自动布局、变量、组件、多步工作流 |
| plugin-api-patterns.md | 创建/编辑节点时 | 填充、描边、自动布局、效果、分组、克隆、样式 |
| api-reference.md | 需要精确的 API 范围时 | 节点创建、变量 API、核心属性、支持和不支持的功能 |
| validation-and-recovery.md | 执行多步写入或恢复错误时 | get_metadata 与 get_screenshot 工作流、强制错误恢复步骤 |
| component-patterns.md | 创建组件/变体时 | combineAsVariants、组件属性、INSTANCE_SWAP、变体布局、查找现有组件、元数据遍历 |
| variable-patterns.md | 创建/绑定变量时 | 集合、模式、作用域、别名、绑定模式、查找现有变量 |
| text-style-patterns.md | 创建/应用文本样式时 | 字号阶梯、通过 listAvailableFontsAsync 查找字体、列出样式、将样式应用到节点 |
| effect-style-patterns.md | 创建/应用效果样式时 | 投影、列出样式、将样式应用到节点 |
| plugin-api-standalone.index.md | 需要了解完整 API 范围时 | Plugin API 中所有类型、方法和属性的索引 |
| plugin-api-standalone.d.ts | 需要精确的类型签名时 | 完整类型定义文件——搜索特定符号,不要一次性加载全部内容 |
11. 代码片段示例
你会在本文档中看到各种代码片段。这些片段包含有用的 Plugin API 代码,可以重新利用。可以直接使用,也可以在需要时以此为基础编写代码。如果有适合以通用代码片段形式记录的关键概念,请指出并写入磁盘,以便日后重复使用。