# 视觉 diff 工作流(pangolin 客户端 ↔ design/ui_kits 原型) 用 `design-distill` skill 的截图 diff 工具,把 Flutter 实现与 `design/ui_kits/{desktop,tablet,mobile}` React 原型对照。 ## 工具 - 原型截图:`~/.claude/skills/design-distill/tools/shoot-prototype.mjs` - 像素 diff:`~/.claude/skills/design-distill/tools/diff.mjs` ## 原型基准(已验证可用) 从项目根运行(脚本自动起临时 http server,让 Babel 原型能 fetch jsx): ```bash SHOOT=~/.claude/skills/design-distill/tools/shoot-prototype.mjs # desktop 连接页 明/暗(920×600 内容,截外层 sand 画布给点余量) node $SHOOT design/ui_kits/desktop/index.html shots/desktop_connect_light.png \ --width 1000 --height 720 --theme light --lang zh --wait-for "#root > *" node $SHOOT design/ui_kits/desktop/index.html shots/desktop_connect_dark.png \ --width 1000 --height 720 --theme dark --lang zh --wait-for "#root > *" ``` > 原型是 SPA,默认显示连接页。截其它页需给 shoot-prototype 加 `--click `(待补)。 ## diff ```bash node ~/.claude/skills/design-distill/tools/diff.mjs --threshold 0.05 ``` ## 实现侧截图:两条路径与现状 ### A. Flutter golden(已启用 ✅,CI 严格回归闸) `flutter test --update-goldens test/golden` 截 `RepaintBoundary`,无 chrome/窗口问题,入 CI。 **字体方案**(已落地):`PangolinFonts.useBundled` 开关 + `test/flutter_test_config.dart` 用 `FontLoader` 注册 `test/fonts/` 真实 Sora/Manrope/JetBrainsMono + Lucide 图标字体,测试态绕过 google_fonts。 - 改组件视觉后:`flutter test test/golden` 失败即回归;确认是预期变更则 `--update-goldens` 重生成基准。 - 现覆盖:连接键三态 + 推荐卡 + 额度卡 × 明暗(`test/golden/components_golden_test.dart`)。 - 注:CJK 文案用 fallback(Noto Sans SC 未打包,体积大),基准自洽不影响回归检测;新增屏/组件按此模式扩展。 ### B. screencapture 真实 app(已可截,但受限) 真实渲染、字体真实,但:macOS 原生标题栏(红绿灯) vs 原型自绘 chrome 结构不同;窗口精确定位需「辅助功能」权限。 **用途**:作为**人工视觉对照**(生成 diff 图定位结构偏差),非严格像素闸。 ### C. iOS 模拟器(最干净的全屏,未接) `xcrun simctl io booted screenshot` 截模拟器无桌面 chrome、字体真实,适合 mobile/tablet。导航多页仍需 integration_test 驱动。 ## 建议 - **严格回归闸** → 走 A,先做 `PangolinText` 字体可注入(一次性小重构),启用 golden。 - **对照设计原型** → 原型基准(本文档)+ A 的 golden 截图,用 diff.mjs 比对。 - desktop 因 chrome 差异,像素级 100% 对齐不是目标;以**布局/间距/颜色结构一致**为验收口径。