首页
/ Novu 仓库 figma-use 技能详解:Agent 如何借助 use_figma 工具与 Figma Plugin API 完成程序化设计

Novu 仓库 figma-use 技能详解:Agent 如何借助 use_figma 工具与 Figma Plugin API 完成程序化设计

2026-09-08 11:42:07作者:秋阔奎Evelyn

本文基于 Novu 开源仓库 .agents/skills/figma-use/SKILL.md 编写。该技能文件是为 AI Agent 准备的「强制前置」规范:任何使用 use_figma 工具在 Figma 文件中执行 JavaScript 之前,都必须先加载它,以规避字体加载、页面切换、Auto Layout 顺序等一系列难以排查的失败模式。读完本文,你将掌握 use_figma 的执行模型、17 条关键 API 使用规则、query/set/createAutoLayout 等高效 API、增量式设计工作流、错误恢复机制与提交前自查清单,能够安全、可复用地让 Agent 在 Figma 中创建、编辑、校验设计产物。

1. 技能定位:为什么它是 use_figma 的强制前置

Novu 仓库在 .agents/skills/ 目录下随源码附带了面向 AI Agent 的一组开发技能(同目录还包括 frontend-designreact-emailemail-best-practices 等)。其中 figma-use 技能的目标非常明确:规范 Agent 通过 use_figma 工具调用 Figma Plugin API,在 Figma 文件上下文中以代码方式执行「写操作或需要 JavaScript 的独特只读操作」——例如创建/编辑/删除节点、建立 variables 与 tokens、构建组件与变体、修改 Auto Layout 或填充、把变量绑定到属性、以编程方式检查文件结构等。

技能文件的 YAML frontmatter 中,description 字段明确将其标注为 MANDATORY prerequisite(强制前置条件):在每一次 use_figma 调用之前都必须先加载该技能,跳过它会导致常见且难以调试的失败。因此它设计的 disable-model-invocation: false,意味着模型可以在任务进行中主动加载这份技能,而不是仅在对话开头被动触发一次。

技能还规定了两条与工具链协作的基本约定:

  • 调用 use_figma 时必须始终传入 skillNames: "figma-use"。这是一个用于记录技能使用情况的日志参数,不影响执行结果。
  • 如果 Figma MCP 工具是以 deferred(延迟加载) 形式出现,应在一次 ToolSearch 调用中批量加载全部 schema,例如使用 select: 语法:ToolSearch query="select:use_figma,get_screenshot,get_metadata,create_new_file"。一次往返远胜六次逐个加载。

在加载技能之后、动手写任何插件 API 代码之前,技能要求先浏览 references/plugin-api-standalone.index.md 了解能力全貌;需要具体类型签名时,对 references/plugin-api-standalone.d.ts 使用 grep 按需检索,而不是一次性全量加载。与设计系统相关的工作(components、variables、text styles、effect styles)则应当从 references/working-with-design-systems/wwds.md 入手。

2. 理解 use_figma 的执行模型

在深入规则前,必须理解 use_figma 与「交互式 Figma 插件」的本质差异。技能文档反复强调一个核心事实:Agent 只能看到代码 return 出去的值,其余一切输出对它不可见。这种沙箱式执行模型决定了代码的组织方式。

技能第 1 节给出 17 条关键规则,可归纳为「运行形态、数据通道、画布操作、失败处理」四组:

2.1 运行形态:顶层 await + return

  1. return 把数据送回给 Agent。 返回值会被自动 JSON 序列化(对象、数组、字符串、数字)。不要调用 figma.closePlugin(),也不要包一层 async IIFE——这些都由执行环境代为处理。
  2. 写普通 JavaScript,允许顶层 awaitreturn 代码会被自动包裹进 async 上下文,无需手工写 (async () => { ... })()
  3. console.log() 不会出现在返回结果中,输出必须走 return
  4. await 每一个 Promise。 被遗忘 await 的异步调用(例如裸写的 figma.loadFontAsync(...)figma.setCurrentPageAsync(page))会变成 fire-and-forget,导致静默失败或竞态:脚本可能在异步操作完成前就返回,产生数据缺失或半应用的修改。

2.2 数据通道:禁用 notify,避开 pluginData

  1. figma.notify() 会抛出 "not implemented",永远不要使用它。 3a. getPluginData() / setPluginData()use_figma 中不受支持,请改用 getSharedPluginData() / setSharedPluginData()(这两个受支持),或者通过 return 节点 ID 并在后续调用中继续跟踪:
// WRONG — not supported in use_figma
node.setPluginData('my_key', 'my_value')

// CORRECT — use shared plugin data (requires a namespace)
node.setSharedPluginData('my_namespace', 'my_key', 'my_value')

// ALSO CORRECT — return node IDs and track them across calls
const rect = figma.createRectangle()
return { nodeId: rect.id }
// 下一次 use_figma 调用中以字符串字面量传入 nodeId

2.3 画布操作:从颜色到布局的类型纪律

  1. 增量、小步工作。 把大操作拆成多次 use_figma 调用,每步都校验。这是避免 bug 最重要的一条实践。
  2. 颜色取值区间是 0–1(不是 0–255){r: 1, g: 0, b: 0} 即红色。{r: 255, g: 0, b: 0} 会触发 ZeroToOne 校验错误。
  3. fills/strokes 是只读数组:不能原地 node.fills[0].color = ...,必须「克隆 → 修改 → 重新赋值」。且 paint 的 color 只接受 {r, g, b},透明应放在 paint 层级的 opacity,写成 { type: 'SOLID', color: {...}, opacity: 0.5 }
  4. 字体必须先加载。不仅是设置文本时才需要——只要节点包含未加载字体,appendChildinsertChildsetBoundVariablesetExplicitVariableModeForCollectionsetValueForMode 乃至 findAll 回调都会失败。建议脚本开头用 await figma.listAvailableFontsAsync() 发现可用字体与样式,再逐个 await figma.loadFontAsync({ family, style }) 加载。
  5. 页面是增量加载的:用 await figma.setCurrentPageAsync(page) 切换页面并加载其内容;同步 setter figma.currentPage = page 会抛错(详见第 3 节)。
  6. setBoundVariableForPaint 会返回一个「新」paint,必须捕获并重新赋值,直接使用原 paint 对象是无效的。
  7. createVariable 接受 collection 对象或 ID 字符串,优先传对象。
  8. layoutSizingHorizontal/Vertical = 'FILL' 必须在 parent.appendChild(child) 之后设置——先设置再 append 会抛错;非 auto-layout 节点设置 'HUG' 同理。
  9. 新创建的顶层节点默认落在 (0,0),直接 append 到 page 会与既有内容重叠。应先扫描 figma.currentPage.children,把新节点放到最右侧节点右侧等空白处(仅对 page 直属节点有意义;嵌套在 frame/auto-layout 里的子节点由父级定位)。
  10. 创建变量时必须显式设置 variable.scopes。默认的 ALL_SCOPES 会让变量出现在每一个属性选择器里,几乎从来不是你想要的。例如背景色用 ["FRAME_FILL", "SHAPE_FILL"]、文本色用 ["TEXT_FILL"]、间距用 ["GAP"],完整的取值清单见 references/variable-patterns.md

2.4 失败处理与产物追踪

  1. use_figma 报错时立即停下,不要马上重试。 失败的脚本是原子性的——脚本一旦出错就完全不会执行,文件不会被改动。仔细阅读错误信息、修正脚本后再重试(详见第 7 节)。
  2. 必须 return 全部创建/变更的节点 ID。 凡是创建了新节点或改动了画布上既有节点的脚本,都要把受影响的 ID 收集进结构化对象(如 return { createdNodeIds: [...], mutatedNodeIds: [...] }),供后续调用引用、校验或清理。

每一条规则的 WRONG/CORRECT 对照示例都收录在 references/gotchas.md 中,该文件是 use_figma 场景下最值得先读的避坑清单。

3. 页面规则:跨调用状态管理与页面切换

use_figma 的页面上下文有两条硬性规则:

  1. 每次调用之间页面上下文会重置——每次调用开始时 figma.currentPage 都停在第一个页面。
  2. 同步 setter 不可用。figma.currentPage = page 会抛出 "Setting figma.currentPage is not supported" figma.currentPage 是安全的,只有赋值会抛错;切换页面必须使用 await figma.setCurrentPageAsync(page)
// Switch to a specific page (loads its content)
const targetPage = figma.root.children.find((p) => p.name === "My Page");
await figma.setCurrentPageAsync(targetPage);
// targetPage.children is now populated

// Iterate over all pages
for (const page of figma.root.children) {
  await figma.setCurrentPageAsync(page);
  // page.children is now loaded — read or modify them here
}

由于每次调用都从第一页开始,跨多步工作流如果要操作非默认页面,必须在每次调用开头执行 await figma.setCurrentPageAsync(page)。反过来也可以利用这一特性:多次调用 use_figma 在文件状态上增量构建,或先写一段只读脚本获取既有节点的元数据并 return,再在下一个脚本里利用这些数据去修改节点。

页面上下文还影响排查方式:icons、variables、components 可能位于第一页以外的页面,get_metadata 只返回你所传节点的子树;因此技能建议用不带 nodeIdget_metadata 以最廉价方式列出文档顶层页面({guid, name}),需要更多细节(子节点数、顶层节点类型)时再退回 use_figma 脚本枚举:

const pages = figma.root.children.map(p => `${p.name} id=${p.id} children=${p.children.length}`);
return pages.join('\n');

4. return 是唯一的输出通道

技能的第三条总原则可以单独成节,因为它是整个开发循环的支点:Agent 只能看到你 return 的值,其余一切都是不可见的。

  • 返回 ID(关键):每个创建或变更画布节点的脚本都必须返回全部受影响节点 ID,这是硬性要求而非可选。推荐结构:
return { createdNodeIds: [...], mutatedNodeIds: [...] }
  • 进度汇报:多步任务中每步都带可执行信息,例如 return { createdNodeIds: [...], count: 5, errors: [] }
  • 错误信息:抛出的错误会被自动捕获并返回——让异常自然传播或显式 throw 即可,无需自行捕获后格式化。
  • console.log() 的输出永远不会回到 Agent 手里。
  • 总是返回可执行的数据(ID、计数、状态),让后续调用能引用已创建的对象。

「返回 ID」与「脚本原子性」两条规则共同支撑起安全的多步设计循环:前一步失败文件不变,前一步成功则返回 ID 作为下一步的输入字面量。

5. 编辑器模式:design / FigJam / Slides 的节点差异

use_figma 默认工作在 design 模式editorType: "figma")。FigJam("figjam")与 Slides("slides")拥有不同的可用节点集合:design 的大部分节点类型在 FigJam 中被封锁,而 FigJam 专属节点在 Slides 中也被封锁。

Design 模式(默认)

类别 节点类型
可用 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
被封锁 Sticky, Connector, ShapeWithText, CodeBlock, Webpage, Page

几点补充:

  • Slides 文件目前没有独立的读取工具,需要用 use_figma 的只读脚本做检查(即第 6 节 "Inspect first" 模式),并用 get_screenshotawait node.screenshot() 获取视觉上下文。
  • 涉及 Slides 专属 API 的指导,原技能约定另行加载 figma-use-slides 技能(该技能不在当前 Novu 仓库快照中)。

6. 高效 API:优先于啰嗦的等价写法

use_figma 环境提供了一批能显著减少样板代码、消除排序错误并压缩 token 输出的 API。技能明确规定:总是优先使用它们,而不是冗长的传统写法

6.1 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]')

选择器语法一览:

  • 类型FRAMETEXTRECTANGLEELLIPSECOMPONENTINSTANCESECTION(大小写不敏感);
  • 属性精确匹配[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() 最后一个匹配节点
.toArray() 转为普通数组
.each(fn) 带回调迭代,返回 this 以支持链式调用
.map(fn) 映射为新数组
.filter(fn) 过滤为新 QueryResult
.values(keys) 抽取属性值:.values(['name', 'x', 'y'])[{name, x, y}, ...]
.set(props) 给所有匹配节点批量设属性(见 6.2)
.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]')

6.2 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之前被应用。这规避了经典的顺序 bug——过去 resize() 的行为会随 layoutMode 是否已设置而不同。
  • 宽高处理widthheight 会被自动路由到 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
})

6.3 figma.createAutoLayout(direction?, props?):即开即用的自动布局容器

创建已启用 Auto Layout、两条轴都 HUG 内容的 frame。任何需要 Auto Layout 的容器都应优先用它,而不是 figma.createFrame()

// 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')

子节点被 append 之后可以立即使用 layoutSizingHorizontal/Vertical = 'FILL',无需手工设置 sizing mode。它还接受可选的 props 对象作为第一个或第二个参数:

figma.createAutoLayout({ name: 'Card', itemSpacing: 12 })               // HORIZONTAL + props
figma.createAutoLayout('VERTICAL', { name: 'Column', itemSpacing: 8 })  // VERTICAL + props

6.4 node.placeholder:进行中的 shimmer 反馈

给节点设置一层视觉 shimmer 叠加,用于向用户表达「正在处理中」。完成后必须移除——残留的 shimmer 会让用户误以为工作尚未结束:

// Mark as in-progress
frame.placeholder = true

// ... build out the content ...

// MUST remove when done — never leave shimmers on finished nodes
frame.placeholder = false

构建复杂版式时推荐做法是:填充各 section 之前先 placeholder = true,每个 section 完成后立即置回 false

6.5 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 })
  • 何时用:创建或修改节点后,在同一脚本内用 screenshot() 做视觉验证,不必再单独调 get_screenshot
  • 自动命名:图片标题携带节点元数据——"Card (300x150 at 0,60).png"——不需要解析图片就能获得空间上下文。
  • 默认缩放:默认 0.5x,并自动封顶使最长边不超过 1024px;显式传入 { scale: N } 则绕过封顶。

7. 增量式工作流:如何从根本上避免 bug

技能文档直言:bug 最常见的成因就是试图在一次 use_figma 调用里做得太多。正确的姿势是小步推进、逐步校验。

关键规则

  • 每次 use_figma 调用最多 10 个逻辑操作。 一个「逻辑操作」指创建节点、设置属性并将其挂到父级之下。要建 20 个节点,就拆成 2~3 次调用。
  • 自顶向下构建,先用占位符。 先用 placeholder = true 标记各 section 建出外层结构,再在后续调用中用真实内容逐段替换占位符。

标准模式(6 步)

  1. 先检查(Inspect first)。 创建任何东西之前,先跑一段只读 use_figma,弄清文件里已有哪些页面、组件、变量与命名约定,让新代码匹配现状。
  2. 搭骨架。 用带 placeholder section 的结构建出顶层骨架,每个 section 都置 placeholder = true,让用户看到进度。
  3. 逐段填充。 每次后续调用填充一个 section,完成后置 placeholder = false,并用 screenshot() 验证。
  4. 每次调用都返回 ID。 始终以对象形式 return 创建的节点 ID、变量 ID、collection ID(如 return { createdNodeIds: [...] }),它们是后续调用的输入。
  5. 每步后校验。get_metadata 验证结构(数量、名称、层级、位置);在关键节点之后用内联 await node.screenshot()get_screenshot 捕捉视觉问题。
  6. 先修复再继续。 校验发现问题就当场修复,绝不要在坏地基上继续搭建。

复杂任务的推荐步骤顺序

Step 1: Inspect file — discover existing pages, components, variables, conventions
Step 2: Create tokens/variables (if needed)
       → validate with get_metadata
Step 3: Create individual components
       → validate with get_metadata + get_screenshot
Step 4: Compose layouts from component instances
       → validate with get_screenshot
Step 5: Final verification

每步该校验什么

步骤之后 get_metadata get_screenshot
创建变量 collection 数量、变量数量、mode 名称
创建组件 子节点数量、variant 名称、属性定义 变体可见、未被折叠、网格可读
绑定变量 节点属性反映绑定关系 颜色/token 正确解析
拼装版式 实例节点具备 mainComponent、层级正确 无文字裁切/遮挡、无元素重叠、间距正确

更完整的校验与恢复流程见 references/validation-and-recovery.md

8. 错误恢复与自纠错:善用脚本的原子性

use_figma 是原子性的——失败的脚本不会执行。 一旦脚本出错,文件完全保持调用前的状态:没有半成品节点、没有孤儿元素,修正后重试是安全的。

use_figma 返回错误时:

  1. 停。 不要立即「改一改就重试」。
  2. 仔细阅读错误信息,判断根因是 API 用法错误、缺少字体还是属性值非法。
  3. 错误不明时,调用 get_metadataget_screenshot 弄清当前文件状态。
  4. 根据错误信息修正脚本。
  5. 重试修正后的脚本。

常见错误与对策速查

错误信息 可能原因 修法
"not implemented" 使用了 figma.notify() 删除它——用 return 输出
"node must be an auto-layout frame..." 在 append 到 auto-layout 父级之前设置了 FILL/HUG appendChild 移到 layoutSizingX = 'FILL' 之前
"Setting figma.currentPage is not supported" 使用了同步 setter(figma.currentPage = page 改用 await figma.setCurrentPageAsync(page)——这是切换页面的唯一方式
属性值超出范围 颜色通道大于 1(用了 0–255 而非 0–1) 除以 255
"Cannot read properties of null" 节点不存在(ID 错误、页面错误) 检查页面上下文,核对 ID
脚本挂起 / 无响应 死循环或未 resolve 的 Promise 检查 while(true) 或缺失的 await,确保代码能终止
"The node with id X does not exist" 子节点 detachInstance() 隐式 detach 了父实例并改变其 ID 从稳定的(非 instance)父 frame 出发按遍历重新发现节点

当脚本成功但结果看起来不对时:

  1. 调用 get_metadata 检查结构正确性(层级、数量、位置)。
  2. 调用 get_screenshot 检查视觉正确性——重点看文字是否被裁切/裁剪(行高切断内容)与元素是否重叠,这两类问题常见又容易被忽略。
  3. 判断差异属于结构性(层级错误、节点缺失)还是视觉性(颜色错误、布局破损、内容被裁切)。
  4. 写只针对破损部分做修改的修复脚本——不要全部重建。

上述错误表中涉及的底层坑(paint 不可变数组、setBoundVariableForPaint 返回新 paint、combineAsVariants 不自动布局、resize() 会把 sizing mode 重置回 FIXED、lineHeight/letterSpacing 必须用 {unit, value} 对象、counterAxisAlignItems 不支持 'STRETCH'、模式数量受套餐限制、变量默认 ALL_SCOPES 等)均有完整的 WRONG/CORRECT 对照,见 references/gotchas.md

9. 提交前的 Pre-Flight 自查清单

技能要求在任何一次 use_figma 调用被提交之前,逐一核对以下事项——这张清单相当于把第 2、3、4、5 节的规则浓缩成可勾选项:

  • [ ] 代码使用 return 回传数据(而不是 figma.closePlugin());
  • [ ] 代码没有包在 async IIFE 里(执行环境会自动包裹);
  • [ ] return 值包含结构化、可执行的数据(ID、计数);
  • [ ] 任何地方都没有使用 figma.notify()
  • [ ] 没有用 console.log() 作为输出(一律用 return);
  • [ ] 所有颜色使用 0–1 区间(不是 0–255);
  • [ ] paint 的 color 只含 {r, g, b},不带 a 字段(不透明度放 paint 层:{ type: 'SOLID', color: {...}, opacity: 0.5 });
  • [ ] fills/strokes 以新数组重新赋值(没有原地修改);
  • [ ] 页面切换使用 await figma.setCurrentPageAsync(page)(同步 figma.currentPage = page 不可用);
  • [ ] layoutSizingVertical/Horizontal = 'FILL'parent.appendChild(child) 之后设置;
  • [ ] 修改文本属性前已调用 loadFontAsync()(不确定字体可用性时先用 listAvailableFontsAsync() 确认);
  • [ ] 样式名称已通过 listAvailableFontsAsync() 核实——绝不凭记忆猜测("SemiBold""Semi Bold" 是常见陷阱);
  • [ ] 对 FONT_FAMILY 作用域的变量:调用 setBoundVariable("fontFamily", …)setValueForModesetExplicitVariableModeForCollection 前,相关 mode 的每个值都已加载;
  • [ ] lineHeight/letterSpacing 使用 {unit, value} 格式(不是裸数字);
  • [ ] resize() 在设置 sizing mode 之前调用(resize 会把 mode 重置为 FIXED);
  • [ ] 多步工作流中,上一步的 ID 以字符串字面量传入(而不是变量);
  • [ ] 新的顶层节点已避开 (0,0),不会与既有内容重叠;
  • [ ] 所有创建/变更的节点 ID 都已收集并包含在 return 值里;
  • [ ] 每个异步调用(loadFontAsyncsetCurrentPageAsyncimportComponentByKeyAsync 等)都被 await——没有 fire-and-forget 的 Promise。

10. 动手前先勘察约定:三个即用型巡检脚本

技能强调:在创建任何东西之前,总是先检查 Figma 文件。不同文件有不同的命名约定、变量结构与组件模式,代码应匹配已有约定而不是强加新约定;当文件里没有可参考的约定时,再看向用户代码库,最后才回退到通用模式。

技能提供的三个巡检脚本可以直接复用:

列出全部页面与顶层节点:

const pages = figma.root.children.map(p => `${p.name} id=${p.id} children=${p.children.length}`);
return pages.join('\n');

跨页面列出既有组件:

const results = [];
for (const page of figma.root.children) {
  await figma.setCurrentPageAsync(page);
  page.findAll(n => {
    if (n.type === 'COMPONENT' || n.type === 'COMPONENT_SET')
      results.push(`[${page.name}] ${n.name} (${n.type}) id=${n.id}`);
    return false;
  });
}
return results.join('\n');

列出变量集合及其约定:

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;

11. 技能自带的可运行模式库与类型参考

snippets 贯穿整个技能文档,其下方的各参考文件本身就是可以直接复制或作为起点的代码库,也是后续深入 use_figma 编程的主入口:

参考文档 何时加载 覆盖内容
gotchas.md 任何 use_figma 调用之前 每一个已知坑,带 WRONG/CORRECT 代码示例
common-patterns.md 需要可运行代码示例 脚本骨架:图形、文本、auto-layout、变量、组件、多步工作流
plugin-api-patterns.md 创建/编辑节点 fills、strokes、Auto Layout、效果、分组、克隆、样式
api-reference.md 需要精确 API 面 节点创建、variables API、核心属性、可用与不可用项
validation-and-recovery.md 多步写入或错误恢复 get_metadataget_screenshot 工作流、强制的错误恢复步骤
component-patterns.md 创建组件/变体 combineAsVariants、组件属性、INSTANCE_SWAP、变体布局、既有组件发现、元数据遍历
variable-patterns.md 创建/绑定变量 collections、modes、scopes、alias、绑定模式、既有变量发现
text-style-patterns.md 创建/应用文本样式 字号阶梯、listAvailableFontsAsync 字体发现、样式列表、应用样式到节点
effect-style-patterns.md 创建/应用效果样式 投影、列出样式、把样式应用到节点
plugin-api-standalone.index.md 需要理解完整 API 面 Plugin API 全部类型、方法、属性的索引
plugin-api-standalone.d.ts 需要精确类型签名 完整类型声明文件——用 grep 检索具体符号,不要一次性全量加载

12. 组合使用:何时联动其它技能与参考

最后,figma-use 并不是孤立存在的。技能文档明确了两条协作路径,有助于在真实 Agent 工作流里判断「该不该现在用它」:

  • 涉及从代码构建或更新一整页/整屏/多 section 版式时,技能约定应额外加载 figma-generate-design 技能,后者提供通过 search_design_system 发现设计系统组件、导入并增量拼装屏幕的工作流。二者分工清晰:figma-use 管 Plugin API 规则,figma-generate-design 管整屏搭建流程(该技能不在当前仓库快照内,需按实际环境加载)。
  • 每次任务都先加载 figma-use 本体,再依据任务类型选择上述参考文件:写代码前 grep plugin-api-standalone.d.ts 确认 API 存在且签名正确——凡是名称「听起来像」但不在类型声明中的属性,写入时几乎必然抛错。涉及设计系统时,则从 references/working-with-design-systems/wwds.md 起步,再按需深入 components、variables、text styles、effect styles 的分册参考。

把这些规则、清单与可复用脚本组合起来,Agent 就能以「小步 → 返回 ID → 校验 → 修复」的稳定节奏,在 Figma 中完成从建立 token、搭建组件变体到拼装完整页面的一系列程序化设计工作,并把失败率与返工成本压到最低。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.74 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.81 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
595
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
920
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.63 K
1.02 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
518
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
389