// Structural family: horizontal belts of cargo running in alternating // directions, stacked up the frame. // // Distinct from Neon City (a static skyline) and Pylon Grid (perspective depth): // this has no depth at all. It is flat, industrial and lateral — the only scene // in the library whose motion is purely sideways, which is exactly what makes it // cut well against everything that recedes. // // Each crate is stamped in the track's signature form, and the belts step in // bar-quantised lurches rather than sliding, so the movement is mechanical. export const cargoBelt = { name: 'Cargo Belt', family: 'structural', kind: 'fragment', // Takes the track's surface grain, but lightly — this is drawn, not filmed. texture: 0.4, traits: ['shape', 'camera', 'style'], params: { belts: { type: 'int', range: [2, 8], default: 4, uniform: 'u_belts', bias: 'density' }, crates: { type: 'float', range: [2, 14], default: 6, uniform: 'u_crates', bias: 'density' }, crateSize:{ type: 'float', range: [0.15, 0.75],default: 0.42, uniform: 'u_crateSize' }, speed: { type: 'float', range: [0.05, 1.0], default: 0.3, uniform: 'u_speed', bias: 'motion', rate: true }, gap: { type: 'float', range: [0.02, 0.3], default: 0.1, uniform: 'u_gap' }, rails: { type: 'float', range: [0, 1], default: 0.45, uniform: 'u_rails' }, lamp: { type: 'float', range: [0, 1.3], default: 0.5, uniform: 'u_lamp', bias: 'energy' }, palette: { type: 'palette', count: 5 }, }, reactive: { lamp: { feature: 'beat', amount: 0.35, response: 'spike' }, rails: { feature: 'bandLow', amount: 0.2, response: 'smooth' }, }, shader: ` vec4 scene(vec2 uv, vec2 p) { float t = u_time * u_speed + u_seed; p = sigCamera(p); vec3 col = pal(0) * 0.05; float span = 2.0 / max(float(u_belts), 1.0); for (int i = 0; i < 8; i++) { if (i >= u_belts) break; float fi = float(i); float centre = -1.0 + span * (fi + 0.5); float dy = p.y - centre; if (abs(dy) > span * 0.5) continue; float dir = mod(fi, 2.0) < 0.5 ? 1.0 : -1.0; // Quantised travel: the belt advances in eighth-bar steps, so cargo // lurches from cell to cell the way a conveyor does. float march = floor((t + fi * 0.37) * 4.0) * 0.25 * dir; float lane = p.x * 0.5 + march; float cell = floor(lane * u_crates); float withinCell = fract(lane * u_crates); float rnd = hash12(vec2(cell, fi)); // Not every cell carries a crate; the gaps are what make it read as // cargo rather than as a stripe pattern. if (rnd > u_gap) { vec2 local = vec2((withinCell - 0.5) * 2.0, dy / max(span * 0.5, 1e-3)); float size = u_crateSize * (0.7 + rnd * 0.5); float d = sigShape(local / max(size, 1e-3)) * size; vec3 crateColor = pal(int(mod(cell + fi, 4.0)) + 1); col = mix(col, crateColor * (0.35 + rnd * 0.5), smoothstep(0.02, -0.02, d)); col += crateColor * sigEdge(d) * (0.4 + u_lamp * 0.5); // Lamp on a minority of crates, pulsing on the beat. Local, not // whole-frame: a per-crate blink is not a flash. if (rnd > 0.82) col += pal(4) * smoothstep(0.06, 0.0, length(local)) * u_lamp; } // Belt rails, top and bottom of each lane. float rail = smoothstep(0.06, 0.0, abs(abs(dy) - span * 0.45)); col += pal(2) * rail * u_rails * 0.5; } col += sigGrain(uv); return vec4(col, 1.0); } `, }; export default cargoBelt;