---
name: dwy-whiteboard-prototype
description: "用 HTML 白板（FigJam/draw.io 风格）画可交互 UI 原型。触发场景：用户说『画原型 / 出原型 / 画白板 / 原型图 / 做个原型 / prototype / 把某页面的各种状态画出来 / 把这几个页面的跳转画清楚』，或要在动手写 UI 代码前先验证页面与交互流程时。产出：每个页面一个 HTML 白板文件，画布二维摆放、SVG 连线表达跳转、左侧导航在白板间切换、右侧标注写交互与边界。这是项目原型的标准做法，画 iOS/移动端页面原型时务必用本 skill，别另起炉灶手搓样式与交互引擎。"
---

# 白板原型（HTML 可交互）

把页面与交互流程画成「白板」：每个页面一个 HTML 文件，文件内把该页面的**所有状态**（默认/空态/加载/错误/禁用…）摆成二维画布，用 SVG 连线表达状态间跳转，左侧固定导航在不同页面白板间切换。

**这套原型是雏形/脚手架**——目的是先把页面齐、状态全、跳转流程理清、交互无 bug，给后续 UI 设计打底。所以重点在覆盖与流程正确，**不必纠结像素级视觉**。图标用稳定图标库（SF Symbols 风格的字符/内联 SVG）占位，**不用 emoji 作功能性图标**。

## 起步：复制模板，别手搓引擎

`assets/template.html` 已含整套白板引擎（平移缩放、SVG 连线、选中高亮、复位展示、左侧导航、拖拽防误触）。**画新原型时复制它，只改三处**：

1. **画布区**（`.stage` 列表）——每个状态一个画布
2. **`EDGES`**（脚本顶部）——声明白板内状态跳转，决定画哪些连线
3. **左侧 `.sidenav`**——把当前页设 `.on`，其余指向对应白板 html

引擎部分（`drawWires`/`select`/`focusOn`/拖拽缩放/`fitAll`）**不要改、不要重写**——这些是反复调试过的，重写极易引入下面「交互铁律」里踩过的坑。

## 组织：按「页面」划分白板

- **一个页面 = 一个 HTML 文件**（如 `connect-spec.html` `home-spec.html`）。文件内放该页面的**全部状态变体**，每个状态一个画布。
- 不要把多个并列功能塞一个白板——页面多了会糊成网格图、画布爆炸。模块间的关系交给左侧导航和跨白板跳转。
- **左侧导航按用户旅程顺序排页面**（例：引导页 → 首页 → 连接页 → 功能页），不是按技术依赖。每个白板的导航内容一致，只有「当前页」标记不同。
- 一个**总览页** `index-spec.html` 串各页入口（卡片 + 链接下钻到各白板）。
- 文件统一放 `docs/prototypes/`，命名 `<页面>-spec.html`。

## 每个画布的结构

左 `.phone`（设备框，内 `.screen` 放 UI）+ 右 `.spec` 标注栏。`.stage` 用 `data-id`（唯一）、`data-x`/`data-y`（白板坐标，列距约 760、行距约 820）；`.canvas-no` 的 `id` 必须 = `data-id`（选中靠它）。

**设备尺寸按目标端定**（不写死）：模板 `.phone` 默认 320×680，复制后**按产品目标端改 `.phone` 的 `width`/`height`**——iOS 用 iPhone 逻辑尺寸（如 390×844）、鸿蒙用对应 vp 尺寸、iPad/平板/Web 用各自真实比例。列距/行距随之放宽以免画布重叠。

**标注栏三段式**（这是原型的核心价值，别省）：

- **用途**：一句话讲清这个页面/状态的职责。
- **交互跳转**：点哪 → 去哪。白板内跳转用 `<a class="jump" data-go="目标id">`；跨白板跳转用 `<a class="xjump" href="目标-spec.html">`（绿色 ↗ 标识）。
- **边界处理**：雏形阶段最该写全的部分——单行文字截断、空态、加载态、禁用态、错误态、超时兜底等，按该状态适用项列。

付费/受限操作：按钮旁加 `<span class="pill lock">PRO</span>`，标注栏加「付费」段（`.gt.pay`），按需。

## 交互铁律（踩过的坑，务必遵守）

这些是反复迭代修出来的，模板已实现；自己改引擎或写新交互时不要违背：

- **编号 = 选中入口，画框不选中**。只有点 `.canvas-no`（编号标题）才选中并「复位展示」。画框本身不响应选中——否则点画框空白、点画框内按钮都容易误触出 bug。
- **按钮 = 跳转**。画框内可点元素用 `data-go="目标id"` 做白板内跳转（点了 select + 复位展示）；跨白板跳转用 `<a href>`。
- **可点元素不启动拖拽**。`pointerdown` 里 `if(e.target.closest('input,a,[data-go],.canvas-no'))return`。原因：真实鼠标点击带几像素抖动，若任意位置都进入拖拽判定，点击会被 `moved` 判成拖拽而吞掉——曾导致「点编号不高亮、点按钮不跳转」。这是最隐蔽的坑，务必保留。
- **复位展示让目标看清**。跳转/选中后调 `focusOn(id)`：缩放到单画布刚好填满视口 + 居中，不管之前缩放多小都清晰。别只 `centerOn`（保持原缩放会看不清）。
- **连线从画框边缘进出**，不从中心（否则被框体盖住像断的）。`edgeAnchor` 已实现选最近边 + 贝塞尔曲线 + 箭头 + 中点标签。
- **禁文本选中**：`body{user-select:none}` + `input{user-select:text}`，拖拽不选中画框文字。
- **单行截断**：`white-space:nowrap;overflow:hidden;text-overflow:ellipsis` + 父级 `min-width:0`（省略号生效前提）。列表项必带。

## 视觉 token

**配色按产品定位推荐，只换色板、不动结构。** 模板 `:root` 是一套**语义变量架构**（`--gold` 主色 / `--device` 背景 / `--surface*` 分层 / `--red`/`--green`/`--pro` 等），默认填的是深色蓝调一套可跑值。复制后**按产品定位重填这些变量的色值 + 明/暗调**：金融稳重、社交活泼、工具中性——AI 自行判断给配色方案。

只换**色值**，`:root` 的变量名、圆角、阴影、间距、质感等**结构不动**（引擎和样式都引用这些变量名，改名会断）。纯系统字体 `-apple-system,"PingFang SC"`，**零外部字体依赖**（符合本地纯客户端定位，也避免离线打不开）。

## 产出后自检

用本地 http 服务打开（`python3 -m http.server`，注意 `?v=` 破缓存），确认：
- 各画布定位正确、连线带箭头无坐标错误（`NaN`）；
- 点编号 → 高亮 + 复位展示；点画框内按钮/标注 jump → 白板内跳转；点跨白板链接 → 切文件；
- 拖拽空白处平移、滚轮缩放正常；点画框空白处不误选中；
- 列表超长文字省略号截断不撑破。

新增页面白板后，记得在 `index-spec.html` 和各白板左侧导航里补上入口。
