关于 figure
Figure 用于以 JSON 编写图表并将其渲染为动画 SVG,适合为文档和 PR 制作说明图。SVG 会嵌入图表数据,之后可读取并编辑。
主要功能
- 01用 JSON 编写图表
- 02从标准输入渲染动画 SVG
- 03表示场景、节拍和箭头
- 04在 SVG 中嵌入可编辑图表数据
- 05导出静态或深色主题 SVG
适用场景
- 01在 PR 描述中解释流程
- 02为 README 添加动画图表
- 03为博客文章制作图表
- 04编辑现有 SVG 图表
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ vectorize-io/ hindsight --skill figure安装后在 Claude Code 中输入/figure确认已加载。
详细介绍
Figure
一个动画 SVG,无脚本、无需上传:它可在任何支持 Markdown 的地方渲染和播放——GitHub README、PR 和 issue 评论、博客文章、Notion。任意尺寸下都清晰锐利,并会跟随读者的浅色或深色主题。
图示采用 Giotto 格式:一个 JSON 文档,与文档站点交互式图示所用的格式相同(hindsight-docs/figures/*.json)。
你只需编写图示 JSON,不用编写 SVG。 运行一条命令即可渲染。无需构建,也无需浏览器。
1. 编写图示
不要将它保存为仓库中的文件。 它是输入,不是交付物——通过管道传入(第 2 步),渲染出的 SVG 会为你保留一份副本。
{
"title": "Retain",
"speed": 2000,
"elements": [
{ "id": "root", "type": "group", "children": ["agent", "api", "bank"], "layout": { "direction": "row", "gap": 48 } },
{ "id": "agent", "type": "rectangle", "content": [{ "type": "title", "text": "Your AI Agent" }] },
{ "id": "api", "type": "group", "label": { "title": "Hindsight API" }, "children": ["retain"], "layout": { "direction": "column", "gap": 24 } },
{ "id": "retain", "type": "rectangle", "content": [{ "type": "title", "text": "Retain" }, { "type": "subtitle", "text": "LLM extraction" }] },
{ "id": "bank", "type": "group", "label": { "title": "Memory Bank" }, "children": ["facts", "obs"], "layout": { "direction": "column", "gap": 28 } },
{ "id": "facts", "type": "cylinder", "content": [{ "type": "title", "text": "Facts" }, { "type": "subtitle", "text": "world · experience" }] },
{ "id": "obs", "type": "cylinder", "content": [{ "type": "title", "text": "Observations" }] },
{ "id": "call", "type": "arrow", "route": "curved", "start": { "id": "agent" }, "end": { "id": "retain" }, "label": { "text": "retain()" } },
{ "id": "store", "type": "arrow", "route": "curved", "start": { "id": "retain" }, "end": { "id": "facts" }, "label": { "text": "extract" } },
{ "id": "consolidate", "type": "arrow", "route": "curved", "start": { "id": "facts" }, "end": { "id": "obs" }, "label": { "text": "consolidate" }, "quiet": true }
],
"scenes": [
{
"label": "retain()",
"beats": [
{ "edges": { "edge": "call", "data": "“Alice joined Google in March”" }, "say": "Your agent sends what happened." },
{
"edges": "store",
"show": { "facts": [{ "tag": "world", "tone": "blue", "text": "Alice joined Google", "meta": "Mar 2026", "mark": "new" }] },
"say": "An LLM pulls out the facts."
},
{
"edges": "consolidate",
"ms": 2600,
"show": { "obs": [{ "text": "Alice works at Google", "meta": "2 sources" }] },
"say": "The worker merges them into one belief."
}
]
}
]
}
元素——一个扁平列表。group 通过 id 列出其 children,并进行布局(layout: { direction: "row" | "column", gap, align });label: { title } 会为其绘制边框。除非布局另有指定,否则子元素会在顶部或左侧对齐:行布局使用 align: "center",列布局使用 align: "stretch"(等宽方框),与文档图示中的做法一致。rectangle 方框表示会执行某种操作的元素;cylinder 表示静态数据;diamond 表示决策。方框的 content 由多个块组成:title、subtitle、text、list、chips、code。为每个元素设置稳定的 id。
箭头——{ type: "arrow", start: { id }, end: { id }, label?: { text }, route: "curved", around?, quiet? };端点可以是方框,也可以是组。around: "above" | "below" 会让箭头弧线绕过中间的方框;quiet: true 则只在场景使用该箭头时绘制(适用于会横穿图示的长箭头)。
场景与节拍——每个场景讲述图示中的一个故事;SVG 会循环播放。一个节拍代表一个时刻:edges(箭头 id、表示反向跳转或数据芯片的 { edge, back, data },也可以是同时执行多个操作的数组)、say(说明文字)、show(在场景结束前,显示填充方框内部卡片的内容)、light(高亮该节拍中的方框;在场景中设置时,则贯穿整个场景)、ms(节拍持续时间)。
卡片行——{ tag?, tone?, text, meta?, mark?, mono? }。tone 可以是 blue | purple | green | orange | red | gray。用 tag 标注对象类型(world、user、page),用 meta 描述细节,用 mark 表示发生了什么(new、✓、cited、↻)。任何文本中都可以使用 **bold** 和 `code`。
完整格式见 node_modules/giotto/lib/edit.js 中的 FORMAT 文本。hindsight-docs/figures/ 中的 13 个图示都是可运行的示例——最快的入门方式是复制最相近的一个。
内容要真实、具体:实际示例数据胜过占位符;标签、卡片或说明文字中的每一项陈述,都必须与代码的实际行为一致——请检查代码,不要想当然。
2. 渲染——从 stdin 传入,不在磁盘上留下任何文件
npx giotto export - path/to/out.svg <<'DOC'
{ "title": …, "elements": […], "scenes": […] }
DOC
giotto 来自文档站点的依赖项(在仓库根目录运行 npm install)。带引号的 <<'DOC' heredoc 会原样传递 JSON,唯一生成的文件是 SVG。布局和场景警告会输出到 stderr:请修复它们。引用不存在的元素(箭头端点、组的子元素、场景要填充的方框)会导致错误:导出失败,且不会写入任何文件。
其他形式:
npx giotto export hindsight-docs/figures/retain.json out.svg # a docs figure, as an SVG
npx giotto export doc.json out.svg --theme dark --static # one still frame, dark
npx giotto spec out.svg # print the diagram an SVG carries
每个 SVG 都会在 <metadata id="giotto-doc"> 中嵌入图示,因此即使没人保留 JSON,图示仍可编辑:用 giotto spec 读回,需要什么就修改什么,然后重新渲染。
3. 发布前先查看效果
务必查看。文字溢出方框、箭头穿过方框、说明文字与动画内容不符——这些问题一眼就能看出来,在源文件中却看不出来。
cd $(dirname out.svg) && python3 -m http.server 8777 & # the browser tool blocks file:// URLs
然后打开 http://localhost:8777/out.svg,截一张图,等待几秒钟后再截一张,以检查后续节拍。有人在旁边查看时,也可以使用 open out.svg。
4. 放在合适的位置
-
PR 或 issue 评论 — 在分支上提交 SVG,然后引用其原始 URL:
。GitHub 会立即渲染并播放动画。 -
README 或仓库文档 — 提交文件,并使用相对路径链接。
-
博客文章 — 放在
hindsight-docs/static/img/blog/,引用路径为/img/blog/<name>.svg。 -
文档站点自己的页面 — 不要使用 SVG。这些页面使用交互式播放器,支持标签页、暂停、调速和悬停。将图表保存为
hindsight-docs/figures/<name>.json,并将其放到页面上:import Figure from '@site/src/components/Figure'; import retain from '@site/figures/retain.json'; <Figure doc={retain} />
SVG 无法实现的功能
它会循环播放每个场景,且没有控制功能:没有标签页、暂停或悬停。如果图表需要这些功能,就应该放在文档站点上。SVG 最好只包含一到两个场景,这样循环播放一轮所需的时间会更短。