// Structural family: a corridor of nested gates receding to a vanishing point,
// travelled through.
//
// Rectilinear depth, which the library did not have: Kaleido Tunnel recedes but
// is radial and folded, Pylon Grid stands still, Neon City is front-on. Here the
// camera moves forward through a series of frames that scale up and pass, and
// the ring geometry is the track's signature form, so a hexagonal video travels
// through hexagonal gates.
//
// Motion is a saw on log-depth, which is what makes gates emerge from the
// vanishing point at a constant apparent rate instead of rushing at the end.

export const gateCorridor = {
    name: 'Gate Corridor',
    family: 'structural',
    kind: 'fragment',
    // Takes the track's surface grain, but lightly — this is drawn, not filmed.
    texture: 0.4,
    consumes: ['cast', 'ink'],
    traits: ['shape', 'camera', 'space', 'style'],

    params: {
        gates:    { type: 'int',   range: [3, 14],     default: 8,    uniform: 'u_gates', bias: 'density' , slowAxis: true },
        aperture: { type: 'float', range: [0.15, 0.9], default: 0.45, uniform: 'u_aperture' },
        thickness:{ type: 'float', range: [0.02, 0.3], default: 0.09, uniform: 'u_thickness' },
        travel:   { type: 'float', range: [0.02, 0.7], default: 0.2,  uniform: 'u_travel', bias: 'motion', rate: true },
        rails:    { type: 'float', range: [0, 1],      default: 0.4,  uniform: 'u_rails' },
        lamps:    { type: 'float', range: [0, 1.4],    default: 0.5,  uniform: 'u_lamps', bias: 'energy' },
        vanish:   { type: 'float', range: [0, 0.5],    default: 0.15, uniform: 'u_vanish' },
        palette:  { type: 'palette', count: 5 },
    },

    reactive: {
        lamps:    { feature: 'beat',    amount: 0.35, response: 'spike' },
        aperture: { feature: 'bandLow', amount: 0.15, response: 'smooth' },
    },

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

    // The vanishing point sits on the track's horizon, slightly off centre.
    vec2 vanishAt = vec2(sin(u_seed) * u_vanish, sigHorizonY() * 0.35);
    vec2 q = p - vanishAt;

    vec3 col = pal(0) * 0.04;

    // Depth rails converging on the vanishing point.
    if (u_rails > 0.01) {
        float ang = atan(q.y, q.x);
        float spokes = abs(fract(ang * 1.9098 + 0.5) - 0.5) * 2.0;   // 12 rails
        float rail = smoothstep(0.06, 0.0, spokes) * smoothstep(0.02, 0.5, length(q));
        col += pal(1) * rail * u_rails * 0.25;
    }

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

        // Log-spaced depth with a saw: each gate walks forward, and when it
        // passes the camera it wraps to the far end.
        float phase = fract((fi / float(u_gates)) + t);
        float scale = u_aperture * exp(phase * 3.2) * 0.35;

        float d = abs(castMain(q / max(scale, 1e-3)) * max(scale, 1e-3));

        // Near gates are drawn thicker and brighter: the only depth cue that
        // matters once the geometry is right.
        float near = phase;
        float w = u_thickness * (0.25 + near * 1.2) * (0.5 + u_sigLine);
        float frame = smoothstep(w, w * 0.25, d);

        vec3 tint = palRamp(fi * 0.13 + 0.1);
        col += tint * frame * (0.25 + near * 0.75);
        col += tint * exp(-d * 14.0) * near * 0.2;

        // A lamp at the top of every third gate, pulsing on the beat.
        if (mod(fi, 3.0) < 0.5) {
            vec2 lampAt = vanishAt + vec2(0.0, scale);
            col += pal(4) * exp(-length(p - lampAt) * 26.0) * u_lamps * (0.3 + near);
        }
    }

    col = sigAir(col, p, 1.0 - smoothstep(0.0, 1.2, length(q)));
    return vec4(inkValue(col), 1.0);
}
`,
};

export default gateCorridor;
