// Flow family: spiral arms winding into a slowly wandering core.
//
// Differential rotation is the point — the inner arms turn faster than the outer
// ones, so the arms wind up over time and the image is never twice the same.
// Distinct from Curl Flow (isotropic advection with no centre) and Kaleido
// Tunnel (rigid radial symmetry receding): this has one centre, real shear, and
// no symmetry at all.
//
// The core is drawn in the track's signature form, so the eye of a hexagonal
// track's vortex is a hexagon.

export const vortexDrift = {
    name: 'Vortex Drift',
    family: 'flow',
    kind: 'fragment',
    consumes: ['cast', 'ink'],
    traits: ['shape', 'camera', 'style'],

    params: {
        arms:      { type: 'int',   range: [1, 7],       default: 3,    uniform: 'u_arms', bias: 'density' },
        winding:   { type: 'float', range: [0.5, 7],     default: 2.5,  uniform: 'u_winding', bias: 'density' },
        shear:     { type: 'float', range: [0.1, 2.5],   default: 1.0,  uniform: 'u_shear' },
        speed:     { type: 'float', range: [0.02, 0.6],  default: 0.15, uniform: 'u_speed', bias: 'motion', rate: true },
        turbulence:{ type: 'float', range: [0, 1.2],     default: 0.4,  uniform: 'u_turbulence' },
        core:      { type: 'float', range: [0.0, 0.4],   default: 0.12, uniform: 'u_core', bias: 'energy' },
        falloff:   { type: 'float', range: [0.2, 2.0],   default: 0.8,  uniform: 'u_falloff'  },
        palette:   { type: 'palette', count: 5 },
    },

    reactive: {
        core:       { feature: 'beat',    amount: 0.3, response: 'spike' },
        turbulence: { feature: 'bandMid', amount: 0.3, response: 'smooth' },
    },

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

    // The eye wanders, so the composition never sits still even when the arms do.
    vec2 eye = vec2(sin(t * 0.6) * 0.22, cos(t * 0.47) * 0.16);
    vec2 q = p - eye;

    float r = max(length(q), 1e-4);
    float a = atan(q.y, q.x);

    // Differential rotation: angular speed falls off with radius, so the arms
    // shear. Bounded rather than 1/r, or the core would spin arbitrarily fast.
    float omega = u_shear / (0.35 + r * 1.6);
    float wound = a + omega * t * 2.0 + log(r + 0.25) * u_winding;

    // Turbulence breaks the arms into filaments instead of clean spokes.
    wound += (fbm(q * 3.0 + t * 0.4, 4) - 0.5) * u_turbulence * 2.0;

    float arms = max(float(u_arms), 1.0);
    float band = sin(wound * arms) * 0.5 + 0.5;
    band = pow(band, 1.8);

    // Density falls off outward, so the frame has a subject.
    float envelope = exp(-r * u_falloff);

    vec3 col = pal(0) * 0.06;
    col += palRamp(wound * 0.08 + r * 0.2) * band * envelope * 0.9;
    col += pal(4) * pow(band, 4.0) * envelope * 0.5;

    // The eye itself, in the signature form.
    if (u_core > 0.004) {
        float d = castMain(q / u_core) * u_core;
        col = mix(col, pal(0) * 0.05, smoothstep(0.004, -0.01, d));
        col += pal(3) * inkStroke(d) * 0.8;
        col += pal(4) * exp(-max(d, 0.0) * 18.0) * 0.35;
    }

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

export default vortexDrift;
