## 一、一次 UI 改动的标准路径

    改颜色/字号/间距   design/tokens/*.css 登记
                         │
                         ▼
            node design-pipeline/export-tokens.mjs
                         │（直写四端消费位置）
       ┌──────────┬──────┴──────┬──────────────┐
       ▼          ▼             ▼              ▼
    desktop    iOS Swift    Android Kotlin   官网 web/
    CSS 变量   DuduTheme    DuduTheme        tokens.css
    （直引源） （生成）      （生成）          （生成，含字体内嵌）

    改组件 / 图标      先在 design/ 登记（components/ + index.html 卡；
                       icons.js + icon-map.json）→ 再到各端实现
    提交               pre-commit 自动跑对应闸；CI 三道闸复验

核心原则（ds-flow）：设计决策只有一个出生地（design/），代码永远是镜像；绕过单源的行为由闸在提交/CI 时拦截。规则写了没上闸 = 没有规则。

## 二、真相源结构（design/）

路径 | 角色
--- | ---
`index.html` | 登记簿（活文档主页）：token 色板 / 组件卡 / 图标映射 / guidelines / ui_kits 单一入口。新元素必须在此登记（check-ds ④ 强制）。评审：`node design/serve.mjs`
`tokens/*.css` | 令牌单源：colors（含 --brand-wechat / --overlay-wave）/ typography / spacing / effects / fonts（Outfit 自托管，禁 CDN）
`icons.js + icon-map.json` | 图标单源（Lucide 线条 24 网格）+ 语义名→三端实现映射表；业务代码禁内联 <path>
`components/`（core/forms/voice） | 参考组件（React），桌面端直接运行时消费；Icon.jsx 渲染 icons.js
`ui_kits/`（desktop/mobile） | 屏级交互原型（新屏 design-first 的出生地）
`guidelines/*.card.html` | 规范卡（品牌/色板/字体/间距/动效）
`readme.md / SKILL.md` | 设计基调、文案基调、视觉硬规则；agent 使用入口
`_ds_manifest.json` | Claude 设计导出的机读清单——非权威、可能滞后，真相以 tokens/ 与登记簿为准

## 三、五端消费方式对照

端 | 技术栈 | 令牌 | 组件/图标
--- | --- | --- | ---
桌面 Mac/Win | Tauri 2 + React | vite alias `@dudu/design` 直引 tokens CSS（无生成层） | 直接 import design/components；Icon 组件渲染 icons.js
iOS | SwiftUI | `ios/dudu/Shared/DuduTheme.swift`（codegen 直写） | SF Symbols，须 ∈ icon-map ios 列（check-code 同集闸）
Android | Compose | `DuduTheme.kt`（codegen 直写）→ `DuduPalette` CompositionLocal | 暂无图标使用；启用后同集闸生效
官网 | 静态单页 | `web/tokens.css`（codegen：custom props + Outfit data URI） | 页面只允许 var(--*)；深色板块挂 `data-theme="dark"` 复用 dark 令牌
原型自身 | React（浏览器内 Babel） | styles.css @import tokens | 与桌面同一套组件源码

codegen 直写消费位置（2026-07-11 改）：此前生成到 design-pipeline/generated/ 再手工拷贝进 app，`--check` 守不到真实文件、拷贝已漂移。现直写 + CI 校验真实消费文件，漂移类型整个消除。

## 四、各道闸全景

闸 | 拦什么 | 何时跑
--- | --- | ---
`check-ds.mjs` 真相源自检（7 道） | ① dark 孤儿 token ② var() 断链/@import 缺失 ③ design/ 内裸色 ∉ tokens 值集 ④ 组件未登记登记簿 ⑤ icons.js 重复 key/填充色 ⑥ icon-map ↔ icons.js 双向不同集 ⑦ 界面文案 emoji | pre-commit（动 design/）+ CI
`export-tokens.mjs --check` | 四端令牌产物与源不一致（改了 tokens 忘 regen / 手改生成文件） | pre-commit（动 design/）+ CI
`check-code.mjs` 代码侧单源（四端） | desktop 字面色/内联 <path>；iOS 字面色/未登记 SF Symbol；Android Color(0x；web 字面色 | pre-commit（动端代码）+ CI

### 豁免机制

- 行级 `ds-ignore: 理由` 注释——必须写理由（mac 红绿灯窗饰、手机外壳装饰、alpha 派生色等）
- codegen 产物（DuduTheme.*、web/tokens.css）自动豁免

### 启用

    # 一次性（每个 clone）
    git config core.hooksPath .githooks

    # 手动全量
    node design-pipeline/check-ds.mjs && node design-pipeline/export-tokens.mjs --check && node design-pipeline/check-code.mjs

## 五、三层分治规则（L1 / L2 / L3）

层 | 规则
--- | ---
L1 设计系统元素 颜色/字号/间距/组件/图标 | 先登记 design/（tokens / components+登记簿 / icons+map）再写端代码，无例外。闸强制。
L2 屏级 | 屏以 ui_kits 原型为基准；小迭代直改代码但不得引入 L1 违规（闸兜底）；整屏改版原型先行。
L3 新屏 | design-first：ui_kits 加屏（serve.mjs 起服务给 URL 评审，不截图）→ 各端实现 → 登记。

## 六、已知滞后与后续项

- todo #26桌面 fidelity 像素闸（Playwright 截 ui_kits 原型 vs Tauri 页面 pixelmatch）——静态闸先行，像素级验收后续补
- 待治理ui_kits 预览页经 unpkg CDN 加载 React/Babel，离线/无代理网络不可用（评审时需网络；可选改为 vendor 本地化）
- 说明_ds_manifest.json 为 Claude 设计导出产物，未纳入闸；以 tokens/ 与登记簿为权威
- 说明移动端不做跨渲染器像素比对（字体度量漂移大，jiu 教训）；iOS/Android 一致性由 token codegen + 同集闸保障