Understand-Anything /understand-figma:把 Figma 设计文件变成可交互的设计知识图谱
/understand-figma 是 Understand-Anything 插件中面向设计资产的专用技能:它通过 Figma REST API 拉取设计文件,用确定性解析器抽取页面、屏幕、组件、组件集、实例与设计令牌,再借助 LLM 子代理补充语义摘要,最终合并出一份 kind:"design" 的知识图谱并挂到现有 Dashboard 上。读完全文,你将掌握该技能的四阶段流水线(Pre-flight / Fetch & Parse / Analyze / Merge & Launch)、增量扫描与缩略图刷新机制、scan-manifest.json 的数据结构,以及 mergeDesignGraph 如何生成图层(layers)与导览(tour)的源码级实现。
一、技能定位与前置条件
/understand-figma 的完整行为规范定义在 SKILL.md。与完全离线的 /understand(分析本地代码库)不同,这个技能会向 api.figma.com 发起出站请求,属于在线技能。执行前需要满足以下前置条件:
FIGMA_TOKEN环境变量:一个 Figma 个人访问令牌(personal access token),在 Figma 账号设置页面创建后通过export FIGMA_TOKEN=<token>注入。缺少该变量时,技能会终止并提示用户先配置令牌。- 运行时要求:Node ≥ 22,pnpm ≥ 10。
技能文档中还有一条明确的安全约束,值得单独强调:令牌只从环境变量读取,只出现在 X-Figma-Token 请求头中,绝不能被写入图谱、meta.json、日志或任何中间文件。这条约束在源码中得到了一致的落实——FigmaApiSource 的 get 方法将令牌固定放入请求头,注释直接写明 "Token travels only in the header — never in the URL, never logged"(令牌只走请求头,不进 URL,不打日志)。
二、Phase 0 —— 预检(Pre-flight)
预检阶段完成四件事,全部为确定性操作:
-
解析参数:从
$ARGUMENTS中取出 Figma URL 或裸文件 key(非 flag 参数),以及可选的--language <lang>参数。 -
解析数据目录
$UA_DIR:这是 Understand-Anything 的兼容层逻辑——UA_DIR="$PROJECT_ROOT/$([ -d "$PROJECT_ROOT/.understand-anything" ] && echo .understand-anything || echo .ua)"即旧版
.understand-anything/目录若已存在则优先复用以保持向后兼容,否则使用新的.ua/目录。由于每个阶段可能运行在全新的 shell 中,文档要求像$PROJECT_ROOT一样把$UA_DIR向后传递,必要时用同一行命令重新解析。脚本侧的实现与之一致,见 figma-scan.mjs 中的uaDir函数,注释也注明这是"镜像 core 的 resolveUaDir 逻辑"。 -
确保 core 已构建:解析
PLUGIN_ROOT后检查packages/core/dist/figma/index.js是否存在;缺失时执行:cd "$PLUGIN_ROOT" && (pnpm install --frozen-lockfile 2>/dev/null || pnpm install) && pnpm --filter @understand-anything/core build技能脚本正是依赖该构建产物——
figma-scan.mjs首行就从@understand-anything/core/figma导入 parseFileKey、FigmaApiSource、parseDocument、extractTokens、applyScreenThumbnails。 -
创建中间目录:
mkdir -p $UA_DIR/intermediate,后续各阶段的中间产物(manifest、分批分析结果)都落在这里。
三、Phase 1 —— 拉取与解析(确定性阶段)
预检通过后运行捆绑的扫描脚本:
FIGMA_TOKEN="$FIGMA_TOKEN" node <SKILL_DIR>/figma-scan.mjs "$PROJECT_ROOT" "<url-or-key>"
脚本成功后写入 $UA_DIR/intermediate/scan-manifest.json 并打印各节点类型计数,技能要求把这些计数转述给用户;若脚本非零退出,则转述 stderr 并停止。下面按源码顺序拆解这条流水线。
3.1 文件 key 解析与 API 访问层
parseFileKey 支持两种输入:从 figma.com/file/... 或 figma.com/design/... URL 中用正则提取 key,或直接接受纯字母数字的裸 key;无法解析时抛出带原始输入的清晰错误。
FigmaApiSource 封装了三个 Figma REST 端点,全部以 https://api.figma.com/v1 为基址:
| 方法 | 端点 | 用途 |
|---|---|---|
fetchDocument() |
GET /files/{fileKey} |
获取完整文档树(根 DOCUMENT,其子节点为各页面 CANVAS) |
fetchStyles() |
GET /files/{fileKey}/styles |
获取已发布样式(design tokens 的来源) |
renderImages(nodeIds) |
GET /images/{fileKey}?ids=...&format=png&scale=1 |
批量渲染屏幕缩略图 |
请求失败时统一抛出 Figma API {path} failed: {status} 错误。构造函数在未设置 FIGMA_TOKEN 时抛出带创建指引的友好错误,与 SKILL.md 的预检要求呼应。
3.2 基于版本号的增量跳过与缩略图就地刷新
figma-scan.mjs 在解析前会读取已有 meta.json 中的 figmaVersion,与本次拉取文档的 version 字段比对。若两者相同且未设置强制重建环境变量,则打印 UP_TO_DATE 并退出——此时技能按 SKILL.md 的要求向用户报告"该 Figma 文件版本的设计图谱已是最新"并停止;若要强制全量重建,需在环境中设置 UNDERSTAND_FIGMA_FORCE=1 后重跑。
这个跳过路径有一个关键细节:直接跳过并不完全等于什么都不做。Figma 的图像渲染 URL 是预签名 URL,数小时后过期,而屏幕缩略图 URL 已持久化在 knowledge-graph.json 中。因此 refreshThumbnailsInPlace 会在 UP_TO_DATE 路径上重新渲染所有 screen 节点对应的缩略图,并就地打补丁回写已有图谱,避免 Dashboard 侧栏出现失效图片;整个过程是尽力而为(best-effort),任何异常都不会让增量路径失败。
3.3 文档树解析:六种节点与四种结构边
parseDocument 把 Figma 文档树翻译为图谱节点与边,规则如下:
- CANVAS →
page:文档根节点的每个 CANVAS 子节点成为一个页面节点,id 形如page:{figmaId}。 - FRAME →
screen:页面下的顶层 FRAME 成为屏幕节点,并把absoluteBoundingBox的宽高记入figmaMeta.dimensions。 - COMPONENT →
component、COMPONENT_SET →componentSet:页面顶层组件与组件集;组件集内的每个 COMPONENT 变体还会产生variant_of边(权重 0.9)连回组件集。 - INSTANCE(深度读取):屏幕节点采用"浅节点集、深读取"策略——
collectInstances递归遍历屏幕子树,收集所有 INSTANCE,建立contains边连到所属屏幕;若实例引用了主组件(componentId),则追加instance_of边(权重 0.8)。此处有个容易混淆的点:figmaMeta.componentKey存的是文档components映射表里全局发布的 GUID key,而instance_of边指向的是文件内局部 node id,两者语义不同(源码注释专门说明了这一点)。 - SECTION:v1 阶段直接拍平(flatten),把 SECTION 的子节点按页面子节点处理,SECTION 本身不建模。
- 其他顶层类型:v1 忽略。
边权重约定为:contains = 1.0,variant_of = 0.9,instance_of = 0.8。所有节点初始 summary 是名称占位符,complexity 为 "simple",等待 Phase 2 的 LLM 充实。该映射逻辑有完整测试覆盖,parse-document.test.ts 用一个包含 Onboarding 页面、Login 屏幕、Button 组件集的双页文档,验证了全部节点 id 与四类边的生成,以及 componentKey 记录的是发布 GUID 而非局部 id。
3.4 设计令牌抽取:只收已发布样式
extractTokens 实现设计令牌的确定性抽取,有两个刻意的边界设计:
- 令牌节点只来自已发布样式(published styles),即
fetchStyles()返回的meta.styles。这是一个有界的集合,防止未发布的本地样式把节点数撑爆。样式类型通过映射表归一为令牌种类:FILL → color、TEXT → type、EFFECT → effect、GRID → grid,未知类型回落到color。令牌 id 形如token:{kind}:{name-slug}(名称经小写、非字母数字转连字符的 slug 化处理)。 uses_token边的归属策略:Figma 中样式通常应用在深层叶子图层(TEXT/RECTANGLE 等)而非浅层结构节点上。解析器在遍历文档树时维护"最近结构祖先"(screen/component/componentSet/instance/page),把样式使用归属到该祖先,确保真实的消费者关系不丢失。文件内局部样式 id(如"2:1")还会通过文档顶层styles映射桥接到已发布的 style key,再与令牌节点匹配;每条(消费者, 令牌)使用关系去重后以权重 0.5 的uses_token边输出。
3.5 屏幕缩略图与 scan-manifest.json
结构解析完成后,脚本只对 screen 类型的节点批量预取 PNG 缩略图(format=png&scale=1),通过 applyScreenThumbnails 把预签名 URL 写入对应节点的 figmaMeta.thumbnailUrl;缩略图是可选能力,渲染失败不会让扫描失败。
最终写入 scan-manifest.json 的结构为:
{
"project": {
"name": "(Figma 文档名)",
"languages": ["figma"],
"frameworks": [],
"description": "Figma design file: <文档名>",
"analyzedAt": "(ISO 时间戳)",
"gitCommitHash": ""
},
"fileKey": "(文件 key)",
"figmaVersion": "(文档 version)",
"nodes": [ "…结构节点 + 令牌节点…", ],
"edges": [ "…contains / instance_of / variant_of / uses_token…", ]
}
控制台输出形如 Figma scan: N pages, M screens, K components, S sets, I instances, T tokens,技能要求把这组计数转述给用户。
四、Phase 2 —— LLM 语义充实
读取 scan-manifest.json 后,把节点按约 15 个一批、尽量按页面聚合地分批,每批派发一个基于 design-analyzer 定义的子代理。派发给子代理的输入包含:该批节点(id、type、name、figmaMeta、子节点名称、令牌使用情况)、全部现有节点 id 列表(供 related 边精确引用)、中间目录 $INTERMEDIATE_DIR,以及用于输出命名的批号。若用户提供了 --language,还需追加 $LANGUAGE_DIRECTIVE(复用 /understand 的语言指令文本)。子代理将结果写入 analysis-batch-<N>.json。
design-analyzer 的职责边界被定义得非常严格,这是整个技能"确定性打底、LLM 只做增量"设计哲学的核心:
- 只做语义层:为每个节点产出 1–2 句
summary(说明该屏幕/组件用来做什么,而非描述像素;令牌则说明其角色,如"用于 CTA 的主品牌色")和 2–5 个小写tags(功能域、角色、状态,如auth、entry、cta、empty-state)。 - 允许但从严:仅可输出保守的
related边,且只限于名称/结构明显同属一个功能流的情况(如同一 onboarding 流程的两个屏幕);一批约 15 个节点,预期产出约 15 条充实与 0–8 条related边。 - 禁止项:不得输出任何
page/screen/component/componentSet/instance/token节点(它们已存在),不得重发结构边(contains、instance_of、variant_of、uses_token),related边必须使用精确的现有 id。
输出格式示例(子代理实际写入的文件内容):
{
"nodes": [
{ "id": "screen:1:1", "summary": "The sign-in screen where returning users authenticate.", "tags": ["auth", "entry"] }
],
"edges": [
{ "source": "screen:1:1", "target": "screen:1:5", "type": "related", "direction": "forward", "weight": 0.5, "description": "Both part of the sign-in flow" }
]
}
并发与容错方面,SKILL.md 规定最多 5 批并发;某批失败时仅记录警告并继续——因为确定性 manifest 本身就是扎实的基础,LLM 批是增强层而非依赖项。
五、Phase 3 —— 合并(Merge)
合并阶段运行捆绑脚本:
node <SKILL_DIR>/figma-merge.mjs "$PROJECT_ROOT"
figma-merge.mjs 读取 scan-manifest.json 与所有匹配 analysis-batch-*.json 的分析文件,调用 core 包的 mergeDesignGraph 完成合并,成功后写出 knowledge-graph.json 与 meta.json,并把统计信息(节点数、边数、图层数、tour 步骤数)与非 auto-corrected 级别的校验问题打印出来。mergeDesignGraph 的内部流程分五步:
- 索引 manifest 节点(克隆以便就地充实)。
- 应用 LLM 充实:按 id 把批分析中的
summary/tags补丁回对应节点——不在 manifest 中的 id 直接忽略,从机制上兜住了子代理"不得发明节点"的规则;分析批的edges(related边)则追加到边列表。 - 构建图层(layers):基于
contains边建立父子映射,对每个节点沿父链向上(带环保护)找到所属 page;component/componentSet/token三类节点不随页面,而是统一收进一个 Design System 图层;找不到页面归属的节点落入layer:unscoped。每个页面生成layer:{pageId}图层并附页面名描述。 - 构建导览(tour):Design System 图层排第一步,随后按页面顺序每页一步;每步
nodeIds截取前 8 个以保持视图可读。 - 组装 + 校验 + 重挂 kind:组装出
{ version: "1.0.0", kind: "design", project, nodes, edges, layers, tour },走统一的validateGraph校验(该函数会剥掉 kind 字段),校验通过后把kind: "design"重新挂回。
这些行为都有单元测试佐证:merge.test.ts 验证了产出图谱的 kind 为 design、屏幕归入其页面图层而组件/令牌归入 Design System 图层、充实按 id 精确回填、tour 首步为 Design System。
合并脚本写出的 meta.json 也值得注意:
{
"lastAnalyzedAt": "(ISO 时间戳)",
"gitCommitHash": "",
"figmaVersion": "(来自 manifest 的 figmaVersion)",
"version": "1.0.0",
"analyzerizedFiles": null
}
其中 figmaVersion 正是 Phase 1 增量跳过的比对依据,形成"扫描写版本 → 下次扫描比版本 → 版本合并进 meta"的闭环(meta.json 的 analyzerizedFiles 字段实为 analyzedFiles,取值是最终节点总数)。
六、Phase 4 —— 保存与启动
合并成功后:
-
清理中间文件(保留 manifest):
INTER="$UA_DIR/intermediate" find "$INTER" -mindepth 1 -maxdepth 1 -not -name 'scan-manifest.json' -exec rm -rf {} +保留
scan-manifest.json是有意的:它是确定性结构层的快照,analysis-batch-*.json等 LLM 中间产物则可安全清除。 -
汇报摘要:项目名、各节点类型计数、各类型边计数、图层、tour 步骤数,以及最终图谱路径
$UA_DIR/knowledge-graph.json。 -
自动启动 Dashboard:通过调用
/understand-dashboard技能把设计图谱渲染出来。Dashboard 对设计图谱的原生支持体现在 NodeInfo.tsx 的FigmaThumbnail组件——当节点带有figmaMeta.thumbnailUrl时,节点信息面板会渲染屏幕预览图;设计边类型(instance_of/variant_of/uses_token)则回落到自动生成的可读标签。
七、Schema 层如何为"design"图谱让路
设计图谱能与代码库图谱、知识图谱共用同一套 schema 与 Dashboard,靠的是 core 包 schema 中的按 kind 分派的别名表。在 schema.ts 中:
kind字段的枚举为codebase | knowledge | design;DESIGN_NODE_TYPE_ALIASES仅在kind === "design"时生效,把frame/artboard→screen、canvas→page、component_set/variant_set/componentset→componentSet、design_token/style→token等别名归一为规范节点类型;- 对应的
DESIGN_EDGE_TYPE_ALIASES把instantiates→instance_of、variant→variant_of、styled_by/applies_token→uses_token; - 反向亦有
NON_DESIGN_NODE_TYPE_ALIASES/NON_DESIGN_EDGE_TYPE_ALIASES:非 design 图谱里page归一为article、instance_of归一为exemplifies——注释解释了原因:sanitizer 无法区分"wiki 页面"和"Figma 页面",由图谱的kind决定哪张别名表生效。
这套机制保证同一套 validateGraph 管道可以安全地承载三种图谱类型,而 Figma 语义(page/screen/token)不会泄漏污染代码库或知识图谱。
八、适用边界与注意事项
从源码与测试的边界设定,可以归纳出当前版本(v1)的明确限制,实际使用时应了解:
- 在线依赖:需要有效的
FIGMA_TOKEN且能访问api.figma.com;这与/understand的全离线定位不同。 - v1 解析范围:SECTION 只拍平不建模,页面下其他顶层类型被忽略;令牌只收录已发布样式,未发布的本地样式不会成为令牌节点。
- 缩略图时效:屏幕缩略图 URL 是预签名 URL,数小时后过期;重新运行技能会走 UP_TO_DATE 路径自动刷新(见 3.2 节),但不重跑时旧图可能失效。
- LLM 批失败不阻塞:个别批次失败只降级该批节点的语义质量,结构层完整不受影响。
- 强制重建:文件版本未变但希望全量重建时,设置
UNDERSTAND_FIGMA_FORCE=1。
小结
/understand-figma 的设计可以概括为"确定性解析打底、LLM 语义增强、统一 schema 收口":figma-scan.mjs 用 parseDocument + extractTokens 产出可复现的 manifest,design-analyzer 子代理在严格约束下只做摘要、标签与保守 related 边,mergeDesignGraph 按页面与 Design System 生成图层和导览,最终产出与代码库图谱同构、可在同一个 Dashboard 中浏览的 kind:"design" 图谱。对维护者而言,最值得关注的扩展点是 parse-document.ts 的类型分派(handlePageChild)与 tokens.ts 的样式归属逻辑——它们决定了哪些 Figma 结构会进入图谱;对使用者而言,掌握 FIGMA_TOKEN 配置、UNDERSTAND_FIGMA_FORCE=1 强制重建与 UP_TO_DATE 增量路径这三点,就足以日常运转这条流水线。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00