// Structural family: an aqueduct marching away across the frame — a lower tier // of wide piers, an upper tier of small fast ones, and daylight through every // opening. // // Pylon Grid is open frame: you see through the whole structure and it has no // mass. This is masonry. The wall is solid, the light comes through holes cut in // it, and the rhythm changes tier to tier — two arches up top for every one // below, which is the thing that makes a real aqueduct read as marching rather // than repeating. The openings are the track's signature form, so a hexagonal // video is an aqueduct of hexagons. // // No declared slow axis, for the reason Contour Map and Balance Stack give: the // candidates were measured — tier height 0.91x, opening size 0.62x, tier count // 0.17x — and none of them beats the camera's own drift in Phase 11's // ten-second average. The structure is legible because it is high-contrast and // mostly still, and that is exactly the kind of image where a slow parameter // walk moves less of the frame than a slow pan does. export const aqueductMarch = { name: 'Aqueduct March', family: 'structural', kind: 'fragment', texture: 0.9, consumes: ['cast', 'ink'], traits: ['shape', 'camera', 'space', 'style'], params: { bays: { type: 'float', range: [1.2, 6], default: 2.2, uniform: 'u_bays', bias: 'density' }, opening: { type: 'float', range: [0.18, 0.6], default: 0.42, uniform: 'u_opening' }, tiers: { type: 'int', range: [1, 4], default: 2, uniform: 'u_tiers' }, rise: { type: 'float', range: [0.3, 1.3], default: 0.7, uniform: 'u_rise' }, recede: { type: 'float', range: [0, 0.8], default: 0.35, uniform: 'u_recede' }, sun: { type: 'float', range: [0, 1.5], default: 0.7, uniform: 'u_sunlight', bias: 'energy' }, march: { type: 'float', range: [0.005, 0.2], default: 0.04, uniform: 'u_march', bias: 'motion', rate: true }, palette: { type: 'palette', count: 5 }, }, reactive: { sun: { feature: 'loudness', amount: 0.3, response: 'smooth' }, recede: { feature: 'bandLow', amount: 0.15, response: 'smooth' }, }, shader: ` // One tier of masonry: a wall with a row of openings cut through it. Returns // how much of this pixel is stone. float tier(vec2 q, float bays, float top, float bottom, float shift) { if (q.y > top || q.y < bottom) return 0.0; float h = top - bottom; float g = q.x * bays + shift; float cx = (fract(g) - 0.5) / bays; // The opening is sized as a FRACTION OF ITS BAY in both directions, not as // a circle of some radius: a bay is much wider than it is tall once there // are three of them across the frame, and a round hole in it is a porthole // rather than an arch. Sized this way the same number reads as the same // opening whatever the bay count is. float cw = 0.5 / bays; // half a bay across float ch = h * 0.4; // half an opening up float k = u_opening * 2.4; vec2 local = vec2(cx / max(cw * k, 1e-4), (q.y - (bottom + h * 0.46)) / max(ch * k, 1e-4)); // The opening sits low in the tier, leaving a solid band above it to carry // the next tier — which is the whole structural point of an aqueduct. float hole = castMain(local) * min(cw, ch) * k; return smoothstep(-0.004, 0.004, hole); } vec4 scene(vec2 uv, vec2 p) { float t = u_time * u_march + u_seed; p = sigCamera(p); float horizon = sigHorizonY() * 0.35 - 0.1; // Sky behind the structure, and the ground it stands on. vec3 col = mix(pal(1) * 0.22, pal(0) * 0.05, sat((p.y - horizon) * 0.7 + 0.2)); col += pal(3) * exp(-abs(p.y - horizon) * 5.0) * u_sunlight * 0.5; col = mix(col, pal(0) * 0.1, smoothstep(horizon + 0.01, horizon - 0.05, p.y)); // Two ranges of the same structure: the far one smaller, slower and hazier, // so the aqueduct crosses a valley rather than standing in a diagram. // lint: fixed-cost — a near range and a far one for (int k = 0; k < 2; k++) { float fk = float(k); float scale = mix(1.0, 0.35, fk * u_recede * 2.0); float lift = horizon + fk * u_recede * 0.25; vec2 q = vec2(p.x / max(scale, 0.15), (p.y - lift) / max(scale, 0.15)); float shift = t * mix(1.0, 0.35, fk); float stone = 0.0; float base = 0.0; // lint: fixed-cost — at most four tiers for (int i = 0; i < 4; i++) { if (i >= u_tiers) break; float fi = float(i); float bottom = fi * u_rise; float top = bottom + u_rise; // Each tier up is twice as fine and half as tall a rhythm. stone = max(stone, tier(q, u_bays * pow(2.0, fi), top, bottom, shift * pow(2.0, fi) + fi * 0.31)); base = max(base, step(bottom, q.y) * step(q.y, top)); } // Stone: lit from the sun side, shadowed on the other, courses picked // out by a horizontal banding that survives the perspective. // Courses are drawn in the track's hand: heavy for a track with a thick // line, barely there for a fine one. float course = 0.5 + 0.5 * sin(q.y * 60.0); course = mix(course, smoothstep(0.35, 0.75, course), u_sigLine); vec3 masonry = mix(pal(2) * 0.35, pal(4) * 0.8, sat(q.x * 0.4 + 0.5)); masonry *= 0.7 + (0.15 + u_sigLine * 0.5) * course; masonry += pal(3) * u_sunlight * 0.22 * sat(q.x * 0.5 + 0.5); masonry += pal(4) * inkStroke(0.5 - abs(fract(q.x * u_bays) - 0.5) - 0.03) * (0.1 + u_sigLine * 0.9); float hazed = mix(1.0, 0.55, fk * u_recede); col = mix(col, masonry * hazed, stone * base); } col = sigAir(col, p, smoothstep(-0.2, 0.9, p.y - horizon)); return vec4(inkValue(col), 1.0); } `, }; export default aqueductMarch;