// Flow family: a drifting swarm of glowing motes advected along a curl-noise
// field. Each mote rides a divergence-free curl flow and wanders on top of it,
// so the swarm pools and diverges like embers on a breeze rather than orbiting.
//
// A base field is always present so the scene stands alone before any feedback
// has converged; the motes just make the movement legible.

export const fireflyDrift = {
    name: 'Firefly Drift',
    family: 'flow',
    kind: 'fragment',
    // Personality: see look/Personality.js.
    traits: ['camera', 'style'],

    params: {
        count:    { type: 'float', range: [6, 48],   default: 22,   uniform: 'u_count', bias: 'density'  },
        speed:    { type: 'float', range: [0.05, 0.8], default: 0.3, uniform: 'u_speed', bias: 'motion', rate: true },
        glow:     { type: 'float', range: [0, 1.2],  default: 0.5, uniform: 'u_glow', bias: 'energy' },
        jitter:   { type: 'float', range: [0, 0.4],  default: 0.12, uniform: 'u_jitter' },
        spread:   { type: 'float', range: [0.4, 1.3], default: 0.95, uniform: 'u_spread' },
        palette:  { type: 'palette', count: 4 },
    },

    reactive: {
        glow:   { feature: 'beat',    amount: 0.3, response: 'spike' },
        jitter: { feature: 'bandHigh', amount: 0.2, response: 'smooth' },
    },

    shader: `
vec4 scene(vec2 uv, vec2 p) {
    float t = u_time * u_speed + u_seed;
    p = sigCamera(p);

    // Soft ambient wash so the frame is never black, even standing alone.
    vec3 col = pal(0) * (0.06 + 0.05 * fbm(p * 1.5 + vec2(0.0, t * 0.3), 3));

    for (int i = 0; i < 48; i++) {
        if (float(i) >= u_count) break;
        float fi = float(i);

        // Seed the mote to a stable place in the frame (deterministic per i).
        vec2 grid = vec2(hash12(vec2(fi, 1.7)), hash12(vec2(fi, 9.1)));
        vec2 base = (grid - 0.5) * 2.0 * u_spread * vec2(1.0, 0.7);

        // Advect along the curl field plus a bounded wander term on top.
        vec2 flow = curl(grid * 3.0 + vec2(0.0, t * 0.15), t * 0.5);
        vec2 pos = base + flow * 1.3
            + vec2(sin(t * (0.4 + fract(fi * 0.13))),
                   cos(t * (0.5 + fract(fi * 0.29)))) * u_jitter;

        float d = length(p - pos);

        vec3 hc = pal(int(mod(fi, 4.0)));
        col += hc * (exp(-d * d / (0.015 + u_glow * 0.04)) * (1.0 + u_glow * 0.6));
        col += hc * exp(-d * d * 60.0);
    }

    col += sigGrain(uv);
    return vec4(col, 1.0);
}
`,
};