Pixelmatch Algorithm
When to Use
Read this when tuning thresholds or debugging "why was this pixel flagged?" — understanding the two algorithmic ideas explains every pixelmatch decision.
Decision
| Pixel pair | Counted as different? |
|---|---|
| Identical RGBA | No |
| Slight chroma shift | Probably no (YIQ weights luma) |
| Slight luminance shift | Yes if past threshold |
| Both pixels are anti-aliased edges | No (skipped) — unless includeAA: true |
| One pixel changed but it's anti-aliased | No (skipped) |
Pattern
Per-pixel decision flow:
- RGBA equal → skip (no diff)
- Compute YIQ delta
- Delta within
threshold²-scaled bound → equal - Either pixel is anti-aliased AND
includeAAis false → mark as AA (yellow), skip - Otherwise → mark as diff (red), increment counter
Two Algorithmic Ideas
YIQ perceptual color difference — converts each pixel to YIQ (NTSC luma + chroma) and computes a perceptually weighted distance. Y (luminance) dominates because the human eye is more sensitive to brightness than chroma. A hue shift (Q channel) is judged less different than a brightness shift (Y channel).
Anti-aliasing detection — before flagging a pixel as different, pixelmatch checks whether either pixel sits on an anti-aliased edge by examining 8 neighbors for the characteristic intensity-slope pattern. AA pixels are skipped by default to suppress false positives from sub-pixel font/edge rendering differences.
Common Mistakes
- Wrong: Expecting pixel-perfect raw-RGB comparison — pixelmatch is perceptual;
threshold: 0does not mean "every byte equal" - Wrong: Setting
includeAA: truewithout understanding consequences — every text rendering tick now counts as a diff - Wrong: Confusing AA detection with masking — AA detection is automatic; masking is the
maskoption in Playwright
See Also
- Threshold — tuning the YIQ tolerance
- Other Options —
includeAA,aaColor,diffColor,diffMask - Reference: mapbox/pixelmatch