npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@pmndrs/upscaler

v0.5.0

Published

AMD FidelityFX Super Resolution (FSR1 spatial + FSR2/3-style temporal upscaling) for three.js WebGPURenderer, implemented as raw WGSL compute passes

Readme

@pmndrs/upscaler

npm live demos license

Render fewer pixels. Get a sharper image.

@pmndrs/upscaler is a temporal upscaler for the web. Render your scene at a fraction of its resolution, and it rebuilds the full-resolution frame from the last several, recovering detail that no single frame ever had and anti-aliasing it along the way. It's the idea behind FSR 2/3, DLSS and XeSS, running in the browser on WebGPU.

What you do with the GPU time it saves is up to you: hold your frame rate on a laptop, or spend it on GI, reflections and heavier materials that wouldn't fit at native resolution.

pipeline.outputNode = upscaleScene(scene, camera);

▶ See it live: showcases and 16 hands-on examples, each one a small, readable integration.

Built on FSR, grown up on the web

It started as a port of AMD's FidelityFX Super Resolution. The spatial EASU/RCAS shaders are faithful WGSL ports of AMD's originals, and the temporal path follows the FSR 2/3 architecture (credits). Then the web asked questions FSR never had to answer, and we measured our way past the port:

  • Leaner than the source. We rebuilt source-faithful FSR 3.1.5 pass graphs and raced them against ours on the GPU. Where they cost 6–76% more for no visible gain, our fused passes stayed. Where the source's design earned its keep, as with the depth reconstruction that keeps history through camera motion, we adopted it in a leaner form. (Why we diverge)
  • Still images that actually settle. A standing scene converges and stays put, instead of shimmering as each jitter phase re-snaps the history.
  • HDR-safe sharpening. Bright highlights stay crisp, and the sharpening is capped so they never blow out into fireflies.
  • Transparent canvases. Alpha is upscaled along with color, so the page shows through where it should.
  • At home in a render pipeline. A native TSL node makes it one line in three's RenderPipeline, and it composes with reduced-resolution SSGI, SSR and GTAO graphs. It also publishes its motion and disocclusion temporal guides so your own effects can reuse them instead of recomputing them.
  • Debuggable by design. Every stage has a debug view, there's an interactive bench, and the tuning decisions are backed by measurement scripts you can re-run.

Where it runs

Today it plugs into three.js WebGPURenderer (r186+). Underneath it's plain WebGPU: hand-written WGSL compute passes dispatched on your renderer's GPUDevice, with no three.js in the shaders. Bringing it to another WebGPU engine means writing an adapter, not rewriting the upscaler; that's tracked in #61. It needs a WebGPU-capable browser, and there's no WebGL fallback.

Install

npm install @pmndrs/upscaler three

WebGPU only: you need a WebGPU-capable browser (Chrome/Edge 113+) and three r186+ (a peer dependency). r184/r185 still work but are deprecated. The TSL node warns once and falls back to the pre-r186 render-pipeline hooks, and that fallback will be removed. There is no WebGL fallback. See Compatibility.

▶ Live demos: pmndrs.github.io/upscaler: 16 interactive examples, covering spatial vs temporal, the aliasing-torture scene, transparency and reactive masks, the composable and spatial-only TSL nodes, SSGI/SSR upscaled in one post graph, temporal guides, and transparent-canvas alpha.

Quick start

The recommended integration is the TSL node. Make it the output of a RenderPipeline, and it renders your scene at reduced resolution and upscales it back, jitter and all:

import * as THREE from 'three/webgpu';
import { upscaleScene, QualityMode } from '@pmndrs/upscaler';

// The upscaler stays linear/HDR; presentation is the renderer's job.
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.outputColorSpace = THREE.SRGBColorSpace;
scene.background = new THREE.Color(0x10141a); // or empty regions stay transparent (see Alpha)

const pipeline = new THREE.RenderPipeline(renderer);
pipeline.outputNode = upscaleScene(scene, camera, { quality: QualityMode.Quality });

renderer.setAnimationLoop(() => pipeline.render());

That's the whole integration: no manual jitter, MRT or velocity wiring. upscaleScene renders the scene in-graph as the upscaler's input, so the sub-pixel jitter lands on it and you get real reconstruction rather than a smart blur.

| Integration | When | | --- | --- | | upscaleScene(scene, camera) | A scene, rendered through a RenderPipeline. | | upscale(color, depth, velocity, camera) | A reduced-resolution effect graph (SSGI/SSR/GTAO) in the same pipeline. | | upscaleSpatial(color) | Only a color texture: single-frame FSR1, no motion data. | | UpscalePass | A plain render loop with no post-processing graph. | | Upscaler | Your own render-target loop, split frames, or inputs the others don't expose. | | temporalGuides() / upscaler.guides | Other temporal effects sharing the upscaler's motion, depth and disocclusion. |

Getting started walks through each one. Inputs and contracts specifies what color, depth, velocity, jitter, reactive masks and exposure must contain. Most integration bugs are contract bugs.

Alpha

Every path upscales RGBA: the input's alpha is filtered and accumulated, not replaced with 1.0, so a transparent canvas stays transparent through the upscale. This is the same convention as three's FSR1Node. An opaque input comes out with alpha exactly 1.

Coming from 0.2: earlier versions wrote alpha 1.0 everywhere. three's WebGPURenderer defaults to alpha: true and clears to alpha 0, so a scene with no scene.background (and no opaque clear color) presented through UpscalePass or the TSL nodes now shows the page through its empty regions, exactly as three does without the upscaler. For the old look, set scene.background or renderer.setClearColor(color, 1), or create the renderer with alpha: false. Likewise, a post graph that scales the upscaled vec4 by a scalar, such as upscale(...).mul(vignette), now scales alpha too. Multiply by vec4(vec3(vignette), 1) to darken color only. Details: Alpha.

Documentation

Status

The pipeline is feature-complete and GPU-verified. It covers the spatial (FSR1) and temporal paths, RGBA (alpha) passthrough, luminance-stability locks, auto-exposure (plus external and host pre-exposure inputs), multi-scale shading-change detection, reactive masks (explicit and auto-generated), RCAS with opt-in denoise, the imperative UpscalePass, the composable TSL nodes, and the raw and linked-TSL temporal-guides surfaces. A benchmarking program A/B-compared this implementation against source-style FSR 3.1.5 pass graphs on the GPU. The measurements and the reasoning for each divergence are in PARITY.md.

Deliberately not planned:

  • Frame generation (the other half of "FSR3"). It needs swapchain-level frame pacing, which browsers don't expose.
  • MSAA input. FSR's temporal path is the anti-aliaser; a multisampled input is redundant and can't bind to the compute passes.
  • Perf-only micro-optimizations (textureGather tap packing, f16 arithmetic, bind-group caching). Each adds correctness risk to a core path with no image-quality gain, so they wait until performance is an actual bottleneck on real content.

Contributing

Bug reports, examples and PRs are welcome. Contributing covers the dev loop, the bench, testing on a real GPU, and how releases are cut.

References

Credits

Built by Dennis Smolek. Maintained under the Poimandres collective.

Based on AMD's FidelityFX Super Resolution — this package ports its MIT-licensed EASU/RCAS shaders and follows the FSR2/3 temporal-upscaling architecture. "FSR" and "FidelityFX" are AMD's; this is an independent, unaffiliated implementation for three.js.

License

MIT — see LICENSE. The EASU/RCAS shaders derive from AMD's MIT-licensed FidelityFX Super Resolution; AMD's copyright notice is included in the license file.