如何将Mermaid图表变成可编辑的Excalidraw白板:lavish-axi转换工程细节完全指南
发布时间:2026/9/25 18:50:29 作者:尧图编辑部 阅读量:1,286

如何将Mermaid图表变成可编辑的Excalidraw白板lavish-axi转换工程细节完全指南【免费下载链接】lavish-axiHTML is the new markdown. Lavish is the new editor for your HTML artifacts.项目地址: https://gitcode.com/gh_mirrors/la/lavish-axilavish-axi 是一个本地优先的 HTML 工件编辑器它把 AI Agent 生成的 HTML 文件打开在本地浏览器里并让其中每一张 Mermaid 图表变成一个可编辑的 Excalidraw 白板——你拖一拖、画一画再一键把编辑摘要发给 Agent 去改回源码。这篇文章带你看懂 lavish-axi 白板里「Mermaid → Excalidraw」转换背后的 5 个关键工程环节以及一个真实线上 bug 的完整修复故事 从 HTML 到白板五步转换流水线先看全局。当页面里有一个classmermaid的图表时转换大致经历五个阶段服务端提取源码从原始 HTML 文件里按文档顺序抽出每段 Mermaid 源码并算出身份哈希沙箱内解析白板块内用excalidraw/mermaid-to-excalidraw把 Mermaid 源码解析成「骨架」元素字体加载后二次生成等 Excalidraw 的字体Excalifont真正加载完再生成一次拿到真实字形尺寸场景修正修复多行标签换行、容器撑开、文本度量迁移等细节落盘与反馈场景自动保存为本地.excalidraw文件 PNG 预览供 Agent 读取。其中第 1 步是整个系统的关键设计浏览器里 Mermaid 渲染后元素文本会被替换成 SVG磁盘上的原始源码才是权威数据。所以 lavish-axi 选择在服务端重新解析 HTML 来恢复源码而不是去「反解」SVG。源码提取为什么选在服务端做extractMermaidSources 用 parse5 解析 HTML遍历所有带mermaidclass 的元素按文档顺序输出{ index, source }列表——index正好和浏览器里document.querySelectorAll(.mermaid)的顺序一致前后端由此对齐。几个容易忽略的细节br/是语义Mermaid 把引号标签里的br/当作有意义的换行提取时会被显式保留否则OBJECTIVE:br/do the thing会粘成一行见 mermaid-source.js身份哈希mermaidSourceHash 对规范化后的源码取 SHA-256 前 16 位作为「底层图到底变没变」的判断依据——这个哈希后面会反复出现HTML 实体解码--gt;、quot;...等实体会被还原保证从 HTML 里抽出来的仍是合法 Mermaid。一个真实的 Bug标签被裁掉一半的真相这张截图修复前多个标签的首尾字符都被「吃」掉了等等这张 before.png 比例偏宽换用更规整的图。实际排版中我们改用根因详见 task-evidence/excalidraw-label-clipping/README.mdconvertToExcalidrawElements在生成元素时同步测量文本宽度但那时 Excalifont 字体还没加载完浏览器只能用一个更窄的衬线字体「占位测量」。字体稍后加载完成画布按旧的更窄的文本框去画更宽的字形——首尾字符就被裁掉了。同一个 Chrome 环境实测标签衬线占位宽度真实 Excalifont 宽度Disposable adapter sidecar171.5210.5Adapter Protocol v1129.8157.4Future adapter92.9119.0修复非常克制convertExcalidrawSkeletonsAfterFontsLoad 让转换器先「预跑」一遍拿到需要哪些字体请求字体加载完成后再正式生成一次同时重跑多行换行计算。注意这个函数只暴露convert/loadFonts两个适配器——它不依赖任何浏览器 API因此在 Node 里可以被单测直接验证。更妙的是存量数据迁移修复前保存的场景没有「文本度量版本」标记repairSavedSceneTextMetrics 在首次重开时只扩大过小的自动换行文本框位置、样式、绑定等其它数据一个字节都不动然后写入当前版本号——迁移只跑一次。多行标签与容器撑开文本渲染的三个细节Mermaid 节点标签里常用br或字面量\n换行而转换器会把它们原样拷进 Excalidraw 的label.text被当成单行——classifybrchecks会渲染成粘连的classifychecks。normalizeMermaidLabelLineBreaks 把这两类都归一成真正的\n。后续还有两步几何修正估算文本盒按字符数 × 字号 × 0.62估算宽、行数 × 字号 × 1.25估算高容器框按文本尺寸向外撑开并以中心为原点扩展保证节点不偏移绑定文本重定位Excalidraw 里文本元素独立保存 x/y容器放大后旧坐标会「跑偏」fitContainersToBoundText 按textAlign/verticalAlign重新把文本放回容器正确位置。另外上游转换器对并行边可能产出重复元素 idExcalidraw 要求唯一findDuplicateElementIds 一旦发现重复就整场重新生成 id——用摘要质量换正确性。源码变了怎么办convert / restore / prompt 三态机自动保存意味着「本地有存档」不等于「用户改过」。当 Mermaid 源码哈希变化时resolveWhiteboardInitAction 做出三种裁决场景动作说明没有本地存档convert直接转换新源码哈希一致restore恢复用户场景哈希变了 存档有实质编辑prompt让用户选择「按新图重新转换丢弃编辑」或「继续编辑旧场景」哈希变了 存档只是样式噪声convert静默重新转换「实质编辑」的判定savedSceneHasPreservableEdits把场景元素和转换基线逐 id 对比但刻意豁免颜色、字体、种子、updated时间戳等良性样式键且 2px 以内的坐标抖动不算「移动」——否则一次自动保存就会把用户「钉」在旧图上。编辑如何回到 Agentdiff 摘要 反馈文件点Queue feedback后lavish-axi 不会把整场 JSON 甩给 Agent而是用 summarizeSceneEdits 生成一份有界的变更摘要按 id 对齐基线和编辑后的场景归类为added / removed / moved / relabeled / drawn五类最多 40 行、每行 200 字符多出来的折叠成...and N more。节点被改名会被识别为一次 relabel而不是「文本元素被移动」——因为绑定文本被折叠进了它的容器。同时whiteboard-store 在状态目录state-dir/whiteboards/下发布两份 Agent 可读文件独立.excalidraw场景文件和 PNG 预览。反馈提示词里附带的是本地文件路径Agent 按需打开即可不污染提示词上下文。最终 Agent 去更新 HTML 里的 Mermaid 源码——源码始终是权威白板只是浏览器视图 ️安全边界沙箱、白名单与目标规整不可信内容只进沙箱白板块以 iframe 嵌入allow-scripts allow-popups但不给allow-same-origin见 whiteboard-frame.jsAgent 写的 Mermaid 里藏什么恶意代码都出不了不透明源链接白名单Mermaid 的click指令可以塞任意 URLsanitizeSceneLink 只放行http(s)://和mailto:javascript:、data:、file:一律丢弃打开外链前还要用户二次确认回程目标规整normalizeExcalidrawSceneTarget 把浏览器回传的反馈目标剥到固定形状防止任意外部 POST 污染状态节点身份标注 Mermaid 节点时锚定稳定的节点 id 标签而不是 CSS 路径mermaid-node.js重排渲染后标注依然找得到目标。主题跟随让图表和页面一起换装一个常见痛点Mermaid 固定主题页面暗色时图表一片刺眼米白。lavish-axi 的 design 指引提供了主题感知的初始化片段按页面背景而非系统偏好选主题并在切换时重渲染——下方截图里操作系统偏好是暗色图表仍正确跟随页面切到了亮色证据见 task-evidence/mermaid-theme/README.md回归保障冷启动 Chrome 的端到端测试这条链路上最容易碎的就是「字体加载时序」这类只在真实浏览器里复现的问题。test/whiteboard-render.browser.test.js 会启动一个冷启动的真实 Chrome/Chromium 配置让 夹具 走完 Mermaid 转换 → Excalidraw 画布导出全流程等 Excalifont 真正加载后逐一核对每个文本盒的字形度量还专门覆盖「旧版场景的一次性修复不改动任何非度量数据」这条迁移路径。而导出 HTML 里的原始 Mermaid 渲染路径完全不受白板注入影响——standalone 截图 验证了直接打开文件无注入时图表与原样一致总结转换设计的三条核心原则单一权威源Mermaid 源码HTML 文件永远是权威Excalidraw 场景只是本地缓存的视图靠哈希判断失效、靠 diff 决定去留正确性优先的取舍字体没加载完就绝不产出最终度量id 重复就整场重发——宁可牺牲一点便利不给渲染留「近似值」纯数据进出核心逻辑转换修正、场景 diff、初始化裁决不碰 DOMNode 里可单测、浏览器里通过 esbuild 打包复用同一份代码两种跑法。想完整体验的话安装 lavish skill 或直接用npx -y lavish-axi即可零配置启动详见 README.md 的 Quick Start本地部署分享后端可参考 docs/self-hosting-share.md。【免费下载链接】lavish-axiHTML is the new markdown. Lavish is the new editor for your HTML artifacts.项目地址: https://gitcode.com/gh_mirrors/la/lavish-axi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考