我总觉得,真正的二次开发不是把功能贴到代码里那么简单,而是要在一个有生命力的开源项目里,摸索出它的气质和脉络,然后把自己的改动像一块合适的木料,打磨到恰好咬合的位置。Excalidraw 正好是那种适合雕琢的项目:接口清晰、结构分明、社区稳健,甚至它的白板本身就鼓励你在上面画来画去。于是我把一个小愿望丢给 SOLO Coder:把文本 → 图形的智能生成做进来,流程图也好,思维导图也罢,最好的结果就是我能在编辑器里写一句话,轻轻一点,就看到图像在面前成形。 
这是一篇完整的AI绘图功能二次开发笔记:我用 SOLO Coder 在 Excalidraw 开源项目中增加文本→图形的 AI 能力,支持流程图与思维导图,并在编辑器里直接预览和插入。文章覆盖环境搭建、前后端改造、联调验证、问题处理与可复制的操作步骤,先看效果吧。

你将获得
- 在主菜单新增AI绘图入口,打开文本转图对话框(TTD)
- 前端将文本与图类型发送到后端;后端接入豆包(Volcengine Ark)生成 Mermaid 文本
- 预览区渲染并一键插入到画布;失败时有清洗与兜底策略
在此之前,我们已经通过SOLO Coder 部署了本地的Excalidraw,接着要找入口,找一个人走近白板时自然会按下的地方。我把AI绘图放到主菜单里,让它像一个轻微的邀请而不是强制的引导。点击以后,前端抛给我第一个态度不好的报错:setAppState is not a function。两秒钟的心情起伏之后,我意识到是这个问题可以通过AI去解决,于是我把AI产生的问题换个了AI。
不难发现,它很快修复了这个问题,Excalidraw 的命令式接口里没有这个方法,应该用 updateScene。把全局事件改成 updateScene({ appState: { openDialog: ... } }),对话框乖乖弹出来,像终于滑到桌面正中间的一杯茶。
这扇窗叫 TTD,对话框的全名是 Text-to-Diagram。也就是 Text-to-Diagram。对话框的形态很友好,左边一个文本框,右边一个预览区,鼠标在文本框里点击一下,那种手指压下去的瞬间,我顺手截了一张图,留作交互起点的标记。
第一次按下Generate,我看到的是一片沉默,预览区安静地不动,还给我抛了一个Generated an invalid diagram。我把这个截图也留下,作为一次不太成功的尝试。那会儿我就明白了,这不是没调用,而是调用了,但返回的 Mermaid 文本不合身。思维导图的 Mermaid 语法算是实验性,转换库不是对所有情况都拿得很稳。于是我把后端派上台,搭了一个干净的 ai-backend ,用 Express 做路由,让它站在 excalidraw-master 的旁边,同时悄悄接入豆包(Volcengine Ark)的 Chat Completions,用 .env.local 留住密钥,不往前端暴露,保持整个结构清爽。 
后端这边,我直接把豆包API输入个SOLO。 
这里有详解的API文档: 
接下来会新建一个 ai-backend,让它站在主项目的旁侧,单纯、安静,读 .env.local 里的密钥,不把任何敏感信息暴露到前端,也不往仓库里乱提交。路由只做一件事:/v1/ai/text-to-diagram/generate 接受 prompt 和 type,优先调用豆包 Ark Chat Completions,把返回的内容清洗一下。
我很在意交互的微妙。TTD 对话框里那段英文提示,说系统目前用 Mermaid 当中间步骤,这句话像一个前置的协议:你要么给我流程、要么给我结构,我来想办法帮你成长为图像。用户写的是人话,模型理解的是人话,但预览需要的是规整的语言。所以我把类型的选择前置到生成动作的上方,让这组 UI 形成一个心智链条:输入、选择、生成、预览、插入。你能感到手势的顺畅,能看到预期的结果,这比任何文档提示都有效。
过程中有一些次要的插曲,比如浏览器标签意外打开旧端口 3000,所以事件监听并没有注册到你看的页面上;比如我一度尝试用 window.addEventListener 做一些全局控制,后来还是把它规整到 useEffect,跟着 excalidrawAPI 走生命周期;比如Mermaid 原文那一页会让人想查看细节,我就保留了View as Mermaid的跳转,给调试者一个后备的工具。每一个小动作都不是必须,但它们是贴心,我希望这套体验不是硬塞进去的功能,而是一种自然的延伸。
豆包的接入自己也带了一点个性。我把密钥放在本地 .env.local 里,不在代码里落笔,也不在终端里写长串的临时变量。模型的参数没有走极端,max_completion_tokens 设个温和的上限,reasoning_effort 放在中等,确保稳定和成本可控。有时为了让预览稳定,我会把 Mindmap 的生成提示悄悄引导成 Flowchart 的层级表达,毕竟转换链路对流程图更友好,这不是背叛,更像是一个实用主义的选择。用户要的是看到结构并可编辑的图形,图的样式可以慢慢打磨,但空白的预览等不及。
这时候整条链路开始有了握手的感觉。我在首页截图之后,又截了一个主菜单展开的画面,那里有AI绘图这个新朋友。我点开对话框,在文本框里敲了一段结构------比如把项目规划放在首行,然后用短句把目标范围时间资源团队预算一行一行列出来,然后按下Generate。这回预览区不再冷场,图像从右边长出来,节点紧紧排列,像把散落的书页用线穿在一起。我让它落到画布中央,放大一点,给这个时刻留一张干净的截图。 
接下来点击Insert按钮,就可以将内容插入到画布中。 
偶尔,它还会闹些情绪。比如你输入了太长的一段话,没有清晰的结构,它会再次用Generated an invalid diagram提醒你,语气像朋友。这个时候,不要把锅丢给模型,稍微调整一下文本,把主题放在第一行,把一级要点一行一个,风格更像大纲,再按一下生成。它会给你面子,预览就出来了。如果你想更确定一点,把右上角的类型切到 Flowchart,它几乎不会让你失望。
写到这里,我开始觉得这件事并不只是给项目加了一个AI功能。它更像是让一个成熟的工具,学会听另一种语言。Excalidraw 原本鼓励你用手去画,现在它也可以理解你说画一个这样的结构。TTD 对话框不是魔法,它只是一个理性的桥梁,把人的表达连接到图的表达,帮你跨过去。SOLO Coder 在这件事上扮演的角色,是把那些易碎的衔接点,替你稳稳地固定住。下载、安装、起服务、修事件、接模型、清文本、兜底,这些看起来像是工程细节,但它们构成了整个体验的实感。
如果你问我,SOLO Coder 在这件事里做了什么,我想说它并没有替我写掉所有代码,但它帮我把那条从下载到看见的路径铺平了。在本地拉起项目,协调工作区依赖、启动 Vite,修好入口事件,把后端服务跑起来,豆包的密钥藏在 .env.local ,调用链条串上去,预览链条又稳住,再给这条路放几个路标,这些工作听起来不起眼,却让一切变得顺畅。二次开发真正的魅力在于此:你不是把自己的想法贴上去,而是把它揉进来,跟项目的语言在一起,跟它的节奏在一起。
我把这篇文章写成一段连续的叙事,不讲首先、其次、最后,不做报告那样堆观点。我只是把自己的实操摊开,让那些按键、链接、路径、拐角、错误和修复全都在地上,带着你走过一次。等你走完,你会发现你也能这样,把一个想法交给 SOLO Coder,给它一个被验证的出口,只要你愿意在中间补上一点点耐心,这条路会变得像一条平整的木板道,踩上去不会发出吱嘎的声响。这个项目于是有了一个新习惯:不仅用手画,还能用话画。图像不再需要你去一个个摆放,它可以按照你的文字,自己站在画布上。