{
  "license": "CC0-1.0",
  "shader": {
    "id": "5t6dnxo6",
    "title": "Piped Up",
    "license": "CC0-1.0",
    "provenance_type": "witnessed_generation",
    "made_with": "Claude",
    "status": "active",
    "compile_ok": true,
    "render_hash": "ffff000000000000",
    "tags": [
      "pipes",
      "piped",
      "windows",
      "pc",
      "plumbing",
      "screensaver",
      "3d"
    ],
    "parents": [],
    "author": "u7y1evhf0znj",
    "author_name": "ksin",
    "author_url": "/u/ksin",
    "created_at": "2026-09-05T11:41:17.940Z",
    "poster_url": "/posters/5t6dnxo6.avif",
    "stats": {
      "slops": 0,
      "views": 138,
      "forks": 0
    },
    "self": "/api/v1/shaders/5t6dnxo6",
    "isf": "/*{\n  \"DESCRIPTION\": \"The 3D Pipes screensaver, raymarched, and it never stops. The pipes are one endless stream of corners walking a 16x16x16 lattice on black: the head lays corners down at a steady rate and the tail eats them away a set distance behind, both ends fractional, so a pipe is consumed as smoothly as it is drawn and new pipes are always being laid while older ones are taken apart. Nothing fades out and the picture never empties. It is still a closed form of the clock - the head is just TIME times a rate - so it can be scrubbed, paused or resumed anywhere and it draws exactly the state that instant deserves; there is no feedback buffer and no state between frames. Right-angle turns, ball joints or real quarter-torus elbows, and a polished floor below that really mirrors the network - that reflection is a second march, grazing-weighted and eaten by distance so the horizon dissolves. The pipes carry animated procedural surfaces driven by distance along the pipe, angle around it and time, so a pattern flows the length of a pipe and round its corners instead of restarting at every joint. Twenty-four of them: plain, flowing rainbow, racing pulses, candy helix, plasma, electric arcs, oil-film iridescence, furnace heat, hazard stripes, circuit traces, overlapping scales, wave beats, zebra, starfield, thermal false-colour, time-quantised glitch, obsidian, blacklight, hologram, magma cracks, falling code, ice, hammered gold and broken static - each with its own emissive glow, which reaches the interreflections and the mirror as well as the surface. Every joint also flashes as it lands and cools off behind the advancing tip, which the shader can only draw because it knows not just where each corner is but exactly how long ago it was laid. Sliders for growth speed, how much pipe stays alive, corners per pipe, straight length, wander, spread, pipe radius, joint size, ball or elbow, bend radius, chrome, saturation, hue, metalness, roughness, interreflection, shadows, ambient occlusion, key light, ambient, sheen, pattern style, pattern blend, pattern scale, pattern speed, glow, floor, mirror, tip glow, orbit speed, distance, height, field of view, exposure, vignette and grain.\",\n  \"CREDIT\": \"CC0\",\n  \"CATEGORIES\": [\"generator\", \"3d\", \"retro\", \"screensaver\"],\n  \"INPUTS\": [\n    { \"NAME\": \"uSpeed\",    \"TYPE\": \"float\", \"DEFAULT\": 1.00,  \"MIN\": 0.0,  \"MAX\": 4.0 },\n    { \"NAME\": \"uCount\",    \"TYPE\": \"float\", \"DEFAULT\": 88.0,  \"MIN\": 16.0,  \"MAX\": 88.0 },\n    { \"NAME\": \"uRun\",      \"TYPE\": \"float\", \"DEFAULT\": 24.0,  \"MIN\": 8.0,  \"MAX\": 32.0 },\n    { \"NAME\": \"uLen\",      \"TYPE\": \"float\", \"DEFAULT\": 4.0,   \"MIN\": 1.0,  \"MAX\": 6.0 },\n    { \"NAME\": \"uWander\",   \"TYPE\": \"float\", \"DEFAULT\": 0.70,  \"MIN\": 0.0,  \"MAX\": 1.0 },\n    { \"NAME\": \"uSpread\",   \"TYPE\": \"float\", \"DEFAULT\": 0.60,  \"MIN\": 0.0,  \"MAX\": 1.0 },\n    { \"NAME\": \"uRadius\",   \"TYPE\": \"float\", \"DEFAULT\": 0.155, \"MIN\": 0.06, \"MAX\": 0.30 },\n    { \"NAME\": \"uJoint\",    \"TYPE\": \"float\", \"DEFAULT\": 0.245, \"MIN\": 0.08, \"MAX\": 0.40 },\n    { \"NAME\": \"uElbow\",    \"TYPE\": \"float\", \"DEFAULT\": 0.0,   \"MIN\": 0.0,  \"MAX\": 1.0 },\n    { \"NAME\": \"uBend\",     \"TYPE\": \"float\", \"DEFAULT\": 0.40,  \"MIN\": 0.20, \"MAX\": 0.45 },\n    { \"NAME\": \"uChrome\",   \"TYPE\": \"float\", \"DEFAULT\": 0.14,  \"MIN\": 0.0,  \"MAX\": 1.0 },\n    { \"NAME\": \"uSat\",      \"TYPE\": \"float\", \"DEFAULT\": 0.92,  \"MIN\": 0.0,  \"MAX\": 1.0 },\n    { \"NAME\": \"uHue\",      \"TYPE\": \"float\", \"DEFAULT\": 0.0,   \"MIN\": 0.0,  \"MAX\": 1.0 },\n    { \"NAME\": \"uMetal\",    \"TYPE\": \"float\", \"DEFAULT\": 0.60,  \"MIN\": 0.0,  \"MAX\": 1.0 },\n    { \"NAME\": \"uRough\",    \"TYPE\": \"float\", \"DEFAULT\": 0.12,  \"MIN\": 0.02, \"MAX\": 0.60 },\n    { \"NAME\": \"uReflect\",  \"TYPE\": \"float\", \"DEFAULT\": 0.70,  \"MIN\": 0.0,  \"MAX\": 1.0 },\n    { \"NAME\": \"uShadow\",   \"TYPE\": \"float\", \"DEFAULT\": 0.70,  \"MIN\": 0.0,  \"MAX\": 1.0 },\n    { \"NAME\": \"uAO\",       \"TYPE\": \"float\", \"DEFAULT\": 0.80,  \"MIN\": 0.0,  \"MAX\": 1.0 },\n    { \"NAME\": \"uLight\",    \"TYPE\": \"float\", \"DEFAULT\": 1.35,  \"MIN\": 0.0,  \"MAX\": 3.0 },\n    { \"NAME\": \"uAmbient\",  \"TYPE\": \"float\", \"DEFAULT\": 0.42,  \"MIN\": 0.0,  \"MAX\": 1.0 },\n    { \"NAME\": \"uSheen\",    \"TYPE\": \"float\", \"DEFAULT\": 0.85,  \"MIN\": 0.0,  \"MAX\": 1.5 },\n    { \"NAME\": \"uStyle\",    \"TYPE\": \"float\", \"DEFAULT\": 1.0,   \"MIN\": 0.0,  \"MAX\": 23.0 },\n    { \"NAME\": \"uPatMix\",   \"TYPE\": \"float\", \"DEFAULT\": 1.00,  \"MIN\": 0.0,  \"MAX\": 1.0 },\n    { \"NAME\": \"uPatScale\", \"TYPE\": \"float\", \"DEFAULT\": 1.00,  \"MIN\": 0.2,  \"MAX\": 4.0 },\n    { \"NAME\": \"uPatSpeed\", \"TYPE\": \"float\", \"DEFAULT\": 1.00,  \"MIN\": 0.0,  \"MAX\": 3.0 },\n    { \"NAME\": \"uEmit\",     \"TYPE\": \"float\", \"DEFAULT\": 1.00,  \"MIN\": 0.0,  \"MAX\": 3.0 },\n    { \"NAME\": \"uFloor\",    \"TYPE\": \"float\", \"DEFAULT\": 1.00,  \"MIN\": 0.0,  \"MAX\": 1.0 },\n    { \"NAME\": \"uMirror\",   \"TYPE\": \"float\", \"DEFAULT\": 0.80,  \"MIN\": 0.0,  \"MAX\": 1.0 },\n    { \"NAME\": \"uTipGlow\",  \"TYPE\": \"float\", \"DEFAULT\": 0.65,  \"MIN\": 0.0,  \"MAX\": 2.0 },\n    { \"NAME\": \"uOrbit\",    \"TYPE\": \"float\", \"DEFAULT\": 0.22,  \"MIN\": 0.0,  \"MAX\": 1.0 },\n    { \"NAME\": \"uDist\",     \"TYPE\": \"float\", \"DEFAULT\": 21.0,  \"MIN\": 10.0,  \"MAX\": 48.0 },\n    { \"NAME\": \"uHeight\",   \"TYPE\": \"float\", \"DEFAULT\": 2.20,  \"MIN\": -4.0, \"MAX\": 6.0 },\n    { \"NAME\": \"uFov\",      \"TYPE\": \"float\", \"DEFAULT\": 1.25,  \"MIN\": 0.6,  \"MAX\": 2.2 },\n    { \"NAME\": \"uExposure\", \"TYPE\": \"float\", \"DEFAULT\": 1.00,  \"MIN\": 0.2,  \"MAX\": 2.5 },\n    { \"NAME\": \"uVignette\", \"TYPE\": \"float\", \"DEFAULT\": 0.45,  \"MIN\": 0.0,  \"MAX\": 1.0 },\n    { \"NAME\": \"uGrain\",    \"TYPE\": \"float\", \"DEFAULT\": 0.03,  \"MIN\": 0.0,  \"MAX\": 0.30 }\n  ]\n}*/\n#define PI 3.14159265359\n\n// iq's anti-unroll guard. ANGLE hands GLSL to the D3D compiler, which tries to\n// fully unroll every constant-bound loop; with a 7x8 scene loop inlined into a\n// march, an AO tap, a shadow and a reflection bounce, the D3D backend gave up\n// and returned a link failure with an EMPTY info log. Starting each loop at a\n// value it cannot prove is zero stops the unrolling dead: 45 ms to link.\n//\n// It cannot ship in the ISF - GLSL ES 1.00 demands a constant loop initialiser\n// and rejects this outright - so isf_convert.py rewrites the line below to\n// \"#define ZERO 0\", which the preprocessor folds back into a constant.\n#define ZERO 0\n\n// 120 lattice corners, plus two sentinels so reading k+1 and k+2 is always in\n// range. The sentinels carry pipe id 31, which no real pipe ever gets (a run is\n// at least 8 corners long, so 120 corners hold at most 15 pipes, ids 0..14),\n// and a pipe id mismatch is exactly how the shader spots the end of a pipe.\n// The pipe field had to widen from 8 ids to 32 for that headroom: at 120\n// corners the old sentinel value 15 was reachable by a real pipe.\n#define NSEG 120\n#define NPT  122\n#define NCH  15\n#define GRID 16.0\n\nfloat gPts[NPT];   // packed lattice corners\nvec4  gB[NCH];     // bounding sphere per chunk of 8 corners: xyz centre, w radius\n// The network is an endless stream of corners with a window cut out of it.\n// gHead is how far the stream has been drawn (fractional, unbounded); gTail is\n// how far it has been eaten from behind. Nothing ever fades: pipes grow at the\n// head while older ones are consumed at the tail, so there is always about\n// uCount corners of pipe alive and the picture never empties.\nfloat gHead;       // leading corner index, fractional\nfloat gTail;       // trailing corner index, fractional\nfloat gG0;         // stream index of array slot 0 - always a pipe boundary\nfloat gRun;        // corners per pipe, whole\nfloat gEmit;       // how hard the surface under the last surfAt() is glowing\nfloat gGloss;      // and whether that style wants to stay a mirror\n\n// Dave Hoskins' hash, not the usual fract(sin(x)*43758.5): the sin version\n// wants sin() of arguments in the tens of thousands, where float32 argument\n// reduction is worth only a few bits and two implementations disagree.\n//\n// This one now drives the film grain and nothing else. Grain is the one place\n// where a value that differs in its last bits between two GPUs does not matter,\n// because nobody can point at a grain speckle and say it is in the wrong place.\n// Everything that decides the shape uses ihash() below.\nfloat h11(float p){\n  p = fract(p * 0.1031);\n  p *= p + 33.33;\n  p *= p + p;\n  return fract(p);\n}\n// Anything that decides the SHAPE uses this instead: integer arithmetic\n// carried in floats, where every intermediate is a whole number below 2^24 and\n// float32 is exact, so two implementations cannot disagree about it.\n//\n// The float hash above was the second one to get this wrong. It is stable for\n// small inputs, but the walk feeds it corner index times a multiplier, so by\n// corner 47 it was handing fract() numbers in the hundreds - and up there\n// float32 has already discarded the bits that decide which way a pipe turns.\n// The WebGL2 build and the ISF build drew measurably different networks from\n// the same seed: mean pixel difference 0.02/255 at TIME 8, 9.2/255 at TIME\n// 61.6, with whole segments present in one and missing in the other.\n//\n// 4091 is prime and 3 does not divide 4090, so n -> n^3 is a permutation of the\n// residues; three affine-then-cube rounds measure as well as a true RNG on\n// lag-1 autocorrelation at every stride the shader actually steps by. The\n// cube is split in two so the largest intermediate is 4090^2, just inside\n// exact range.\n#define IM 4091.0\nfloat ihash(float n){\n  n = mod(n, IM);\n  n = mod(n * 3192.0 + 3096.0, IM); n = mod(mod(n * n, IM) * n, IM);\n  n = mod(n *  745.0 +  531.0, IM); n = mod(mod(n * n, IM) * n, IM);\n  n = mod(n * 1109.0 + 3358.0, IM); n = mod(mod(n * n, IM) * n, IM);\n  return n * (1.0 / IM);\n}\nvec3 ihash3(float n){\n  return vec3(ihash(n), ihash(n + 1949.0), ihash(n + 3803.0));\n}\n\n// ---- packing ---------------------------------------------------------------\n// A corner is just a cell in a 16x16x16 lattice now, one exact integer in\n// 0..4095. The pipe id and the \"starts here\" flag used to be packed alongside\n// it; with pipes a fixed number of corners long, both are arithmetic on the\n// stream index instead - which also retired the sentinel value that had to be\n// widened every time the corner budget grew.\nfloat packPt(vec3 c){ return c.x + 16.0 * c.y + 256.0 * c.z; }\nvec3 cellOf(float v){\n  float q = mod(v, 4096.0);\n  return vec3(mod(q, 16.0), mod(floor(q / 16.0), 16.0), floor(q / 256.0));\n}\nfloat pipeAtG(float g){ return floor(g / gRun); }          // which pipe\nfloat startsAt(float g){ return mod(g, gRun) < 0.5 ? 1.0 : 0.0; }\nfloat endsAt(float g){ return mod(g + 1.0, gRun) < 0.5 ? 1.0 : 0.0; }\nvec3  posOf(float v){ return cellOf(v) - vec3((GRID - 1.0) * 0.5); }\n\n// ---- the walk --------------------------------------------------------------\n// A self-avoiding-ish random walk on the lattice: every corner is a 90 degree\n// turn, straights are 1..uLen cells, and each candidate direction is scored on\n// three things - a random roll, how far it moves away from where the pipe has\n// just been (a running mean of recent corners), and a pull back toward the\n// middle of the box. That last term is what keeps a pipe from crawling along a\n// wall, and the middle one is what stops it folding back through itself.\nvoid buildPath(){\n  vec3 cell = vec3(0.0), dir = vec3(1.0, 0.0, 0.0), ema = vec3(0.0);\n  float last = 0.0;\n\n  for (int i = ZERO; i < NSEG; i++){\n    float g = gG0 + float(i);\n    if (g > gHead + 1.0) break;               // not drawn yet, and not needed\n    // The pipe index, wrapped so the hash keys stay exact integers however long\n    // the shader has been running. 512 pipes is well over an hour.\n    float pw = mod(pipeAtG(g), 512.0);\n\n    if (startsAt(g) > 0.5){                   // a new pipe begins at this corner\n      float sk = pw * 571.0;\n      vec3  r  = ihash3(sk);\n      cell = floor(r * (GRID - 2.0)) + 1.0;\n      float a = floor(ihash(sk + 11.0) * 3.0);\n      dir  = (1.0 - min(abs(a - vec3(0.0, 1.0, 2.0)), 1.0))\n             * (ihash(sk + 23.0) < 0.5 ? -1.0 : 1.0);\n      ema  = cell;\n    }\n\n    gPts[i] = packPt(cell);\n    last    = gPts[i];\n\n    float within = mod(g, gRun);\n    float best = -1e9, blen = 1.0;\n    vec3  bdir = dir;\n    for (int d = ZERO; d < 6; d++){\n      float ax = floor(float(d) * 0.5);\n      float sg = 1.0 - 2.0 * mod(float(d), 2.0);\n      vec3  v  = (1.0 - min(abs(ax - vec3(0.0, 1.0, 2.0)), 1.0)) * sg;\n      if (abs(dot(v, dir)) > 0.5) continue;                 // it has to turn\n      float ln  = 1.0 + floor(ihash(pw * 911.0 + within * 13.0 + float(d) * 7.0)\n                              * max(uLen, 1.0));\n      vec3  tgt = clamp(cell + v * ln, vec3(0.0), vec3(GRID - 1.0));\n      float act = length(tgt - cell);\n      if (act < 0.5) continue;                              // wall, no room\n      // Normalised, or the spread term swamps the roll and the walk collapses\n      // into a plane: the first build zigzagged across two axes and never used\n      // the third. The centre pull stays unnormalised on purpose - it should do\n      // nothing in the middle of the box and shove hard at the wall, and its\n      // weight scales inversely with the box or it doubles when the box does.\n      vec3  away = cell - ema;\n      float al   = length(away);\n      float sc = ihash(pw * 337.0 + within * 29.0 + float(d) * 3.0 + 1.0) * uWander\n               + dot(v, al > 0.001 ? away / al : vec3(0.0)) * uSpread * 0.50\n               + dot(v, vec3((GRID - 1.0) * 0.5) - cell) * (0.8 / GRID);\n      if (sc > best){ best = sc; bdir = v; blen = act; }\n    }\n\n    dir  = bdir;\n    cell = clamp(cell + bdir * blen, vec3(0.0), vec3(GRID - 1.0));\n    ema  = mix(ema, cell, 0.40);\n  }\n\n  gPts[NSEG] = last;                          // never read as geometry, but the\n  gPts[NSEG + 1] = last;                      // k+1 / k+2 reads must be in range\n\n  // One bounding sphere per 8 corners. Nine corners go into each, because the\n  // eighth segment of a chunk reaches into the next one. This is the whole\n  // acceleration structure: a march step tests fifteen spheres and only opens\n  // the chunks that could possibly be nearer than what it already holds.\n  float pad = max(uJoint, uBend + uRadius) + 0.35;\n  for (int c = ZERO; c < NCH; c++){\n    vec3  lo = vec3(1e6), hi = vec3(-1e6);\n    float any = 0.0;\n    for (int j = ZERO; j < 9; j++){\n      float g = gG0 + float(c * 8 + j);\n      if (g > gHead) break;\n      if (g + 1.0 < gTail) continue;          // eaten; contributes no geometry\n      vec3 w = posOf(gPts[c * 8 + j]);\n      lo = min(lo, w); hi = max(hi, w); any = 1.0;\n    }\n    gB[c] = any > 0.5 ? vec4((lo + hi) * 0.5, length(hi - lo) * 0.5 + pad)\n                      : vec4(0.0, 0.0, 0.0, -1000.0);\n  }\n}\n\n// ---- primitives ------------------------------------------------------------\nfloat sdCapsule(vec3 p, vec3 a, vec3 b, float r){\n  vec3 pa = p - a, ba = b - a;\n  float h = clamp(dot(pa, ba) / max(dot(ba, ba), 1e-6), 0.0, 1.0);\n  return length(pa - ba * h) - r;\n}\n\n// A real quarter torus. The pipe arrives along a and leaves along b; the arc\n// centre sits at R*(b-a) from the corner, which is the one point R away from\n// both pipe axes, and the arc sweeps from -R*b round to +R*a. Clamping the\n// in-plane coordinates into that quadrant before projecting onto the circle is\n// what keeps the elbow a quarter and not a full ring hanging in the air.\nfloat sdElbow(vec3 p, vec3 a, vec3 b, float R, float r){\n  vec3  o  = R * (b - a);\n  vec3  q  = p - o;\n  float qa = max(dot(q, a), 0.0);\n  float qb = min(dot(q, b), 0.0);\n  float l  = length(vec2(qa, qb));\n  vec3  nr = l > 1e-5 ? o + (a * qa + b * qb) * (R / l) : o + a * R;\n  return length(p - nr) - r;\n}\n\n// ---- the scene -------------------------------------------------------------\nfloat mapPipes(vec3 p){\n  float d = 1e6;\n  float bend = uElbow > 0.5 ? uBend : 0.0;\n\n  for (int c = ZERO; c < NCH; c++){\n    if (length(p - gB[c].xyz) - gB[c].w > d) continue;\n\n    for (int j = ZERO; j < 8; j++){\n      float g = gG0 + float(c * 8 + j);\n      if (g >= gHead) break;                       // not drawn yet\n\n      // How much of the segment from corner g to g+1 is alive: the tail has\n      // eaten up to s0 and the head has drawn up to s1. Both ends are\n      // fractional, so a pipe is consumed as smoothly as it is laid down.\n      float s0 = clamp(gTail - g, 0.0, 1.0);\n      float s1 = clamp(gHead - g, 0.0, 1.0);\n      if (s1 <= s0) continue;                      // wholly eaten\n\n      vec3  A = posOf(gPts[c * 8 + j]);\n      if (endsAt(g) > 0.5){                        // last corner of its pipe\n        if (g >= gTail) d = min(d, length(p - A) - uJoint);\n        continue;\n      }\n      if (startsAt(g) > 0.5 && s0 <= 0.0) d = min(d, length(p - A) - uJoint);\n\n      vec3  B  = posOf(gPts[c * 8 + j + 1]);\n      vec3  ab = normalize(B - A);\n      vec3  P0 = mix(A, B, s0), P1 = mix(A, B, s1);\n      float goes = endsAt(g + 1.0) > 0.5 ? 0.0 : 1.0;   // does it turn at B\n      float e0 = (startsAt(g) > 0.5 || s0 > 0.0) ? 0.0 : bend;\n      float e1 = (s1 >= 1.0 ? goes : 0.0) * bend;\n      d = min(d, sdCapsule(p, P0 + ab * e0, P1 - ab * e1, uRadius));\n\n      if (s1 < 1.0) continue;                      // still growing toward B\n      if (goes < 0.5){ d = min(d, length(p - B) - uJoint); continue; }\n\n      if (uElbow > 0.5){\n        d = min(d, sdElbow(p - B, ab, normalize(posOf(gPts[c * 8 + j + 2]) - B),\n                           uBend, uRadius));\n      } else {\n        d = min(d, length(p - B) - uJoint);\n      }\n    }\n  }\n  return d;\n}\n\n// Where on the network a surface point is: which pipe owns it, how far along\n// that pipe it lies, and where it sits around the pipe's circumference. The\n// distance-along is what makes a pattern able to FLOW: it is accumulated across\n// segments in order and reset at each pipe's start, so a stripe can run the\n// length of a pipe and round its corners instead of restarting at every joint.\n//\n// Nearest segment, not nearest corner - the corner version painted a pipe in\n// two colours wherever another pipe crossed nearer to it than its own next\n// joint. Only ever asked at a hit point, so a linear scan is fine; the chunk\n// bounding spheres are skipped here because the running length has to be\n// accumulated in order.\nvoid surfAt(vec3 p, out float id, out float flow, out float ang){\n  float best = 1e6, run = 0.0;\n  vec3  bA = vec3(0.0), bax = vec3(1.0, 0.0, 0.0);\n  float bh = 0.0;\n  id = 0.0; flow = 0.0; ang = 0.0;\n\n  for (int c = ZERO; c < NCH; c++){\n    // The chunk bounding spheres still apply, but a skipped chunk cannot just\n    // be jumped over: the running length has to pass through it. So a far\n    // chunk still walks its segments, it just does not do the geometry.\n    bool near = length(p - gB[c].xyz) - gB[c].w <= best;\n    for (int j = ZERO; j < 8; j++){\n      float g = gG0 + float(c * 8 + j);\n      if (g >= gHead) break;\n      // The running length is measured from where the pipe originally started,\n      // not from where the tail has eaten to, so a pattern stays put on the\n      // pipe while it is being consumed instead of sliding along it.\n      if (startsAt(g) > 0.5) run = 0.0;\n      if (endsAt(g) > 0.5) continue;\n      vec3  A   = posOf(gPts[c * 8 + j]);\n      vec3  ba  = posOf(gPts[c * 8 + j + 1]) - A;\n      // Every segment is axis-aligned, so its length is the sum of the\n      // magnitudes of its components - no square root anywhere in this loop.\n      float len = max(dot(abs(ba), vec3(1.0)), 1e-4);\n      if (near && gHead - g > 0.0 && gTail - g < 1.0){\n        vec3  ax = ba / len;\n        float h  = clamp(dot(p - A, ax), 0.0, len);\n        float d  = length(p - A - ax * h);\n        if (d < best){\n          best = d; id = pipeAtG(g); flow = run + h;\n          bA = A; bax = ax; bh = h;\n        }\n      }\n      run += len;\n    }\n  }\n\n  // The angle needs a frame perpendicular to the axis, built once for the\n  // winner rather than for every segment tested.\n  vec3 u = normalize(abs(bax.y) < 0.9 ? cross(bax, vec3(0.0, 1.0, 0.0))\n                                      : cross(bax, vec3(1.0, 0.0, 0.0)));\n  vec3 w = cross(bax, u);\n  vec3 r = p - bA - bax * bh;\n  ang = atan(dot(r, w) + 1e-7, dot(r, u) + 1e-7);\n}\n\n// Tetrahedron, not central differences: four scene lookups instead of six for\n// the same normal. Normals are taken at the primary hit, at the mirror hit and\n// at the interreflection hit, so the two saved lookups are worth three each.\nvec3 normalAt(vec3 p){\n  vec2 k = vec2(1.0, -1.0) * 0.0016;\n  return normalize(k.xyy * mapPipes(p + k.xyy) + k.yyx * mapPipes(p + k.yyx)\n                 + k.yxy * mapPipes(p + k.yxy) + k.xxx * mapPipes(p + k.xxx));\n}\n\nfloat aoAt(vec3 p, vec3 n){\n  float s = 0.0, w = 1.0;\n  for (int i = ZERO + 1; i <= 5; i++){\n    float h = 0.035 * float(i) * float(i);\n    s += w * max(h - mapPipes(p + n * h), 0.0) / h;\n    w *= 0.65;\n  }\n  return clamp(1.0 - s * 0.55 * uAO, 0.0, 1.0);\n}\n\nfloat shadowAt(vec3 ro, vec3 rd){\n  float res = 1.0, t = 0.08;\n  for (int i = ZERO; i < 20; i++){\n    float h = mapPipes(ro + rd * t);\n    res = min(res, 13.0 * h / t);\n    t += clamp(h, 0.07, 0.75);\n    if (res < 0.02 || t > 16.0) break;\n  }\n  return clamp(res, 0.0, 1.0);\n}\n\n// ---- the light -------------------------------------------------------------\n// There is no room. The background is black, permanently: no walls, no floor\n// checker, no ceiling panel, no slider to bring any of it back. What is left is\n// one key light above and to one side - off camera, and off-centre on purpose,\n// because straight overhead every shadow lands directly under its pipe and\n// reads as a smudge.\n#define LIGHTP vec3(3.6, 5.85, 2.6)\n\n// ...and a two-lobe studio gradient, which is what a reflection lands on now\n// that there is nothing to reflect. It is a lighting function, not a scene: it\n// is never drawn, only sampled by reflected rays, and uSheen turns it off.\nvec3 envAt(vec3 dir){\n  float up  = dir.y * 0.5 + 0.5;\n  vec3  col = mix(vec3(0.020, 0.023, 0.032), vec3(0.10, 0.12, 0.16), up * up);\n  vec3  L   = normalize(LIGHTP);\n  col += vec3(0.85, 0.87, 0.95) * pow(max(dot(dir, L), 0.0), 6.0) * 0.55;\n  col += vec3(0.30, 0.42, 0.70) * pow(max(dot(dir, normalize(vec3(-4.0, 1.2, -3.0))), 0.0), 4.0) * 0.22;\n  return col * uSheen;\n}\n\n// ---- colour ----------------------------------------------------------------\nvec3 hue2rgb(float h){\n  return clamp(abs(mod(h * 6.0 + vec3(0.0, 4.0, 2.0), 6.0) - 3.0) - 1.0, 0.0, 1.0);\n}\n\nvec3 pipeColour(float id){\n  // The run picks one random hue and the pipes in it step away by the golden\n  // angle. Hashing each pipe independently kept handing a run two blues a few\n  // degrees apart, and two pipes the same colour is two pipes you cannot tell\n  // apart - the one thing the colour is there to do.\n  // Consecutive pipes step by the golden angle, wrapped so the multiply stays\n  // precise however far into the stream we are.\n  float h = fract(mod(id, 512.0) * 0.381966 + uHue);\n  vec3  c = hue2rgb(h);\n  c = mix(vec3(1.0), c, uSat);                       // toward white\n  return mix(c, vec3(0.86, 0.87, 0.90), uChrome);    // toward chrome\n}\n\n// ---- the pipe patterns -----------------------------------------------------\n// Eight surface treatments, all of them functions of (distance along the pipe,\n// angle around it, world position, time) - which is exactly the coordinate set\n// surfAt() hands back. `emit` comes back separately because these are meant to\n// glow: an emissive term is added after shading, so a pattern is not something\n// the key light has to find in order to be visible.\nvec3 pipePattern(vec3 p, vec3 base, float id, float flow, float ang,\n                 vec3 n, vec3 rd, out float emit){\n  float T = TIME * uPatSpeed;\n  float f = flow * uPatScale;\n  emit = 0.0;\n\n  if (uStyle < 0.5) return base;                                    // 0 plain\n\n  if (uStyle < 1.5){                                                // 1 flow\n    float h = fract(f * 0.10 - T * 0.25 + id * 0.13 + uHue);\n    emit = 0.40;\n    return hue2rgb(h);\n  }\n  if (uStyle < 2.5){                                                // 2 pulse\n    // Sawtooth, so the leading edge is a wall and the tail is a fade: a comet\n    // running down the pipe rather than a sine that breathes in place.\n    float k = fract(f * 0.09 - T * 0.55 + id * 0.31);\n    float g = pow(1.0 - k, 16.0) + 0.30 * pow(1.0 - k, 3.0);\n    emit = g * 1.9;\n    return mix(base * 0.30, mix(base, vec3(1.0), 0.80), g);\n  }\n  if (uStyle < 3.5){                                                // 3 candy\n    // Two saturated colours with a hard edge between them. Mixing toward\n    // \"one minus the base\" gave a pair of near-greys and the helix vanished.\n    float st = sin(f * 1.7 + ang * 2.0 - T * 2.0);\n    vec3  c2 = hue2rgb(fract(id * 0.381966 + 0.47 + uHue));\n    emit = 0.28;\n    return mix(base, c2, smoothstep(-0.14, 0.14, st));\n  }\n  if (uStyle < 4.5){                                                // 4 plasma\n    float v = sin(p.x * 1.7 + T) + sin(p.y * 1.9 - T * 1.3)\n            + sin(p.z * 1.5 + T * 0.7) + sin(length(p.xz) * 2.3 - T * 1.7);\n    emit = 0.50;\n    return hue2rgb(fract(v * 0.11 + id * 0.2 + uHue));\n  }\n  if (uStyle < 5.5){                                                // 5 arc\n    float a1 = sin(f * 2.7 + T * 3.1 + id * 2.0) * sin(ang * 2.0 - T * 1.9);\n    float a2 = sin(f * 5.3 - T * 4.3) * sin(ang * 3.0 + T * 2.7);\n    float arc = pow(max(0.0, 1.0 - abs(a1 + a2 * 0.6) * 2.2), 5.0);\n    emit = arc * 3.0;\n    return mix(base * 0.24, vec3(0.72, 0.90, 1.0), arc);\n  }\n  if (uStyle < 6.5){                                                // 6 oil\n    // Thin film: the hue is a function of how edge-on the surface is, so the\n    // bands sit still on the pipe and swim when the camera moves.\n    float ct = 1.0 - abs(dot(n, -rd));\n    emit = 0.22;\n    return mix(base, hue2rgb(fract(ct * 1.7 + f * 0.02 - T * 0.10 + uHue)), 0.9);\n  }\n  if (uStyle < 7.5){                                                // 7 furnace\n    // Cold iron with hot bands running through it. The first version used a\n    // soft falloff and a mid-orange floor, so every pipe sat at the same\n    // lukewarm tan; the body has to be nearly black for the hot part to read.\n    float q    = fract(f * 0.06 - T * 0.40);\n    float turb = 0.5 + 0.5 * sin(f * 2.3 + T * 3.0 + ang * 1.7)\n                           * sin(f * 0.7 - T * 1.1);\n    float heat = clamp(pow(1.0 - q, 6.0) * (0.5 + 0.9 * turb), 0.0, 1.0);\n    vec3  c    = mix(vec3(0.040, 0.018, 0.010), vec3(1.0, 0.30, 0.03), sqrt(heat));\n    c = mix(c, vec3(1.0, 0.85, 0.45), pow(heat, 4.0));\n    emit = heat * 2.2;\n    return c;\n  }\n  if (uStyle < 8.5){                                                // 8 hazard\n    // Mixing axial and angular in one fract is what tilts the stripes: the\n    // ratio between the two is the barber-pole pitch.\n    float k = fract(f * 0.55 + ang * 0.55 - T * 0.35);\n    float m = smoothstep(0.46, 0.54, k);\n    emit = m * 0.55;\n    return mix(vec3(0.035, 0.030, 0.020), vec3(1.0, 0.76, 0.04), m);\n  }\n  if (uStyle < 9.5){                                                // 9 circuit\n    float gx = abs(fract(f * 0.5) - 0.5);\n    float gy = abs(fract(ang * 1.6) - 0.5);\n    float ln = smoothstep(0.07, 0.0, min(gx, gy));\n    float dt = pow(max(0.0, 1.0 - abs(fract(f * 0.5 - T * 0.55) - 0.5) * 9.0), 4.0);\n    emit = ln * 0.55 + dt * 2.2;\n    return mix(vec3(0.015, 0.045, 0.028), vec3(0.24, 1.0, 0.55), ln * 0.65 + dt);\n  }\n  if (uStyle < 10.5){                                               // 10 scales\n    // Every other row offset by half a scale, which is what makes them overlap\n    // like roof tiles instead of sitting in a grid.\n    float u1  = f * 0.8;\n    float v1  = ang * 1.8 + 0.5 * mod(floor(u1), 2.0);\n    float d1  = length(vec2(fract(u1) - 0.5, (fract(v1) - 0.5) * 1.2));\n    float sc  = smoothstep(0.46, 0.22, d1);\n    emit = sc * 0.55;\n    return mix(base * 0.12, mix(base, vec3(1.0), 0.55), sc);\n  }\n  if (uStyle < 11.5){                                               // 11 beat\n    // Two travelling waves at different speeds; what you see is the beat\n    // between them, which drifts along the pipe on its own schedule.\n    float iw = (sin(f * 1.6 - T * 2.0) + sin(f * 2.3 + T * 1.4)) * 0.5;\n    float m  = smoothstep(0.55, 0.95, iw);\n    emit = m * 1.8;\n    return mix(base * 0.12, vec3(0.55, 0.92, 1.0), m);\n  }\n  if (uStyle < 12.5){                                               // 12 zebra\n    float w = sin(f * 1.2 + sin(ang * 2.0 + T * 0.8) * 1.6 + T * 0.5);\n    emit = 0.06;\n    return mix(vec3(0.025), vec3(0.97), smoothstep(-0.09, 0.09, w));\n  }\n  if (uStyle < 13.5){                                               // 13 stars\n    float ca = floor(f * 6.0), cb = floor(ang * 5.0);\n    float r1 = h11(ca * 3.7 + cb * 17.3 + 0.5);\n    float tw = 0.5 + 0.5 * sin(T * 3.0 + r1 * 40.0);\n    float st = step(0.86, r1) * pow(tw, 3.0);\n    emit = st * 3.0;\n    return mix(vec3(0.020, 0.020, 0.045), vec3(1.0, 0.95, 0.85), st);\n  }\n  if (uStyle < 14.5){                                               // 14 thermal\n    float w = sin(f * 0.7 + T * 0.5) * 0.5 + sin(ang * 1.5 - T * 0.7) * 0.3\n            + sin(f * 0.21 - T * 0.31) * 0.5;\n    float k = clamp(w * 0.55 + 0.5, 0.0, 1.0);\n    emit = k * 0.9;\n    return vec3(smoothstep(0.35, 0.92, k),\n                smoothstep(0.12, 0.98, k) * smoothstep(1.06, 0.52, k),\n                smoothstep(0.52, 0.0, k));\n  }\n  if (uStyle < 15.5){                                               // 15 glitch\n    // Quantised in space AND in time - the block index and the frame index are\n    // both floored, so it jumps rather than slides.\n    float blk = floor(f * 2.5) + floor(ang * 3.0) * 31.0;\n    float r2  = h11(blk + floor(T * 6.0) * 7.31);\n    vec3  c   = hue2rgb(fract(r2 * 3.0 + uHue));\n    float hot = step(0.93, r2);\n    emit = 0.55 + hot * 1.6;\n    return mix(c, vec3(1.0), hot);\n  }\n  if (uStyle < 16.5){                                             // 16 obsidian\n    // Black, and it stays black: no emission at all, so the whole read is the\n    // key light skidding off the curve and a cold rim where the surface turns\n    // away. This is the one style that wants MORE specular, not less, which is\n    // why the gloss damp below is per-style rather than \"any pattern is matte\".\n    float rim = pow(1.0 - abs(dot(n, -rd)), 3.0);\n    emit = 0.0;\n    return vec3(0.012, 0.013, 0.016) + vec3(0.10, 0.12, 0.17) * rim;\n  }\n  if (uStyle < 17.5){                                           // 17 blacklight\n    float b1 = sin(f * 1.5 - T * 1.1) * sin(ang * 1.7 + T * 0.7);\n    float gl = smoothstep(0.1, 0.9, b1);\n    emit = gl * 2.0;\n    return mix(vec3(0.030, 0.010, 0.055), vec3(0.65, 0.18, 1.0), gl)\n         + vec3(0.35, 0.55, 0.30) * pow(gl, 6.0);\n  }\n  if (uStyle < 18.5){                                            // 18 hologram\n    // Scanlines across the pipe plus a fresnel edge, and a flicker that drops\n    // the whole thing for a frame now and then the way a bad projection does.\n    float scan  = 0.55 + 0.45 * sin(f * 9.0 - T * 5.0);\n    float edge  = pow(1.0 - abs(dot(n, -rd)), 2.0);\n    float flick = step(0.06, h11(floor(T * 12.0) * 3.7)) * 0.75 + 0.25;\n    emit = (scan * 0.5 + edge * 1.6) * flick;\n    return vec3(0.20, 0.95, 1.0) * (0.25 + 0.55 * scan + edge) * flick;\n  }\n  if (uStyle < 19.5){                                               // 19 magma\n    // Cracks, not bands: the product of two waves is near zero along curves,\n    // and thresholding that gives a branching seam instead of a stripe.\n    float w  = sin(f * 1.3 + ang * 2.1) * sin(f * 0.7 - ang * 1.3 + T * 0.3);\n    float cr = 1.0 - smoothstep(0.0, 0.10, abs(w));\n    float pu = 0.65 + 0.35 * sin(T * 2.0 + f * 0.5);\n    emit = cr * 2.4 * pu;\n    return mix(vec3(0.018, 0.015, 0.014), vec3(1.0, 0.35, 0.05), cr * pu);\n  }\n  if (uStyle < 20.5){                                              // 20 matrix\n    float cm = floor(ang * 4.0);\n    float r3 = h11(cm * 7.3 + 1.7);\n    float y  = fract(f * 0.25 - T * (0.45 + r3 * 0.9) - r3);\n    float hd = pow(1.0 - y, 26.0);\n    float tl = pow(1.0 - y, 3.0);\n    emit = hd * 2.6 + tl * 0.45;\n    return mix(vec3(0.010, 0.040, 0.018), vec3(0.35, 1.0, 0.45), tl)\n         + vec3(0.75, 1.0, 0.80) * hd;\n  }\n  if (uStyle < 21.5){                                                 // 21 ice\n    float w  = sin(f * 1.9 - ang * 1.1) * sin(f * 0.8 + ang * 2.3 + T * 0.2);\n    float cr = 1.0 - smoothstep(0.0, 0.07, abs(w));\n    float dp = 0.5 + 0.5 * sin(f * 0.6 + T * 0.25);\n    emit = cr * 0.5;\n    return mix(vec3(0.30, 0.52, 0.68) * (0.6 + 0.5 * dp), vec3(0.92, 0.98, 1.0), cr);\n  }\n  if (uStyle < 22.5){                                                // 22 gold\n    // Hammered: a low-frequency wobble stands in for the dents, and the seams\n    // are the lines where it turns over.\n    float ham  = sin(f * 3.1 + ang * 2.7) * sin(f * 1.7 - ang * 1.9 + T * 0.15);\n    float seam = smoothstep(0.02, 0.16, abs(ham));\n    emit = 0.10;\n    return mix(vec3(0.06, 0.035, 0.008), vec3(1.0, 0.76, 0.28), seam)\n         * (0.72 + 0.38 * ham);\n  }\n  // 23 static. Per-cell noise re-rolled every frame - the one pattern here that\n  // is meant to look broken rather than designed.\n  float sn = h11(floor(f * 20.0) + floor(ang * 12.0) * 37.0 + floor(T * 14.0) * 91.0);\n  emit = sn * 0.9;\n  return vec3(sn * sn);\n}\n\n// One call for \"what colour is the pipe here, and how much does it glow\".\nvec3 pipeSurface(vec3 p, vec3 n, vec3 rd, out float emit){\n  float id, flow, ang;\n  surfAt(p, id, flow, ang);\n  vec3 base = pipeColour(id);\n  vec3 pat  = pipePattern(p, base, id, flow, ang, n, rd, emit);\n  emit *= uEmit * uPatMix;\n  gEmit = emit;\n  // Most patterns read as paint and want the metalness pulled down; plain,\n  // oil, obsidian, ice and gold are surfaces whose whole point is a reflection.\n  gGloss = (uStyle < 0.5\n         || (uStyle > 5.5  && uStyle < 6.5)\n         || (uStyle > 15.5 && uStyle < 16.5)\n         || (uStyle > 20.5 && uStyle < 22.5)) ? 1.0 : 0.30;\n  return mix(base, pat, uPatMix);\n}\n\nvec3 shadePipe(vec3 p, vec3 n, vec3 rd, vec3 base){\n  // Taken before the interreflection bounce, which runs its own surface query\n  // and would otherwise leave the neighbour's glow in the global.\n  float myEmit = gEmit;\n  // Most patterned pipes are paint, not chrome. Left at full metalness the\n  // studio gradient and the white specular between them put a warm sheen on\n  // every dark pattern, and the furnace style - cold iron with hot bands - came\n  // out uniformly lukewarm tan. Which styles keep their gloss is per-style:\n  // obsidian is black BECAUSE of its reflection, not in spite of it.\n  float mtl  = uMetal * mix(1.0, gGloss, uPatMix);\n  float damp = 1.0 / (1.0 + myEmit * 2.0);\n  vec3  L    = normalize(LIGHTP - p);\n  float ao   = aoAt(p, n);\n  float ndl  = max(dot(n, L), 0.0);\n  // A face turned away from the key gets nothing from the key, so the shadow\n  // ray can only ever confirm what ndl already says. Half the pipe is facing\n  // away at any moment, and this was the single most expensive thing here.\n  float sh   = (uShadow > 0.001 && ndl > 0.001)\n             ? mix(1.0, shadowAt(p + n * 0.01, L), uShadow) : 1.0;\n\n  vec3  H    = normalize(L - rd);\n  float gloss = 2.0 / max(uRough * uRough, 0.0008);\n  float spec = pow(max(dot(n, H), 0.0), gloss) * (gloss + 8.0) * 0.02;\n\n  // The reflection: the room in closed form, plus one bounce off the other\n  // pipes when it is asked for - chrome that only reflects the walls looks like\n  // plastic the moment two pipes cross.\n  vec3  Rf  = reflect(rd, n);\n  vec3  env = envAt(Rf);\n  if (uReflect > 0.001){\n    float t = 0.05, hit = 0.0;\n    for (int i = ZERO; i < 28; i++){\n      float d = mapPipes(p + Rf * t);\n      if (d < 0.004 + t * 0.002){ hit = 1.0; break; }\n      t += d * 0.95;\n      if (t > 13.0) break;\n    }\n    if (hit > 0.5){\n      vec3  q  = p + Rf * t;\n      vec3  qn = normalAt(q);\n      float qe;\n      vec3  qc = pipeSurface(q, qn, Rf, qe);\n      float qd = max(dot(qn, normalize(LIGHTP - q)), 0.0);\n      // The pattern has to reach the reflections too. A pipe that pulses but\n      // whose reflection in its neighbour does not is a decal, not a material.\n      env = mix(env, qc * (0.10 + 0.55 * qd + qe) * 0.85, uReflect);\n    }\n  }\n\n  // Reflection is added on top of a lit body rather than crossfaded with it.\n  // The crossfade version handed 86% of the pixel to a reflection of a very\n  // dark room, and every pipe came out the colour of pond weed.\n  float fres = 0.04 + 0.96 * pow(1.0 - max(dot(n, -rd), 0.0), 5.0);\n  vec3  diff = base * (ndl * sh * uLight * 0.62 + uAmbient * ao * 0.55)\n             * mix(1.0, 0.42, mtl);\n  // A glowing surface stops being a mirror. Without this the studio gradient\n  // lifted every dark pattern - the furnace style came out a uniform lukewarm\n  // tan instead of cold iron with hot bands running through it.\n  vec3  refl = env * mix(vec3(1.0), base, mtl) * mix(0.30, 1.0, fres) * ao\n             * (0.55 + 0.95 * mtl) * damp;\n  vec3  hi   = vec3(1.0, 0.98, 0.94) * spec * sh * uLight\n             * mix(1.0, 0.6, clamp(uRough * 2.0, 0.0, 1.0)) * damp;\n\n  return diff + refl + hi;\n}\n\n// ---- the void --------------------------------------------------------------\n// Below the lattice is a black polished floor, and it is a real mirror: the\n// reflection is a second march, not a trick. The air above it is not empty\n// either - a shaft of light comes down through the network, and the network\n// stands in its own shadow inside it.\n#define FLOORY (-(GRID - 1.0) * 0.5 - 0.5)\n\n// A reflection does not need a reflection of its own. This is shadePipe minus\n// the interreflection bounce, the AO taps and the shadow ray - three of the\n// four expensive things - and at one bounce nobody can tell.\nvec3 shadeCheap(vec3 p, vec3 n, vec3 rd, vec3 base){\n  vec3  L   = normalize(LIGHTP - p);\n  float ndl = max(dot(n, L), 0.0);\n  vec3  Rf  = reflect(rd, n);\n  vec3  env = envAt(Rf);\n  float fres = 0.04 + 0.96 * pow(1.0 - max(dot(n, -rd), 0.0), 5.0);\n  float mtl  = uMetal * mix(1.0, gGloss, uPatMix);\n  return base * (ndl * uLight * 0.55 + uAmbient * 0.50) * mix(1.0, 0.42, mtl)\n       + env * mix(vec3(1.0), base, mtl) * mix(0.30, 1.0, fres)\n             * (0.55 + 0.95 * mtl) / (1.0 + gEmit * 2.0);\n}\n\nvec3 shadeFloor(vec3 p, vec3 rd){\n  vec3 n = vec3(0.0, 1.0, 0.0);\n  vec3 col = vec3(0.0);\n\n  if (uMirror > 0.001){\n    vec3  Rf = reflect(rd, n);\n    float t = 0.05, hit = 0.0;\n    for (int i = ZERO; i < 34; i++){\n      float d = mapPipes(p + Rf * t);\n      if (d < 0.004 + t * 0.003){ hit = 1.0; break; }\n      t += d * 0.99;\n      if (t > 20.0) break;\n    }\n    if (hit > 0.5){\n      vec3 q = p + Rf * t;\n      // Grazing angles mirror hardest and distance eats the rest. A floor that\n      // reflects perfectly at every angle and every range is not a floor, it is\n      // a hole with a copy of the scene in it.\n      float fres = 0.06 + 0.94 * pow(1.0 - max(-dot(rd, n), 0.0), 4.0);\n      vec3  qn = normalAt(q);\n      float qe;\n      vec3  qb = pipeSurface(q, qn, Rf, qe);\n      col += (shadeCheap(q, qn, Rf, qb) + qb * qe)\n           * uMirror * mix(0.26, 1.0, fres) * exp(-t * 0.075);\n    }\n  }\n\n  float sh = uShadow > 0.001\n           ? mix(1.0, shadowAt(p + n * 0.03, normalize(LIGHTP - p)), uShadow) : 1.0;\n  col += vec3(0.055, 0.058, 0.070) * uLight * sh * exp(-dot(p.xz, p.xz) * 0.016);\n  return col * uFloor * exp(-dot(p.xz, p.xz) * 0.0040);   // the horizon dissolves\n}\n\n// The advancing tip, and the joints that have just landed. Only possible\n// because the run is a closed form: the shader knows not just where every joint\n// is but exactly how long ago it was placed: the stream index of a corner and\n// the current head are the same quantity, so the difference is its age.\nvec3 tipGlow(vec3 ro, vec3 rd, float tHit){\n  if (uTipGlow < 0.001) return vec3(0.0);\n  vec3 g = vec3(0.0);\n  for (int i = ZERO; i < NSEG; i++){\n    float gi = gG0 + float(i);                    // not g: that is the glow\n    if (gi >= gHead) break;\n    float age = gHead - gi;\n    if (age > 2.2) continue;                      // only the freshest few\n    vec3  P  = posOf(gPts[i]);\n    vec3  c  = mix(pipeColour(pipeAtG(gi)), vec3(1.0), 0.55);\n\n    float tp = max(dot(P - ro, rd), 0.0);\n    float dj = length(ro + rd * tp - P);\n    if (tp < tHit + 0.4)\n      g += c * exp(-age * 2.4)\n             * (exp(-dj * dj * 22.0) * 0.55 + 0.05 / (1.0 + dj * dj * 70.0));\n\n    if (age < 1.0){                               // this one is still moving\n      if (endsAt(gi) < 0.5){\n        vec3  T  = mix(P, posOf(gPts[i + 1]), age);\n        float tq = max(dot(T - ro, rd), 0.0);\n        float dt = length(ro + rd * tq - T);\n        if (tq < tHit + 0.4)\n          g += c * (exp(-dt * dt * 26.0) * 0.80 + 0.06 / (1.0 + dt * dt * 80.0));\n      }\n    }\n  }\n  return g * uTipGlow;\n}\n\nvoid main(){\n  vec2 fragCoord = gl_FragCoord.xy;\n  vec2 R  = RENDERSIZE.xy;\n  vec2 uv = (fragCoord - 0.5 * R) / R.y;\n\n  // No runs and no fade: the stream just keeps going. The head lays corners\n  // down at a steady rate and the tail eats them uCount corners later, so old\n  // pipes are being taken apart at the same time as new ones are being drawn.\n  //\n  // The window starts at a pipe boundary rather than exactly at the tail, so\n  // the array always begins where some pipe began - which is what lets the walk\n  // be regenerated from a pipe's own seed instead of from the beginning of\n  // time. That costs up to gRun spare slots, so uCount + uRun must fit in NSEG.\n  gRun   = max(floor(uRun), 4.0);\n  float alive = min(uCount, float(NSEG) - gRun);\n  gHead  = TIME * uSpeed * 1.6;\n  gTail  = max(gHead - alive, 0.0);\n  gG0    = floor(gTail / gRun) * gRun;\n\n  buildPath();\n\n  float ang = TIME * uOrbit * 0.35 + 0.9;\n  vec3  ro  = vec3(sin(ang), 0.0, cos(ang)) * uDist\n            + vec3(0.0, uHeight + 0.35 * sin(TIME * 0.11), 0.0);\n  // Never let the camera get under its own floor: height can be dragged to the\n  // floor level and the bob would take it through.\n  if (uFloor > 0.001) ro.y = max(ro.y, FLOORY + 0.45);\n  vec3 ta = vec3(0.0, 0.2 * sin(TIME * 0.07), 0.0);\n  vec3 ww = normalize(ta - ro), uu = normalize(cross(ww, vec3(0.0, 1.0, 0.0)));\n  vec3 vv = cross(uu, ww);\n  vec3 rd = normalize(uv.x * uu + uv.y * vv + uFov * ww);\n\n  // Nothing to hit but the pipes and the floor; a ray that misses both runs\n  // out to a far clip and comes back black.\n  float tRoom  = 60.0;\n  float tFloor = 1e9;\n  if (uFloor > 0.001 && rd.y < -1e-4){\n    float tf = (FLOORY - ro.y) / rd.y;\n    if (tf > 0.02) tFloor = tf;\n  }\n  float tBack = min(tRoom, tFloor);\n\n  float t = 0.02, hit = 0.0;\n  for (int i = ZERO; i < 96; i++){\n    float d = mapPipes(ro + rd * t);\n    // The scene is a plain union of exact primitives, so the distance is a\n    // true bound and the march does not need to be talked down from it.\n    if (d < 0.0018 + t * 0.0013){ hit = 1.0; break; }\n    t += d * 0.99;\n    if (t > tBack) break;\n  }\n\n  vec3 col;\n  if (hit > 0.5){\n    vec3  p = ro + rd * t;\n    vec3  nn = normalAt(p);\n    float em;\n    vec3  b = pipeSurface(p, nn, rd, em);\n    col = shadePipe(p, nn, rd, b) + b * em;\n  } else if (tFloor < tRoom){\n    t   = tFloor;                       // the march overshot; the glows need it\n    col = shadeFloor(ro + rd * tFloor, rd);\n  } else {\n    t   = tRoom;\n    col = vec3(0.0);                    // black, and there is no knob for it\n  }\n\n  // Everything from here is added in front of whatever was hit: the cage is a\n  // hologram, the tip is a bloom, and the air is between you and both.\n  col += tipGlow(ro, rd, t);\n\n  col *= uExposure;\n  col  = col / (1.0 + col * 0.72);                       // tonemap\n  col  = pow(max(col, 0.0), vec3(0.4545));\n  col *= 1.0 - uVignette * dot(uv, uv) * 0.85;\n  col += (h11(fragCoord.x * 1.7 + fragCoord.y * 91.3 + TIME * 60.0) - 0.5)\n       * uGrain * 0.12;\n\n  gl_FragColor = vec4(clamp(col, 0.0, 1.0), 1.0);\n}\n",
    "generator": {
      "model": "Claude-Opus-5",
      "provider": null,
      "prompt": null,
      "params": null
    }
  }
}