odiff-image-diffing

v2026.09.24

odiff pixel-by-pixel image diffing. Use when comparing screenshots, detecting visual regressions, diffing before/after PNGs, asserting golden images.

GitHub
Install command
npx skhub add laurigates/odiff-image-diffing
Markdown
SKILL.md

odiff Image Diffing

odiff is a native, SIMD-accelerated, pixel-by-pixel image comparator. It is the fastest popular image-diff tool in its class (~10-100x faster than pixelmatch / resemble.js), supports PNG/JPEG/WebP/TIFF/BMP, writes a diff artifact to disk, and exits with structured codes that make it CI-friendly.

When to Use This Skill

Use this skill when...Use another skill instead when...
Comparing two PNG/JPEG screenshots on diskAsserting Playwright snapshots in a test suite (use playwright-testing)
Detecting visual regressions between before/after rendersConfiguring a Playwright snapshot workflow from scratch (use configure-ux-testing)
Diffing rendered output against a golden fileTransforming, resizing, or converting images (use imagemagick-conversion)
Validating that a CSS or template change is visually neutralGenerating a new image from a prompt (use generate-image)
Failing CI on pixel drift with a machine-readable exit codeProducing the screenshot itself (use playwright-cli)

Installation

# Recommended: npm package ships the native binary
npm install -g odiff-bin

# Project-local
npm install --save-dev odiff-bin

# Verify
odiff --version

The npm package is odiff-bin; the installed command is odiff. Native binaries are also available from GitHub Releases for sandboxes without npm registry access.

Core Usage

odiff <base_image> <comp_image> [diff_output] [options]
  • base_image and comp_image are the two images to compare. Any of PNG, JPEG, WebP, TIFF, BMP. Cross-format compares are fine.
  • diff_output is an optional PNG path. When supplied, odiff writes a visual diff highlighting the changed pixels in #cd2cc9 magenta.
  • Exit code carries the verdict — read it instead of parsing prose stdout.
odiff before.png after.png diff.png

Exit Codes

odiff is exit-code-first by design. Branch on the exit code, not on stdout text:

CodeMeaning
0Images match within threshold
21Layout difference (only when --fail-on-layout is set; otherwise treated as pixel diff)
22Pixel differences found
1Usage / file error (e.g. base image could not be loaded)

CI pattern:

if odiff before.png after.png diff.png --parsable-stdout; then
  echo "visual match"
else
  code=$?
  echo "visual drift (exit $code) — see diff.png"
  exit $code
fi

Machine-Readable Output

--parsable-stdout swaps the human report for a single line that's trivial to parse:

Resultstdout
Match0
Pixel diff<changed_pixels>;<percentage> (e.g. 1681;16.81)
Layout diff (with --fail-on-layout)layout

Pair with the exit code for a complete verdict; the line itself is the metric to log or post as a CI annotation.

Composition Recipes

1. Before/After diff with playwright-cli

playwright-cli saves PNG screenshots to .playwright-cli/. Pair the two ends of a change with odiff to confirm the visual delta is what you expected.

# Baseline
playwright-cli goto https://app.example.com/dashboard
playwright-cli screenshot --filename=baseline.png

# Make the code change, then re-screenshot
playwright-cli goto https://app.example.com/dashboard
playwright-cli screenshot --filename=current.png

# Diff — exit 0 = visually unchanged, exit 22 = drift
odiff .playwright-cli/baseline.png .playwright-cli/current.png \
  .playwright-cli/diff.png --parsable-stdout --antialiasing

--antialiasing ignores antialiased pixels, which suppresses noise from font-rendering jitter across runs.

2. Batch directory compare

For a baseline directory (golden files) and a current directory (fresh renders), iterate matched filenames:

baseline_dir=tests/__snapshots__
current_dir=tests/__current__
mkdir -p tests/__diff__

fail=0
for img in "$baseline_dir"/*.png; do
  name=$(basename "$img")
  current="$current_dir/$name"
  diff="tests/__diff__/$name"

  if odiff "$img" "$current" "$diff" --parsable-stdout --antialiasing; then
    echo "OK    $name"
  else
    echo "DRIFT $name"
    fail=1
  fi
done

exit $fail

3. CI exit-code pattern with layout protection

Treat layout changes as a distinct failure mode from pixel drift — a layout shift usually wants human attention, while a pixel diff may be tolerable under a small threshold.

odiff before.png after.png diff.png \
  --fail-on-layout \
  --threshold 0.05 \
  --antialiasing \
  --parsable-stdout
case $? in
  0)  echo "::notice::visual unchanged" ;;
  21) echo "::error::layout shifted — review diff.png"; exit 1 ;;
  22) echo "::warning::pixel drift — review diff.png"; exit 1 ;;
  *)  echo "::error::odiff failure"; exit 1 ;;
esac

Advanced Options

FlagWhen to use
--threshold <0.0-1.0>Raise from default 0.1 to be stricter; lower to tolerate more colour noise
--antialiasing (--aa)Suppress antialiased-pixel noise — recommended for any rendered-text comparison
--fail-on-layoutExit 21 (distinct from pixel diff 22) when dimensions differ
--diff-maskDiff output is just the changed pixels over a transparent background (compositing-friendly)
--diff-overlayWhite-shaded overlay on the unchanged regions — easier human review
--diff-color <hex>Override the default #cd2cc9 highlight colour
-i, --ignore <regions>Skip rectangular regions: x1:y1-x2:y2,x3:y3-x4:y4 — useful for timestamps, ads, avatars
--reduce-ram-usageTrade speed for memory on very large images
--enable-asmAVX-512 fast path on x86_64 CPUs that support it
--serverLong-running daemon reading JSON jobs from stdin — for batch processors

Agentic Optimizations

ContextCommand
Quick pass/failodiff a.png b.png --parsable-stdout
Pass/fail with diff artifactodiff a.png b.png diff.png --parsable-stdout
Suppress font-rendering noiseodiff a.png b.png diff.png --aa --parsable-stdout
Treat layout shift as distinct failureodiff a.png b.png diff.png --fail-on-layout --parsable-stdout
Ignore dynamic regionsodiff a.png b.png diff.png -i 0:0-200:40 --parsable-stdout
Strict threshold for golden filesodiff a.png b.png diff.png -t 0.02 --aa --parsable-stdout
Composite-friendly diffodiff a.png b.png diff.png --diff-mask --parsable-stdout

Quick Reference

FlagDefaultDescription
-t, --threshold <value>0.1Per-pixel colour-difference tolerance (0.0–1.0)
--aa, --antialiasingoffIgnore antialiased pixels
--fail-on-layoutoffExit 21 when dimensions differ
--parsable-stdoutoffEmit 0 / <pixels>;<pct> / layout
--diff-color <hex>#cd2cc9Highlight colour in diff PNG
--diff-maskoffDiff = only changed pixels on transparent bg
--diff-overlay [value?]offWhite shaded overlay on unchanged areas
--output-diff-linesoffPrint line numbers of differences
-i, --ignore <regions>noneRect list: x1:y1-x2:y2,...
--reduce-ram-usageoffSlower, lower-memory mode
--enable-asmoffAVX-512 path (x86_64)
--serveroffJSON-over-stdin server mode

See Also

  • playwright-cli — produces the .playwright-cli/*.png screenshots that odiff consumes
  • playwright-testing — Playwright's own toHaveScreenshot() snapshot assertions for in-test diffing
  • imagemagick-conversion — pre-process images (resize, normalize format) before diffing
  • configure-ux-testing — set up a full visual-regression pipeline with snapshot directories
  • Official site: https://odiff.opa.dev
  • Repository: https://github.com/dmtrKovalenko/odiff
  • npm: https://www.npmjs.com/package/odiff-bin
Discovery
Tags

No tags published for this skill.

Version
Latest version metadata

Version

v2026.09.24

Published

Sep 24, 2026

Category

Uncategorized

License

MIT

Source path

testing-plugin/skills/odiff-image-diffing

Default branch

main

Latest commit

1668324

Tree SHA

b2d4cc3