mcpField
F
figure

figure

github.com/vectorize-io设计与 UI55.5k50 次安装今天更新
代码仓库

关于 figure

Figure 用于以 JSON 编写图表并将其渲染为动画 SVG,适合为文档和 PR 制作说明图。SVG 会嵌入图表数据,之后可读取并编辑。

主要功能

  1. 01用 JSON 编写图表
  2. 02从标准输入渲染动画 SVG
  3. 03表示场景、节拍和箭头
  4. 04在 SVG 中嵌入可编辑图表数据
  5. 05导出静态或深色主题 SVG

适用场景

  1. 01在 PR 描述中解释流程
  2. 02为 README 添加动画图表
  3. 03为博客文章制作图表
  4. 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: ![figure](https://raw.githubusercontent.com/<owner>/<repo>/<branch>/<path>.svg)。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 最好只包含一到两个场景,这样循环播放一轮所需的时间会更短。

评论

支持 Markdown