GPU-accelerated particle effect backgrounds. Four distinct environments -- Clouds with boids, ThunderStorm with procedural lightning, Galaxy, and Gradient Flow. Dual renderer architecture: Three.js for 3D, Pixi.js for 2D. TypeScript. GLSL shaders. Adaptive quality that scales to any hardware.
FXBackgrounds is a library of GPU-accelerated particle effects designed as website backgrounds. Each effect is a standalone module that renders at 60fps while consuming minimal CPU. The dual renderer approach uses Three.js for effects that need 3D geometry (Galaxy, ThunderStorm) and Pixi.js for 2D effects (Clouds, Gradient Flow). An adaptive quality system monitors FPS and scales particle counts, shader complexity, and resolution to match the device.
First TypeScript project. First GLSL shaders. Vite for the build, with separate renderer modules loaded dynamically based on the selected effect.
Two renderers, each optimized for different types of effects. The engine loads only what is needed.
3D geometry, camera, lighting
2D sprites, particles, filters
The procedural lightning shader -- generates branching bolts in GLSL with randomized offsets and glow falloff.
precision mediump float; uniform float u_time; uniform vec2 u_resolution; uniform vec2 u_bolt_origin; uniform float u_intensity; varying vec2 v_uv; float hash(float n) { return fract(sin(n) * 43758.5453); } float bolt(vec2 uv, vec2 origin, float seed) { float segments = 12.0; float glow = 0.0; vec2 pos = origin; vec2 dir = vec2(0.0, 1.0); for (float i = 0.0; i < segments; i++) { // Random offset per segment float offset = (hash(i + seed) - 0.5) * 0.15; pos += dir * (1.0 / segments); pos.x += offset; // Distance-based glow float d = length(uv - pos); glow += 0.002 / (d + 0.001); } return glow * u_intensity; } void main() { vec2 uv = v_uv; float light = bolt(uv, u_bolt_origin, u_time); vec3 color = vec3(0.6, 0.7, 1.0) * light; gl_FragColor = vec4(color, light * 0.8); }
Writing shaders is like programming a different computer. No garbage collection, no objects, no strings. Just math running on thousands of cores simultaneously. The lightning bolt effect -- a simple loop with distance fields -- produces something that looks physically plausible.
Three.js excels at 3D geometry. Pixi.js excels at 2D sprites. Using both, loaded dynamically, means each effect uses the best tool. The abstraction layer -- a shared EffectManager interface -- keeps the API consistent.
A background effect that drops below 30fps is worse than no effect. The adaptive quality system was not a nice-to-have -- it was the core feature. Monitoring FPS, scaling resolution, reducing particles. The user's device sets the quality, not the developer's ambition.
GLSL has no type safety. But TypeScript on the JavaScript side catches uniform type mismatches, missing parameters, and wrong data shapes before they hit the GPU. The typed boundary between JS and GLSL saves hours of debugging.