Inspired by STDOOM, RetroPass is a WebGL post-processing effect for Three.js that enables you to give your project a retro look and feel, with pixelation and colour quantisation for a nostalgic, low-res aesthetic — ideal for games or apps evoking classic video game vibes.
Specify any number of colours up to 4096 to create a performance optimised (quantised cube) palette, or create a custom palette of any size from 2 to 4096 colours.
npm install @mesmotronic/three-retropassRequires three as a peer dependency.
Here’s an example of how to use RetroPass in your Three.js project, showing a basic scene with a retro effect at 320x200 resolution with 16 colours and dithering enabled.
import * as THREE from "three";
import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
import { RenderPass } from "three/addons/postprocessing/RenderPass.js";
import { RetroPass } from "@mesmotronic/three-retropass";
// Scene setup
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.outputColorSpace = THREE.SRGBColorSpace;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Composer setup
const composer = new EffectComposer(renderer);
const renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass);
// Add RetroPass
const retroPass = new RetroPass({ resolution: new THREE.Vector2(320, 200), colorCount: 16, dithering: true });
composer.addPass(retroPass);
// Render loop
function animate() {
requestAnimationFrame(animate);
composer.render();
}
animate();Here's the equivalent example using RetroPass as a TSL node with WebGPURenderer and RenderPipeline.
import * as THREE from "three";
import { WebGPURenderer, RenderPipeline } from "three/webgpu";
import { pass } from "three/tsl";
import { retroPass } from "@mesmotronic/three-retropass/webgpu";
// Scene setup
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new WebGPURenderer();
renderer.outputColorSpace = THREE.SRGBColorSpace;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Post processing setup
const scenePass = pass(scene, camera);
const retroNode = retroPass(scenePass.getTextureNode(), {
resolution: new THREE.Vector2(320, 200),
colorCount: 16,
dithering: true,
});
const renderPipeline = new RenderPipeline(renderer);
renderPipeline.outputNode = retroNode;
// Render loop
async function animate() {
requestAnimationFrame(animate);
await renderPipeline.renderAsync();
}
animate();Properties can be updated at any time:
retroNode.colorCount = 4;
retroNode.dithering = false;
retroNode.inverted = true;| Name | Description | Constructor | Property |
|---|---|---|---|
resolution |
THREE.Vector2 specifying the resolution of the retro effect. |
✓ | ✓ |
autoResolution |
Boolean to enable or disable automatic resolution handling. |
✓ | ✓ |
pixelRatio |
Number for the pixel ratio, overrides resolution if set. |
✓ | ✓ |
colorCount |
Number indicating the number of colours in the palette. |
✓ | ✓ |
colorPalette |
Array of THREE.Color objects defining the colour palette. |
✓ | ✓ |
dithering |
Boolean to enable or disable dithering. |
✓ | ✓ |
ditheringOffset |
Number controlling the dithering offset. |
✓ | ✓ |
autoDitheringOffset |
Boolean to enable or disable automatic dithering offset handling. |
✓ | ✓ |
Example screenshots using default palettes with Littlest Tokyo by Glen Fox, CC Attribution.
320x200 2 colours (monochrome)
320x200 4 colours (CGA mode 1)
320x200 256 colours (web safe)
320x200 256 colours (web safe)
This project is licensed under the BSD 2-Clause License - see the LICENSE file for details.
Copyright (c) 2025, Mesmotronic Limited

