Agent skill
postfx-composer
EffectComposer setup and architecture for Three.js post-processing pipelines. Use when setting up multi-pass rendering, combining effects, creating custom passes, managing render targets, or building reusable effect stacks. Foundation skill for all post-processing work.
Install this agent skill to your Project
npx add-skill https://github.com/Bbeierle12/Skill-MCP-Claude/tree/main/skills/postfx-composer
SKILL.md
Post-Processing Composer
EffectComposer architecture, render pipelines, and custom pass creation.
Quick Start
npm install @react-three/postprocessing postprocessing three
import { Canvas } from '@react-three/fiber';
import { EffectComposer, Bloom, Vignette } from '@react-three/postprocessing';
function App() {
return (
<Canvas>
<Scene />
<EffectComposer>
<Bloom intensity={1} />
<Vignette darkness={0.5} />
</EffectComposer>
</Canvas>
);
}
Core Concepts
Render Pipeline Flow
Scene Render → EffectComposer → Effect 1 → Effect 2 → ... → Screen
↓
[Render Target A] → [Render Target B] → [Screen]
EffectComposer Configuration
import { EffectComposer } from '@react-three/postprocessing';
import { HalfFloatType } from 'three';
function PostProcessing() {
return (
<EffectComposer
enabled={true}
depthBuffer={true}
stencilBuffer={false}
multisampling={8}
frameBufferType={HalfFloatType}
>
{/* Effects processed in order */}
</EffectComposer>
);
}
Effect Ordering
Recommended Order
<EffectComposer>
{/* 1. Scene modification (needs scene data) */}
<SSAO />
<DepthOfField />
{/* 2. Lighting/color effects */}
<Bloom />
<ToneMapping />
{/* 3. Color grading */}
<HueSaturation />
<BrightnessContrast />
<LUT />
{/* 4. Screen-space effects */}
<ChromaticAberration />
<Vignette />
{/* 5. Noise/grain (always last) */}
<Noise />
</EffectComposer>
Why Order Matters
// WRONG: Bloom after color grading reduces glow
<EffectComposer>
<HueSaturation saturation={-0.5} />
<Bloom intensity={2} />
</EffectComposer>
// CORRECT: Bloom before color grading
<EffectComposer>
<Bloom intensity={2} />
<HueSaturation saturation={-0.5} />
</EffectComposer>
Conditional Effects
Toggle Effects at Runtime
function DynamicEffects({ enableBloom, enableDOF }) {
return (
<EffectComposer>
{enableBloom && <Bloom luminanceThreshold={0.2} intensity={1.5} />}
{enableDOF && <DepthOfField focusDistance={0.02} focalLength={0.05} />}
<Vignette darkness={0.4} />
</EffectComposer>
);
}
Effect Presets
const PRESETS = {
cinematic: {
bloom: { intensity: 0.8, threshold: 0.3 },
vignette: { darkness: 0.5, offset: 0.3 },
grain: { opacity: 0.03 }
},
scifi: {
bloom: { intensity: 2.0, threshold: 0.1 },
chromatic: { offset: [0.003, 0.003] },
vignette: { darkness: 0.6, offset: 0.2 }
},
minimal: { vignette: { darkness: 0.3, offset: 0.4 } }
};
function PresetEffects({ preset = 'cinematic' }) {
const config = PRESETS[preset];
return (
<EffectComposer>
{config.bloom && <Bloom {...config.bloom} />}
{config.chromatic && <ChromaticAberration offset={config.chromatic.offset} />}
{config.vignette && <Vignette {...config.vignette} />}
{config.grain && <Noise {...config.grain} />}
</EffectComposer>
);
}
Custom Effects
Basic Custom Effect
import { Effect } from 'postprocessing';
import { Uniform } from 'three';
import { forwardRef, useMemo } from 'react';
class ColorShiftEffect extends Effect {
constructor({ shift = 0.0 }) {
super('ColorShiftEffect', /* glsl */`
uniform float shift;
void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) {
vec3 color = inputColor.rgb;
float hueShift = shift * uv.x;
color.r = color.r * cos(hueShift) - color.g * sin(hueShift);
color.g = color.r * sin(hueShift) + color.g * cos(hueShift);
outputColor = vec4(color, inputColor.a);
}
`, {
uniforms: new Map([['shift', new Uniform(shift)]])
});
}
set shift(value) {
this.uniforms.get('shift').value = value;
}
}
const ColorShift = forwardRef(({ shift = 0 }, ref) => {
const effect = useMemo(() => new ColorShiftEffect({ shift }), []);
useEffect(() => { effect.shift = shift; }, [shift, effect]);
return <primitive ref={ref} object={effect} />;
});
Custom Effect with Time
class PulseEffect extends Effect {
constructor() {
super('PulseEffect', /* glsl */`
uniform float uTime;
uniform float uIntensity;
void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) {
float pulse = sin(uTime * 2.0) * 0.5 + 0.5;
float vignette = 1.0 - length(uv - 0.5) * pulse * uIntensity;
outputColor = vec4(inputColor.rgb * vignette, inputColor.a);
}
`, {
uniforms: new Map([
['uTime', new Uniform(0)],
['uIntensity', new Uniform(0.5)]
])
});
}
update(renderer, inputBuffer, deltaTime) {
this.uniforms.get('uTime').value += deltaTime;
}
}
Render Targets
Manual Render Target Management
import { useFBO } from '@react-three/drei';
function CustomRenderPipeline() {
const { gl, scene, camera } = useThree();
const targetA = useFBO({ width: 1024, height: 1024 });
useFrame(() => {
gl.setRenderTarget(targetA);
gl.render(scene, camera);
gl.setRenderTarget(null);
gl.render(scene, camera);
});
return null;
}
Performance Patterns
Resolution Scaling
function ScaledEffects() {
const { size } = useThree();
const scale = 0.5;
return (
<EffectComposer frameBufferType={HalfFloatType} multisampling={0}>
<Bloom intensity={1.5} width={size.width * scale} height={size.height * scale} />
</EffectComposer>
);
}
Adaptive Quality
import { useDetectGPU } from '@react-three/drei';
function AdaptiveQuality() {
const { tier } = useDetectGPU();
const quality = useMemo(() => {
if (tier >= 3) return { multisampling: 8, bloomLevels: 8 };
if (tier >= 2) return { multisampling: 4, bloomLevels: 5 };
return { multisampling: 0, bloomLevels: 3 };
}, [tier]);
return (
<EffectComposer multisampling={quality.multisampling}>
<Bloom levels={quality.bloomLevels} />
</EffectComposer>
);
}
Temporal Collapse Setup
import { EffectComposer, Bloom, ChromaticAberration, Vignette, Noise, ToneMapping } from '@react-three/postprocessing';
import { ToneMappingMode, BlendFunction } from 'postprocessing';
import { HalfFloatType } from 'three';
function TemporalCollapseComposer({ children }) {
return (
<EffectComposer multisampling={4} frameBufferType={HalfFloatType}>
<ToneMapping mode={ToneMappingMode.ACES_FILMIC} />
<Bloom luminanceThreshold={0.15} luminanceSmoothing={0.9} intensity={2.0} radius={0.85} mipmapBlur />
<ChromaticAberration offset={[0.002, 0.001]} radialModulation modulationOffset={0.3} />
<Vignette darkness={0.6} offset={0.25} />
<Noise opacity={0.025} blendFunction={BlendFunction.OVERLAY} />
{children}
</EffectComposer>
);
}
Reference
- See
postfx-bloomfor bloom-specific techniques - See
postfx-effectsfor individual effect configurations - See
shaders-glslfor writing custom effect shaders
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
r3f-materials
Three.js materials in R3F, built-in materials (Standard, Physical, Basic, etc.), ShaderMaterial with custom GLSL, uniforms binding and animation, and material properties. Use when choosing materials, creating custom shaders, or binding dynamic uniforms.
audio-router
Router for audio domain including playback, analysis, and audio-reactive visuals. Use when implementing any audio functionality including music, sound effects, visualizers, or audio-driven animations. Routes to 3 specialized skills.
case-studies-reference
Game building mechanics case studies and decision frameworks. Use when designing building systems, evaluating trade-offs, or learning from existing games. Reference-only skill with detailed analysis of Fortnite, Rust, Valheim, Minecraft, No Man's Sky, and Satisfactory building systems.
brainstorming
Use when starting any feature, project, or design work. Guides collaborative design refinement through incremental questioning before any code is written.
shader-router
Decision framework for GLSL shader projects. Routes to specialized shader skills (fundamentals, noise, SDF, effects) based on task requirements. Use when starting a shader project or needing guidance on which shader techniques to combine.
audio-playback
Audio playback using Tone.js including players, transport, scheduling, and loading audio. Use when implementing background music, sound effects, audio synchronization, or timed audio events. Essential for any audio-enabled web application.
Didn't find tool you were looking for?