From f932768e35074726c7197b0d0113afea17f679b0 Mon Sep 17 00:00:00 2001 From: zyh Date: Mon, 13 Apr 2026 16:32:18 +0000 Subject: [PATCH] sync: visual-diff-pencil - add name normalization, pages.json cross-validation, structure check using .pen node tree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This improves detection accuracy: 1. Add name normalization for numbered design frame names (e.g., '12. Withdraw' → 'withdraw') 2. Add pages.json cross-validation to ensure no pages are missed 3. Add structure check using .pen node tree before visual comparison - detects missing blocks early 4. Add enforced checklist for correct difference counting - icon mismatch must be counted as moderate 5. Add examples for correct grading --- .../skills/d8d-dev/visual-diff-mode-pencil.md | 113 ++++++++++++++---- 1 file changed, 90 insertions(+), 23 deletions(-) diff --git a/.claude/skills/d8d-dev/visual-diff-mode-pencil.md b/.claude/skills/d8d-dev/visual-diff-mode-pencil.md index 4734ff1..de97b0c 100644 --- a/.claude/skills/d8d-dev/visual-diff-mode-pencil.md +++ b/.claude/skills/d8d-dev/visual-diff-mode-pencil.md @@ -30,16 +30,18 @@ ``` Phase PVD-0: 准备 ├── 读取 .pen 文件 → 使用 Pencil MCP 发现设计页面 - ├── 读取 pipeline-context.md → 获取实际应用 URL + ├── 设计帧名称标准化 → 提取清晰名称用于路由匹配 ├── 构建页面映射表(设计帧 ↔ 实际路由) + ├── 交叉验证补全 → 用 pages.json 确保不漏页 └── 创建截图输出目录 Phase PVD-1: 逐页对比循环 对每个映射页面: ├── A. Pencil MCP 导出设计帧截图 ├── B. Playwright 截取实际页面 - ├── C. UI 差异对比(ui_diff_check) - └── D. 差异分级 + 记录 + ├── C. 结构校验(.pen节点树)+ AI 视觉对比 + ├── D. 差异分级 + 强制执行计数 + └── E. PAGE GATE-CHECK 门禁检查 Phase PVD-2: 汇总报告 ├── 生成 visual-diff-pencil-report.md @@ -76,20 +78,37 @@ Phase PVD-2: 汇总报告 - 认证凭据 - 已实现的路由 -### 0.3 构建页面映射表 +### 0.3 设计帧名称标准化 + +**输入**: 原始设计帧列表(从 Pencil MCP 获取) +**输出**: 标准化后的列表,用于路由匹配 + +``` +名称标准化算法: + 对每个设计帧: + 1. 取 node.name 原始名称 + 2. 移除开头的数字和点: ^[\d]+\.\s* → 删除 + 3. 移除常见后缀: \s*(Screen|Page|Frame|[-_]\d+)$ → 删除 + 4. 转为小写 → 得到标准化名称 + 5. 示例: + - "1. Login Screen" → "login" + - "12. Withdraw" → "withdraw" + - "06-pay-result" → "pay-result" + - "Home" → "home" +``` + +### 0.4 构建页面映射表 **自动映射规则**: ``` -对每个设计帧(从 Pencil MCP 获取): - 1. 提取帧名称(如 "Login", "Dashboard") - 2. 在实际路由中查找匹配: - - 帧名=Login → /login 或 /admin/login - - 帧名=Dashboard → / 或 /dashboard - - 帧名=Register → /register - - 其他 → /{帧名小写} 或 /admin/{帧名小写} - 3. 验证实际路由可访问(curl 检查非 404) - 4. 不可访问的页面标记为 skipped +对每个(标准化后)设计帧: + 1. 用标准化名称在实际路由中查找匹配: + - 标准化名=login → /pages/login/index 或 /login + - 标准化名=withdraw → /pages/withdraw/index 或 /withdraw + - 其他 → /pages/{标准化名}/index 或 /{标准化名} + 2. 验证实际路由可访问(curl 检查非 404) + 3. 不可访问的页面标记为 skipped ``` **映射输出格式**(记录到 pipeline-state.yaml): @@ -98,7 +117,7 @@ Phase PVD-2: 汇总报告 visual_diff_pencil_mapping: - design_frame: "Login" design_frame_id: "node-123" - actual_route: "/login" + actual_route: "/pages/login/index" group: "frontend" status: "active" # active / skipped / error @@ -109,7 +128,24 @@ visual_diff_pencil_mapping: status: "active" ``` -### 0.4 创建截图输出目录 +### 0.5 交叉验证补全(确保不漏页) + +``` +原理:代码中存在的页面一定要对比,不能因为自动映射失败就漏掉。 + 1. 读取 app/mini-program/src/pages.json + 2. 提取所有 pages 和 subpackages 中的页面路径 + 3. 对每个页面路径: + - 提取页面名 = 路径倒数第二段("pages/withdraw/index" → "withdraw") + - 检查当前映射表中是否已有该页面 + - 没有 → 在 Pencil MCP 所有设计帧中搜索名称包含该页面名 + - 找到匹配的设计帧 → 自动添加到映射表,status = active + - 没找到 → 记录 warning 到报告:"代码存在页面 {page} 但设计中找不到对应帧" + 4. 最终映射表写回 pipeline-state.yaml +``` + +这样可以确保**代码中有的页面一定会被对比**,不会因为名称提取问题漏掉。 + +### 0.6 创建截图输出目录 ```bash mkdir -p tests/e2e/screenshots/visual-diff-pencil @@ -163,31 +199,62 @@ PVD-1 PER-PAGE LOOP: → tests/e2e/screenshots/visual-diff-pencil/{name}-actual.png ``` -### 1.C AI 视觉对比 +### 1.C 结构校验 + AI 视觉对比 -使用 Read 工具分别查看设计截图和实际截图,然后综合分析差异: +**分两步:先做结构校验,再做视觉对比** ``` 步骤: - 1. Read 工具查看设计截图 → 理解设计意图(布局、颜色、组件) - 2. Read 工具查看实际截图 → 识别实现状态 - 3. 综合两图分析差异,关注: + 1. 从 Pencil MCP batch_get 获取当前设计帧的完整节点树 + 2. 提取所有顶层命名节点(name 属性存在的节点)→ 得到"必须存在的组件列表" + 示例: availableCard / amountInput / amountActions / withdrawMethod / recentWithdrawals / confirmBtn + 3. 读取实际页面源码(app/mini-program/src/pages/{page}/index.vue),检查每个组件是否存在: + - 节点存在(源码中对应区块存在)→ 继续 + - 节点整个区块缺失 → 直接判定为 🔴 严重差异 → critical_count += 1 + 4. 结构校验通过后,使用 Read 工具分别查看设计截图和实际截图,AI 综合分析视觉差异: - 布局结构(网格/弹性/定位) - 组件排列(导航栏、卡片、按钮、图标) - 颜色(Neon Pulse 规范:#000000 背景、#ffb3b5 粉色、#e8b3ff 紫色、#00dce5 青色) - 间距(内边距、外边距、元素间距) - 字体(大小、粗细、颜色) - - 图标(是否存在、是否 emoji 替代、是否损坏) + - 图标(是否存在、形状是否正确、是否 emoji 替代) ``` +**优势**: +- 利用设计文件本身的结构信息,比纯视觉分析更可靠 +- 确保不会漏检"整个区块缺失"(如支付结果页订单信息卡片整个不见了) +- 帮助 AI 聚焦到每个具体组件,差异分析更准确 + ### 1.D 差异分级 | 级别 | 标准 | 示例 | |------|------|------| -| 🔴 严重 | 布局结构不同、关键组件缺失 | 原型有两列布局实际一列 | -| 🟡 中等 | 颜色/间距偏差、图标不一致 | 卡片圆角不一致 | +| 🔴 严重 | 布局结构不同、关键组件缺失 | 原型有两列布局实际一列;整个设计区块在源码中缺失 | +| 🟡 中等 | 颜色/间距偏差、图标不一致 | 卡片圆角不一致;图标形状与设计不符 | | 🟢 轻微 | 微小像素差异 | 1-2px 偏移 | +### 强制执行清单(必须严格遵守,不得跳过) + +⛔ **禁止以"不影响功能"为由降级差异分级** +⛔ **禁止故意不计数**来让页面"看起来更好看" + +| 情况 | 级别 | 是否计数 | +|------|------|----------| +| 布局结构不同、关键组件缺失 | 🔴 严重 | `critical_count += 1` | +| 颜色/间距偏差、**图标不一致** | 🟡 中等 | `moderate_count += 1` | +| 微小像素差异 (1-2px 偏移) | 🟢 轻微 | `minor_count += 1` | + +**门禁规则再强调**: +- 通过条件: `critical_count == 0 AND moderate_count <= 3` +- 即使有 1-3 个中等差异,仍然可以 PASS → **不需要故意不计数** +- 只有当 `critical_count > 0 OR moderate_count > 3` 才需要修复 + +**正确定级示例**: +| 案例 | 定级 | 结果 | +|------|------|------| +| 设计微信气泡图标,实际菜单图标(形状不对) | 🟡 中等 → `moderate_count += 1` | critical 0, moderate 1 → **仍然 PASS** (1 ≤ 3) | +| 设计 recentWithdrawals 区块存在,实际源码无此区块 | 🔴 严重 → `critical_count += 1` | 需要修复 | + ### 1.E PAGE GATE-CHECK ⛔(每页门禁) **每页对比完成后必须执行门禁检查。不通过则阻断,进入修复循环。** -- 2.49.1