BlazeDiff vs honeydiff
@blazediff/core-native is ~3.2x faster
than honeydiff over our 34 fixtures, with image decode and diff PNG writing
included. Both are Rust image diffs that ship as native Node addons. The
difference is scope and openness: BlazeDiff publishes its full source and also
runs in browsers, Python and Rust.
honeydiff is the diff engine of the Vizzly visual testing service, published on
npm as @vizzly-testing/honeydiff. Its binaries carry an MIT license, but its
public repository holds only a README and a changelog, not the Rust source. It
returns rich JSON: changed-region statistics, perceptual scores, and
accessibility checks.
At a glance
| honeydiff | BlazeDiff | |
|---|---|---|
| License | MIT binaries, source not public | MIT, full source on GitHub |
| Runtimes | Node 22 or later | Node, browsers, Workers, Deno, Bun, Python, Rust |
| Platforms | macOS arm64, Linux x64 and arm64, Windows x64 | macOS, Linux and Windows on x64 and arm64 |
| Input | File path or encoded bytes | File path or encoded bytes (core-native), raw RGBA (core) |
| Color metric | CIEDE2000 ΞE (default threshold 2) | YIQ |
| Anti-aliasing | Detected | Detected |
| Region output | Built in (difference.regions) | Separate package: @blazediff/interpret-native |
| Perceptual scores | SSIM, MS-SSIM, GMSD through analyze() | SSIM, MS-SSIM, GMSD and MILO in separate packages |
Benchmarks
Both libraries run at their defaults with anti-aliasing on and write a diff PNG. honeydiff thresholds on CIEDE2000 and BlazeDiff on YIQ, so the chart compares speed, not identical output.
JavaScript Native Binary (@blazediff/core-native vs honeydiff) (image IO included)
TOTAL TIME Β· 34 FIXTURES Β· MEAN OF 25 RUNS Β· IO INCLUDED
Both libraries run at their defaults with antialiasing on and write a diff PNG. honeydiff thresholds on CIEDE2000 ΞE and BlazeDiff on YIQ, so this compares speed, not identical output.
Apple M1 Max Β· darwin/arm64 Β· Node v22.14.0 Β· rustc 1.97.1 (8bab26f4f 2026-07-14) Β· 2026-10-22 Β· 234b300-dirty Β· pnpm benchmark honeydiff
Per-fixture results (34)
| Fixture | honeydiff | BlazeDiff | BlazeDiff vs honeydiff |
|---|---|---|---|
| 4k/1 | 1.60s | 325ms | 4.93x |
| 4k/1 (identical) | 548ms | 190ms | 2.88x |
| 4k/2 | 1.43s | 377ms | 3.78x |
| 4k/2 (identical) | 652ms | 229ms | 2.84x |
| 4k/3 | 1.30s | 423ms | 3.06x |
| 4k/3 (identical) | 731ms | 239ms | 3.06x |
| blazediff/1 | 4.29ms | 2.46ms | 1.74x |
| blazediff/1 (identical) | 4.43ms | 0.92ms | 4.84x |
| blazediff/2 | 4.17ms | 4.08ms | 1.02x |
| blazediff/2 (identical) | 3.90ms | 1.05ms | 3.70x |
| blazediff/3 | 45.38ms | 24.76ms | 1.83x |
| blazediff/3 (identical) | 40.41ms | 15.04ms | 2.69x |
| blazediff/4 | 30.89ms | 28.47ms | 1.08x |
| blazediff/4 (identical) | 24.95ms | 4.59ms | 5.44x |
| page/1 | 764ms | 630ms | 1.21x |
| page/1 (identical) | 780ms | 253ms | 3.08x |
| page/2 | 1.54s | 320ms | 4.82x |
| page/2 (identical) | 400ms | 42.36ms | 9.45x |
| pixelmatch/1 | 5.05ms | 1.89ms | 2.66x |
| pixelmatch/1 (identical) | 2.92ms | 1.52ms | 1.93x |
| pixelmatch/2 | 4.85ms | 1.93ms | 2.51x |
| pixelmatch/2 (identical) | 1.70ms | 0.66ms | 2.55x |
| pixelmatch/3 | 2.69ms | 1.86ms | 1.45x |
| pixelmatch/3 (identical) | 2.53ms | 0.88ms | 2.88x |
| pixelmatch/4 | 12.25ms | 4.98ms | 2.46x |
| pixelmatch/4 (identical) | 5.94ms | 1.99ms | 2.98x |
| pixelmatch/5 | 1.77ms | 1.07ms | 1.65x |
| pixelmatch/5 (identical) | 1.55ms | 0.61ms | 2.56x |
| pixelmatch/6 | 5.24ms | 2.65ms | 1.98x |
| pixelmatch/6 (identical) | 1.91ms | 0.88ms | 2.17x |
| pixelmatch/7 | 3.74ms | 2.81ms | 1.33x |
| pixelmatch/7 (identical) | 3.46ms | 0.64ms | 5.45x |
| same/1 | 16.00ms | 3.45ms | 4.64x |
| same/1 (identical) | 16.74ms | 3.44ms | 4.86x |
| TOTAL | 9.99s | 3.14s | 3.18x |
Switching
honeydiff returns different and a pixels.changed.total count. BlazeDiff
returns match, a reason, and a diffCount.
// Before
import { compare } from "@vizzly-testing/honeydiff";
const before = await compare("baseline.png", "current.png", {});
if (before.different) console.log(`${before.pixels.changed.total} pixels differ`);// After
import { compare } from "@blazediff/core-native";
const after = await compare("baseline.png", "current.png", "diff.png", {
antialiasing: true,
});
if (!after.match && after.reason === "pixel-diff") {
console.log(`${after.diffCount} pixels differ`);
}For the region data honeydiff puts in its result, run difference analysis. It labels each changed region as an addition, a deletion, a shift, a recolor or rendering noise.
When to keep honeydiff
- You use Vizzly, which builds on it.
- You want region statistics, perceptual scores and contrast checks from one call.
- You need CIEDE2000 color thresholds, or alignment of inserted rows.