The skin's code
//! name: Disco Fever
//! author: MusicBar
//! kind: visualizer
//! description: Mirror-ball light spots glide across the bar and burst into starry flashes on every beat.
float hash2(float2 p)
{
float3 q = frac(float3(p.x, p.y, p.x) * 0.1031);
q += dot(q, q.yzx + 33.33);
return frac((q.x + q.y) * q.z);
}
void layer(inout float3 acc, inout float cover, float3 rgb, float a)
{
a = saturate(a);
acc = rgb * a + acc * (1.0 - a);
cover = a + cover * (1.0 - a);
}
// One reflection of the mirror ball per cell, sliding along as the ball turns.
float4 spots(float2 px, float2 cellSize, float speed, float spotSize, float seed)
{
float2 q = float2(px.x - time * speed, px.y + sin(px.x * 0.004 + time * 0.3) * 2.0);
float2 cell = floor(q / cellSize);
float2 local = q - cell * cellSize;
float r = hash2(cell + seed);
float2 at = cellSize * float2(0.3 + 0.4 * hash2(cell + seed + 1.7), 0.3 + 0.4 * hash2(cell + seed + 4.3));
float2 d = local - at;
float sz = spotSize * (0.7 + 0.6 * hash2(cell + seed + 9.1)) * (1.0 + 0.35 * beat);
float facet = max(abs(d.x) * 0.8, abs(d.y));
float core = smoothstep(sz + 0.7, sz - 0.5, facet);
float halo = exp(-length(d) / (sz * 1.7));
float twinkle = 0.2 + 0.8 * pow(0.5 + 0.5 * sin(time * 4.5 + r * 60.0), 3.0);
float present = step(0.58 - 0.28 * level, r);
float flash = beat * step(0.74, r);
float flare = (exp(-abs(d.y) / 0.55) * exp(-abs(d.x) / (2.0 + 7.0 * beat))
+ exp(-abs(d.x) / 0.55) * exp(-abs(d.y) / (1.5 + 4.0 * beat))) * flash;
float a = present * (core * (0.3 + 0.7 * twinkle) + halo * 0.28 * twinkle) + flash * (core + halo * 0.5) + flare * 0.6;
float pick = frac(r * 7.13);
float3 c = pick < 0.4 ? colorA.rgb : (pick < 0.75 ? colorB.rgb : colorC.rgb);
return float4(lerp(c, float3(1, 1, 1), 0.25 + 0.45 * flash), saturate(a));
}
float4 main(float2 uv : TEXCOORD) : COLOR
{
float2 px = float2(uv.x * size.x, rise(uv) * size.y);
float s = size.y / 40.0;
float3 acc = float3(0, 0, 0);
float cover = 0;
// Two colored beams sweeping slowly over the floor, brighter on the beat.
float b1 = exp(-abs(px.x - (0.5 + 0.42 * sin(time * 0.33)) * size.x) / (size.x * 0.07));
float b2 = exp(-abs(px.x - (0.5 + 0.42 * sin(time * 0.33 + 2.6)) * size.x) / (size.x * 0.07));
float fall = 0.55 + 0.45 * (1.0 - rise(uv));
layer(acc, cover, colorA.rgb, b1 * fall * (0.07 + 0.08 * beat + 0.05 * level));
layer(acc, cover, colorB.rgb, b2 * fall * (0.07 + 0.08 * beat + 0.05 * level));
// The floor lights up along the screen edge on a beat.
layer(acc, cover, lerp(colorC.rgb, float3(1, 1, 1), 0.2), exp(-px.y / (4.0 * s)) * beat * 0.22);
// Far spots, small and slow; near spots, bigger and quicker.
float4 far = spots(px, float2(17.0, size.y / 3.0), 21.0, 0.9 * s, 0.0);
layer(acc, cover, far.rgb, far.a * 0.55);
float4 nearSpots = spots(px, float2(31.0, size.y / 2.0), 40.0, 1.7 * s, 31.0);
layer(acc, cover, nearSpots.rgb, nearSpots.a);
return paint(acc / max(cover, 0.001), cover);
}