关于 figma-spec
figma-spec 是用于读取、创建和编辑原生 Figma 规范文档的技能,文档采用 Markdown。它涵盖规范定位、内容安全编辑及评论标记保留。
主要功能
- 01跨页面查找规范文档
- 02读取并验证 Markdown 内容
- 03在画布中创建嵌入式规范
- 04定点修改文档内容
- 05保留评论锚点和链接
适用场景
- 01查找 Figma 文件中的嵌入式规范
- 02起草或更新规范文档
- 03修改文本而不替换整份文档
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ figma/ mcp-server-guide --skill figma-spec安装后在 Claude Code 中输入/figma-spec确认已加载。
详细介绍
使用 Figma 规格说明
在使用任何 figma.spec.* API 之前,必须始终调用 whoami,并确认目标文件所属方案(或新文件的目标方案)已启用 specs_enabled: true。whoami 无法识别文件所属的方案。如果方案不明确,必须询问用户;切勿根据文件键或其他方案的访问权限推断。如果该方案的 specs_enabled 为 false 或未设置,请说明 Specs 不可用,并停止工作流。
原生 Figma 规格说明是 SPEC_BLOCK 节点下的 GitHub 风格 Markdown(GFM)。独立的 Figma 规格说明只包含一个规格说明;FigJam 或 Design 文件可以包含多个嵌入式规格说明。
查找并选择 Figma 规格说明
如果提供的 URL 中包含 node-id,则使用 figma.getNodeByIdAsync 解析该 ID,并要求 type === "SPEC_BLOCK" 且 specBlockType === "DOCUMENT"。否则,使用 findAllWithCriteria({ types: ['SPEC_BLOCK'] }) 搜索当前页面,并筛选出 specBlockType === "DOCUMENT" 的节点(必要时使用 figma.spec.getContent 检查内容),直到找到目标。如果目标不在当前页面,则一次加载一个其他页面,使用 page.loadAsync() 并重复查询,直到找到目标。
将已解析的根 ID 传递给每次内容调用。仅当已知文件恰好包含一个 Figma 规格说明时,才省略 specNodeId;否则省略会导致错误。切勿将普通画布文本节点作为后备方案进行编辑。
在画布上创建 Figma 规格说明
// Creates an embedded Figma spec on a Design or FigJam canvas (not a standalone Figma spec file).
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 用于命名根节点;需要的 # H1 应包含在 content 中。
内容方法
// READ — returns specNodeId, markdown, title, etc.
// The body is `markdown`, not `content`.
const before = await figma.spec.getContent({ specNodeId: chosenSpec.id })
const page = await figma.spec.getContent({
specNodeId: before.specNodeId,
offset: 100,
maxLines: 50,
})
// REPLACE — clears + recreates the document; use only for an empty first draft.
await figma.spec.setContent({
specNodeId: before.specNodeId,
content: '# Title\n\nA paragraph.\n',
})
// EDIT — find/replace; each oldText must match exactly once.
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 中的图像数据 URL。 - 将 Markdown 与节点遍历分开处理。
figma.spec.*负责处理内容;节点遍历只能访问文档根节点和嵌入式画布分支。 - **保留评论标记。**保持重叠的
[comment:<uuid>]…[/comment:<uuid>]配对不变,并确保它们仍包围相同的文本;否则线程可能会脱离或消失。如有疑问,请原样复制带标记的文本段,只编辑其周围内容。 - **使用可移植的引用。**共享的 Figma 规格说明必须使用 GitHub 永久链接等链接,绝不能使用本机路径或
localhostURL。
样式
- 标题区块必须始终位于最前面,并格式化为 H1,即使其文本为空也不例外。切勿移除它,也不要在它之前插入区块。
- 表格标题行优先使用粗体文本。
- 下划线使用
<ins>,包括组合格式:<ins>**粗体并带下划线**</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', // MUST appear exactly once
contextText: 'a longer unique substring containing anchorText', // optional; disambiguates repeats
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。