compare-screenshots
Compare screenshots to judge which image is less wrong, not to match a baseline. Use when a UI, game, document, render, chart, or generated asset needs objective visual telemetry, side-by-side inspect
SKILL.mdskills/compare-screenshots/SKILL.md
GitHubCompare Screenshots
Decide which image is less wrong against what the scene should show — not whether the candidate matches the baseline. The baseline is just an earlier attempt; it can be wrong too. Treat both images as candidates measured against a target you establish yourself. Metrics locate where the images differ; they never decide who is right.
Workflow
- Establish the target from first principles. Before looking at distance,
decide what this image should show: the visual requirement, the design
intent, what the thing depicts in reality, and any domain skill that owns the
look. This — not the baseline — is ground truth. Write it down in one or two
concrete sentences ("low sun should cast long shadows east; trees fill the
canopy; labels stay legible at this zoom").
- If the right answer isn't clear — competing valid readings, a taste or product-intent call, a tradeoff only the owner can settle — stop and ask the user what the correct answer should be. Show them the comparison. Do not quietly default to the baseline to avoid asking; that bakes in whatever the baseline got wrong.
- Confirm comparability so the differences you see are real, not capture artifacts: same viewport, DPR, route/page, frozen time/tick, camera intent, UI state, data, fonts/assets where they matter. If not comparable, fix capture setup or compare only a crop/feature where the mismatch is harmless.
- Generate artifacts to locate divergence, sized to the question: side-by-side, key-feature crops/zooms, grayscale, absolute grayscale heatmap, pixelmatch diff, per-image Sobel/edge maps, edge-difference heatmap, JSON metrics.
- Judge each divergence against the target. For every place the two images differ, name what is actually there in plain terms — missing content, wrong camera, bad hierarchy, weak contrast, wrong depth, text overlap, layout shift, clipped edge, unexpected blur, style mismatch — and decide which side is closer to correct. The answer can be the candidate, the baseline, both wrong, or a genuine toss-up.
- Get a neutral second opinion when a disputed or high-stakes call warrants
independent review. Give the reviewer the target, relevant platform and
state constraints, and both images labeled A/B. Hide chronology and previous
verdicts, not the requirements. Use
references/subagent-visual-review.md. - Conclude with one verdict: candidate is less wrong (recommend acceptance), baseline is less wrong (recommend rejection), both wrong (another pass needed — say what's still off), or unclear (ask the user). Keep comparison-only requests read-only. Update or re-bless a baseline only when the user has authorized that change. Never accept on a lower score alone or reject on a higher one. Never hide content, blur detail, crop away differences, or make the capture less truthful to move a number.
Useful Metrics
Pick metrics that answer the question. For full visual comparisons, report:
mae: mean absolute grayscale difference, 0..255, lower is closer.rmse: grayscale root mean square error, lower is closer.diffRatio16,diffRatio32,diffRatio64: fraction of pixels over each grayscale delta threshold.pixelmatchRatio: mismatch ratio from pixelmatch over grayscale images.edgeEnergyCurrentandedgeEnergyCandidate: average Sobel edge strength.edgeEnergyRatio: candidate/current. Far below 1 usually means missing geometry, props, labels, or terrain; far above 1 usually means noisy or incorrect detail.edgeDiffRatio32: fraction of pixels whose Sobel edge differs materially.avgLuminanceCurrent,avgLuminanceCandidate,avgLuminanceDelta: average brightness and delta. Use when a render is visibly too dark/light even if a broader distance score improves.- Content proxies relevant to the scene: black/void ratio, terrain-like ratio, water-like ratio, team-color ratio, label/text mask ratio.
For UI/document/layout reviews, also use crop bounds, text/foreground mask coverage, contrast checks, edge clipping, element positions, and before/after dimensions when those beat global pixel distance.
Distance Score
When a single fixed-pair number is useful, this default works for structural changes:
distance = 0.35 * diffRatio32 + 0.25 * pixelmatchRatio + 0.25 * edgeDiffRatio32 + 0.15 * min(1, abs(log2(edgeEnergyRatio)))
It measures distance from the other image, nothing more. Because the baseline can be wrong, a distance of 0 is not success and a large distance is not failure — a richer scene, clearer models, stronger labels, real depth, or better lighting all legitimately raise it. Use the score to find where the images move; decide who is right in step 4. Name the field for what it measures (distance, not "parity") so no one reads it as a verdict.
Report the full-frame score and, when UI dominates the shot, a labeled world-crop score. Use the world-crop score to locate renderer movement and keep the full-frame score so UI/camera mistakes stay visible.
Score Discipline
- Quote the previous and new distance for the same pair each iteration, then say whether the movement is toward the target, away from it, or diagnostic noise.
- Prefer edge metrics for missing-content bugs. A flat top-down map can show a deceptively moderate grayscale diff while edge energy proves trees, roads, city forms, or army silhouettes are absent.
- Segment out stable UI when it dominates and the question is the world render; keep a full-frame score too, labeled.
- If the camera is wrong, pixel scores are diagnostic only. Fix camera intent first, then judge the render.
Tooling
Keep comparison scripts inside the skill or a temporary workspace, not in product code, unless the product genuinely needs screenshot comparison at runtime.
scripts/visual-parity-diff.mjsis a reusable local helper. Run it withREFERENCE_DIR=<png-folder>,CANDIDATE_DIR=<png-folder>, and optionalOUT_DIR=<artifact-folder>.REPORT_ORDER=a,b,cpins ordering;CROPS_JSON=<file>adds labeled crops (keyed by image id, each crop in pixels or{ "unit": "ratio" }normalized bounds).- For other tasks, adapt the same artifact set rather than adding one-off scripts to the application. Extend the helper if a needed pair is uncovered.
References
references/subagent-visual-review.md: neutral subagent prompt/config for an independent judgment when history could bias you.