figma-spec

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Work with a Figma spec

使用 Figma spec

You MUST always call
whoami
before using any
figma.spec.*
API and confirm that the target file’s plan (or the destination plan for a new file) has
specs_enabled: true
.
whoami
does not identify which plan owns a file. If the plan is unclear, you MUST ask the user; never infer it from the file key or another plan’s access. If
specs_enabled
is false or absent for that plan, explain that Specs is unavailable and stop the workflow.
A native Figma spec is GitHub-Flavored Markdown (GFM) under a
SPEC_BLOCK
node. A standalone Figma spec is just one spec; a FigJam or Design file can contain several embedded specs.
在调用任何
figma.spec.*
API 前,必须始终调用
whoami
,并确认目标文件的套餐(或新文件的目标套餐)具有
specs_enabled: true
。
whoami
无法识别哪个套餐拥有某个文件。如果套餐不明确,必须询问用户;绝不能根据 file key 或其他套餐的访问权限进行推断。如果该套餐的
specs_enabled
为 false 或不存在,请说明 Specs 不可用并停止工作流。
原生 Figma spec 是位于
SPEC_BLOCK
节点下的 GitHub-Flavored Markdown(GFM)。独立的 Figma spec 只包含一个 spec;FigJam 或 Design 文件可以包含多个嵌入式 spec。

Discover and choose the Figma spec

发现并选择 Figma spec

Resolve a supplied URL
node-id
when present with
figma.getNodeByIdAsync
and require
type === "SPEC_BLOCK"
plus
specBlockType === "DOCUMENT"
. Otherwise, search the current page with
findAllWithCriteria({ types: ['SPEC_BLOCK'] })
, filtering for
specBlockType === "DOCUMENT"
(and examine content with
figma.spec.getContent
if needed) until you find your target. If it's not on the current page, load other pages one at a time with
page.loadAsync()
and repeat your query, stopping once the target is resolved.
Pass the resolved root ID to every content call. Omit
specNodeId
only when the file is known to contain exactly one Figma spec; omission throws otherwise. Never edit ordinary canvas text nodes as a fallback.
如果提供的 URL 中包含
node-id
,请使用
figma.getNodeByIdAsync
解析该节点,并要求
type === "SPEC_BLOCK"
且
specBlockType === "DOCUMENT"
。否则,使用
findAllWithCriteria({ types: ['SPEC_BLOCK'] })
搜索当前页面,并筛选
specBlockType === "DOCUMENT"
的节点(必要时可通过
figma.spec.getContent
检查内容),直到找到目标。如果当前页面中不存在目标,请使用
page.loadAsync()
逐个加载其他页面并重复查询,找到目标后立即停止。
每次调用内容 API 时,都要传入解析后的根节点 ID。仅当已知文件中恰好包含一个 Figma spec 时,才可以省略
specNodeId
;否则省略会抛出异常。绝不能通过编辑普通画布文本节点来代替操作。

Create a Figma spec on a canvas

在画布上创建 Figma spec

js
// 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')
}
Always pass a non-empty
title
and a
content
string (
''
is allowed).
title
names the root; include any desired
# H1
in
content
.
js
// 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
中。

Content methods

内容方法

js
// 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')
}
  • Use
    getContent
    with the same
    specNodeId
    before edits and to verify writes; DON'T rely on screenshots.
  • Default to multiplayer-safe, surgical
    editContent
    .
  • Use destructive
    setContent
    only for an empty first draft or an explicit whole-document replacement.
js
// 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
    。

Critical rules

关键规则

  1. editContent
    requires exactly one match.
    Zero or multiple
    oldText
    matches fail without changes. Add surrounding context to make it unique.
  2. Pass Markdown as plain strings. Never encode it with
    Buffer
    /base64 or decode it with
    atob()
    . Base64 is only for image data URLs inside Markdown.
  3. Keep Markdown and traversal separate.
    figma.spec.*
    handles content; node traversal exposes only document roots and embedded-canvas branches.
  4. Preserve comment markers. Keep overlapping
    [comment:<uuid>]…[/comment:<uuid>]
    pairs unchanged around the same text, or the thread may detach or disappear. When in doubt copy the marked span exactly and edit around it.
  5. Use portable references. Shared Figma specs must use links such as GitHub permalinks, never machine-local paths or
    localhost
    URLs.
  1. editContent
    要求仅匹配一次。
    如果
    oldText
    没有匹配项或存在多个匹配项,操作将失败且不会进行更改。请添加上下文以确保匹配项唯一。
  2. 以纯字符串形式传入 Markdown。 绝不要使用
    Buffer
    /base64 进行编码,也不要使用
    atob()
    进行解码。Base64 仅可用于 Markdown 内的图片 data URL。
  3. 将 Markdown 与节点遍历分开。
    figma.spec.*
    负责处理内容;节点遍历仅用于公开文档根节点和嵌入式画布分支。
  4. 保留评论标记。 保持相互重叠的
    [comment:<uuid>]…[/comment:<uuid>]
    标记对及其对应文本不变,否则评论线程可能会分离或消失。如果不确定,请精确复制带标记的内容片段,并在其外部进行编辑。
  5. 使用可移植引用。 共享的 Figma spec 必须使用 GitHub 永久链接等引用,绝不能使用机器本地路径或
    localhost
    URL。

Style

样式

  • Keep the title block first and formatted as H1, even when its text is empty. Never remove it or insert blocks before it.
  • Prefer bold text in table header row.
  • Use
    <ins>
    for underline, including combined formatting:
    <ins>**bold and underlined**</ins>
    . Do not use
    <u>
    , which only works in HTML imports.
  • 即使标题文本为空,也要将标题块放在最前面并设置为 H1 格式。绝不能删除标题块,也不能在其前面插入其他块。
  • 表头行优先使用粗体文本。
  • 使用
    <ins>
    表示下划线,包括组合格式:
    <ins>**bold and underlined**</ins>
    。不要使用
    <u>
    ,因为它仅适用于 HTML 导入。

Images

图片

Images use GFM image syntax inside
setContent
or
editContent
:
  • ![alt](data:image/png;base64,...)
    embeds bytes that are decoded and uploaded.
  • ![alt](https://host/img.png)
    is fetched server-side; disallowed hosts are rejected.
getContent
emits image URLs as
https://<host>/spec/<fileKey>/image/<sha>?w=<width>&h=<height>
.
在
setContent
或
editContent
中使用 GFM 图片语法:
  • ![alt](data:image/png;base64,...)
    会嵌入经过解码并上传的字节。
  • ![alt](https://host/img.png)
    会在服务器端获取;不允许的主机会被拒绝。
getContent
输出的图片 URL 格式为
https://<host>/spec/<fileKey>/image/<sha>?w=<width>&h=<height>
。

Comments

评论

Use
figma.spec.comments.*
for anchored threads. Prefer comments over leaving silent edits when you're unsure of a change.
js
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
    must match exactly once in the rendered Figma spec. Use a longer
    contextText
    containing it to disambiguate repeated text.
  • getThread
    and
    reply
    require the root comment UUID surfaced by a
    [comment:<uuid>]
    marker; never pass a reply UUID to
    reply
    .
使用
figma.spec.comments.*
创建带锚点的评论线程。如果不确定某项更改是否合适,应优先添加评论,而不是进行未说明的静默编辑。
js
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 spec 中的文本完全匹配且仅出现一次。使用包含
    anchorText
    的更长
    contextText
    来消除重复文本造成的歧义。
  • getThread
    和
    reply
    需要使用由
    [comment:<uuid>]
    标记公开的根评论 UUID;绝不能将回复 UUID 传给
    reply
    。