Agent skill
postfx-bloom
Bloom and glow effects using Three.js UnrealBloomPass with React Three Fiber. Use when implementing glow, bloom, luminance-based effects, selective bloom on specific meshes, or neon/ethereal lighting. Essential for cyberpunk aesthetics, energy effects, magic spells, and UI glow.
Install this agent skill to your Project
npx add-skill https://github.com/Bbeierle12/Skill-MCP-Claude/tree/main/skills/postfx-bloom
SKILL.md
Post-Processing Bloom
Bloom effects using UnrealBloomPass for luminance-based glow and selective object bloom.
Quick Start
npm install three @react-three/fiber @react-three/postprocessing
import { Canvas } from '@react-three/fiber';
import { EffectComposer, Bloom } from '@react-three/postprocessing';
function Scene() {
return (
<Canvas>
<mesh>
<sphereGeometry args={[1, 32, 32]} />
<meshStandardMaterial emissive="#00F5FF" emissiveIntensity={2} />
</mesh>
<EffectComposer>
<Bloom
luminanceThreshold={0.2}
luminanceSmoothing={0.9}
intensity={1.5}
/>
</EffectComposer>
</Canvas>
);
}
Core Concepts
How Bloom Works
- Threshold — Pixels brighter than threshold are extracted
- Blur — Extracted pixels are blurred in multiple passes
- Composite — Blurred result is added back to original image
Key Parameters
| Parameter | Range | Description |
|---|---|---|
luminanceThreshold |
0-1 | Brightness cutoff for bloom (lower = more glow) |
luminanceSmoothing |
0-1 | Softness of threshold transition |
intensity |
0-10 | Bloom brightness multiplier |
radius |
0-1 | Blur spread/size |
levels |
1-9 | Blur quality/iterations |
Patterns
Cosmic Glow Effect
import { EffectComposer, Bloom } from '@react-three/postprocessing';
import { KernelSize } from 'postprocessing';
function CosmicBloom() {
return (
<EffectComposer>
<Bloom
luminanceThreshold={0.1}
luminanceSmoothing={0.9}
intensity={2.5}
radius={0.8}
kernelSize={KernelSize.LARGE}
mipmapBlur
/>
</EffectComposer>
);
}
Neon Cyberpunk Bloom
// High-contrast neon with sharp falloff
function NeonBloom() {
return (
<EffectComposer>
<Bloom
luminanceThreshold={0.4}
luminanceSmoothing={0.2}
intensity={3.0}
radius={0.4}
mipmapBlur
/>
</EffectComposer>
);
}
// Emissive material for neon objects
function NeonTube({ color = '#FF00FF' }) {
return (
<mesh>
<cylinderGeometry args={[0.05, 0.05, 2]} />
<meshStandardMaterial
emissive={color}
emissiveIntensity={4}
toneMapped={false}
/>
</mesh>
);
}
Selective Bloom with Layers
import { useRef } from 'react';
import { useThree } from '@react-three/fiber';
import { EffectComposer, SelectiveBloom } from '@react-three/postprocessing';
function SelectiveGlow() {
const glowRef = useRef();
return (
<>
{/* Non-blooming object */}
<mesh position={[-2, 0, 0]}>
<boxGeometry />
<meshStandardMaterial color="#333" />
</mesh>
{/* Blooming object */}
<mesh ref={glowRef} position={[2, 0, 0]}>
<sphereGeometry args={[0.5, 32, 32]} />
<meshStandardMaterial
emissive="#00F5FF"
emissiveIntensity={3}
/>
</mesh>
<EffectComposer>
<SelectiveBloom
selection={glowRef}
luminanceThreshold={0.1}
intensity={2}
mipmapBlur
/>
</EffectComposer>
</>
);
}
Multi-Selection Bloom
import { Selection, Select, EffectComposer } from '@react-three/postprocessing';
import { SelectiveBloom } from '@react-three/postprocessing';
function MultiSelectBloom() {
return (
<Selection>
{/* Non-blooming */}
<mesh position={[-2, 0, 0]}>
<boxGeometry />
<meshStandardMaterial color="#333" />
</mesh>
{/* Blooming objects wrapped in Select */}
<Select enabled>
<mesh position={[0, 0, 0]}>
<sphereGeometry args={[0.5]} />
<meshStandardMaterial emissive="#00F5FF" emissiveIntensity={2} />
</mesh>
</Select>
<Select enabled>
<mesh position={[2, 0, 0]}>
<octahedronGeometry args={[0.5]} />
<meshStandardMaterial emissive="#FF00FF" emissiveIntensity={2} />
</mesh>
</Select>
<EffectComposer>
<SelectiveBloom
luminanceThreshold={0.1}
intensity={1.5}
mipmapBlur
/>
</EffectComposer>
</Selection>
);
}
Animated Bloom Intensity
import { useRef } from 'react';
import { useFrame } from '@react-three/fiber';
import { EffectComposer, Bloom } from '@react-three/postprocessing';
function PulsingBloom() {
const bloomRef = useRef();
useFrame(({ clock }) => {
if (bloomRef.current) {
const pulse = Math.sin(clock.elapsedTime * 2) * 0.5 + 1.5;
bloomRef.current.intensity = pulse;
}
});
return (
<EffectComposer>
<Bloom
ref={bloomRef}
luminanceThreshold={0.2}
intensity={1.5}
mipmapBlur
/>
</EffectComposer>
);
}
Audio-Reactive Bloom
function AudioReactiveBloom({ audioData }) {
const bloomRef = useRef();
useFrame(() => {
if (bloomRef.current && audioData) {
// Map bass frequency (0-255) to bloom intensity (1-4)
const bassLevel = audioData[0] / 255;
bloomRef.current.intensity = 1 + bassLevel * 3;
// Map mid frequencies to threshold
const midLevel = audioData[4] / 255;
bloomRef.current.luminanceThreshold = 0.1 + (1 - midLevel) * 0.3;
}
});
return (
<EffectComposer>
<Bloom
ref={bloomRef}
luminanceThreshold={0.2}
intensity={1.5}
mipmapBlur
/>
</EffectComposer>
);
}
Emissive Materials
Standard Emissive Setup
// For bloom to work, objects need emissive materials
function GlowingSphere({ color = '#00F5FF', intensity = 2 }) {
return (
<mesh>
<sphereGeometry args={[1, 32, 32]} />
<meshStandardMaterial
color="#000"
emissive={color}
emissiveIntensity={intensity}
toneMapped={false} // Important: prevents HDR clamping
/>
</mesh>
);
}
Emissive with Texture
import { useTexture } from '@react-three/drei';
function EmissiveTextured() {
const emissiveMap = useTexture('/glow-pattern.png');
return (
<mesh>
<planeGeometry args={[2, 2]} />
<meshStandardMaterial
emissiveMap={emissiveMap}
emissive="#FFFFFF"
emissiveIntensity={3}
toneMapped={false}
/>
</mesh>
);
}
Shader Material with Emissive
import { shaderMaterial } from '@react-three/drei';
import { extend } from '@react-three/fiber';
const GlowMaterial = shaderMaterial(
{ uTime: 0, uColor: [0, 0.96, 1], uIntensity: 2.0 },
// Vertex shader
`
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
// Fragment shader - outputs HDR values for bloom
`
uniform float uTime;
uniform vec3 uColor;
uniform float uIntensity;
varying vec2 vUv;
void main() {
float pulse = sin(uTime * 2.0) * 0.3 + 0.7;
vec3 glow = uColor * uIntensity * pulse;
gl_FragColor = vec4(glow, 1.0);
}
`
);
extend({ GlowMaterial });
function PulsingGlowMesh() {
const materialRef = useRef();
useFrame(({ clock }) => {
materialRef.current.uTime = clock.elapsedTime;
});
return (
<mesh>
<sphereGeometry args={[1, 32, 32]} />
<glowMaterial ref={materialRef} toneMapped={false} />
</mesh>
);
}
Performance Optimization
Resolution Scaling
<EffectComposer
multisampling={0} // Disable MSAA for performance
>
<Bloom
luminanceThreshold={0.2}
intensity={1.5}
mipmapBlur // More efficient blur method
radius={0.8}
levels={5} // Reduce for performance (default: 8)
/>
</EffectComposer>
Mobile-Optimized Bloom
import { useDetectGPU } from '@react-three/drei';
function AdaptiveBloom() {
const { tier } = useDetectGPU();
const config = tier < 2
? { levels: 3, radius: 0.5, intensity: 1.0 }
: { levels: 5, radius: 0.8, intensity: 1.5 };
return (
<EffectComposer multisampling={tier < 2 ? 0 : 4}>
<Bloom
luminanceThreshold={0.2}
luminanceSmoothing={0.9}
mipmapBlur
{...config}
/>
</EffectComposer>
);
}
Temporal Collapse Theme
Bloom configuration for the New Year countdown cosmic aesthetic:
// Cosmic void with cyan/magenta glow
function TemporalCollapseBloom() {
return (
<EffectComposer>
<Bloom
luminanceThreshold={0.15}
luminanceSmoothing={0.9}
intensity={2.0}
radius={0.85}
mipmapBlur
/>
</EffectComposer>
);
}
// Color palette for emissive materials
const TEMPORAL_COLORS = {
cyan: '#00F5FF',
magenta: '#FF00FF',
gold: '#FFD700',
void: '#050508'
};
// Time digit with glow
function GlowingDigit({ digit, color = TEMPORAL_COLORS.cyan }) {
return (
<Text3D font="/fonts/cosmic.json" size={2} height={0.2}>
{digit}
<meshStandardMaterial
color="#111"
emissive={color}
emissiveIntensity={3}
toneMapped={false}
/>
</Text3D>
);
}
Troubleshooting
| Issue | Solution |
|---|---|
| No bloom visible | Ensure emissiveIntensity > 1 and toneMapped={false} |
| Bloom too subtle | Lower luminanceThreshold, increase intensity |
| Performance issues | Reduce levels, enable mipmapBlur, disable multisampling |
| Selective bloom not working | Verify ref is passed and object has emissive material |
| Bloom bleeding everywhere | Raise luminanceThreshold to isolate bright areas |
Reference
- See
postfx-composerfor EffectComposer setup patterns - See
postfx-effectsfor combining bloom with other effects - See
shaders-glslfor custom emissive shader techniques
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?