
Threejs Postprocessing
- 5.4k installs
- 2.8k repo stars
- Updated July 9, 2026
- cloudai-x/threejs-skills
threejs-postprocessing is an agent skill for Three.js EffectComposer bloom DOF SSAO and custom post-processing passes.
About
The threejs-postprocessing skill documents Three.js post-processing using EffectComposer and common passes for bloom, depth of field, FXAA, SMAA, SSAO, film grain, vignette, color correction, pixelation, glitch, halftone, and outline effects. Quick start assumes a base scene and renderer, then stacks passes with guidance on selective bloom for specific objects, custom ShaderPass examples like invert colors and chromatic aberration, and multi-pass render-to-texture workflows. WebGPU post-processing for Three.js r150+ is included alongside classic EffectComposer patterns. Performance tips recommend limiting pass count because each adds a full-screen render, lowering resolution on blur passes, disabling unused effects, preferring FXAA over MSAA, and toggling passes only when needed. Related skills point to threejs-shaders for custom shader development, threejs-textures for render targets, and threejs-fundamentals for renderer setup. Use when adding visual effects, color grading, blur, glow, or custom screen-space shaders to Three.js scenes.
- Centers on EffectComposer pass stacks for bloom DOF SSAO and screen effects.
- Documents selective bloom, custom ShaderPass, and multi-pass render-to-texture patterns.
- Includes WebGPU post-processing guidance for Three.js r150 and later versions.
- Performance tips: limit passes, lower blur resolution, disable unused effects, prefer FXAA.
- Cross-links threejs-shaders, threejs-textures, and threejs-fundamentals related skills.
Threejs Postprocessing by the numbers
- 5,447 all-time installs (skills.sh)
- +505 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #88 of 2,277 Frontend Development skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
threejs-postprocessing capabilities & compatibility
- Capabilities
- effectcomposer pass stacking · bloom dof ssao and anti aliasing passes · custom shaderpass templates · webgpu post processing notes · performance optimization guidance
- Use cases
- frontend · ui design
What threejs-postprocessing says it does
Three.js post-processing - EffectComposer, bloom, DOF, screen effects.
WebGPU Post-Processing (Three.js r150+)
npx skills add https://github.com/cloudai-x/threejs-skills --skill threejs-postprocessingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 5.4k |
|---|---|
| repo stars | ★ 2.8k |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 9, 2026 |
| Repository | cloudai-x/threejs-skills ↗ |
How do I add bloom, depth of field, or custom screen shaders to a Three.js scene efficiently?
Add Three.js post-processing with EffectComposer, bloom, DOF, SSAO, custom ShaderPass, and WebGPU effects for visual polish.
Who is it for?
Frontend developers adding cinematic effects and color grading to Three.js WebGL scenes.
Skip if: Skip when basic lighting alone suffices; use threejs-lighting instead.
When should I use this skill?
User adds post-processing, bloom, DOF, screen effects, or custom ShaderPass to Three.js.
What you get
Configured EffectComposer pass chains with performance-aware settings and optional WebGPU path.
- EffectComposer pipeline
- Bloom and DOF pass configuration
- Custom screen-space shader passes
By the numbers
- Recommends limiting full-screen post-processing passes
- Documents WebGPU path for Three.js r150+
Files
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";
// Setup composer
const composer = new EffectComposer(renderer);
// Render scene
const renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass);
// Add bloom
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
1.5, // strength
0.4, // radius
0.85, // threshold
);
composer.addPass(bloomPass);
// Animation loop - use composer instead of renderer
function animate() {
requestAnimationFrame(animate);
composer.render(); // NOT renderer.render()
}EffectComposer Setup
import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
import { RenderPass } from "three/addons/postprocessing/RenderPass.js";
const composer = new EffectComposer(renderer);
// First pass: render scene
const renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass);
// Add more passes...
composer.addPass(effectPass);
// Last pass should render to screen
effectPass.renderToScreen = true; // Default for last pass
// Handle resize
function onResize() {
const width = window.innerWidth;
const height = window.innerHeight;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize(width, height);
composer.setSize(width, height);
}Common Effects
Bloom (Glow)
import { UnrealBloomPass } from "three/addons/postprocessing/UnrealBloomPass.js";
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
1.5, // strength - intensity of glow
0.4, // radius - spread of glow
0.85, // threshold - brightness threshold
);
composer.addPass(bloomPass);
// Adjust at runtime
bloomPass.strength = 2.0;
bloomPass.threshold = 0.5;
bloomPass.radius = 0.8;Selective Bloom
Apply bloom only to specific objects.
import { UnrealBloomPass } from "three/addons/postprocessing/UnrealBloomPass.js";
import { ShaderPass } from "three/addons/postprocessing/ShaderPass.js";
// Layer setup
const BLOOM_LAYER = 1;
const bloomLayer = new THREE.Layers();
bloomLayer.set(BLOOM_LAYER);
// Mark objects to bloom
glowingMesh.layers.enable(BLOOM_LAYER);
// Dark material for non-blooming objects
const darkMaterial = new THREE.MeshBasicMaterial({ color: 0x000000 });
const materials = {};
function darkenNonBloomed(obj) {
if (obj.isMesh && !bloomLayer.test(obj.layers)) {
materials[obj.uuid] = obj.material;
obj.material = darkMaterial;
}
}
function restoreMaterial(obj) {
if (materials[obj.uuid]) {
obj.material = materials[obj.uuid];
delete materials[obj.uuid];
}
}
// Custom render loop
function render() {
// Render bloom pass
scene.traverse(darkenNonBloomed);
composer.render();
scene.traverse(restoreMaterial);
// Render final scene over bloom
renderer.render(scene, camera);
}FXAA (Anti-Aliasing)
import { ShaderPass } from "three/addons/postprocessing/ShaderPass.js";
import { FXAAShader } from "three/addons/shaders/FXAAShader.js";
const fxaaPass = new ShaderPass(FXAAShader);
fxaaPass.material.uniforms["resolution"].value.set(
1 / window.innerWidth,
1 / window.innerHeight,
);
composer.addPass(fxaaPass);
// Update on resize
function onResize() {
fxaaPass.material.uniforms["resolution"].value.set(
1 / window.innerWidth,
1 / window.innerHeight,
);
}SMAA (Better Anti-Aliasing)
import { SMAAPass } from "three/addons/postprocessing/SMAAPass.js";
const smaaPass = new SMAAPass(
window.innerWidth * renderer.getPixelRatio(),
window.innerHeight * renderer.getPixelRatio(),
);
composer.addPass(smaaPass);SSAO (Ambient Occlusion)
import { SSAOPass } from "three/addons/postprocessing/SSAOPass.js";
const ssaoPass = new SSAOPass(
scene,
camera,
window.innerWidth,
window.innerHeight,
);
ssaoPass.kernelRadius = 16;
ssaoPass.minDistance = 0.005;
ssaoPass.maxDistance = 0.1;
composer.addPass(ssaoPass);
// Output modes
ssaoPass.output = SSAOPass.OUTPUT.Default;
// SSAOPass.OUTPUT.Default - Final composited output
// SSAOPass.OUTPUT.SSAO - Just the AO
// SSAOPass.OUTPUT.Blur - Blurred AO
// SSAOPass.OUTPUT.Depth - Depth buffer
// SSAOPass.OUTPUT.Normal - Normal bufferDepth of Field (DOF)
import { BokehPass } from "three/addons/postprocessing/BokehPass.js";
const bokehPass = new BokehPass(scene, camera, {
focus: 10.0, // Focus distance
aperture: 0.025, // Aperture (smaller = more DOF)
maxblur: 0.01, // Max blur amount
});
composer.addPass(bokehPass);
// Update focus dynamically
bokehPass.uniforms["focus"].value = distanceToTarget;Film Grain
import { FilmPass } from "three/addons/postprocessing/FilmPass.js";
const filmPass = new FilmPass(
0.35, // noise intensity
0.5, // scanline intensity
648, // scanline count
false, // grayscale
);
composer.addPass(filmPass);Vignette
import { ShaderPass } from "three/addons/postprocessing/ShaderPass.js";
import { VignetteShader } from "three/addons/shaders/VignetteShader.js";
const vignettePass = new ShaderPass(VignetteShader);
vignettePass.uniforms["offset"].value = 1.0; // Vignette size
vignettePass.uniforms["darkness"].value = 1.0; // Vignette intensity
composer.addPass(vignettePass);Color Correction
import { ShaderPass } from "three/addons/postprocessing/ShaderPass.js";
import { ColorCorrectionShader } from "three/addons/shaders/ColorCorrectionShader.js";
const colorPass = new ShaderPass(ColorCorrectionShader);
colorPass.uniforms["powRGB"].value = new THREE.Vector3(1.2, 1.2, 1.2); // Power
colorPass.uniforms["mulRGB"].value = new THREE.Vector3(1.0, 1.0, 1.0); // Multiply
composer.addPass(colorPass);Gamma Correction
import { GammaCorrectionShader } from "three/addons/shaders/GammaCorrectionShader.js";
const gammaPass = new ShaderPass(GammaCorrectionShader);
composer.addPass(gammaPass);Pixelation
import { RenderPixelatedPass } from "three/addons/postprocessing/RenderPixelatedPass.js";
const pixelPass = new RenderPixelatedPass(6, scene, camera); // 6 = pixel size
composer.addPass(pixelPass);Glitch Effect
import { GlitchPass } from "three/addons/postprocessing/GlitchPass.js";
const glitchPass = new GlitchPass();
glitchPass.goWild = false; // Continuous glitching
composer.addPass(glitchPass);Halftone
import { HalftonePass } from "three/addons/postprocessing/HalftonePass.js";
const halftonePass = new HalftonePass(window.innerWidth, window.innerHeight, {
shape: 1, // 1 = dot, 2 = ellipse, 3 = line, 4 = square
radius: 4, // Dot size
rotateR: Math.PI / 12,
rotateB: (Math.PI / 12) * 2,
rotateG: (Math.PI / 12) * 3,
scatter: 0,
blending: 1,
blendingMode: 1,
greyscale: false,
});
composer.addPass(halftonePass);Outline
import { OutlinePass } from "three/addons/postprocessing/OutlinePass.js";
const outlinePass = new OutlinePass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
scene,
camera,
);
outlinePass.edgeStrength = 3;
outlinePass.edgeGlow = 0;
outlinePass.edgeThickness = 1;
outlinePass.pulsePeriod = 0;
outlinePass.visibleEdgeColor.set(0xffffff);
outlinePass.hiddenEdgeColor.set(0x190a05);
// Select objects to outline
outlinePass.selectedObjects = [mesh1, mesh2];
composer.addPass(outlinePass);Custom ShaderPass
Create your own post-processing effects.
import { ShaderPass } from "three/addons/postprocessing/ShaderPass.js";
const CustomShader = {
uniforms: {
tDiffuse: { value: null }, // Required: input texture
time: { value: 0 },
intensity: { value: 1.0 },
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform sampler2D tDiffuse;
uniform float time;
uniform float intensity;
varying vec2 vUv;
void main() {
vec2 uv = vUv;
// Wave distortion
uv.x += sin(uv.y * 10.0 + time) * 0.01 * intensity;
vec4 color = texture2D(tDiffuse, uv);
gl_FragColor = color;
}
`,
};
const customPass = new ShaderPass(CustomShader);
composer.addPass(customPass);
// Update in animation loop
customPass.uniforms.time.value = clock.getElapsedTime();Invert Colors Shader
const InvertShader = {
uniforms: {
tDiffuse: { value: null },
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform sampler2D tDiffuse;
varying vec2 vUv;
void main() {
vec4 color = texture2D(tDiffuse, vUv);
gl_FragColor = vec4(1.0 - color.rgb, color.a);
}
`,
};Chromatic Aberration
const ChromaticAberrationShader = {
uniforms: {
tDiffuse: { value: null },
amount: { value: 0.005 },
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform sampler2D tDiffuse;
uniform float amount;
varying vec2 vUv;
void main() {
vec2 dir = vUv - 0.5;
float dist = length(dir);
float r = texture2D(tDiffuse, vUv - dir * amount * dist).r;
float g = texture2D(tDiffuse, vUv).g;
float b = texture2D(tDiffuse, vUv + dir * amount * dist).b;
gl_FragColor = vec4(r, g, b, 1.0);
}
`,
};Combining Multiple Effects
import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
import { RenderPass } from "three/addons/postprocessing/RenderPass.js";
import { UnrealBloomPass } from "three/addons/postprocessing/UnrealBloomPass.js";
import { ShaderPass } from "three/addons/postprocessing/ShaderPass.js";
import { FXAAShader } from "three/addons/shaders/FXAAShader.js";
import { VignetteShader } from "three/addons/shaders/VignetteShader.js";
import { GammaCorrectionShader } from "three/addons/shaders/GammaCorrectionShader.js";
const composer = new EffectComposer(renderer);
// 1. Render scene
composer.addPass(new RenderPass(scene, camera));
// 2. Bloom
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
0.5,
0.4,
0.85,
);
composer.addPass(bloomPass);
// 3. Vignette
const vignettePass = new ShaderPass(VignetteShader);
vignettePass.uniforms["offset"].value = 0.95;
vignettePass.uniforms["darkness"].value = 1.0;
composer.addPass(vignettePass);
// 4. Gamma correction
composer.addPass(new ShaderPass(GammaCorrectionShader));
// 5. Anti-aliasing (always last before output)
const fxaaPass = new ShaderPass(FXAAShader);
fxaaPass.uniforms["resolution"].value.set(
1 / window.innerWidth,
1 / window.innerHeight,
);
composer.addPass(fxaaPass);Render to Texture
// Create render target
const renderTarget = new THREE.WebGLRenderTarget(512, 512);
// Render scene to target
renderer.setRenderTarget(renderTarget);
renderer.render(scene, camera);
renderer.setRenderTarget(null);
// Use texture
const texture = renderTarget.texture;
otherMaterial.map = texture;Multi-Pass Rendering
// Multiple composers for different scenes/layers
const bgComposer = new EffectComposer(renderer);
bgComposer.addPass(new RenderPass(bgScene, camera));
const fgComposer = new EffectComposer(renderer);
fgComposer.addPass(new RenderPass(fgScene, camera));
fgComposer.addPass(bloomPass);
// Combine in render loop
function animate() {
// Render background without clearing
renderer.autoClear = false;
renderer.clear();
bgComposer.render();
// Render foreground over it
renderer.clearDepth();
fgComposer.render();
}WebGPU Post-Processing (Three.js r150+)
import { postProcessing } from "three/addons/nodes/Nodes.js";
import { pass, bloom, dof } from "three/addons/nodes/Nodes.js";
// Using node-based system
const scenePass = pass(scene, camera);
const bloomNode = bloom(scenePass, 0.5, 0.4, 0.85);
const postProcessing = new THREE.PostProcessing(renderer);
postProcessing.outputNode = bloomNode;
// Render
function animate() {
postProcessing.render();
}Performance Tips
1. Limit passes: Each pass adds a full-screen render 2. Lower resolution: Use smaller render targets for blur passes 3. Disable unused effects: Toggle passes on/off 4. Use FXAA over MSAA: Less expensive anti-aliasing 5. Profile with DevTools: Check GPU usage
// Disable pass
bloomPass.enabled = false;
// Reduce bloom resolution
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth / 2, window.innerHeight / 2),
strength,
radius,
threshold,
);
// Only apply effects in high-performance scenarios
const isMobile = /iPhone|iPad|Android/i.test(navigator.userAgent);
if (!isMobile) {
composer.addPass(expensivePass);
}Handle Resize
function onWindowResize() {
const width = window.innerWidth;
const height = window.innerHeight;
const pixelRatio = renderer.getPixelRatio();
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize(width, height);
composer.setSize(width, height);
// Update pass-specific resolutions
if (fxaaPass) {
fxaaPass.material.uniforms["resolution"].value.set(
1 / (width * pixelRatio),
1 / (height * pixelRatio),
);
}
if (bloomPass) {
bloomPass.resolution.set(width, height);
}
}
window.addEventListener("resize", onWindowResize);See Also
threejs-shaders- Custom shader developmentthreejs-textures- Render targetsthreejs-fundamentals- Renderer setup
Related skills
Forks & variants (1)
Threejs Postprocessing has 1 known copy in the catalog totaling 260 installs. They canonicalize to this original listing.
- calesthio - 260 installs
How it compares
Pick threejs-postprocessing over general Three.js scene skills when the task is EffectComposer pass chains and screen effects, not geometry or lighting setup.
FAQ
Who is threejs-postprocessing for?
Frontend developers implementing Three.js EffectComposer and screen-space visual effects.
When should I use it?
When adding bloom, DOF, anti-aliasing passes, or custom post-processing shaders.
Is it safe to install?
Review Security Audits panel; it provides rendering patterns without external API calls.