Examples

Every live demo, deployed and runnable in your own browser.

All demos below are live, deployed pages — not screenshots or embeds. Every one needs a WebGPU browser (Chrome/Edge stable, Safari 26+, Firefox rolling out); see Introduction if a demo shows a "needs WebGPU" banner instead of running.

Hello world

The 10-line story: a noisy render → Denoiser.create() → denoise() → canvas. No three.js, no build tricks — the page shows the exact source next to the result. Start here. Walkthrough: Quick start.

The flagship quality demo. Pre-rendered path-traced scenes at 1–16 samples per pixel (plus aux buffers and a converged reference), denoised live in the browser: drag the before/after divider (there is no camera to orbit), step the noise ladder, toggle albedo+normal guidance on the same frame. For an interactive scene, use the three.js path tracer demo.

Aux inputs

What the network actually sees. Shows color, albedo, and normal exactly as fed to the model, alongside examples of the real mistakes that degrade aux quality — environment-hit normals, alpha-blended normals, HDR albedo clamping. The live companion to Models & weights and the aux-inputs guide.

webgpu-raw

Proof of engine-neutrality: a single-file WGSL toy path tracer with no framework — no three.js, no Babylon, no bundler magic — feeding denoiseTextures on the same GPUDevice. The reference for integrating a custom engine that isn't three.js.

Pipeline Lab

The full offline pipeline in one page: three-gpu-pathtracer renders below the output size, this library denoises it, and @pmndrs/upscaler (FSR1) scales it back up, all on one GPUDevice through the path tracer's own setDenoiser / setUpscaler hooks. Every stage is tweakable, there are four scenes (or drop in your own .glb), and a benchmark times each stage and scores it against a high-sample reference. See Benchmarking on your machine. Upscaling is spatial only for now: the temporal (FSR3) path needs a fresh, jittered render every frame, and the path tracer accumulates one image instead (pmndrs/upscaler#93).

three.js path tracer

three r186 WebGPUPathTracer and this library sharing one GPUDevice: progressive path tracing, denoised live while it accumulates, CPU-copy and zero-copy paths side by side. See The GPUDevice for how the shared device works. ?fsr=1 path-traces and denoises at half resolution, then upscales 2x with @pmndrs/upscaler's FSR1 (EASU + RCAS).

Note

The WebGPU path tracer is early-stage upstream work in three-gpu-pathtracer (main, 0.0.27), pinned to a commit SHA for this demo — expect rough edges.

LDraw Eiffel Tower

A LEGO Eiffel Tower on a table: fast raster preview while you orbit, path-trace + denoise the moment the camera comes to rest. Same pinned-pathtracer caveat as above.

Benchmark

The performance harness behind the numbers in Performance: cold + warm timings, per-stage stats, and fp16-vs-fp32 PSNR across image sizes — reproducible in your own browser, on your own hardware.

Real-time (temporal) denoising

These use the FidelityFX denoisers (denoiser/ffx, denoiser/three), not OIDN. See Which denoiser do I need?

Ray-traced shadows and reflections in a raster app

The "when would I use this?" demo. A furnished room in a normal three.js raster pipeline, with two effects ray traced at 1 ray per pixel: area-light shadows, traced against the real scene meshes with three-mesh-bvh's WebGPU BVH, and glossy SSR. ffxShadows() and ffxReflections() denoise them every frame. Toggle each one against what three.js does without ray tracing (a VSM shadow map, env-map-only reflections) and against a converged reference. Use the light-size slider to see contact hardening. A live table shows each pass's GPU cost. There's an optional half-resolution + FSR3 path.

Reflections, explained: probe, SSR, ray tracing

An explainer for the three ways a real-time renderer finds reflections, and the hybrid that mixes them: a box-projected reflection probe (captured once, prefiltered per roughness), three's SSR, and rays traced against the scene with three-mesh-bvh. A guided tour sets up one situation per weakness (a mirror, things off screen, moving objects, contact, rough surfaces) and shows two methods split-screen; a "where reflections come from" view tints every pixel by what answered it. Every noisy mode takes one sample per pixel, denoised by ffxReflections(), with a cost table and a "which one should I use?" guide.

Reflections in two rooms: probes, SSR and rays

The two rooms from Ben Houston's reflection probes example, with a polished floor, lights that change colour and a mirror ball rolling through the doorway. One probe per room plus a doorway probe give every surface its own room's reflection for almost nothing per frame. SSR and one traced ray per pixel (three-mesh-bvh), denoised by ffxReflections(), add what probes can't have: the moving ball (kept out of the captures), contact, and what the probe never saw. A guided tour compares the modes split-screen; the probes re-bake when the lights change (about 2 ms for all three) or can be frozen to show them going stale. A cost table times each pass.

Reflection probes on r186 (preview of three.js #35046)

Ben Houston's reflection probes (three.js #35046) running on three r186 until that PR lands: probes you place per room, box-projected onto the walls, blended at their edges, with smaller probes (a doorway) taking priority and scene.environment filling the rest. Same API and scene as the PR's example. r186 can't bind cube arrays, so the cubes live in a 2D array texture and the lookup picks the face itself, with a seam fix so rough surfaces don't show face edges. Matches the PR's output to within 8-bit noise; three probes bake in 3–5 ms. This is example code, not part of the denoiser package: when #35046 ships, swap the imports for three's and re-bake.

Baked + dynamic shadows: when to split

The static / dynamic split engines use for lightmaps, in the browser: the static half of the shadow baked once into a lightmap (16 rays per texel, cleaned by OIDN) or gathered in a world-space cache, and 1 ray per pixel against only the moving objects, denoised every frame by ffxShadows(). Explains what the split buys (converged, steady static shadows; rays that only test moving objects) and costs (bake time, UVs, memory, a light that can't move), with measured numbers and when to use it. Both denoisers on one page: OIDN at bake time, FFX live.

three.js SSR: FidelityFX vs recurrentDenoise

three's webgpu_postprocessing_ssr_denoise example with ffxReflections() swapped in, split-screen against three's own temporal denoiser.

FidelityFX denoisers, raw WGSL

The test bed behind the numbers in Real-time (temporal) denoising: 1-sample shadows and reflections, noisy / denoised / reference panels, no three.js.