// Flow family: sheets of rain falling through three depth layers, sheared by a
// wind that gusts on the phrase, over a wet ground that catches the light.
//
// The flow family is otherwise made of continuous fields — smoke, curl, aurora,
// all of which advect and diffuse. Rain does neither: it is thousands of
// discrete hard streaks travelling in one direction at three different speeds,
// and the only thing that makes it read as a single weather system is that the
// wind shears every layer by the same angle. Smoke Column rises and spreads;
// this falls and stays separate.

export const rainColumn = {
    name: 'Rain Column',
    family: 'flow',
    kind: 'fragment',
    traits: ['camera', 'space', 'style'],

    params: {
        sheets:  { type: 'float', range: [6, 90],      default: 30,   uniform: 'u_sheets', bias: 'density' },
        fall:    { type: 'float', range: [0.12, 0.85], default: 0.4,  uniform: 'u_fall', bias: 'motion', rate: true },
        streak:  { type: 'float', range: [0.05, 0.7],  default: 0.28, uniform: 'u_streak', slowAxis: true },
        wind:    { type: 'float', range: [-0.9, 0.9],  default: 0.25, uniform: 'u_wind' },
        gust:    { type: 'float', range: [0, 0.5],     default: 0.15, uniform: 'u_gust' },
        wet:     { type: 'float', range: [0, 1],       default: 0.55, uniform: 'u_wet' },
        glow:    { type: 'float', range: [0, 1.4],     default: 0.5,  uniform: 'u_glow', bias: 'energy' },
        palette: { type: 'palette', count: 5 },
    },

    reactive: {
        glow:   { feature: 'loudness', amount: 0.3,  response: 'smooth' },
        wet:    { feature: 'bandLow',  amount: 0.2,  response: 'smooth' },
    },

    shader: `
// One sheet of rain: a column grid, one drop per column, each with its own
// phase and a slightly different fall speed so the sheet never marches in step.
float sheet(vec2 q, float cols, float t, float len, float w, float salt) {
    float x = q.x * cols;
    float ci = floor(x);
    float fx = (fract(x) - 0.5) / cols;          // back into scene units
    float ph = hash11(ci * 12.71 + salt + u_seed);

    float y = fract(q.y * 0.55 + t * (0.8 + ph * 0.5) + ph);
    float head = smoothstep(len, 0.0, y);        // bright at the head, fading behind
    // Soft-edged, deliberately. A hard streak is a one-pixel feature travelling
    // a couple of percent of the frame per frame, which reads as a fizzing
    // sparkle rather than as rain and dominates every frame-distance the gates
    // take.
    float body = smoothstep(w, w * 0.5, abs(fx));
    return head * head * body;
}

vec4 scene(vec2 uv, vec2 p) {
    float t = u_time * u_fall + u_seed;
    p = sigCamera(p);

    float horizon = sigHorizonY() * 0.5 - 0.1;
    float above = p.y - horizon;

    // The wind is one angle for the whole storm, gusting on the phrase so the
    // rain leans as a body rather than per layer.
    float lean = u_wind + sin(u_phrasePhase * 6.28318530718) * u_gust;

    // Sky: darkest overhead, brightest where the light gets under the cloud.
    vec3 col = mix(pal(1) * 0.22, pal(0) * 0.06, sat(above * 0.7 + 0.1));
    col += pal(3) * exp(-abs(above) * 6.0) * u_glow * 0.35;

    // Three depth layers: far is dense, slow and dim; near is sparse, fast and
    // wide. Same shear, so they read as one storm seen through itself.
    float rain = 0.0;
    // lint: fixed-cost — three depth layers, not a search
    for (int i = 0; i < 3; i++) {
        float d = float(i);
        float near = d * 0.5;                                  // 0 far .. 1 near
        vec2 q = p;
        q.x += q.y * lean;
        q *= mix(2.2, 0.9, near);                              // parallax scale
        q.x += near * 3.7;                                     // decorrelate layers
        float s = sheet(q, u_sheets * mix(1.4, 0.6, near), t * mix(0.7, 1.6, near),
                        u_streak, mix(0.35, 0.9, near) / u_sheets, d * 31.0);
        rain += s * mix(0.35, 1.0, near);
    }
    rain *= smoothstep(-0.05, 0.35, above);                    // no rain below the ground

    col += palRamp(0.55 + rain * 0.2) * rain * (0.55 + u_glow * 0.65);

    {
        float depth = sat(-above * 2.4);
        vec3 ground = mix(pal(2) * 0.3, pal(0) * 0.12, depth);

        // Wet ground: a compressed mirror of the sky glow, broken up by the
        // ripples the rain is putting into it. The mirror is what makes the
        // ground read as water rather than as a dark half of the frame.
        ground += pal(3) * exp(above * 4.0) * u_glow * 1.1 * u_wet;

        float ripple = sin((-above * 26.0) - t * 5.0 + vnoise(vec2(p.x * 5.0, t * 0.7)) * 7.0);
        ground += pal(4) * sat(ripple) * u_wet * (0.06 + depth * 0.3);
        ground += pal(3) * sat(ripple) * exp(above * 8.0) * u_wet * 0.5;

        col = mix(col, ground, smoothstep(0.03, -0.03, above));
    }

    col = sigAir(col, p, smoothstep(0.2, 1.5, abs(p.x) * 0.6 + sat(above)));
    col += sigGrain(uv);
    return vec4(col, 1.0);
}
`,
};

export default rainColumn;
