VISUAL-EXPLAIN · 整体概览

visual-explain 是什么,怎么把一段聊天讲明白的事

visual-explain 是个发"解释稿"的小工具。聊到一半,你说"画一张讲清楚 X",我把 X 写成一个 HTML 页面,发上去就有公网链接。一个 topic 是一个东西(比如 tools-backend),一个 scope 是这件事的一面(比如 请求路径 / Auth)。每个 scope 一个 HTML。同名再发就盖掉,新角度就开新 tab。没有 v1/v2/v3。

topic · visual-explain scope · model-overview 这页讲的就是这个工具自己
SECTION 01

一张图看整套系统怎么连

三块东西:你这边的发布脚本 (bash cli)、跑在 Cloudflare 上的 worker、放文件的 R2 桶。Worker 是中间那个唯一动 R2 的人 — 客户端不直接碰 R2。

SHELL POST WRITE R2 READ GET HTML SHELL 你 + agent 写 HTML 到 /tmp CLI visual-explain-publish bash + curl + jq FOCAL · WORKER visual-explain-backend Hono · 路由 · 渲染 STORE R2 桶 tobatsu adhoc/visual-explain/ METADATA manifest.json · _topics.json topic 和 scope 的目录 READER 浏览器 (用户) 点链接看页面 LEGEND 焦点 · 所有 R2 读写都从这里过 本地 / 工具 R2 存储 人 / 客户端
Worker 是唯一动 R2 的人 — agent 不直接写 R2,浏览器也不直接读 R2。所有路径都过 worker,它管:写 HTML、维护两份目录(topic 内的 manifest + 全局 _topics)、收到 GET 时拼成 dashboard 或 topic 页。
域名
visual-explain.fpai.io
Cloudflare custom domain,跟 R2 同账户
技术栈
Hono + R2
一个 worker 既写又读又渲染
认证
单 bearer token
wrangler secret,每台发布机一份副本
总代码量
~600 行 TS
app.ts + manifest.ts + render.ts + types.ts
SECTION 02 · FOCAL

两个名词:topic 和 scope

理解 visual-explain 只需要这两个词。所有页面排布、所有 URL、所有 R2 路径都是它俩的组合。

topic = 你在讲的东西

  • 例子tools-backend / mai-checkpoint-flow / ingest-pipeline-v2
  • 命名kebab-case,最长 31 字符
  • 承担一个名字、一个可选 title(人话)、一个可选 vibe 标签

scope = 这件事的一面

  • 例子request-path / auth-flow / error-handling
  • 命名同样 kebab-case,跟 topic 不冲突
  • 承担就是一个完整 HTML 页 + 一个标签名
# R2 里长这样
adhoc/visual-explain/
├── _topics.json                       # 全局 topic 列表,dashboard 拿这个渲
├── tools-backend-arch/
│   ├── manifest.json                  # 这个 topic 下的 scope 列表
│   ├── request-path.html              # scope 1
│   └── auth-flow.html                 # scope 2
└── visual-explain/
    ├── manifest.json
    └── model-overview.html            # 就是你正在看的这个
为什么不分 v1 v2 v3
Notion / 文档系统都倾向"最新版盖旧版"。一个 scope 只有一份当前 HTML,改一次盖一次。要新角度就开新 scope(新 tab)。这样切换"看新角度"和"看历史" 不会混在一起。
SECTION 03

怎么把一个 HTML 发上去

本地写一个 HTML 文件,跑 publish cli 把它推给 worker。worker 三件事:写 R2、更新两份 manifest、回 URL。

# 1. 写 HTML 到 /tmp
$ vim /tmp/visual-explain-tools-backend-request-path.html

# 2. 跑 publish
$ ~/.smux/skills/visual-explain/bin/visual-explain-publish \
    tools-backend-arch request-path \
    /tmp/visual-explain-tools-backend-request-path.html \
    "请求路径" "Tools Backend" "kami-paper"

scope 覆盖 (topic 现有 2 scope)
  dashboard : https://visual-explain.fpai.io/
  topic     : https://visual-explain.fpai.io/tools-backend-arch/
  scope     : https://visual-explain.fpai.io/tools-backend-arch/request-path.html

参数 6 个,前 3 个必填:

位置 必填 作用
1 · topic这次发的属于哪个 topic(kebab-case)
2 · scopescope slug(kebab-case)
3 · html 文件路径本地 HTML 文件,会原样上 R2
4 · scope_titletab 上显示的中文("请求路径")
5 · topic_titledashboard 卡片上显示的中文(只第一次发用)
6 · vibe一个标签 ("kami-paper" / "linear-modern" 这种)
SECTION 04

发布的三种情况

worker 看到 POST /publish 时,根据 topic/scope 是否已存在,分三条路。

情况 worker 做什么 响应里告诉你
topic 不存在 开新 topic + 第一个 scope + 写 manifest + 加进 _topics.json was_new_topic: true
topic 在 / scope 不在 追加 scope + 更新 manifest + 更新 _topics.json 里 scope_count was_new_scope: true
topic 和 scope 都在 原地覆盖 HTML + manifest 更新 updated_at 两个都 false · scope 标记为覆盖
SECTION 05

worker 公开的几个路由

worker 只暴露几条路 — 一条发布,剩下都是给浏览器看的。

URL 谁来 给什么
POST /publishcli带 bearer token,body 是 JSON {topic, scope, html, ...}
GET /浏览器dashboard 渲染所有 topic 卡片
GET /:topic/浏览器topic 页 — 上方 chrome + 下方 scope HTML 嵌 iframe
GET /:topic/:scope.html浏览器scope HTML 本体(R2 直读)
GET /:topic/manifest.json调试用这个 topic 的 scope 列表
GET /_health探活简单 200 OK
为什么把发布也藏在 worker 后面
Worker 拿 R2 binding 直接写,agent 不需要任何 R2 API 密钥。同时 worker 顺手维护 manifest 和 _topics.json —— 这两个文件是给 dashboard / topic 页用的索引,没人手动碰,全靠 worker 在每次 publish 时回写。
SECTION 06

读者从哪进,看到什么

收到 URL 的人不需要任何 token,直接打开。 worker 根据路径决定渲染哪一层。

进档案首页(visual-explain.fpai.io/)

  • 看见所有 topic 的卡片
  • 每张卡显示 topic 名 + scope 数量 + 上次更新 + vibe
  • 顶上一个搜索框,可以按 slug / title 过滤
  • 点卡片 → 进 topic 页

进 topic 页(/tools-backend-arch/)

  • 顶上一行 chrome:kicker + topic 标题 + scope tab 切换
  • 下面 iframe 直接嵌当前 scope 的 HTML
  • 点 tab 切换 scope,URL 加 ?scope=xxx
  • 往下滑 chrome 跟着走,让出阅读空间
直链最快
如果只想把一个 scope 发给同事看,直接给 /tools-backend-arch/request-path.html,那是全屏 HTML,没有 chrome 干扰。如果想给"这个 topic 几个角度都看下",给 topic 页 /tools-backend-arch/