Pixel-by-pixel Comparison with WebAssembly
@blazediff/core-wasm is the Rust diff core compiled to wasm32 with v128
SIMD, in about 32KB. It runs in browsers, Web Workers, Deno, Bun, Cloudflare
Workers, and any other wasm host, with no native dependency and no network call.
Reach for it when you want compiled-code speed on the client or at the edge. In Node, the native binding is faster still and decodes images for you. In an environment where you cannot ship a wasm file at all, use the pure-JS core.
Installation
npm install @blazediff/core-wasmDecoding images to RGBA
The wasm module takes pre-decoded RGBA and does not bundle an image decoder, so the browserβs own decoder does that half:
async function loadRgba(url: string) {
const bitmap = await createImageBitmap(await (await fetch(url)).blob());
const canvas = new OffscreenCanvas(bitmap.width, bitmap.height);
const ctx = canvas.getContext("2d")!;
ctx.drawImage(bitmap, 0, 0);
const { data, width, height } = ctx.getImageData(0, 0, bitmap.width, bitmap.height);
return { data: new Uint8Array(data.buffer), width, height };
}Examples
Basic Comparison

Image 1

Image 2
Result
import { initBlazediff, diff } from "@blazediff/core-wasm";
await initBlazediff(); // loads the sibling .wasm; call once
const a = await loadRgba("3a.png");
const b = await loadRgba("3b.png");
const output = new Uint8Array(a.width * a.height * 4);
const diffCount = await diff(a.data, b.data, a.width, a.height, output);initBlazediff resolves the sibling .wasm by default. Loading it from a CDN, a
bundler, or the filesystem instead? It also accepts a URL, a Response, or raw
bytes.
What it costs
Against pixelmatch on the same fixtures, decode excluded, M1 Max, Node 22, 25 iterations:
| Case | pixelmatch | @blazediff/core-wasm |
|---|---|---|
| 4K pair | 332.26-423.14ms | 33.18-68.37ms |
| 4K pair, identical | 19.86-30.53ms | 17.47-22.17ms |
So 5x to 10x on a changed 4K pair, and ~51% faster averaged over the whole
fixture set. Identical images are the weak spot: wasm32-unknown-unknown has no
libc, so the byte-equality shortcut the other cores use lowers to a scalar memcmp
and is skipped here. The block scan reaches the same answer with v128 compares,
which is why that row is close rather than behind.
Full tables and the history of that fix.
Next
- Region-level classification runs in wasm too: Image difference analysis
- In Node, prefer the native binding
- Every option and its default:
@blazediff/core-wasmreference