Files
hms/docs/superpowers/specs/2026-05-17-design-handoff-skill-design.md
iven 3aa71a94d2 docs(skills): design-handoff 设计稿 + spec + .gitignore 更新
- mp-11-doctor-core 设计交付包(截图 + tokens)
- mp-13/mp-14 新原型 HTML
- design-handoff skill 设计规格文档
- .gitignore 排除 dist-h5/test-results/uploads 等构建产物
2026-05-18 02:13:29 +08:00

32 KiB
Raw Blame History

design-handoff Skill 设计规格

日期: 2026-05-17 | 状态: 草案 问题: HTML 原型到实际实现的翻译层缺失,新会话 LLM 无法高保真还原原型设计 方案: 结构化交付包(截图 + SPEC.md + Token 映射)

目录

  1. 背景与问题 — 现状分析、核心矛盾、解决目标
  2. Skill 架构 — 触发方式、输入输出、核心流程
  3. SPEC.md 核心格式 — 页面结构、组件映射、交互规格的文档模板
  4. Token 映射系统 — 混合匹配算法、配置文件、产出格式
  5. 截图提取与交互推断 — Playwright 截图、交互规则引擎
  6. 多平台支持与集成 — 多平台映射、huashu-design 协作、Prompt 模板

1. 背景与问题

1.1 现状

项目使用 huashu-design skill 产出 HTML 原型稿React inline styles + 设计 Token 对象 T)。目前已有 20 个原型文件docs/design/mp-*.html),覆盖小程序访客端、患者端、医生端全部页面。

实施时的工作流是:

  1. 会话 A:调用 huashu-design → 选定设计风格 → 扩展到所有页面原型
  2. 会话 B(新会话):拿 HTML 原型实现 Taro/React 组件代码

1.2 核心矛盾

会话 B 的 LLM 与会话 A 完全隔离,丢失了所有设计上下文。三层翻译丢失:

丢失层 原因 表现
视觉丢失 LLM 读 HTML 源码,看不到渲染结果 颜色、字号、间距与原型不一致
Token 断裂 原型用 #C4623A,代码用 var(--tk-pri) 映射关系丢失,硬编码泛滥
组件错配 原型全是 <div style={...}>,代码要用组件库 应复用 ContentCard/PageShell 但没复用
交互缺失 原型暗示的按压反馈、滑动、状态切换无文档化 交互行为被忽略

1.3 解决目标

创建 design-handoff skill在 HTML 原型完成后自动产出结构化交付包,让新会话的 LLM 能:

  • 看到原型渲染效果(截图)
  • 知道每个值对应哪个项目 Token映射表
  • 选用正确的现有组件(组件映射)
  • 实现原型暗示的交互(交互规格)

2. Skill 架构

2.1 触发方式

# 单个原型
/design-handoff docs/design/mp-00-visitor.html

# 批量处理
/design-handoff docs/design/mp-*.html

# 指定平台
/design-handoff docs/design/mp-00-visitor.html --platform web

触发词design-handoff设计交付handoff

2.2 输入

参数 必需 默认值 说明
HTML 文件路径 原型文件路径,支持 glob
--platform miniprogram 目标平台miniprogram / web / h5
--tokens .design/tokens.yml Token 映射配置文件路径

2.3 输出目录结构

docs/design/
├── mp-00-visitor.html                  # 原始原型(不修改)
├── mp-00-visitor/                      # 交付包目录
│   ├── SPEC.md                         # 主规格文件LLM 消费入口)
│   ├── screenshots/                    # 截图目录
│   │   ├── home.png
│   │   ├── home-slide-1.png
│   │   ├── home-slide-2.png
│   │   ├── home-slide-3.png
│   │   └── profile.png
│   ├── tokens.json                     # Token 映射表(机器可校验)
│   └── META.yml                        # 元数据
├── mp-01-login/
│   └── ...
└── .design/                            # 全局配置(项目级)
    └── tokens.yml                      # Token 映射配置

2.4 核心流程

输入: HTML 原型文件
  │
  ├─ Step 1: 解析 HTML ──────────────────────┐
  │   提取 T 对象Token 引用)                │
  │   提取组件树(页面结构)                    │
  │   识别 IosFrame 实例(截图目标)            │
  │                                           │
  ├─ Step 2: 截图提取 ───────────────────────┤
  │   Playwright 打开 HTML                     │
  │   逐 IosFrame 截图                         │
  │   裁剪设备框,保留屏幕内容                   │
  │                                           │
  ├─ Step 3: Token 匹配 ─────────────────────┤
  │   优先级 1: 别名直查aliases              │
  │   优先级 2: 值精确匹配                      │
  │   优先级 3: 色彩模糊匹配ΔE < 3          │
  │   产出 tokens.json                         │
  │                                           │
  ├─ Step 4: 组件映射 ───────────────────────┤
  │   原型元素 → 项目组件库匹配                  │
  │   标记需新建的组件                          │
  │                                           │
  ├─ Step 5: 交互推断 ───────────────────────┤
  │   DOM 模式 → 交互规则匹配                   │
  │   高/中/低置信度分级                        │
  │                                           │
  └─ Step 6: 组装 SPEC.md ───────────────────┘
      截图 + 结构 + Token + 组件 + 交互
      → 单一规格文档

2.5 Skill 文件清单

.claude/skills/design-handoff/
├── SKILL.md                         # Skill 入口
├── scripts/
│   ├── extract-screenshots.mjs      # Playwright 截图
│   ├── parse-prototype.mjs          # HTML 解析T 对象 + 组件树)
│   ├── match-tokens.mjs             # Token 三层匹配
│   └── infer-interactions.mjs       # 交互推断规则引擎
├── templates/
│   └── spec-template.md             # SPEC.md 模板
├── defaults/
│   └── tokens.yml                   # 初始 Token 配置
└── rules/
    └── interaction-rules.yml        # 交互推断规则表

前置依赖

  • Node.js ≥ 18运行 .mjs 脚本)
  • Playwright截图提取huashu-design 已依赖,无需额外安装)
  • 项目需包含 styles/tokens.scss 或等效的 Token 定义文件

3. SPEC.md 核心格式

SPEC.md 是 LLM 在新会话里消费的唯一入口文件。设计原则:

  • 自包含:截图通过 markdown 图片引用内嵌,一个文件看全貌
  • 结构化六个固定章节LLM 可按需定位
  • 可操作:每个值都映射到项目 Token 或组件,不含模糊描述

3.1 文档结构(六个固定章节)

# {页面名称} 设计规格

> 来源: {原型文件名} | 平台: {platform} | 页面数: {n}

## 页面索引
(截图缩略图 + 路由映射表)

## 一、Token 映射
(原型值 → 项目 Token含匹配状态标记

## 二、页面结构
(逐页:截图 + 布局层级描述 + 尺寸标注)

## 三、组件映射
(原型元素 → 项目组件库组件,含来源路径)

## 四、交互规格
(元素 × 交互类型 × 触发 × 反馈 × 备注)

## 五、状态变体
(加载中 / 空数据 / 错误 / 已登录等边界状态)

## 六、样式清单
(间距 / 字号 / 圆角 / 阴影的 Token 汇总)

3.2 页面索引

用表格关联截图与路由LLM 一眼定位:

## 页面索引

| 页面 | 截图 | 路由 |
|------|------|------|
| 访客首页 | ![home](./screenshots/home.png) | pages/index/index |
| 访客"我的" | ![profile](./screenshots/profile.png) | pages/profile/index |

3.3 Token 映射章节

三级状态标记LLM 知道哪些可以直接用:

标记 含义 LLM 行为
confirmed 已确认映射 直接使用对应 Token
⚠️ pending 模糊匹配,待确认 使用但需人工复核
unmatched 无匹配 硬编码或新建 Token
## 一、Token 映射

| 原型值 | 项目 Token | 状态 |
|--------|-----------|------|
| #C4623A (T.pri) | var(--tk-pri) | ✅ |
| #F5F0EB (T.bg) | var(--tk-bg-base) | ✅ |
| 32px (轮播标题) | var(--tk-font-h1) | ⚠️ 待确认28→32 不匹配) |
| serif 字体 | — | ❌ 无 Token硬编码 font-family |

3.4 页面结构章节

每个页面一个子节,以截图开头,紧跟布局层级:

### 2.1 访客首页

![首页全貌](./screenshots/home.png)

布局层级(从上到下):

1. **轮播区域** (height: 280px)
   - 容器: `<Swiper>` (Taro)autoplay + circular
   - 3 张品牌轮播:渐变背景 + 装饰圆 + 标题文案 + 指示点
   - 指示点: 活跃 24×4 白色,非活跃 8×4 半透明白

2. **健康资讯** (padding: 20px → var(--tk-gap-lg))
   - 标题行: SectionTitleserif 18px bold + "更多›"
   - 文章卡片 ×2: ContentCard variant="default"
     - 左侧配图 110px 宽,右侧标题 15px + 摘要 13px

3. **登录引导** (padding: 28px 20px 40px)
   - CTA: PrimaryButton size="large",阴影 var(--tk-shadow-btn)

每个元素标注:用什么组件 + 尺寸/间距的 Token 引用 + 视觉特征

3.5 组件映射章节

表格形式,明确"用哪个组件"

## 三、组件映射

| 原型元素 | 推荐组件 | 来源 | 备注 |
|----------|---------|------|------|
| 文章卡片 | ContentCard | @components/ui/ContentCard | variant="default" |
| 区块标题 | SectionTitle | @components/ui/SectionTitle | action="更多›" |
| CTA 按钮 | PrimaryButton | @components/ui/PrimaryButton | size="large" |
| 页面容器 | PageShell | @components/ui/PageShell | padding="md" safeBottom |
| 功能卡片 | — | 需新建 | 3 列等宽圆形图标卡片 |
| 轮播 | Swiper | @tarojs/components | autoplay circular |
| TabBar | Taro TabBar | 框架配置 | 原型不实现 |

来源列使用 @components/ 前缀LLM 可直接 import。"需新建"标记让 LLM 知道这个需要从头写。

组件映射推断规则H4 修复)

组件映射通过 DOM 结构特征推断,规则定义在 skill 中:

原型 DOM 特征 推断组件 匹配依据
容器 + borderRadius + boxShadow + 内含标题+正文 ContentCard 卡片结构
容器 + 左侧竖线装饰 + 标题文本 + 可选右侧链接 SectionTitle 区块标题结构
按钮 + 主色背景 + 白色文字 + 高度 44-56px PrimaryButton CTA 按钮特征
按钮 + 边框 + 透明背景 SecondaryButton 次按钮特征
页面最外层容器 + padding + 滚动 PageShell 页面壳结构
圆形小容器 + 内含数字/文字 + 配色背景 StatusTag 标签/徽章
列表行 + 左图标 + 中间双行文字 + 右箭头 ListItem 列表项结构
未匹配上述任何规则 — (需新建) 标记为"需新建"

推断失败时默认标记为"需新建",不强制匹配错误组件。

3.6 交互规格章节

五列表格,覆盖触发 → 反馈 → 生命周期:

## 四、交互规格

| 元素 | 交互 | 触发 | 反馈 | 备注 |
|------|------|------|------|------|
| 轮播 | 自动播放+滑动 | 页面显示 | 3s 切换 | useDidShow 启动useDidHide 暂停 |
| 文章卡片 | 点击跳转 | onPress | activeFeedback="bg" | 跳转文章详情 |
| CTA 按钮 | 点击登录 | onPress | loading 态 | 跳转登录页 |
| 功能卡片 | 点击跳转 | onPress | opacity 反馈 | 各卡跳不同服务页 |
| 资讯区域 | 下拉刷新 | onPullDownRefresh | — | 无数据时显示功能引导 |

3.7 状态变体章节

覆盖边界场景,避免实现时遗漏:

## 五、状态变体

- **无数据**: 资讯为空 → 显示功能引导卡片3 个固定入口)
- **加载中**: LoadingCard layout="card" count=2
- **已登录**: 自动跳转 HomeDashboard不由本页处理
- **网络错误**: ErrorState + onRetry 重新加载

3.8 样式清单章节

Token 维度的汇总,便于 LLM 快速查表:

## 六、样式清单

间距: 页面 padding 20px (--tk-gap-lg), 卡片 padding 16px (--tk-gap-md)
字号: 标题 18px (--tk-font-nav), 正文 15px (硬编码), 摘要 13px (--tk-font-cap)
圆角: 卡片 16px (--tk-card-radius), 按钮 14px (--tk-radius-lg)
阴影: 卡片 (--tk-shadow-sm), 按钮 (--tk-shadow-btn)

4. Token 映射系统

4.1 全局配置文件

项目级配置 .design/tokens.yml,所有原型共享。首次运行自动生成,从项目代码库扫描:

  • styles/tokens.scss → CSS 运行时 Token--tk-*
  • styles/variables.scss → SCSS 编译时变量($pri, $r 等)

生成后可手动微调,后续运行直接读取。

配置文件结构分为五个 Token 类别 + 一个别名映射区:

# .design/tokens.yml

version: 1
updated: 2026-05-17

# 色彩 Token — 从 tokens.scss 中 --tk-pri 等提取
colors:
  - token: --tk-pri
    value: "#C4623A"
  - token: --tk-pri-l
    value: "#F0DDD4"
  # ...

# 字号 Token — 从 tokens.scss 中 --tk-font-* 提取
typography:
  - token: --tk-font-h1
    value: "28px"
    note: 页面标题 serif bold
  # ...

# 间距 Token — 从 tokens.scss 中 --tk-gap-* 提取
spacing:
  - token: --tk-gap-md
    value: "16px"
  # ...

# 圆角 Token — 从 tokens.scss 中 --tk-card-radius 等提取
radius:
  - token: --tk-card-radius
    value: "16px"
  # ...

# 阴影 Token — 从 tokens.scss 中 --tk-shadow-* 提取
shadow:
  - token: --tk-shadow-sm
    value: "0 1px 4px rgba(45,42,38,0.04)"
  # ...

# 原型 Token 别名 — 手动或自动积累的映射
aliases:
  prototype_keys:
    T.pri: --tk-pri
    T.priL: --tk-pri-l
    T.bg: --tk-bg-base
    T.card: --tk-bg-card
    T.r: --tk-card-radius
    T.rSm: --tk-radius-sm
    # ...

4.2 三层匹配算法

从原型 HTML 中提取的每个 Token 引用,按以下优先级匹配:

优先级 1: 别名直查
  原型中 T.pri → 查 aliases.prototype_keys → --tk-pri ✅
  预估覆盖率: 最高(已有 aliases 的常用 Token
  特点: 零歧义,直接确认

优先级 2: 值精确匹配(按 CSS 属性上下文消歧)
  原型中 #C4623A → 仅在 colors 类别中查找 → --tk-pri ✅
  原型中 borderRadius: 16px → 仅在 radius 类别中查找 → --tk-card-radius ✅
  原型中 padding: 16px → 仅在 spacing 类别中查找 → --tk-gap-md ✅
  预估覆盖率: 中等(值恰好一致的 Token
  特点: 按 CSS 属性类别过滤,避免同值多 Token 歧义

优先级 3: 色彩模糊匹配(仅颜色类)
  原型中 #C4623B → 与 colors 中各值算色差 ΔE
  ΔE < 3 → 视为近似色 → ⚠️ pending 待确认
  预估覆盖率: 较低(设计迭代中微调的色值)
  特点: 仅限色彩,必须人工确认

未匹配: ❌ unmatched
  无任何匹配结果
  需人工决定: 新建 Token / 硬编码 / 忽略

值归一化规则M4

  • "16px""16" 视为相同(去除 px 后缀比较数值)
  • "#C4623A""c4623a" 视为相同(大小写不敏感)
  • 不支持 rem/em 转换,遇此单位标记为 pending

4.3 首次运行流程

/design-handoff docs/design/mp-00-visitor.html

Step 0: 格式校验C3 弹性检查)
  - 检查文件是否为合法 HTML
  - 检查是否包含 React/Babel 脚本标签huashu-design 特征)
  - 检查是否包含 T 对象定义const T = { ... }
  - 任何检查失败 → 输出清晰错误信息并终止
    - 缺少 T 对象: "未检测到设计 Token 对象 (T),请确认是否为 huashu-design 产物"
    - 缺少 React: "未检测到 React 渲染环境,无法解析原型"

Step 1: 检查 .design/tokens.yml
  → 不存在: 自动扫描项目 SCSS 文件生成
    - 解析 tokens.scss → 提取所有 --tk-* 变量及值
    - 解析 variables.scss → 提取所有 $ 变量及值
    - 生成 .design/tokens.yml
  → 存在: 直接使用

Step 2: 解析 HTML 中的 TokenC2 提取方式)
  方式: 静态解析 T 对象定义 + 内联 style 值
  - 用正则匹配 "const T = { ... }" 提取完整对象定义
  - 解析 T 对象的每个 key-value 对(如 T.pri: '#C4623A'
  - 扫描内联 style 中的硬编码值: fontSize, padding, borderRadius 等
  - 不依赖 React 运行时,纯文本解析
  - 值归一化规则: "16px" 和 "16" 视为相同; 不支持 rem/em 转换

Step 3: 三层匹配
  - 匹配时按 CSS 属性上下文消歧H1 修复)
    - borderRadius / radius 相关属性 → 只匹配 radius 类别 Token
    - padding / margin / gap → 只匹配 spacing 类别 Token
    - fontSize / fontWeight → 只匹配 typography 类别 Token
    - color / background → 匹配 colors 类别 Token
  - 如果同值多 Token 且无属性上下文 → 标记为 ⚠️ pending
  - 产出 tokens.json

Step 4: 处理未确认项
  - pending + unmatched 项在终端列表展示
  - 用户确认后更新 aliases
  - 后续原型自动复用已确认的映射

4.3.1 .design/ 目录管理

  • .design/ 目录提交到 gittokens.yml 是团队共享的项目级配置)
  • .design/config.yml(个人偏好配置,如 auto_handoff可加入 .gitignore
  • 首次生成 tokens.yml 后建议立即提交,作为团队基线

4.4 产出文件 tokens.json

{
  "source": "mp-00-visitor.html",
  "platform": "miniprogram",
  "generated": "2026-05-17T10:30:00Z",
  "tokens": {
    "T.pri": {
      "value": "#C4623A",
      "mapped": "var(--tk-pri)",
      "match": "alias",
      "status": "confirmed"
    },
    "fontSize:32": {
      "value": "32px",
      "closest": "var(--tk-font-h1)",
      "closestValue": "28px",
      "match": "fuzzy",
      "status": "pending",
      "note": "原型 32px vs 最近 Token 28px (--tk-font-h1),差 4px"
    },
    "T.serif": {
      "value": "Georgia, 'Times New Roman', serif",
      "mapped": null,
      "match": "none",
      "status": "unmatched",
      "note": "项目无字体族 Token需硬编码或新建"
    }
  },
  "summary": {
    "total": 18,
    "confirmed": 13,
    "pending": 2,
    "unmatched": 3
  }
}

字段说明

字段 说明
value 原型中的原始值
mapped 匹配到的项目 Tokennull 表示未匹配)
match 匹配方式alias / exact / fuzzy / none
status 状态confirmed / pending / unmatched
note 补充说明(模糊匹配的差异原因等)

4.5 映射积累效应

每次运行 /design-handoff 并确认 pending 项后,映射自动写入 aliases

第 1 次运行: 13 confirmed + 2 pending + 3 unmatched
  → 确认 2 个 pending → aliases 新增 2 条
第 2 次运行: 15 confirmed + 1 pending + 2 unmatched
  → 确认 1 个 pending → aliases 新增 1 条
第 N 次运行: 18 confirmed + 0 pending + 0 unmatched
  → 全部自动匹配,无需人工干预

随着项目推进,手动确认越来越少,最终趋近全自动。


5. 截图提取与交互推断

5.1 截图提取

5.1.1 提取流程

使用 Playwrighthuashu-design 已内置 verify.py 依赖 Playwright

1. Playwright 启动浏览器,打开 HTML 原型文件
2. 等待 React + Babel 渲染完成(检测 #root 内有子元素)
3. 遍历所有 IosFrame 实例,逐个截图
4. 裁剪设备框12px padding + 54px 状态栏 + 34px 底部指示器)
5. 输出到 screenshots/ 目录

5.1.2 IosFrame 定位规则

原型 HTML 中 screen-labelIosFrame兄弟节点,不是父子关系:

<div class="screen-wrap">
  <span class="screen-label">访客首页 — 完整页</span>  <!-- 兄弟节点 -->
  <IosFrame time="9:41" battery={85}>                   <!-- 兄弟节点 -->
    <GuestHome />
  </IosFrame>
</div>

定位方式:

1. 查找所有 class="screen-wrap" 的容器
2. 每个容器内:
   - <span class="screen-label"> 的文本 → 截图文件名
   - <IosFrame> 实例 → 截图目标
3. 如果容器无 screen-label → 使用序号命名 (screen-1.png, screen-2.png)

如果原型未使用 screen-wrap + IosFrame 结构,进入降级方案(见 5.1.4)。

5.1.3 文件命名规则

规则 示例
使用 screen-label 文本 访客首页 — 完整页home.png
轮播编号保留 访客首页 — 轮播 1home-slide-1.png
中文翻译为英文简写 我的profile, 登录login
同名页面加序号 home-2.png, home-3.png

翻译映射表内置在 skill 中(覆盖项目已有的 20 个原型中出现的所有中文标签)。

5.1.4 降级方案

当原型未使用 IosFrame 时(如早期部分原型或 Web 端原型):

  1. 整页截图:截取完整渲染页面
  2. 手动标注:用户通过 --crop "x,y,w,h" 参数指定裁剪区域
  3. CSS 选择器:通过 --selector ".screen-content" 指定截图目标

5.2 交互推断

5.2.1 推断策略

从原型 HTML 的 DOM 结构推断交互行为。不做运行时分析,纯静态代码模式匹配。

推断规则存储在 rules/interaction-rules.yml 中,按 DOM 模式匹配。

5.2.2 内置规则表

# rules/interaction-rules.yml

rules:
  - id: swiper-autoplay
    name: 自动轮播 + 手动滑动
    patterns:
      - "连续多个子元素含渐变背景 + 底部指示点(宽窄交替)"
      - "Swiper / swiper / carousel 关键词"
    infer:
      interaction: "自动播放 + 手动滑动"
      trigger: "页面显示"
      feedback: "3s 间隔自动切换"
      lifecycle: "useDidShow 启动useDidHide 暂停"
    confidence: high

  - id: card-tap
    name: 卡片点击跳转
    patterns:
      - "卡片容器含标题+摘要+配图"
      - "onClick / onPress 事件"
    infer:
      interaction: "点击跳转"
      trigger: "onPress"
      feedback: "activeFeedback 按组件类型自动选择"
    confidence: high

  - id: form-submit
    name: 表单提交
    patterns:
      - "输入框 + 按钮在同一容器内"
      - "input / textarea + button 组合"
    infer:
      interaction: "表单提交"
      trigger: "onPress按钮"
      feedback: "loading 态 + 禁用重复提交 + 错误提示"
    confidence: high

  - id: list-scroll
    name: 列表滚动加载
    patterns:
      - "列表容器含多个重复结构子元素"
      - "overflow: auto / scroll"
      - "3 个以上同类卡片连续排列"
    infer:
      interaction: "下拉刷新 + 上拉加载"
      trigger: "onPullDownRefresh / onReachBottom"
      feedback: "分页加载"
    confidence: medium

  - id: tab-switch
    name: 标签页切换
    patterns:
      - "多个平行区域 + 选中态样式差异"
      - "tab / segment / filter 关键词"
      - "一组按钮样元素,其中一个高亮"
    infer:
      interaction: "标签页切换"
      trigger: "onPresstab 项)"
      feedback: "选中态样式切换 + 内容区切换"
    confidence: high

  - id: static-decoration
    name: 静态装饰
    patterns:
      - "渐变背景 + 装饰圆/波浪/几何图形"
      - "无事件绑定"
      - "position: absolute + opacity < 1"
    infer:
      interaction: "无(纯装饰)"
      trigger: "—"
      feedback: "—"
    confidence: high

  - id: login-cta
    name: 登录/注册 CTA
    patterns:
      - "按钮含 '登录' / '注册' / '立即' 文案"
      - "主色按钮 + 阴影"
    infer:
      interaction: "点击触发登录流程"
      trigger: "onPress"
      feedback: "PrimaryButton loading 态"
      guard: "GuestGuard 拦截未登录态"
    confidence: high

  - id: empty-fallback
    name: 空数据降级
    patterns:
      - "条件渲染: data.length > 0 ? ... : ..."
      - "占位符文字 '暂无' / '空'"
      - "硬编码的固定内容(非 API 数据)"
    infer:
      interaction: "无数据时显示替代内容"
      trigger: "数据加载完成且为空"
      feedback: "EmptyState 组件或固定引导卡片"
    confidence: medium

5.2.3 置信度分级

级别 阈值 处理方式
high (≥80%) 结构明确,模式唯一 直接写入 SPEC.md 交互规格表
medium (50-80%) 结构合理但有歧义 写入交互规格表,标注 ⚠️ 待确认
low (<50%) 模式模糊,可能是静态 不写入交互规格,末尾单独列出 ## 待人工补充的交互

5.2.4 推断结果示例

mp-00-visitor.html 的推断输出:

元素 推断交互 置信度 来源规则
轮播区域 自动播放 3s + 手动滑动 high swiper-autoplay
文章卡片 ×2 点击跳转详情 high card-tap
"更多›" 链接 点击跳转列表页 high card-tap
功能卡片 ×3 点击跳转各服务页 high card-tap
CTA"立即登录" 点击触发登录 high login-cta
TabBar 占位 无(小程序原生处理) high static-decoration
资讯为空降级 显示功能引导卡片 medium empty-fallback

5.3 截图与规格的关联机制

SPEC.md 中每个页面结构块都以对应截图开头,形成视觉-规格一一对应:

### 2.1 访客首页

![首页全貌](./screenshots/home.png)    ← LLM 读到此处时看到截图

布局层级(从上到下):                    ← 对照截图理解每层
1. 轮播区域 (height: 280px) ...         ← 截图中顶部渐变区域
2. 健康资讯 (padding: 20px) ...         ← 截图中卡片列表区域
3. 登录引导 ...                         ← 截图中底部 CTA 按钮

LLM 无需在多个文件间跳转。一个 SPEC.md = 视觉 + 结构 + 映射 + 交互的全景图


6. 多平台支持与集成

6.1 多平台 Token 映射

tokens.yml 中的每个 Token 支持按平台指定不同变量名和引用方式:

# 单平台通用(大多数 Token值和引用方式相同
- token: --tk-pri
  value: "#C4623A"
  # 无 platforms 字段 → 所有平台统一用 var(--tk-pri)

# 多平台差异映射(值相同,引用方式不同)
- token: --tk-pri
  value: "#C4623A"
  platforms:
    miniprogram: "var(--tk-pri)"
    web: "token('color.primary')"          # Ant Design Token 系统
    h5: "var(--color-primary)"             # H5 独立 CSS 变量体系

运行时按 --platform 参数展开对应平台的映射:

# 默认展开 miniprogram 映射
/design-handoff mp-00-visitor.html

# 展开 web 映射
/design-handoff mp-00-visitor.html --platform web

SPEC.md 和 tokens.json 中仅包含目标平台的映射,不混淆。

6.2 多平台组件映射

可选配置文件 .design/components.yml,定义各平台的组件对应关系:

# .design/components.yml — 自动扫描生成,可手动调整

components:
  ContentCard:
    miniprogram:
      import: "@components/ui/ContentCard"
      props: "variant, padding, margin, activeFeedback, onPress, className"
    web:
      import: "@app/components/ContentCard"
      props: "variant, padding, margin, onClick, className"

  PrimaryButton:
    miniprogram:
      import: "@components/ui/PrimaryButton"
      props: "children, onClick, disabled, loading, size"
    web:
      import: "antd/es/button"
      props: "children, onClick, disabled, loading, type='primary'"

  PageShell:
    miniprogram:
      import: "@components/ui/PageShell"
      props: "padding, safeBottom, scroll, className"
    web:
      import: "@app/layouts/PageLayout"
      props: "padding, children, className"

  Swiper:
    miniprogram:
      import: "@tarojs/components"
      tag: "Swiper"
    web:
      import: "antd/es/carousel"
      tag: "Carousel"

  TabBar:
    miniprogram:
      type: "framework-config"
      note: "小程序原生 TabBar在 app.config.ts 配置"
    web:
      import: "@app/components/AppTabBar"
      note: "Web 端自定义 TabBar 组件"

扫描生成规则

  • miniprogram → 扫描 apps/miniprogram/src/components/ui/ 目录
  • web → 扫描 apps/desktop/src/components/ 或对应 Web 目录
  • 只在对应平台目录存在时才生成映射

6.3 huashu-design 协作方式

两种集成方式,不修改 huashu-design 本身

方式 A串行调用默认

会话 1: /huashu-design → 原型 HTML设计阶段
会话 2: /design-handoff mp-00-visitor.html → 交付包(规格化)
会话 3: "按 SPEC.md 实现" → Taro/React 代码(实施阶段)

三个阶段各自独立,松耦合。用户按需调用。

方式 B自动追加可选配置

.design/config.yml 中开启:

# .design/config.yml
auto_handoff: true

开启后huashu-design 完成原型写入时skill 检测到 auto_handoff: true,自动提示:

原型已生成: docs/design/mp-00-visitor.html
检测到 auto_handoff 开启。是否自动生成设计交付包?
  → 是: 立即运行 /design-handoff
  → 否: 跳过,稍后手动调用

6.4 实施 Prompt 模板

交付包生成完毕后skill 在终端输出推荐 prompt用户直接复制到新会话

📋 实施时复制以下 prompt 到新会话:

请按设计规格实现「访客首页」页面。

设计规格: docs/design/mp-00-visitor/SPEC.md
Token 映射: docs/design/mp-00-visitor/tokens.json
目标平台: miniprogram (Taro + React)
组件库: apps/miniprogram/src/components/ui/
样式 Token: apps/miniprogram/src/styles/tokens.scss

要求:
1. 先阅读 SPEC.md 中的截图和规格
2. 按组件映射表使用现有组件,不要用 div 堆砌
3. 按 Token 映射表使用 CSS 变量,不要硬编码颜色值
4. 按交互规格表实现所有交互行为
5. 覆盖所有状态变体(加载/空数据/错误)

注意SPEC.md 中的截图路径为相对路径(./screenshots/home.pngLLM 应使用项目根目录的绝对路径读取(如 docs/design/mp-00-visitor/screenshots/home.png)。

批处理索引M3 修复)

批量运行时(/design-handoff docs/design/mp-*.html),完成后自动在 docs/design/ 下生成 INDEX.md

# 设计交付包索引

> 生成时间: 2026-05-17 | 原型数: 20

| 原型 | 交付包 | 页面数 | 未匹配 Token |
|------|--------|--------|-------------|
| mp-00-visitor | [SPEC](mp-00-visitor/SPEC.md) | 2 | 2 |
| mp-01-login | [SPEC](mp-01-login/SPEC.md) | 2 | 1 |
| ... | ... | ... | ... |

LLM 可通过 docs/design/INDEX.md 定位所需的交付包。

6.5 META.yml 元数据

每个交付包的元数据文件:

# docs/design/mp-00-visitor/META.yml

source: mp-00-visitor.html
platform: miniprogram
generated: 2026-05-17T10:30:00Z
generator: design-handoff v1

pages:
  - name: 访客首页
    screenshot: screenshots/home.png
    route: pages/index/index
  - name: 访客"我的"
    screenshot: screenshots/profile.png
    route: pages/profile/index

tokens:
  total: 18
  confirmed: 13
  pending: 2
  unmatched: 3

components:
  reused: 5        # 已有组件
  new: 1           # 需新建组件

interactions:
  total: 7
  high_confidence: 6
  medium_confidence: 1

附录 A. 交互推断规则表

完整内置规则清单(见 §5.2.2),共 8 条:

规则 ID 名称 置信度 匹配模式
swiper-autoplay 自动轮播 + 手动滑动 high 渐变背景 + 指示点宽窄交替
card-tap 卡片点击跳转 high 卡片容器 + 标题摘要配图
form-submit 表单提交 high 输入框 + 按钮同容器
list-scroll 列表滚动加载 medium 3+ 同类卡片连续排列
tab-switch 标签页切换 high 平行区域 + 选中态差异
static-decoration 静态装饰 high 渐变 + 装饰圆 + 无事件
login-cta 登录/注册 CTA high 按钮含登录文案 + 主色
empty-fallback 空数据降级 medium 条件渲染 / 占位符文字

扩展方式:在 rules/interaction-rules.yml 中追加新规则即可。

附录 B. Token 配置文件完整模板

见 §4.1 的 .design/tokens.yml 结构。首次运行时自动从以下文件扫描生成:

源文件 提取内容
styles/tokens.scss 所有 --tk-* CSS 变量
styles/variables.scss 所有 $ SCSS 变量
styles/mixins.scss mixin 名称和用途(用于注释)

附录 C. SPEC.md 完整示例mp-00-visitor

见 §3.2 - §3.8 的完整格式定义。以 mp-00-visitor 为实际案例,涵盖:

  • 5 张截图(首页全貌 + 3 张轮播 + 我的页)
  • 15+ Token 映射11 confirmed + 2 pending + 2 unmatched
  • 7 个组件映射5 复用 + 1 新建 + 1 框架配置)
  • 7 条交互规格6 high + 1 medium
  • 4 个状态变体(加载 / 空数据 / 已登录 / 错误)