// Structural family: an overhead truss, seen from underneath. // // Distinct from Pylon Grid (columns standing on the ground), Gate Corridor // (frames receding head-on) and Neon City (a skyline at eye level): this is the // only scene in the library whose subject is ABOVE the camera. Two parallel // chords run away toward the horizon with diagonal bracing zigzagging between // them, and the whole thing is looked up at, so the perspective converges // downward rather than inward. // // Joint plates are stamped in the track's signature form. // // Scaffolded by tools/new-scene.js. See HOWTO-visualizers.md. export const girderLattice = { name: 'Girder Lattice', family: 'structural', kind: 'fragment', traits: ['shape', 'camera', 'space', 'style'], params: { bays: { type: 'int', range: [3, 16], default: 8, uniform: 'u_bays', bias: 'density' }, beam: { type: 'float', range: [0.01, 0.12],default: 0.04, uniform: 'u_beam' }, depth: { type: 'float', range: [0.3, 2.2], default: 1.0, uniform: 'u_depth' }, brace: { type: 'float', range: [0, 1], default: 0.7, uniform: 'u_brace', bias: 'density' }, travel: { type: 'float', range: [0.0, 0.6], default: 0.12, uniform: 'u_travel', bias: 'motion', rate: true }, plate: { type: 'float', range: [0, 0.12], default: 0.05, uniform: 'u_plate' }, lamp: { type: 'float', range: [0, 1.4], default: 0.45, uniform: 'u_lamp', bias: 'energy' }, palette: { type: 'palette', count: 5 }, }, reactive: { lamp: { feature: 'beat', amount: 0.3, response: 'spike' }, brace: { feature: 'bandLow', amount: 0.15, response: 'smooth' }, }, shader: ` // Distance to a line segment. The truss is nothing but segments. float segment(vec2 p, vec2 a, vec2 b) { vec2 pa = p - a, ba = b - a; float h = clamp(dot(pa, ba) / max(dot(ba, ba), 1e-6), 0.0, 1.0); return length(pa - ba * h); } vec4 scene(vec2 uv, vec2 p) { float t = u_time * u_travel + u_seed; p = sigCamera(p); // Looking up: the vanishing point sits BELOW the frame's horizon, and the // structure spans above it. Everything converges toward that point. float vanishY = sigHorizonY() * 0.5 - 0.35; float above = p.y - vanishY; // Sky between the members. vec3 col = mix(pal(0) * 0.1, pal(1) * 0.06, sat(above * 0.6)); if (above <= 0.001) { col = sigAir(col, p, 1.0); col += sigGrain(uv); return vec4(col, 1.0); } float best = 1e3; float nearest = 0.0; float plateHit = 1e3; // Bays march toward the camera on a wrapping saw, so the truss travels // overhead rather than sitting still. for (int i = 0; i < 16; i++) { if (i >= u_bays) break; float fi = float(i); float phase = fract(fi / float(u_bays) + t); // Perspective: nearer bays are further up the frame and further apart. float y0 = vanishY + exp(phase * 2.4) * 0.12 * u_depth; float y1 = vanishY + exp((phase + 1.0 / float(u_bays)) * 2.4) * 0.12 * u_depth; float halfW0 = (y0 - vanishY) * 1.5; float halfW1 = (y1 - vanishY) * 1.5; // The two chords, running away from the camera. best = min(best, segment(p, vec2(-halfW0, y0), vec2(-halfW1, y1))); best = min(best, segment(p, vec2(halfW0, y0), vec2(halfW1, y1))); // Cross member at this joint. best = min(best, segment(p, vec2(-halfW0, y0), vec2(halfW0, y0))); // Diagonal bracing, alternating direction bay to bay: the zigzag is // what makes it a truss rather than a ladder. if (u_brace > 0.05) { float flip = mod(fi, 2.0) < 0.5 ? 1.0 : -1.0; float d = segment(p, vec2(-halfW0 * flip, y0), vec2(halfW1 * flip, y1)); best = min(best, d + (1.0 - u_brace) * 0.05); } if (u_plate > 0.004) { float pd = sigShape((p - vec2(halfW0, y0)) / u_plate) * u_plate; plateHit = min(plateHit, pd); pd = sigShape((p - vec2(-halfW0, y0)) / u_plate) * u_plate; plateHit = min(plateHit, pd); } if (phase > 0.75) nearest = max(nearest, phase); } // Members are drawn thicker nearer the camera, which is the only depth cue // a wireframe has. float weight = u_beam * (0.4 + above * 0.9) * (0.5 + u_sigLine); float steel = smoothstep(weight, weight * 0.3, best); col = mix(col, pal(2) * (0.3 + above * 0.5), steel); col += pal(3) * sigEdge(best - weight) * 0.4; // Joint plates. col = mix(col, pal(4) * 0.7, smoothstep(0.006, -0.006, plateHit)); // A lamp slung under the nearest bay, pulsing on the beat. Local. col += pal(4) * exp(-length(p - vec2(0.0, vanishY + nearest * 1.4)) * 14.0) * u_lamp; col = sigAir(col, p, 1.0 - smoothstep(0.0, 1.4, above)); col += sigGrain(uv); return vec4(col, 1.0); } `, }; export default girderLattice;