Skip to main content Home Creators afovea game-dev-skills threejs-postprocessing
threejs-postprocessing Three.js post-processing with EffectComposer — RenderPass, UnrealBloomPass, SSAOPass, BokehPass, FilmPass, OutlinePass, FXAA/SMAA anti-aliasing, custom ShaderPass, multi-pass composition, selective bloom, resize handling, and performance. Use when adding bloom, depth-of-field, ambient occlusion, outlines, colour grading, or any screen-space effect to a Three.js scene. Adapted from CloudAI-X/threejs-skills (MIT).
Jump to install Skills Marketplace Discover and explore AI skills built by the community.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Copy promptShow prompt details A direct command skips the review prompt. Inspect the source before running it.
npx skills add https://github.com/afovea/game-dev-skills --skill threejs-postprocessingThe command stays on one line. Scroll horizontally to inspect it before copying.
Prefer a local copy? Download the files currently available to SkillsMP.
Download Zip Downloading... More from this repository
Art Director persona for visual style, pillars, art bible, cross-discipline visual consistency, art critique, and art QA. Use when a task needs visual direction, style enforcement, or cohesion across concept, environment, character, VFX, and lighting.
Related occupations SOC
Based on SOC occupation classification
name threejs-postprocessing description Three.js post-processing with EffectComposer — RenderPass, UnrealBloomPass, SSAOPass, BokehPass, FilmPass, OutlinePass, FXAA/SMAA anti-aliasing, custom ShaderPass, multi-pass composition, selective bloom, resize handling, and performance. Use when adding bloom, depth-of-field, ambient occlusion, outlines, colour grading, or any screen-space effect to a Three.js scene. Adapted from CloudAI-X/threejs-skills (MIT). license MIT compatibility Portable reference skill for agents that support markdown skills or prompt files. Works best alongside project Three.js source files and Chrome DevTools GPU profiling. disable-model-invocation true metadata {"owner":"game-delivery","version":"2.0.0","language":"en-GB","category":"web-rendering","upstream_references":["https://github.com/CloudAI-X/threejs-skills (MIT — see NOTICE.md)"],"tags":["three-js","post-processing","effect-composer","bloom","ssao","depth-of-field","anti-aliasing","outline","shader-pass","screen-space-effects"],"intents":["effect-composition","bloom-setup","ambient-occlusion","depth-of-field","outline-effect","antialiasing-selection","custom-pass-authoring"],"output_types":["code-example","api-reference","pass-chain-plan"]}
Three.js Post-Processing
Quick Start
import * as THREE from 'three' ;
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js' ;
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js' ;
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js' ;
const composer = new EffectComposer (renderer);
composer.addPass (new RenderPass (scene, camera));
composer.addPass (new UnrealBloomPass (
new THREE .Vector2 (window .innerWidth , window .innerHeight ),
0.5 ,
0.4 ,
0.85 ,
));
function animate ( ) {
requestAnimationFrame (animate);
composer.render ();
}
EffectComposer Setup
import { } ;
{ } ;
renderTarget = . (
. ,
. ,
{
: . ,
: . ,
: . ,
: ,
}
);
composer = (renderer, renderTarget);
composer. ( (scene, camera));
( ) {
composer. ( . , . );
composer. ( . ( . , ));
}
. ( , onResize);
EffectComposer
from
'three/addons/postprocessing/EffectComposer.js'
import
RenderPass
from
'three/addons/postprocessing/RenderPass.js'
const
new
THREE
WebGLRenderTarget
window
innerWidth
window
innerHeight
type
THREE
HalfFloatType
format
THREE
RGBAFormat
colorSpace
THREE
SRGBColorSpace
samples
4
const
new
EffectComposer
addPass
new
RenderPass
function
onResize
setSize
window
innerWidth
window
innerHeight
setPixelRatio
Math
min
window
devicePixelRatio
2
window
addEventListener
'resize'
Pass Reference
RenderPass — Required First Pass import { RenderPass } from 'three/addons/postprocessing/RenderPass.js' ;
const renderPass = new RenderPass (scene, camera);
renderPass.clearColor = new THREE .Color (0x000000 );
renderPass.clearAlpha = 1 ;
composer.addPass (renderPass);
UnrealBloomPass — Glow / Bloom import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js' ;
const bloom = new UnrealBloomPass (
new THREE .Vector2 (window .innerWidth , window .innerHeight ),
1.5 ,
0.4 ,
0.85 ,
);
bloom.enabled = true ;
composer.addPass (bloom);
bloom.strength = 1.0 ;
bloom.radius = 0.5 ;
bloom.threshold = 0.8 ;
SSAOPass — Screen-Space Ambient Occlusion import { SSAOPass } from 'three/addons/postprocessing/SSAOPass.js' ;
const ssao = new SSAOPass (scene, camera, window .innerWidth , window .innerHeight );
ssao.kernelRadius = 16 ;
ssao.minDistance = 0.005 ;
ssao.maxDistance = 0.1 ;
composer.addPass (ssao);
BokehPass — Depth of Field import { BokehPass } from 'three/addons/postprocessing/BokehPass.js' ;
const bokeh = new BokehPass (scene, camera, {
focus : 500.0 ,
aperture : 0.025 ,
maxblur : 0.01 ,
});
composer.addPass (bokeh);
bokeh.uniforms ['focus' ].value = focusDistance;
bokeh.uniforms ['aperture' ].value = apertureValue;
FilmPass — Film Grain and Scanlines import { FilmPass } from 'three/addons/postprocessing/FilmPass.js' ;
const film = new FilmPass (
0.35 ,
0.0 ,
648 ,
false
);
composer.addPass (film);
DotScreenPass — Pop-Art Halftone import { DotScreenPass } from 'three/addons/postprocessing/DotScreenPass.js' ;
const dotScreen = new DotScreenPass (
new THREE .Vector2 (0 , 0 ),
0.5 ,
0.8 ,
);
composer.addPass (dotScreen);
GlitchPass — Digital Glitch import { GlitchPass } from 'three/addons/postprocessing/GlitchPass.js' ;
const glitch = new GlitchPass ();
glitch.goWild = false ;
composer.addPass (glitch);
OutlinePass — Object Outlines import { OutlinePass } from 'three/addons/postprocessing/OutlinePass.js' ;
const outline = new OutlinePass (
new THREE .Vector2 (window .innerWidth , window .innerHeight ),
scene,
camera,
);
outline.edgeStrength = 3.0 ;
outline.edgeGlow = 0.5 ;
outline.edgeThickness = 1.0 ;
outline.visibleEdgeColor .set ('#ffffff' );
outline.hiddenEdgeColor .set ('#190a05' );
composer.addPass (outline);
outline.selectedObjects = [mesh1, mesh2];
outline.selectedObjects = [];
Anti-Aliasing MSAA built into the renderer is the simplest; post-process AA is needed when using a custom render target.
FXAA — Fast Approximate AA import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js' ;
import { FXAAShader } from 'three/addons/shaders/FXAAShader.js' ;
const fxaa = new ShaderPass (FXAAShader );
fxaa.material .uniforms ['resolution' ].value .x = 1 / (window .innerWidth * renderer.getPixelRatio ());
fxaa.material .uniforms ['resolution' ].value .y = 1 / (window .innerHeight * renderer.getPixelRatio ());
composer.addPass (fxaa);
function onResize ( ) {
fxaa.material .uniforms ['resolution' ].value .x = 1 / (window .innerWidth * renderer.getPixelRatio ());
fxaa.material .uniforms ['resolution' ].value .y = 1 / (window .innerHeight * renderer.getPixelRatio ());
}
SMAA — Sub-pixel Morphological AA (Higher Quality) import { SMAAPass } from 'three/addons/postprocessing/SMAAPass.js' ;
const smaa = new SMAAPass (
window .innerWidth * renderer.getPixelRatio (),
window .innerHeight * renderer.getPixelRatio (),
);
composer.addPass (smaa);
TAA — Temporal AA (Reduces Shimmer) import { TAARenderPass } from 'three/addons/postprocessing/TAARenderPass.js' ;
const taa = new TAARenderPass (scene, camera);
taa.sampleLevel = 2 ;
composer.addPass (taa);
Custom ShaderPass import { ShaderPass } from 'three/addons/postprocessing/ShaderPass.js' ;
const vignetteShader = {
uniforms : {
tDiffuse : { value : null },
uStrength : { value : 0.5 },
uOffset : { value : 1.2 },
},
vertexShader : `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
` ,
fragmentShader : `
uniform sampler2D tDiffuse;
uniform float uStrength;
uniform float uOffset;
varying vec2 vUv;
void main() {
vec4 colour = texture2D(tDiffuse, vUv);
vec2 uv = (vUv - 0.5) * 2.0;
float vignette = 1.0 - dot(uv, uv) * uStrength;
vignette = clamp(vignette, 0.0, 1.0);
gl_FragColor = vec4(colour.rgb * vignette, colour.a);
}
` ,
};
const vignettePass = new ShaderPass (vignetteShader);
vignettePass.uniforms ['uStrength' ].value = 0.7 ;
composer.addPass (vignettePass);
Selective Bloom (Objects Only) Bloom only selected objects without affecting the full scene.
const BLOOM_LAYER = 1 ;
const bloomLayer = new THREE .Layers ();
bloomLayer.set (BLOOM_LAYER );
emissiveMesh.layers .enable (BLOOM_LAYER );
const darkMaterial = new THREE .MeshBasicMaterial ({ color : 0x000000 });
const materialMap = new Map ();
function darkenNonBloomed (obj ) {
if (obj.isMesh && !bloomLayer.test (obj.layers )) {
materialMap.set (obj.uuid , obj.material );
obj.material = darkMaterial;
}
}
function restoreMaterials (obj ) {
if (materialMap.has (obj.uuid )) {
obj.material = materialMap.get (obj.uuid );
materialMap.delete (obj.uuid );
}
}
function render ( ) {
scene.traverse (darkenNonBloomed);
bloomComposer.render ();
scene.traverse (restoreMaterials);
finalComposer.render ();
}
Colour Grading — LUT Pass Apply a 3D look-up table for colour grading.
import { LUTPass } from 'three/addons/postprocessing/LUTPass.js' ;
import { LUTCubeLoader } from 'three/addons/loaders/LUTCubeLoader.js' ;
new LUTCubeLoader ().load ('lut/warm.cube' , result => {
const lutPass = new LUTPass ();
lutPass.lut = result.texture3D ;
lutPass.intensity = 1.0 ;
composer.addPass (lutPass);
});
Resize Handling function onWindowResize ( ) {
const w = window .innerWidth ;
const h = window .innerHeight ;
camera.aspect = w / h;
camera.updateProjectionMatrix ();
renderer.setSize (w, h);
composer.setSize (w, h);
if (fxaaPass) {
fxaaPass.material .uniforms ['resolution' ].value .set (
1 / (w * renderer.getPixelRatio ()),
1 / (h * renderer.getPixelRatio ()),
);
}
}
window .addEventListener ('resize' , onWindowResize);
Performance Tips
Fewer passes = better — each pass is a full-screen render; keep total passes under 5
HalfFloatType render target — required for HDR bloom; higher precision than UnsignedByteType
FXAA over MSAA for post-processing pipelines — MSAA doesn't apply after render-to-target
Disable passes when not visible — pass.enabled = false skips execution entirely
Reduce resolution for expensive passes — halve the render target size for SSAO/DoF
Profile with Spector.js — inspect each pass's GPU cost individually
if (isMobile) {
bloomPass.enabled = false ;
}
const halfResTarget = new THREE .WebGLRenderTarget (
window .innerWidth / 2 ,
window .innerHeight / 2 ,
);
See Also
threejs-shaders — writing custom fragment shaders for ShaderPass
threejs-fundamentals — renderer setup and pixel ratio
threejs-materials — MeshPhysicalMaterial transmission as alternative to DoF
three-js-best-practices — GPU budget and mobile scaling rules