news 2026/4/16 19:45:04

用Excalidraw打造中文手写风格画板

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用Excalidraw打造中文手写风格画板

用 Excalidraw 打造中文手写风格画板

在技术团队的日常协作中,一张随手勾勒的草图往往比千言万语更高效。无论是架构讨论、流程推演,还是产品原型构思,可视化表达始终是沟通的核心工具。而 Excalidraw 正是这一场景下的明星选手——它以极简界面和“手绘风”视觉效果著称,让数字白板拥有了纸笔般的亲和力。

但当我们真正投入中文环境使用时,却总感觉哪里不对劲:英文文本用了 Virgil 这类手写字体,线条歪歪扭扭很自然;可一旦输入中文,立刻变成规整冷峻的黑体或宋体,像是一张温柔的手稿里突然插入了打印标签,风格割裂感扑面而来。

有没有办法让中文也“写”得随意一点?答案是肯定的。本文将带你从零开始,深度定制 Excalidraw,引入一款优雅的开源中文字体,实现真正的“全手写风”统一体验,并部署为可共享的 Web 应用。

整个过程不仅解决了一个具体问题,更是一次对现代前端项目架构的实战演练:如何理解 Monorepo 结构、干预字体加载机制、处理服务端渲染兼容性,以及完成静态站点发布。


准备工作:获取并运行 Excalidraw 源码

要定制一个开源项目,第一步永远是跑通它的本地开发环境。

前往 Excalidraw 官方仓库,点击右上角Fork按钮复制到你的 GitHub 账户下,然后克隆到本地:

git clone git@github.com:yourname/excalidraw.git cd excalidraw

建议创建一个独立分支用于本次功能开发:

git checkout -b feature/chinese-handwriting-font

这样后续即使官方更新主干代码,也能通过 rebase 或 merge 平滑合并,保留我们的修改痕迹。

接下来安装依赖并启动服务:

yarn install yarn run start

Excalidraw 使用 Yarn 管理依赖,基于 Vite 构建。几分钟后浏览器会自动打开 http://localhost:3000,你应该能看到熟悉的绘图界面,可以自由添加形状、文本、箭头等元素。

✅ 提示:若启动失败,请确认 Node.js 版本是否为 v16+,这是项目推荐的基础运行环境。


字体选择:寻找一款“会呼吸”的中文字体

我们想要的不是普通的书法字,而是一种带有轻微抖动、笔画粗细变化、仿佛真实书写留下的痕迹——这种质感才能与 Excalidraw 的“手绘风”融为一体。

关键要求如下:
- 支持常用汉字(至少覆盖 GBK)
- 视觉风格自然流畅,避免机械感
- 免费可商用,规避版权风险

目前市面上有不少优秀开源字体平台可供筛选:
-猫啃网(maoken.com):专注免费可商用字体分享,标注清晰
-字由(hellofont.cn):设计师常用资源库
-Google Fonts 中文镜像:部分字体支持

本文选用“平方雨桐体”(YuTong Type Foundry 出品),这是一款圆润自然、略带连笔感的开源字体,其轻重变化恰到好处,非常适合模拟手写情境下的非均匀运笔效果。

下载.ttf格式的文件后,重命名为Yutong.ttf,便于后续引用。


集成字体:打通客户端与服务端的渲染链路

Excalidraw 采用 Monorepo 架构,字体系统分布在多个子包中。我们需要同时配置前端显示和服务端导出能力,否则会出现“页面看着正常,导出图片变黑体”的尴尬情况。

1. 放置字体文件

Yutong.ttf复制到两个关键目录:

cp Yutong.ttf packages/excalidraw/fonts/assets/ cp Yutong.ttf public/

前者用于构建时打包进字体模块,后者供 Node.js 服务直接提供静态资源访问。

2. 声明字体:CSS @font-face

编辑packages/excalidraw/fonts/assets/fonts.css,末尾添加:

@font-face { font-family: "Yutong"; src: url(./Yutong.ttf) format("truetype"); style: normal; display: swap; }

⚠️ 注意:必须写format("truetype")而非format("ttf"),这是 WOFF 规范的要求,否则浏览器可能拒绝解析。

3. Node 端注册字体(导出 PNG/SVG 必须)

编辑packages/excalidraw/index-node.ts,找到已有字体注册代码:

registerFont("./public/Virgil.woff2", { family: "Virgil" }); registerFont("./public/Cascadia.woff2", { family: "Cascadia" });

在其下方加入:

registerFont("./public/Yutong.ttf", { family: "Yutong" });

这一步至关重要。没有它,当你点击“Export as PNG”时,Canvas 将无法绘制该字体,导致中文回退为默认字体甚至乱码。

4. 添加预加载提升性能

为了避免首次加载时出现字体闪烁(FOIT/FOUT),需在 HTML 中预加载字体资源。

修改excalidraw-app/index.html,在<head>内添加:

<link rel="preload" href="/Yutong.ttf" as="font" type="font/ttf" crossorigin="anonymous" />

如果你使用了自定义 Vite 插件处理字体注入(如scripts/woff2/woff2-vite-plugins.js),也应同步添加此 preload 标签。

5. 扩展字体枚举常量

打开packages/excalidraw/constants.ts,查找FONT_FAMILY对象:

export const FONT_FAMILY = { Virgil: 1, Helvetica: 2, Cascadia: 3, Excalifont: 5, Nunito: 6, "Lilita One": 7, };

为了避免与未来官方新增字体冲突,我们使用一个较大的数值作为键值:

Yutong: 999

最终结果为:

export const FONT_FAMILY = { // ... existing fonts Yutong: 999 };
6. 添加字体选择器 UI

编辑packages/excalidraw/components/FontPicker/FontPicker.tsx,这是顶部工具栏中的字体下拉菜单组件。

在选项数组中新增一项:

{ value: FONT_FAMILY.Yutong, icon: FontFamilyHandDrawnIcon, // 复用手绘图标 text: "手写体 (中文)", testId: "font-family-yutong", },

💡 可选优化:你可以将"手写体 (中文)"提取为国际化字段,写入lang/zh-CN.json等语言包,实现多语言支持。

7. 注册字体元数据(防止 fallback)

最后一步,确保字体被正确纳入 Excalidraw 内部的字体管理系统。

编辑packages/excalidraw/fonts/index.ts,在_register调用后添加:

import Yutong from "./assets/Yutong.ttf"; // ... _register("Yutong", FONT_METADATA[FONT_FAMILY.Excalifont], { uri: Yutong, });

这里复用了Excalifont的度量信息(如行高、基线偏移),虽然不完全匹配,但在大多数场景下足以保证排版一致性。如果追求极致精准,也可以单独测量并定义新的FONT_METADATA条目。


功能验证:看看“写的字”像不像人写的

重新启动应用:

yarn run start

进入页面后操作如下:
1. 点击左侧 “T” 文本工具
2. 输入一段中文,例如:“用户登录流程”
3. 在顶部样式面板中选择新添加的“手写体 (中文)”选项
4. 观察文字是否呈现自然笔触

✅ 成功标志:中文字体呈现出轻微的粗细波动和圆润转角,与英文手绘线条风格协调一致,整体画面不再有割裂感。

此时你已经拥有了一款真正意义上的“双语手绘风”画板。


构建与部署:让它被世界看见

为了让团队成员或公众也能使用这个定制版本,我们可以将其部署为静态站点。推荐使用GitHub Pages实现免费托管。

1. 安装 gh-pages 工具
yarn add -D gh-pages
2. 添加 deploy 脚本

package.jsonscripts字段中增加:

"deploy": "gh-pages -d excalidraw-app/build"

完整示例如下:

"scripts": { "start": "concurrently \"yarn:start:app\" \"yarn:start:svr\"", "build": "yarn build:app", "deploy": "gh-pages -d excalidraw-app/build" }
3. 配置相对路径(适配二级目录)

如果你计划部署在https://yourname.github.io/excalidraw-zh/这样的子路径下,必须启用相对路径。

编辑excalidraw-app/vite.config.mts

export default defineConfig({ base: './', // 改为相对路径 // ... });

否则所有资源请求都会指向根目录/assets/...,导致 404 错误。

4. 执行构建与部署

依次运行:

yarn run build yarn run deploy

gh-pages会自动创建一个名为gh-pages的分支,并推送构建产物。几分钟后,前往仓库 Settings > Pages 即可看到部署成功的提示。

访问链接形如:https://yourname.github.io/excalidraw-zh/

即可全球访问你专属的中文手写风格 Excalidraw 画板


常见问题与解决方案(实战踩坑记录)

❌ 问题1:字体未生效,显示为方块或默认字体

原因分析
-@font-faceformat('ttf')不合法
- 浏览器缓存旧 CSS 或字体文件
- 字体路径错误或未正确复制到public/

解决方法
1. 检查fonts.css是否使用format("truetype")
2. 清除浏览器缓存(Ctrl + F5 强刷)
3. 打开 DevTools Network 面板,确认Yutong.ttf是否成功加载

❌ 问题2:导出 PNG/SVG 时中文乱码或缺失

根本原因:Node.js 环境未注册字体。

修复方式:务必确认已在index-node.ts中调用registerFont(),且路径相对于public/目录正确无误。

❌ 问题3:部署后报错Could not parse as value list

典型错误信息:

DOMException: The source provided ('url(/assets/Yutong-Bla.ttf) format('ttf')') could not be parsed...

根源:Excalidraw 内部根据扩展名自动生成format(xxx),而.ttf被误判为ttf,但标准应为truetype

修复方案

修改packages/excalidraw/fonts/ExcalidrawFont.ts中的getFormat方法:

private static getFormat(url: URL) { try { const pathname = new URL(url).pathname; const parts = pathname.split("."); if (parts.length === 1) return ""; let ext = parts.pop()?.toLowerCase(); switch (ext) { case "ttf": return "format('truetype')"; case "woff": return "format('woff')"; case "woff2": return "format('woff2')"; case "otf": return "format('opentype')"; default: return ""; } } catch (error) { return ""; } }

重新构建后,该问题即可消除。


进阶方向:结合 AI 快速生成图表

Excalidraw 不只是一个绘图工具,它还能成为AI 驱动的知识生产引擎

想象一下这样的场景:你在会议中说了一句“帮我画个电商系统的微服务架构”,下一秒白板上就出现了带注释的组件图——这不是科幻,而是完全可以实现的工作流。

推荐集成路径:
方案说明
Excalidraw + Mermaid + AI Prompt利用 AI 解析自然语言生成 Mermaid 代码,再通过转换器导入 Excalidraw
Custom AI Plugin开发插件调用 OpenAI API,输入描述返回 JSON 元素数组
Obsidian 插件联动若你使用 Obsidian,可通过其 Excalidraw 插件实现笔记内嵌 AI 生图

示例 Prompt:

“请生成一个包含用户登录、订单管理、支付网关的电商系统架构图,使用手绘风格。”

这类能力不仅能极大提升敏捷开发中的原型效率,也让非技术人员能轻松参与系统设计。


这种高度集成的设计思路,正引领着智能协作工具向更自然、更高效的方向演进。而你刚刚完成的,不只是一个字体替换,更是一次对开源生态的创造性回应——当工具不再只是“可用”,而是真正“好用”于你的母语文化时,创造力才真正获得了自由。

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 12:21:13

4.2符号机制详解

4.2 深入理解符号包装机制 4.2.1 POSIX 应用与实时需求的冲突 本章将深入探讨 Xenomai 中独特的符号包装机制&#xff0c;这一机制在保证 POSIX 应用兼容性的同时&#xff0c;巧妙地引入实时功能&#xff0c;为开发人员在构建实时应用时提供了极大的灵活性和便利。 传统的 POSI…

作者头像 李华
网站建设 2026/4/16 10:42:25

LangFlow与知识图谱构建工具融合应用研究

LangFlow与知识图谱构建工具融合应用研究 在AI应用开发日益复杂的今天&#xff0c;如何快速构建可解释、高准确性的智能系统&#xff0c;成为企业与开发者共同面临的挑战。大语言模型&#xff08;LLM&#xff09;虽然在文本生成和语义理解上表现出色&#xff0c;但其“黑箱”特…

作者头像 李华
网站建设 2026/4/16 10:39:31

Qwen3-8B-AWQ生产部署安全与性能优化

Qwen3-8B-AWQ生产部署安全与性能优化 在企业级AI应用快速落地的今天&#xff0c;如何以合理的成本部署一个既安全又高效的对话模型&#xff0c;成为许多技术团队的核心命题。Qwen3-8B-AWQ正是在这个背景下脱颖而出&#xff1a;它用仅80亿参数&#xff0c;在保持接近FP16精度的同…

作者头像 李华
网站建设 2026/4/16 10:40:49

PyTorch分布式训练YOLO多卡加速配置

PyTorch分布式训练YOLO多卡加速配置 在工业质检、自动驾驶和智能监控等场景中&#xff0c;目标检测模型的训练效率直接决定了产品迭代速度。以YOLO系列为代表的实时检测模型虽然推理迅速&#xff0c;但随着数据量和模型规模的增长&#xff0c;单张GPU往往需要数天才能完成一轮完…

作者头像 李华
网站建设 2026/4/16 2:02:54

个人开发者游戏发行平台指南

作为个人游戏开发者,选择合适的发行平台对于游戏的成功至关重要。以下是国内主要面向个人开发者的H5和安卓游戏发行平台介绍,帮助您找到最适合自己作品的发布渠道。 1. Bilibili游戏中心 Bilibili游戏中心是国内知名的游戏发行平台,特别适合二次元风格和独立游戏。平台用户…

作者头像 李华