用途
figma-spec 用于在 Figma 中创建、读取、编辑、评审或评论 Figma 规范。当需要处理 PRD、brief、RFC 或任何类似文档时,要求读取本技能。
原生 Figma 规范是位于 SPEC_BLOCK 节点下的 GitHub-Flavored Markdown(GFM)。独立的 Figma 规范就是一个规范;FigJam 或 Design 文件可以包含多个嵌入式规范。
使用前提与方案检查
在使用任何 figma.spec.* API 之前,必须先调用 whoami,并确认目标文件所在的方案(或新文件的目标方案)具有 specs_enabled: true。whoami 不会标识某个文件属于哪个方案。如果方案不明确,必须询问用户,绝不能从文件 key 或另一个方案的访问权限中推断。如果该方案的 specs_enabled 为 false 或缺失,应说明 Specs 不可用并停止工作流。
发现与选择 Figma 规范
当提供了 URL 中的 node-id 时,使用 figma.getNodeByIdAsync 解析,并要求 type === "SPEC_BLOCK" 且 specBlockType === "DOCUMENT"。否则,使用 findAllWithCriteria({ types: ['SPEC_BLOCK'] }) 搜索当前页面,过滤 specBlockType === "DOCUMENT"(必要时可用 figma.spec.getContent 检查内容),直到找到目标。如果目标不在当前页面,则使用 page.loadAsync() 一次加载一个其他页面并重复查询,找到目标后停止。
将解析出的根 ID 传递给每次内容调用。只有在已知文件恰好包含一个 Figma 规范时才能省略 specNodeId;否则省略会抛错。绝不能把普通画布文本节点作为后备来编辑。
在画布上创建 Figma 规范
以下代码在 Design 或 FigJam 画布上创建嵌入式 Figma 规范(不是独立的 Figma 规范文件):
const { specNodeId } = await figma.spec.createOnCanvasAsync({
title: 'Untitled spec',
content: '# Title\n\nA paragraph.\n',
})
const specNode = await figma.getNodeByIdAsync(specNodeId)
if (!specNode) throw new Error('The created Figma spec could not be resolved')
const after = await figma.spec.getContent({ specNodeId })
if (!after.markdown.includes('A paragraph.')) {
throw new Error('The new Figma spec content was not applied')
}
始终传入非空 title 和 content 字符串(允许 '')。title 命名根节点;在 content 中可包含所需的 # H1。
内容方法
读取:返回 specNodeId、markdown、title 等。正文是 markdown,不是 content。
const before = await figma.spec.getContent({ specNodeId: chosenSpec.id })
const page = await figma.spec.getContent({
specNodeId: before.specNodeId,
offset: 100,
maxLines: 50,
})
替换:清除并重建文档;仅用于空白的初稿。
await figma.spec.setContent({
specNodeId: before.specNodeId,
content: '# Title\n\nA paragraph.\n',
})
编辑:查找/替换;每个 oldText 必须恰好匹配一次。
await figma.spec.editContent({
specNodeId: before.specNodeId,
edits: [{ oldText: 'First paragraph.', newText: 'Edited first paragraph.' }],
})
const after = await figma.spec.getContent({ specNodeId: before.specNodeId })
if (!after.markdown.includes('Edited first paragraph.')) {
throw new Error('The targeted Figma spec edit was not applied')
}
编辑前和验证写入时,对同一 specNodeId 使用 getContent;不要依赖截图。默认使用多人在线安全、精确的 editContent 局部编辑。仅在空白初稿或明确整文替换时使用破坏性的 setContent。
关键规则
editContent 要求恰好一次匹配。oldText 匹配零次或多次都会失败且不做更改。添加周围上下文使其唯一。
Markdown 以纯字符串传递。绝不能用 Buffer/base64 编码,也不能用 atob() 解码。Base64 仅用于 Markdown 中的图片 data URL。
保持 Markdown 与遍历分离。figma.spec.* 处理内容;节点遍历只暴露文档根和嵌入式画布分支。
保留评论标记。围绕相同文本保持重叠的 [comment:<uuid>]…[/comment:<uuid>] 对不变,否则线程可能脱离或消失。拿不准时,原样复制标记的文本范围并围绕它编辑。
使用可移植引用。共享的 Figma 规范必须使用 GitHub 永久链接等链接,绝不能使用机器本地路径或 localhost URL。
样式
保持标题块在最前并格式化为 H1,即使其文本为空。绝不删除它或在它之前插入块。表头行中建议使用粗体文本。下划线使用 <ins>,包括组合格式:<ins>bold and underlined</ins>。不要使用 <u>,它只在 HTML 导入中有效。
图片
图片在 setContent 或 editContent 中使用 GFM 图片语法:
 嵌入字节,会被解码并上传。
 由服务端抓取;不允许的主机会被拒绝。
getContent 输出的图片 URL 形如 https://<host>/spec/<fileKey>/image/<sha>?w=<width>&h=<height>。
评论
对锚定线程使用 figma.spec.comments.*。当不确定某项更改时,优先使用评论而不是留下静默编辑。
const comment = await figma.spec.comments.create({
specNodeId: before.specNodeId,
anchorText: 'the exact rendered text to anchor to', // 必须恰好出现一次
contextText: 'a longer unique substring containing anchorText', // 可选;用于区分重复文本
message: 'Comment body (markdown).',
})
const { root, replies, hasMore } = await figma.spec.comments.getThread({ uuid: comment.uuid })
await figma.spec.comments.reply({ uuid: comment.uuid, message: 'A reply.' })
anchorText 必须在渲染后的 Figma 规范中恰好匹配一次。使用包含它的更长 contextText 来区分重复文本。getThread 和 reply 需要由 [comment:<uuid>] 标记暴露的根评论 UUID;绝不能把回复 UUID 传给 reply。
适用场景与限制
适用于在 Figma 中处理 PRD、brief、RFC 等规范类文档的创建、读取、编辑、评审与评论场景,尤其适合需要多人在线协作、保持评论线程锚定的情况。限制包括:必须先调用 whoami 并确认方案的 specs_enabled 为 true,否则需询问用户或停止;editContent 要求每个 oldText 恰好唯一匹配;省略 specNodeId 仅在文件恰好包含一个规范时可行,否则抛错;不能把普通画布文本节点当作后备编辑对象;共享规范必须使用可移植链接;下划线只能用 <ins> 而非 <u>;图片仅支持 data URL 或服务端可抓取的主机。关于该技能的具体收费、价格、支持平台、性能效果等信息,资料暂未提供。