// 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', traits: ['shape', 'camera', 'space', 'style'], params: { gates: { type: 'int', range: [3, 14], default: 8, uniform: 'u_gates', bias: 'density' }, 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(sigShape(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))); col += sigGrain(uv); return vec4(col, 1.0); } `, }; export default gateCorridor;