mcpField
C
compare-screenshots

compare-screenshots

github.com/dzhng测试与质量1.4k290 次安装今天更新
代码仓库

关于 compare-screenshots

用于将截图与预期且获认可的设计进行比较的视觉审查技能,不默认历史基线正确。它结合图像指标和局部检查;目标不明确时会要求用户判断。

主要功能

  1. 01明确视觉比较目标
  2. 02确认截图采集条件可比
  3. 03生成图像与边缘对比
  4. 04检查边界和局部差异
  5. 05将指标用于诊断而非判定

适用场景

  1. 01按获认可的设计审查 UI 改动
  2. 02发现视觉效果的裁切或重叠
  3. 03在没有参考图时评估截图

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dzhng/skills --skill compare-screenshots

安装后在 Claude Code 中输入/compare-screenshots确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
reference-landmarks.md
subagent-visual-review.md
scripts/
visual-parity-diff.eval.mjs
visual-parity-diff.mjs
test/
visual-parity-diff.test.mjs
test/fixtures/target-without-helper-packages/
README.md
vendor/pixelmatch/
index.js
LICENSE
package.json
vendor/pngjs/lib/
bitmapper.js
bitpacker.js
chunkstream.js
constants.js
crc.js
filter-pack.js
filter-parse-async.js
filter-parse-sync.js
filter-parse.js
format-normaliser.js
interlace.js
packer-async.js
packer-sync.js
packer.js
paeth-predictor.js
parser-async.js
parser-sync.js
parser.js
png-sync.js
png.js
sync-inflate.js

详细介绍

比较截图

根据预期结果评判图像。用户认可的设计才是目标; 历史基线只是较早的一次尝试,可能并不正确。指标可以定位 差异,但不能决定正确与否。完整的探索到实现流程请参阅 design-with-images。

工作流

  1. 确定目标。 如有用户认可的参考和明确的设计要求,请以此为准;不要用自己的喜好取而代之。否则,根据视觉要求、事物在现实中的呈现方式,以及负责该外观的领域技能来推导目标。用一两句具体的话写下来(“低角度的阳光应向东投下长影;树木填满树冠;在此缩放级别下标签应清晰可读”)。
    • 如果无法确定正确答案——存在多种合理解读、涉及审美或产品意图的判断,或存在只有负责人才能决定的权衡——请停下来询问用户正确答案是什么。向用户展示对比。不要为了避免提问而默默默认以基线为准;那样会把基线中已有的问题一并保留下来。
  2. 确认可比性,确保看到的差异是真实差异,而非截图伪影:视口、DPR、路由/页面、冻结的时间/帧、相机意图、UI 状态、数据,以及相关的字体/资源都应相同。如果无法做到可比,请修正截图设置,或只比较差异无关紧要的裁剪区域/特征。
  3. 测量已认可的设计。 对于参考匹配,在更改代码或接受候选方案之前,先阅读并完成 Reference Landmarks。然后根据问题生成所需的产物:并排图、关键特征裁剪图/放大图、灰度图、绝对灰度热力图、pixelmatch 差异图、每张图的 Sobel/边缘图、边缘差异热力图、JSON 指标。
  4. 判断整体之前先检查边界。 对每种发生变化的视觉效果,都应在原始比例下检查所有边缘,并查看对齐的细节裁剪图。应包含效果完整的渐隐区域及周围空间;如果裁剪止于组件边界,就会隐藏溢出。分别对照可见文本、线条或轮廓,而非推测的 CSS 边界,检查上/右/下/左各边的范围。检查效果覆盖的所有前景特征(线条、图标、文本、相邻面板):亮度、颜色、清晰度和连续性必须与目标一致。即使线条清晰可读,也仍可能被错误调暗。将每项检查记录为:参考观察 → 候选方案观察 → 通过/修复/不确定,并附上对应裁剪图。使用地标表确定局部距离和对比度;全图平均值无法判定局部缺陷。
  5. 根据目标判断每处差异。 对于两张图中每个不同之处,用直白的语言说明实际问题是什么——内容缺失、相机错误、层级不佳、对比度不足、深度错误、文本重叠、布局偏移、边缘裁切、意外模糊、风格不匹配——然后判断哪一方更接近正确结果。答案可以是候选方案、基线、两者都不正确,或确实难分高下。
  6. 对有争议或影响重大的判断征求中立的第二意见:根据 references/subagent-visual-review.md,让一个全新的子 Agent 仅依据两张图和中立标签进行评审。
  7. 依据已认可的目标解决差异。 实施选定设计时,记录间距、形状、柔和度、排版和层级方面的重大差异;修订、重新截图并重复检查,直到问题解决或用户更改目标。不要因为代码更简单就默默将差异排除在外。
  8. 以一个结论收尾: 候选方案较不差(接受;如存在基线,则重新确认基线)、基线较不差(拒绝)、两者都不正确(需要再迭代一次——说明仍有哪些问题),或无法确定(询问用户)。只有在所有边界/重叠检查均通过,或有明确的用户认可偏差时,才能接受;存在不确定性时应收集更有力的证据,而不是直接判定通过。整体相似度高或第二意见偏正面,都不能抵消局部缺陷。绝不能仅因分数更低就接受,也不能仅因分数更高就拒绝。绝不要隐藏内容、模糊细节、裁掉差异,或降低截图的真实性来改变数值。

有用的指标

选择能回答问题的指标。进行全面的视觉比较时,请报告:

  • mae:灰度平均绝对差,范围为 0..255,越低表示越接近。
  • rmse:灰度均方根误差,越低表示越接近。
  • diffRatio16、diffRatio32、diffRatio64:超过各灰度差阈值的像素占比。
  • pixelmatchRatio:对灰度图像使用 pixelmatch 得出的不匹配比例。
  • edgeEnergyCurrent 和 edgeEnergyCandidate:平均 Sobel 边缘强度。
  • edgeEnergyRatio:候选图像与当前图像的比值。远低于 1 通常意味着几何结构、道具、标签或地形缺失;远高于 1 通常意味着细节嘈杂或不正确。
  • edgeDiffRatio32:Sobel 边缘有明显差异的像素占比。
  • avgLuminanceCurrent、avgLuminanceCandidate、avgLuminanceDelta:平均亮度及其差值。当渲染明显过暗或过亮,即使整体距离分数有所改善时,也应使用这些指标。
  • 与场景相关的内容代理指标:黑色/空白区域占比、类地形区域占比、类水体区域占比、队伍颜色占比、标签/文本遮罩占比。

对于 UI/文档/布局审查,当裁剪范围、文本/前景遮罩覆盖率、对比度检查、边缘裁切、元素位置以及前后尺寸比全局像素距离更有用时,也应使用这些指标。

单图指标

上述每项指标都用于衡量一张图像与另一张图像之间的差异,因此在没有对比图像时,它们都无法回答“这张截图有没有价值?”——而且,成对评分具有对称性,所以即使差异巨大,也无法说明哪一边是空白画面。以下几个绝对值则是根据单张 PNG 的粗略网格计算得出的:

  • colorEntropyBits 低于约 3.0,或 dominantColorShare 高于约 0.6:画面被单一颜色占据。可能是场景内容稀疏、没有打光,或主体根本没有绘制出来。
  • edgeDensity 低于约 0.04:画面几乎没有任何形状。可能是取景为空、场景以基础图元为主,或主体落在裁剪范围之外。
  • luminanceContrast 低于约 60:雾、黑暗或薄雾将整个画面的亮度压缩到了一个区间内。
  • 如果截图本应不透明,但 transparentShare 高于 0:说明截图本身有问题。透明像素会保留原有的 RGB 值,因此在合成之前,隐形画面看起来可能色彩丰富;场景指标会先进行合成再测量,并直接标出透明区域占比,无需你自行推断。上述成对指标仍会读取存储的 RGB 值,因此这个字段能明确指出透明度问题。

这些阈值用于提示可能存在问题,而非作为门槛。刻意极简的设计、夜景、空状态屏幕和白板都会如实触发这些指标。用它们来决定该检查哪里,然后描述画面实际呈现的内容——切勿为了提高数值而调整截图,那和裁掉差异是同一种错误。

距离分数

如果需要一个固定的成对数值,以下默认公式适用于结构性变化:

distance = 0.35 * diffRatio32 + 0.25 * pixelmatchRatio + 0.25 * edgeDiffRatio32 + 0.15 * min(1, abs(log2(edgeEnergyRatio)))

它衡量的只是与另一张图像的距离。由于基准图像可能有误,距离为 0 不代表成功,距离很大也不代表失败——场景更丰富、模型更清晰、标签更醒目、有真实景深或光照更好,都可能合理地使该值升高。用这个分数找出图像发生变化的位置;至于哪张图是正确的,请在步骤 5 中判断。字段名称应体现其衡量的内容(距离,而非“奇偶性”),以免被误读为结论。

报告全画面分数;如果画面主要由 UI 占据,还应报告带标签的世界区域裁剪分数。使用世界区域裁剪分数定位渲染器的变化,同时保留全画面分数,以便 UI/摄像机错误仍清晰可见。

评分规范

  • 每轮都引用同一对对象的上一次和本次距离,然后说明变化是朝目标靠近、远离目标,还是诊断噪声。
  • 对于缺失内容类问题,优先使用边缘指标。平坦的俯视地图可能显示出看似适中的灰度差异,但边缘能量可以证明树木、道路、城市形态或军队轮廓缺失。
  • 当稳定的 UI 占据主要画面且问题关注的是世界渲染时,将其分割出来;同时保留完整画面的评分,并明确标注。
  • 如果摄像机不对,像素评分就只能用于诊断。先修正摄像机意图,再评估渲染结果。

工具

将比较脚本保存在技能目录或临时工作区中,而不是产品代码里,除非产品确实需要在运行时比较截图。

  • scripts/visual-parity-diff.mjs 是可复用的本地辅助工具。它的 PNG 和像素差异运行时已随技能打包,因此目标仓库无需安装 pngjs 或 pixelmatch。使用 REFERENCE_DIR=<png-folder>、CANDIDATE_DIR=<png-folder> 运行,并可选设置 OUT_DIR=<artifact-folder>。 REPORT_ORDER=a,b,c 可固定排序; CROPS_JSON=<file> 可添加带标签的裁剪区域(按图像 ID 作为键,每个裁剪区域使用像素坐标,或使用 { "unit": "ratio" } 指定归一化边界)。成对报告的每一侧都包含一个 sceneMetrics 块。
  • 移除 REFERENCE_DIR,即可对没有对应项的文件夹运行同一辅助工具:它会写入 scene-metrics.json,其中包含上述单图数值,且不生成差异产物。可将其用于单张截图、任何人审核前的一组完整截图,或用于找出较大距离中哪一侧是空的。
  • scripts/visual-parity-diff.eval.mjs 是该辅助工具自身的评估脚本:它会生成正确答案通过构造已知的测试样例——空白、透明、基础图元占主导、人工制作、退化——并断言分类结果、不变性以及 CLI 约定。更改脚本后,使用相同的 REPO_ROOT 运行它。在确认问题出在测试样例而非代码之前,绝不要通过放宽阈值来让失败的检查通过。
  • 对于其他任务,调整同一组产物,而不是为应用添加一次性脚本。如果缺少所需的对象对,就扩展辅助工具。

参考资料

  • references/subagent-visual-review.md:用于在历史记录可能造成偏见时进行独立判断的中立子 Agent 提示词/配置。

评论

支持 Markdown