Quick start
Install
npm install denoiser
This one package is enough to get going: the default runtime has no runtime
dependencies. onnxruntime-web is an optional peer dependency, needed only if you
opt into the ORT runtime (denoiser/ort; see
Choosing a runtime).
Everything here was validated on Apple GPUs only. The default runtime is
AutoRuntime: WebNN fp16 for base/large models when WebNN is available (Chrome
with a feature flag), the hand-written WGSL runtime otherwise.
Hello world
This is the entire "noisy image in, clean image out" flow — no three.js, no build
tricks. It's lifted directly from
examples/hello-world/src/main.ts:
import { Denoiser } from 'denoiser';
async function run(): Promise<Denoiser> {
const noisyImg = document.querySelector<HTMLImageElement>('#noisy-img')!;
await noisyImg.decode();
const denoiser = await Denoiser.create({ quality: 'balanced' });
const denoised = await denoiser.denoise(noisyImg);
const canvas = document.querySelector<HTMLCanvasElement>('#denoised')!;
canvas.getContext('2d')!.putImageData(denoised!, 0, 0);
return denoiser;
}
Three calls do the work:
Denoiser.create()— creates the WebGPU device (or adopts the one you pass asdevice) and loads a model.qualitypicks its size:'fast'(the default, the small network),'balanced'(the base network: visibly cleaner, about 1.5x the time) or'high'(the large network where one exists).denoiser.denoise(imageLike)— runs it. Accepts anHTMLImageElement,HTMLCanvasElement,ImageBitmap,ImageData,HTMLVideoElement,OffscreenCanvas, or a raw{ data, width, height }object; returnsImageData.putImageData— paint the result.
Live demo → — the deployed page shows this exact source next to the noisy/denoised comparison.
What happens on first run
Denoiser.create() fetches the weights it needs from the default CDN
(tzaUrl, jsDelivr by default) — nothing ships inside the npm package itself.
Weight files run about 0.6–7.7 MB depending on quality tier (see
Models & weights for the full size table); only the one
variant your call actually needs is fetched, not the full set. The fetched bytes are
cached in memory for the life of the page (and by the browser's normal HTTP cache
across page loads), so only the very first denoise() call pays the download.
Production apps should host the weights themselves rather than rely on the default
CDN URL — see Models & weights for the
tzaUrl option.
Next
- Models & weights — quality tiers, aux inputs, self-hosting.
- How it works — what's actually happening on the GPU.
- The GPUDevice — sharing the device with three.js for a zero-copy pipeline.