Zenmetrics

Compare image quality and explore spatial error. Images stay on your device.

SourceDownloads

Images

40

The encoded reference becomes the distorted image, and a new quality or encoder encodes it again. Each encoder uses its own scale: JPEG and WebP quality, AVIF quality at speed 6, JPEG XL quality mapped to a distance at effort 7. WebP, AVIF and JPEG XL load their modules the first time they are used. JPEG, PNG, WebP and JPEG XL use Zen decoders. SDR RGB8 ingress matches the CLI: transparency is preserved and scoring refuses non-opaque pixels. ICC metadata is not applied. Use already composited sRGB images for color-managed comparison.

Metric

The bar at the top stays in view: its metric sets the score, the map and the encoder loop's steering, and choosing another metric's map there or in the loop panel switches the metric. Metrics marked score only have no spatial map in this build.

Score–
Compute time–

Reference, score and map timings appear after comparison.

Worker startup: starting…

Checking browser capabilities…

Brave: turn Shields off · Browser requirements

In Brave, turn Shields off for this site, then reload. Relaxed SIMD128, shared memory and working Web Workers are required. HTTPS and cross-origin isolation enable the Rayon worker pool. WebGPU readiness is checked separately; the selectable metrics in this build run on the CPU.

Starting threaded SIMD WASM…

Run the same native metric

Use the same opaque sRGB files. Generated JPEG candidates can be downloaded below. Zensim scoring and its map use the selected SDR model.

Image comparison

100%
LowHigh error
Load a pair or try the demo sceneMove over the image to inspect a pixel

Map scaling changes only the visualization. Scores and downloaded raw values retain their metric definitions. Native similarity maps retain their metric sampling grids; visualization uses 1−similarity. VSI displays saliency-weighted quality contributions. FSIM/FSIMc maps show luminance similarity. Hatched cells mark uncovered borders or undefined native values; HaarPSI has undefined local similarity in zero-weight windows. The Map menu lists every map the metric publishes; the first is its default. NLPD, VIF, MS-SSIM, IW-SSIM, DSSIM and SSIMULACRA2 default to their fused maps: the score broken down over every scale with the metric's own weights (mean NLPD, 1 − VIF, −ln MS-SSIM, −ln IW-SSIM, DSSIM's 1 − SSIM, or SSIMULACRA2's weighted sum), and also list their per-scale maps. PSNR-HVS, MAD and VMAF show one native component (per-block CSF error, MAD's high-quality strategy, VMAF's SPEED chroma-U blocks), and mDCT-PSNR each window's detection probability. IW-SSIM maps need both sides of at least 176 pixels; VMAF v1 needs even dimensions, both sides of at least 33 and one of at least 216. SSIMULACRA2 shows its per-pixel terms fused with the score's own weights; the map's mean is the weighted sum the score transforms. Browser timings are interactive feedback, not accepted fleet benchmark observations.

Encoder loop player

The demo scene's loop encodes once the worker starts.

The reference image is encoded with jxl-encoder's perceptual quantization loop in this page, and each iteration appears as it is scored: the map over the reconstruction, with the palette's middle at the target distance. The loop's constants were calibrated on butteraugli: each 8×8 block's 16-norm (×1.2) is compared with the target distance, and the map's maximum is the score. Another metric steers it through its map read as error (1 − similarity for similarity maps), resampled to pixels, then scale · error^exponent; the fitted defaults put each map's block distances on butteraugli's scale over a corpus of encodes. Each frame is one iteration, and from iteration 2 the loop only refines blocks above the target, so once none are, later iterations repeat the same image: the reconstruction it scored, the metric's per-pixel diffmap (one square-root scale for all frames), each 8×8 block's distance against the target (half the scale is the target; blocks above it get finer quantization next), the quant field that iteration encoded with, and how the loop changed it for the next one (red finer, blue coarser). Save a trace to reopen it later, or write one natively with cargo run --release --example loop_trace_dump -- in.png out.ltrace [distance] [effort] [iterations] in jxl-encoder.