// Ported from party-stage's "Classic Wave". The original picked a hue from a
// rolling HSV ramp; here the ramp indexes the palette instead, so the look
// generator can actually recolour it.

export const classicWave = {
    name: 'Classic Wave',
    family: 'flow',
    kind: 'fragment',
    // Personality: see look/Personality.js.
    // Smooth concentric colour: grain only mutes the ramp it is built on.
    texture: 0,
    traits: ['shape', 'camera', 'style'],

    params: {
        rings:     { type: 'float', range: [4, 40],    default: 18,  uniform: 'u_rings', bias: 'density' },
        spokes:    { type: 'int',   range: [0, 12],    default: 5,   uniform: 'u_spokes' },
        speed:     { type: 'float', range: [0.2, 2.5], default: 1.0, uniform: 'u_speed', bias: 'motion', rate: true },
        // colorRoll is capped low on purpose. palRamp() steps through all six
        // palette entries per unit of t, and the palette generator deliberately
        // spreads their luminance — so this multiplies into a whole-frame
        // brightness oscillation at six times its own rate. At the original
        // range of [0, 0.5] this scene measured 7 flashes per second at every
        // output resolution, well past the WCAG 2.3.1 ceiling of 3. Capped here,
        // the worst case is ~0.9 Hz. See engine/flash.js.
        colorRoll: { type: 'float', range: [0, 0.06],  default: 0.02, uniform: 'u_colorRoll', rate: true },
        softness:  { type: 'float', range: [0, 1],     default: 0.4, uniform: 'u_softness' },
        bloomCore: { type: 'float', range: [0, 1.5],   default: 0.5, uniform: 'u_bloomCore', bias: 'energy' },
        palette:   { type: 'palette', count: 5 },
    },

    reactive: {
        bloomCore: { feature: 'beat',    amount: 0.4, response: 'spike' },
        rings:     { feature: 'bandMid', amount: 0.12 },
    },

    shader: `
vec4 scene(vec2 uv, vec2 p) {
    p = sigCamera(p);
    // The rings take the track's signature form: round tracks get circles,
    // hexagonal tracks get hexagonal rings, and it costs one call.
    float d = sigShape(p) + 1.0;
    float angle = atan(p.y, p.x);
    float t = u_time * u_speed + u_seed;

    float wave = sin(d * u_rings - t * 2.0);
    float spoke = u_spokes > 0 ? sin(angle * float(u_spokes) + t) * u_beat : 0.0;

    float v = 0.5 + 0.5 * sin(wave + spoke);

    // TRAIT style: the track's hand on the crests. The scene's own u_softness
    // decides HOW MUCH the wave is contrasted; the track decides what that
    // contrast looks like — u_sigSoft widens the transition, u_sigLine tightens
    // it. Centred on 0.5 so changing the hand does not change the exposure.
    float edge = mix(0.06, 0.42, sat(u_sigSoft)) * mix(1.3, 0.6, sat(u_sigLine));
    v = mix(v, smoothstep(0.5 - edge, 0.5 + edge, v), u_softness);

    // ...and independently of u_softness, which a track is free to sample at
    // zero: a heavier line concentrates the crest rather than letting it bloom
    // across the whole ring.
    vec3 col = palRamp(t * u_colorRoll + d * 0.25) * pow(v, mix(1.0, 2.2, sat(u_sigLine)));

    // Core glow, the part that reads as the "hit".
    col += pal(0) * (1.0 - smoothstep(0.0, 0.7, d)) * u_bloomCore * 0.6;

    // Keep the corners from clipping to flat colour.
    col *= 0.6 + 0.4 * (1.0 - smoothstep(0.8, 1.8, d));
    col += sigGrain(uv);

    return vec4(col, 1.0);
}
`,
};

export default classicWave;
