2026-03-11
Five Decades to Real Time
1974 to 2016, in 0.3 ms
v2.3.0 release notes →Scrutinizer simulates peripheral vision by degrading content away from your gaze. Until now, that meant MIP blur — fast and stable, but it averages away everything. v2.3.0 replaces it with a WebGPU compute pipeline that keeps what MIP blur destroys.
The theoretical basis is the Texture Tiling Model (Freeman & Simoncelli 2011, Rosenholtz 2016): peripheral vision pools summary statistics — mean, variance, orientation energy — not blur. A simulation that preserves those statistics while destroying spatial layout produces mongrels (Rosenholtz et al. 2012): textures that look wrong up close, right in the periphery. MIP blur approximates acuity falloff models from the 1970s. This catches Scrutinizer up with the last decade.
WebGPU is less mature than WebGL — it can hard-crash the renderer, not just drop frames. Whether this could run in real time on integrated graphics was an open question. It can: ~900 lines, under 0.3 ms, with a safety harness that falls back to MIP blur if anything goes wrong.
The pipeline
Two WGSL compute passes run alongside the existing WebGL renderer on a half-resolution copy of each frame.
The key idea: Pass 1 measures what’s in each tile (in Oklab, a perceptually uniform color space). Pass 2 synthesizes new pixels that match those measurements without preserving the original spatial layout. The result blends into the WebGL pipeline via eccentricity-dependent alpha. Implementation details in the v2.3.0 release notes.
Measuring the difference
Sample rectangular patches at each eccentricity from both rendering modes, convert to Oklab, and compare L-channel variance:
varianceRatio = var(mongrel_L) / var(mipBlur_L)
Above 1.0: the mongrel preserved more luminance contrast. Below 1.0: it smoothed more.
Results
We measured at three eccentricities using golden captures from a crowding test stimulus.
Each row averages rectangular patches above and below the fixation point at a given eccentricity. The key column is L Ratio — luminance variance of the compute mongrel divided by MIP blur. Green means the mongrel preserved more local contrast (ratio > 1.0).
| Ecc | MIP | Mongrel | L Ratio | C Ratio |
|---|---|---|---|---|
| 3° * | 2.6 | 4.4 | 1.69 | 0.93 |
| 6° | 4.1 | 4.1 | 1.04 | 0.89 |
| 10° | 6.6 | 6.8 | 1.03 | 0.93 |
* 3° straddles the foveal boundary — transition zone, not true peripheral. 28px column, golden captures from v2.2. Full per-band data with above/below splits in the validation report. These measurements cover 3–10°; extending to wider eccentricities (>10°) is a planned follow-up.
The L ratios at 6° and 10° are both above 1.0 — modest (3–4%), but consistent. Both modes pool color similarly (C Ratio ≈ 0.9), which is expected: color is pooled aggressively in the periphery regardless of method. Luminance is where the two pipelines diverge.
Score card
| # | Hypothesis | Result |
|---|---|---|
| H5 | Oklab L variance ratio > 1.0 at ≥6° | PASS (avg 1.04) |
| H6 | Chrominance variance ratio ≈ 1.0 at ≥6° (±0.25) | PASS (avg 0.91) |
| 3° L ratio ≈ 1.0 | 1.69 — transition zone, not passthrough |
Finer pooling regions or a larger Gabor bank would likely increase the advantage. The pipeline and the measurement are in place — as of v2.3.0, this is the default rendering path.
Also in v2.3.0
- Bouma-scaled edge density gate — the congestion map now gets MIP-sampled at the MIP level matching Bouma’s critical spacing (0.5 × eccentricity). The GPU MIP chain integrates edge density over a Bouma-sized neighborhood. V1 handles eccentricity-dependent displacement; MIP handles spacing-dependent pooling.
- Seeded flanker RNG — the crowding test page now uses a deterministic
PRNG (mulberry32, seed 42) for flanker letter selection. Previous captures used
Math.random(), meaning the MIP blur and compute mongrel captures had different flanker arrangements — a content confound. Override with?seed=N. - Oklab variance metrics —
node scripts/compare-crowding-modes.jsnow outputs luminance and chrominance variance tables alongside the existing cyan-based crowding metrics.--jsonincludesluminancePatchesand per-hypothesis results.