Loaded by tsl-harness.html (Vite serves it at /tsl-harness.html).
Exposes window.__tslHarness with primitives that render registered
fullscreen passes or the composed bloom pipeline through both backends
and return the result for pixel-diffing in a Playwright spec.
The harness internals live in ./tsl-harness/, split by shader family:
types.ts — the RegistryEntry registry contract
shared.ts — cross-family camera / colormap-LUT helpers
lines.ts — line + line-pick variants (both primitives)
gsplats.ts — gsplat + gsplat-pick variants
mesh.ts — mesh + mesh-pick variants
erf.ts — shared-math erf polynomial
render.ts — the single-pass and composed bloom executors
index.ts — merges the families into SHADER_REGISTRY (use
listShaders() for the live entry count — hardcoded totals drift)
Why a dedicated page rather than reusing the main viewer:
Construction order is explicit and minimal — no app/state machine
to wait on, no scene graph to mock around.
Both backends (WebGL2 via THREE.WebGLRenderer, WebGPU-via-WebGL2
via WebGPURenderer({ forceWebGL: true })) live side by side; the
test toggles between them per call rather than per page load.
The TSL path drives GLSLNodeBuilder directly so the generated
GLSL strings are recoverable for snapshot-diff.
Not in scope: real WebGPU dispatch. That requires Chrome stable +
?renderer=webgpu and runs in a separate spec. This harness
validates the WebGL2 fallback parity, which is what
forceWebGL: true covers.
TSL ↔ GLSL parity harness — page entry.
Loaded by
tsl-harness.html(Vite serves it at/tsl-harness.html). Exposeswindow.__tslHarnesswith primitives that render registered fullscreen passes or the composed bloom pipeline through both backends and return the result for pixel-diffing in a Playwright spec.The harness internals live in
./tsl-harness/, split by shader family:types.ts— theRegistryEntryregistry contractshared.ts— cross-family camera / colormap-LUT helperspost-processing.ts— const-rgb, fxaa, bloom-threshold, mega*points.ts— point + point-pick variantslines.ts— line + line-pick variants (both primitives)gsplats.ts— gsplat + gsplat-pick variantsmesh.ts— mesh + mesh-pick variantserf.ts— shared-math erf polynomialrender.ts— the single-pass and composed bloom executorsindex.ts— merges the families intoSHADER_REGISTRY(uselistShaders()for the live entry count — hardcoded totals drift)Why a dedicated page rather than reusing the main viewer:
THREE.WebGLRenderer, WebGPU-via-WebGL2 viaWebGPURenderer({ forceWebGL: true })) live side by side; the test toggles between them per call rather than per page load.GLSLNodeBuilderdirectly so the generated GLSL strings are recoverable for snapshot-diff.Not in scope: real WebGPU dispatch. That requires Chrome stable +
?renderer=webgpuand runs in a separate spec. This harness validates the WebGL2 fallback parity, which is whatforceWebGL: truecovers.