// Structural family: a cold aisle. Two walls of equipment running to a
// vanishing point, indicator lights on every unit, a lit floor between them.
//
// Neon City is the other lit structure and it is exterior, vast and far: the
// lights are windows in buildings a mile off. This is interior and close enough
// to touch — two flat walls a couple of metres apart, the geometry is a corridor
// rather than a skyline, and the lights are not decoration but the only thing
// telling you the machines are running. What moves is the camera down the aisle.

export const dataAisle = {
    name: 'Data Aisle',
    family: 'structural',
    kind: 'fragment',
    texture: 0.6,
    consumes: ['ink'],
    traits: ['camera', 'space', 'style'],

    params: {
        width:   { type: 'float', range: [0.25, 1.1],  default: 0.55, uniform: 'u_aisle' },
        racks:   { type: 'float', range: [1, 8],       default: 3,    uniform: 'u_racks', bias: 'density' },
        units:   { type: 'float', range: [3, 20],      default: 9,    uniform: 'u_units', bias: 'density' },
        leds:    { type: 'float', range: [0, 1.5],     default: 0.7,  uniform: 'u_leds', bias: 'energy' },
        activity:{ type: 'float', range: [0, 1],       default: 0.45, uniform: 'u_activity' },
        run:     { type: 'float', range: [0.02, 0.5],  default: 0.12, uniform: 'u_run', bias: 'motion', rate: true },
        palette: { type: 'palette', count: 5 },
    },

    reactive: {
        leds:     { feature: 'bandHigh', amount: 0.35, response: 'smooth' },
        activity: { feature: 'flux',     amount: 0.25, response: 'spike' },
    },

    shader: `
// One wall of racks. 'along' is metres down the aisle, 'up' is height on the
// wall, and the return is the wall's colour.
vec3 wall(vec2 at, float side, float t, float lightAmount) {
    // Rack bays, and the gap between two racks.
    float bay = at.x * u_racks;
    float bayId = floor(bay);
    float bx = fract(bay) - 0.5;

    float unit = at.y * u_units;
    float unitId = floor(unit);
    float uy = fract(unit) - 0.5;

    // The metalwork: a dark case with a seam at every unit and every bay.
    float seam = min(0.5 - abs(bx), 0.5 - abs(uy));
    vec3 col = mix(pal(0) * 0.3, pal(2) * 0.42, sat(at.y * 0.6 + 0.2));
    float seamW = 0.03 + u_sigLine * 0.12;
    col = mix(col, pal(0) * 0.12, smoothstep(seamW, seamW * 0.2, seam));

    // Indicators: a row per unit, most of them steady, a few of them working.
    float id = hash12(vec2(bayId * 7.1 + unitId, side + floor(at.x * 0.5)));
    float slot = fract(bx * 8.0 + 0.5);
    float led = smoothstep(0.34, 0.16, abs(slot - 0.5)) * smoothstep(0.3, 0.12, abs(uy));

    // Blinking is quantised onto the bar grid rather than free-running: on a
    // wall of two hundred lights, free-running flicker is a fizz, and stepping
    // it keeps the whole wall under the flash ceiling as well.
    float step8 = floor(u_barPhase * 8.0) + floor(at.x * 3.0);
    float busy = step(1.0 - u_activity, hash12(vec2(id * 31.0, step8)));
    float bright = mix(0.25, 1.0, busy);

    col += palRamp(0.55 + id * 0.35) * led * bright * lightAmount * 1.8;
    col += pal(4) * inkStroke(seam - seamW) * (0.15 + u_sigLine * 0.9);
    return col;
}

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

    float horizon = sigHorizonY() * 0.25;
    vec2 c = vec2(p.x, p.y - horizon);

    // Corridor: the nearest of four planes. Distance down the aisle is 1/|c|,
    // which is the whole of the perspective.
    float dx = abs(c.x), dy = abs(c.y);
    bool onWall = dx * (1.0 / max(u_aisle, 0.05)) > dy * 2.4;

    float alongDist = onWall ? u_aisle / max(dx, 0.004) : 0.42 / max(dy, 0.004);
    float along = alongDist * 0.5 + t * 6.0;

    vec3 col;
    if (onWall) {
        // Height on the wall, corrected for distance so the racks stay upright.
        float up = c.y * alongDist / u_aisle * 0.5 + 0.5;
        col = wall(vec2(along, sat(up)), sign(c.x), t, 0.6 + u_leds * 0.9);
    } else if (c.y < 0.0) {
        // Floor: a lit strip down the middle, and the spill off both walls.
        float across = c.x * alongDist / 0.42;
        col = pal(0) * 0.16 + pal(2) * 0.12;
        col += pal(3) * exp(-abs(across) * 2.5) * (0.45 + u_leds * 0.5);
        col += pal(1) * 0.05 * step(0.5, fract(along * 0.5));
    } else {
        // Ceiling: cable trays and the occasional fitting.
        float across = c.x * alongDist / 0.42;
        col = pal(0) * 0.07;
        col += pal(1) * 0.12 * smoothstep(0.35, 0.2, abs(fract(across * 1.5) - 0.5));
        col += pal(3) * smoothstep(0.12, 0.0, abs(fract(along * 0.25) - 0.5)) * u_leds * 0.25;
    }

    // Distance haze, and the vanishing point itself, which is where the aisle
    // ends and the only part of the frame that never resolves.
    float far = sat(1.0 - alongDist * 0.06);
    col = mix(col, pal(1) * 0.12, sat(far * 0.7));
    col = sigAir(col, p, far);
    return vec4(inkValue(col), 1.0);
}
`,
};

export default dataAisle;
