Build-up burst filter
A bar fills for 5.5 s. When it's full, the screen takes one hit, gone in half a second.
Left: the bar alone, the picture never changes.
Right: colour drains and edges split as it fills, then one burst.
The problem
Some status effects build up and then go off once. Bloodborne's Frenzy works this way: a meter fills, and when it's full it hits all at once. If the screen only reacts at the end, the build-up has nothing to read. If it reacts the same way the whole time, the burst doesn't land. The filter needs two phases.
How it works
Build-up, driven by one value b from 0 to 1:
1. Saturation goes to −0.7 × b (pmndrs HueSaturation: colour moves toward its average).
2. Chromatic aberration grows to 0.0045 × b^1.5 of the screen width. Red samples one way, blue the other. Radial modulation keeps the centre clean and splits more toward the edges.
Burst, on the frame b reaches 1:
1. Shock wave: a ring moves out from the subject's screen position. Inside the ring, UVs shift toward the centre by amplitude × (1 − cos) / 2 × a falloff, so pixels look pushed outward.
2. Aberration flash: +0.016, decaying with a 0.11 s time constant.
3. Shake: a UV offset of up to 1.4% of the screen, decaying over 0.14 s.
Then b falls back to 0 over 0.5 s, and saturation goes with it.
What I hit
I pasted the shader code into a three.js ShaderPass, which compiles as GLSL ES 3.00. There `active` is a reserved word, and the shock wave's `uniform bool active` stopped compilation. Renaming it fixed it.
The shock wave's default speed is 2. The effect stays on until its radius reaches 2 × (maxRadius + waveSize), which at speed 2 is 1.3 s, too slow for a hit. At 5.2 it's 0.5 s and the ring crosses the screen in about 0.23 s.
My build
three.js 0.170. I ported the GLSL of three pmndrs/postprocessing effects into one pass: ShockWave (with its update logic: radius = time − waveSize, centre = projected world point, size scaled by camera distance), ChromaticAberration and HueSaturation. The shake is my own. Night plaza, all procedural, 11.5 m camera orbit. The middle of the clip replays the burst 8× slower and adds the 3 layers one at a time.
Trade-offs
- One pass, 3 texture reads per pixel
- Two parameters to drive: b, and the time since the burst
- Aberration and shake are hard on motion-sensitive players; offer a toggle
- The shock wave is screen-space, so it doesn't bend around geometry
- Without the build-up phase the burst reads as a random glitch
When to use it
Status meters that fill and then trigger once: madness, overload, rage, a curse. Keep the burst short and rare.
Source and credits
Repo: github.com/pmndrs/postprocessing (Zlib license), branch main, commit 9cf03cf
Code: I ported the GLSL and update logic of three effects into one three.js ShaderPass: ShockWaveEffect (src/effects/ShockWaveEffect.js, glsl/shock-wave.frag/.vert), ChromaticAberrationEffect with radial modulation (glsl/chromatic-aberration.frag/.vert) and HueSaturationEffect, saturation part (glsl/hue-saturation.frag). Changes: uniform active renamed (reserved in GLSL ES 3.00), shock wave speed 5.2, all three driven by a build-up value and a burst timer. The build-up/burst timing, screen shake, scene and HUD are my own. No external assets.
Inspired by Bloodborne's Frenzy effect (FromSoftware). No Bloodborne assets, UI or sounds were used or imitated.