react-postprocessing
Declarative postprocessing effects for react-three-fiber, wrapping the postprocessing library as composable JSX components.
Repository Health
Technical Analysis
@react-three/postprocessing wraps the standalone postprocessing library so react-three-fiber scenes can compose GPU post-processing effects — bloom, depth of field, outlines, chromatic aberration, and more — as ordinary JSX children of an EffectComposer. Effects are automatically merged into as few render passes as possible, following the same manual pass-merging rules the underlying library exposes by hand, so a chain of several effects avoids the performance cost of running each as its own full-screen pass.
Under the hood it tracks the JSX effect tree via r3f’s own scene graph, live-updates effect properties in place without tearing down GPU resources when possible, and falls back to full reconstruction only for options that require it (e.g. Bloom’s mipmapBlur). Effects with no zero-argument constructor — Outline, SelectiveBloom, ShockWave, GodRays — are hand-implemented against the same live-prop machinery instead of relying on the shared component factory.
What You Get
- A declarative <EffectComposer> component that owns the underlying postprocessing EffectComposer instance, its render passes, and size syncing to the WebGL renderer
- 30+ ready-made effect components — Bloom, DepthOfField, Vignette, Noise, ChromaticAberration, Outline, Glitch, GodRays, SSAO, N8AO, LUT, Water, ASCII, and more
- Automatic pass merging so consecutive effects share a single EffectPass by default, with an escape hatch (mergeMode: auto/all/none) for manual control
- EffectGroup and Selection helpers for toggling groups of effects and driving effects like Outline/SelectiveBloom off a set of selected objects
- Live prop updates that mutate existing effect instances in place instead of reconstructing them on every render, preserving GPU state
- Full TypeScript types derived directly from postprocessing’s own effect constructor option types
Common Use Cases
- Adding a bloom + vignette + noise look to a react-three-fiber scene without hand-writing an effect composer
- Outlining or highlighting selected objects in a 3D editor or product configurator
- Building a depth-of-field camera focus effect for cinematic scenes
- Adding ambient-occlusion passes (N8AO/SSAO) for more realistic scene shading
- Object pick/hover highlight workflows via Selection combined with Outline or SelectiveBloom
Under The Hood
Architecture
The library centers on EffectComposer.tsx, which owns a postprocessing EffectComposerImpl instance created in a useEffect keyed on renderer/camera/scene/buffer options, and a useLayoutEffect pair that reads the r3f-managed child group’s resolved node list every render (via readGroupChildren), diffs it against the previous pass list, and rebuilds only the passes that changed. createEffectComponent registers each stateless effect class once as an r3f intrinsic via extend, letting r3f’s own reconciler handle construction-from-args, prop diffing, and disposal exactly as it does for <mesh>; effects whose constructor takes required scene/camera arguments (Outline, SelectiveBloom, ShockWave, GodRays) bypass that factory and are hand-written directly against the same EffectComposerContext and live-prop utilities. Ref-counted guards (createRendererPropertyGuard) restore a shared WebGLRenderer’s autoClear/toneMapping only when the last composer using them unmounts, which matters because multiple <EffectComposer> instances can share one canvas’s renderer.
Tech Stack
Built on TypeScript targeting ES6/ESNext with strict mode, React 19 with the new ref-as-prop pattern, and @react-three/fiber 9.x as the reconciler bridge into three.js; the actual effect implementations are delegated entirely to the postprocessing package (peer dependency, extending vanilla three.js’s own postprocessing examples), with n8ao and maath as direct dependencies for the N8AO pass and vector math helpers respectively. The build is a Vite library build emitting a single ES module plus a separate tsc pass for declaration files, with a custom Vite plugin that inlines postprocessing enum values (BlendFunction, EffectAttribute) at build time to avoid pulling the whole enum module into consumers’ bundles.
Code Quality
Tests run under Vitest against a custom test-utils render root that mounts real EffectComposer/effect trees and asserts on the underlying postprocessing effect instances directly (e.g. checking that a ref identity is preserved across a live update but changes on a reconstructing one), rather than just snapshotting output — this is a meaningful quality signal since it verifies the reconstruct-vs-mutate behavior that’s the library’s core value proposition. ESLint (flat config, typescript-eslint + react-hooks + import plugins) and Prettier are both wired, and CI (main.yml) gates every PR on pnpm build, pnpm eslint:ci, and pnpm test before merge. Source comments are unusually dense and specifically explain non-obvious invariants (why a WeakSet tracks generated-vs-user passes, why glSize is excluded from an effect’s dependency array, why blendFunction/opacity are pierced into a nested blendMode object) rather than restating what the code does.
What Makes It Unique
Rather than exposing a thin one-to-one effect wrapper, the library actively optimizes the underlying pass graph: consecutive non-convolution effects are silently merged into one shared EffectPass (mirroring an optimization postprocessing otherwise requires doing by hand), while still allowing a mixed tree of raw Pass instances and Effect instances to compose in JSX order. Its live-prop system distinguishes between props with a real runtime setter (applied in place, no effect lost) and construction-only options (which trigger a full effect swap while preserving the wrapping composer state) — a distinction most postprocessing wrappers don’t attempt, and one this library’s own comments flag as the reason a naive prop diff would silently break behavior like blend-mode opacity.
Used by 2 apps in this directory
highlight.io
Developer Tools · Analytics · Monitoring
Open-source full-stack monitoring that unifies session replay, error tracking, logging, and distributed tracing so you can stop context-switching between tools.
Markdrop
Note Taking
Visual drag-and-drop markdown editor with GitHub-specific blocks, cloud sync, and offline PWA support