Thunder Documentation
Effect Language
Thunder effects are implemented as WebGPU fragment shaders. We take inspiration from Shadertoy and each shader is implemented using raytracing. While shadertoy uses GLSL, Thunder instead uses WGSL as it’s shader language. If you use chrome, you can get a great online tour of WGSL.
effectMain
Every effect must have an effectMain
function.
fn effectMain(in: vec2<f32>) -> vec4<f32> {
let alpha = sin(in.x + u.beat*5.0)*0.5 + 0.5;
return vec4<f32>(1.0, 0.0, 0.0, alpha);
}
This function is called for every light in a fixture. The in
parameter
gives the pixel x
and y
coordinates. An LED strip only uses the x
coordinate
with y
always equal to 0
.
The return value is the pixel rgba colour: (r,g,b,alpha)
where each component
is a number in [0,1]
.
Signal Uniform
You can access metadata about the light, as well as current audio signal data through the signal uniform.
struct Uniform {
width: f32, // Width of the fixture.
height: f32, // Height of the fixture.
frame: f32, // Frame number.
time: f32, // Time in milliseconds.
beat: f32, // Beat clock.
downbeat: f32, // Downbeat clock.
spec_high: f32, // High frequency spectrum.
spec_mid_high: f32, // Mid-high frequency spectrum.
spec_mid_low: f32, // Mid-low frequency spectrum.
spec_low: f32, // Low frequency spectrum.
};
This is bound to the parameter u
. For example, the width can be accessed in
your code as u.width
.
Beat Clock
There are two beat clocks available: beat
and downbeat
. The beat clock
counts each beat, and between beats it gives a floating point value. For example,
2.5
is the moment in time half way between beats 2
and 3
. These clocks
count upwards until the software is restarted. The downbeat clock works exactly
the same way, but counts each downbeat instead.
Frequncy Information
The uniform members spec_low
, spec_mid_low
, spec_mid_high,
and spec_high
are the sum of the mel spectrogram over the last several milliseconds. The values
are typically from 0
to 100
, but at times can go beyond 100
.
Parameter Bindings
Effects can have a variable number of user defined parameters. These can be
accessed via a parameter binding p
. Each parameter becomes a member of the
parameter struct bound to p
with an lowercase underscored version of its name.
For example, if you have a colour palette called Main Colours
it will be
accessible as p.main_colours
. Special characters are stripped out.
Palette
A colour palette parameter can have one or more colours. Each colour is
represented as a vec4<f32>
with each component mapped to [0,1]
.
Integer
An integer parameter is represented as an i32
.
Float
A float parameter is represented as an f32
.
Random Number Functions
Thunder provides several pseudo-random numbers that are seeded from various
signals. Usually you’d use the x
and y
as input, but could use other values
too.
Time Based
These functions product new random values on every frame. They are useful for production general noise.
fn time_hash2(seed: vec2<f32>) -> vec3<u32>
Returns three random u32
values based on x and y and the time.
fn time_rand2(seed: vec2<f32>) -> vec3<f32>
Returns three f32
values in the range [0,1]
based on x and y and the time.
Beat Based
These functions provide random numbers that only change every time there is a new beat. These are useful to build effects that have random varations based on the beat.
fn beat_hash2(seed: vec2<f32>) -> vec3<u32>
Returns three random u32
values based on x and y and the beat
clock.
fn beat_rand2(seed: vec2<f32>) -> vec3<f32>
Returns three f32
values in the range [0,1]
based on x and y and the beat
clock.