dsh-excalidraw-board
DSH Web GUI 画板插件:右上角一键打开全屏 Excalidraw 白板,直接嵌入官方原站,侧边栏感知不遮挡
- Stars
- 0
- Language
- JavaScript
- Created
- Aug 19, 2026
- Updated
- Aug 20, 2026
Introduction
dsh-excalidraw-board
让 DSH 拥有一个全功能的白板
右上角一键打开,直接嵌入官方 Excalidraw 原站
绘图 · 协作 · 素材库 · 导出 · 快捷键 —— 与独立浏览器访问完全一致
新用户? 从 安装 开始——两步注册,右上角立刻出现铅笔图标。
核心承诺:原站即功能。 不转码、不自托管、不加沙箱限制,iframe 里跑的就是 excalidraw.com 本体,官方怎么用,这里就怎么用。
运行效果
① 右上角入口 —— 会话窗口右上角(工具区最右)的铅笔图标,点击打开、再点关闭(浮层右上角的圆形 X 也可关闭):
| 状态 | 行为 |
|---|---|
| 侧边栏展开 | 画板从侧边栏右侧铺开,左侧会话列表完全可见可点,不遮挡 |
| 侧边栏折叠(56px rail) | 画板全屏铺满 |
| 打开期间拖拽侧边栏 | 画板左边缘每 250ms 自动跟随,实时调整 |
② Excalidraw 编辑器(浅色主题) —— 打开后即官方编辑器全貌:

③ Excalidraw 编辑器(深色主题) —— 与官方站点一致支持暗色模式:

④ 实际绘图效果 —— 手绘风格图形、箭头、文字标签、自由绘制,全部可用:

为什么直接嵌入原站
| 顾虑 | 结论 |
|---|---|
| 官方是否允许嵌入? | ✅ 允许。实测响应头无 X-Frame-Options、无 CSP frame-ancestors 拦截,且页面内置了 iframe 场景的适配代码(官方明确支持嵌入场景) |
| 功能是否完整? | ✅ 完全一致。iframe 加载同一 URL、同一份线上代码,零裁剪、零转码、零自托管 |
| 剪贴板 / 全屏 / 分享? | ✅ 显式授予 clipboard-read、clipboard-write、fullscreen、web-share、camera/microphone 等权限 |
| 会不会被沙箱限制? | ✅ 不加 sandbox 属性,不限制任何站点能力 |
| 版本更新? | ✅ 永远跟随官方最新版,无需维护本地副本 |
特性
来自 Excalidraw(官方原站能力,引用自 Excalidraw 官方 README)
| 能力 | 说明 |
|---|---|
| ✍️ 手绘风格 | 独有 hand-drawn 观感,图纸/线框/草图都好看 |
| 🎨 无限画布 | 基于 canvas 的无限大画板,缩放平移流畅 |
| ⚒️ 全工具集 | 矩形、圆形、菱形、箭头、直线、自由绘制、橡皮…… |
| ➡️ 箭头绑定 | 箭头吸附形状,带标签箭头 |
| 🔙 撤销 / 重做 | 完整历史栈 |
| 🔍 缩放与平移 | 滚轮缩放、抓手平移 |
| 😀 素材库 | 内建形状库 + 社区素材库 |
| 📷 图片支持 | 插入图片、调整裁剪 |
| 🖼️ 导出 | PNG / SVG / 剪贴板 / .excalidraw JSON 开放格式 |
| 🌓 深色模式 | 明暗主题一键切换 |
| 🌐 本地化 | 支持中文等 i18n |
| 📡 PWA | 离线可用(官方站点能力) |
| 🤼 实时协作 | 多人实时协作白板 |
| 🔒 端到端加密 | 协作内容端到端加密 |
| 💾 本地优先 | 自动保存到浏览器 |
| 🔗 分享链接 | 导出只读分享链接 |
本插件的 DSH 集成能力
| 能力 | 说明 |
|---|---|
| 右上角一键开关 | 铅笔图标 ⇄ X 图标,状态高亮(品牌色),悬停反馈 |
| 侧边栏感知 | 展开不遮挡、折叠全屏、拖拽实时跟随(250ms 轮询测量) |
| 全屏浮层 | shell.overlay 浮层 + 圆形 X 关闭按钮 |
| 主题自适应 | 按钮颜色走 DSH 主题 token,明暗主题自动适配 |
| 零侵入 | 全部注册在 replaceRisk: none 槽位,不替换任何原生 UI |
| 可卸载 | 停止插件即完全清理(样式、定时器、槽位注册全部随生命周期释放) |
安装
本插件是 DSH 静态 Client 模块(v0.2.0 起):随 DSH 启动自动加载,重启/升级不丢,无需每次 cordis_define。源码见 lib/client.js(静态版)与 lib/plugin.client.js(动态版,备选)。
方式 A:静态 Client 模块(推荐,自动加载、升级不丢)
-
安装包到 DSH 主 node_modules(部署根目录):
# 从 GitHub 安装 npm install --no-save CSlawyer1985/dsh-excalidraw-board # 或本地目录 npm install --no-save /path/to/dsh-excalidraw-board包内
package.json已声明dsh.client(platform: web),DSH 启动时自动把它编入window.__DSH_BOOT__条目,浏览器按需加载/plugins/dsh-excalidraw-board/client.js——无需本地构建。 -
在 DSH profile 的补丁层声明该行(如
~/.dsh/profiles/web/cordis.patch.yml):- insert: - id: ui-excalidraw-board name: 'dsh-excalidraw-board' -
重启 DSH(
dsh --profile web或你的启动命令)。重启后插件自动生效,此后升级 DSH 不再丢失。
方式 B:动态插件(备选,无需重启)
- 复制
lib/plugin.client.js中return { ... }的函数体; - 在 DSH 会话中调用
cordis_define(Client 代码粘贴到code.client),再cordis_run激活; - 批准运行后,右上角即出现铅笔图标。
注意:动态插件注册在进程内,DSH 重启后需要重新加载;静态模块方式无此限制,是本插件主推路径。
使用
- 点击会话右上角铅笔图标 → 画板打开(侧边栏展开时从侧边栏右侧开始铺开);
- 绘图、插入素材、协作、导出……与独立访问 excalidraw.com 完全一致;
- 再点右上角 X 图标(或浮层右上角圆形 X)→ 关闭画板。
实现方法
架构总览
DSH Web GUI(浏览器端)
│
├─ conversation.session.header.utilities 右上角开关按钮(铅笔 ⇄ X)
│ └─ 共享 store(open / sidebarLeft + 订阅)
├─ conversation.input.dock 0 尺寸测量元素(每 250ms 读 rect.left)
│ └─ 侧边栏右边缘 = 对话列左边缘
└─ shell.overlay 全屏浮层
├─ iframe → https://excalidraw.com/(权限全开,无 sandbox)
└─ 圆形 X 关闭按钮
核心机制
| 机制 | 实现 | 解决的问题 |
|---|---|---|
| 侧边栏感知 | 在对话列全宽行(conversation.input.dock)挂 0 尺寸隐藏元素,timer.interval 250ms 轮询 getBoundingClientRect().left,该值即侧边栏右边缘(DSH 布局常量:展开默认 280px / 可拖 264–420px,折叠 rail 56px) | 展开时不遮左侧栏,折叠时全屏 |
| 全屏浮层 | shell.overlay(root 级、点击穿透层,条目自行 opt-in pointer-events),position: fixed + 动态 left | 浮层永远盖在所有列之上、滚动容器之外 |
| 样式作用域免疫 | 全部样式走 React 内联 style(不依赖 styles.insert 类名选择器) | 浮层渲染在插件根作用域之外时样式不失效(v0.1.0 修复) |
| 状态共享 | apply 闭包内 store + 订阅集合,两个槽位组件通过 hook 同步 open / sidebarLeft | 按钮与浮层状态一致 |
| 生命周期 | 定时器、订阅、DOM 全部挂在 Cordis fiber 上,stop/undefine 自动清理 | 卸载无残留 |
| 权限全开 | allow="clipboard-read; clipboard-write; fullscreen; camera; microphone; display-capture; autoplay; encrypted-media; picture-in-picture; web-share; geolocation" + allowFullScreen | 剪贴板、全屏、分享、演示等与独立访问一致 |
目录结构
dsh-excalidraw-board/
├── lib/
│ ├── index.js # Host 半入口(空 apply)+ 元数据 + 动态版源码引用
│ ├── client.js # 静态 Client 模块(__ModuleLoader__.load 格式,主推)
│ └── plugin.client.js # 动态插件版源码(备选,可喂给 cordis_define)
├── docs/
│ ├── scene-demo.json # 效果图所用示例场景
│ ├── shot-excalidraw.js # 效果图生成脚本(headless Chrome + CDP)
│ └── screenshots/ # 运行效果插图
├── package.json # dsh.client 声明 + exports["./client"]
└── README.md
设计原则
- 原站即功能——不转码、不自托管、不加沙箱。官方站点允许嵌入(无 frame 拦截头),就用最忠实的方式嵌入。
- 零侵入——只注册
replaceRisk: none的增量槽位,不替换、不遮挡任何原生 UI。 - 感知优先——浮层位置由实时测量驱动,拖拽侧边栏、切换折叠均即时跟随,不依赖任何内部状态 API。
- 可逆——所有副作用(样式、定时器、订阅、注册)挂在插件生命周期上,卸载即完全清理。
- 内联优先——渲染在插件作用域之外的 UI 一律用内联样式,免疫作用域隔离。
迭代日志
| 日期 | 版本 | 类型 | 要点 |
|---|---|---|---|
| 2026-08-19 | v0.1.0 | 初始发布 | 右上角铅笔图标开关 + 全屏 iframe 嵌入 Excalidraw 原站 + 权限全开 |
| 2026-08-19 | v0.1.0 | 增强 | 侧边栏感知:展开不遮挡、折叠全屏、拖拽实时跟随(250ms 测量) |
| 2026-08-19 | v0.1.0 | 修复 | 浮层样式作用域失效(左上角小窗口)→ 全量改内联样式 |
| 2026-08-20 | v0.2.0 | 架构 | 改为静态 Client 模块(dsh.client 声明 + __ModuleLoader__.load),随 DSH 启动自动加载、重启/升级不丢;保留动态插件版为备选 |
许可证
MIT。Excalidraw 本体为 MIT 协议的开源项目(github.com/excalidraw/excalidraw),本站点为官方托管版本。