{
  "license": "CC0-1.0",
  "shader": {
    "id": "zhf2v4um",
    "title": "mothcore",
    "license": "CC0-1.0",
    "provenance_type": "witnessed_generation",
    "made_with": "glslop",
    "status": "active",
    "compile_ok": true,
    "render_hash": "000000dfff7f5f6f",
    "tags": [
      "peaceful",
      "night"
    ],
    "parents": [],
    "author": "pt1fjuktt2w0",
    "author_name": "deafadil",
    "author_url": "/u/deafadil",
    "created_at": "2026-09-10T02:40:03.970Z",
    "poster_url": "/posters/zhf2v4um.avif",
    "stats": {
      "slops": 1,
      "views": 122,
      "forks": 0
    },
    "self": "/api/v1/shaders/zhf2v4um",
    "isf": "/*{\n  \"DESCRIPTION\": \"THE ROAD AT NIGHT. A straight two-lane road through an empty grass field, sparse sodium streetlights, and around every lamp a swarm of several thousand moths. The swarm is the point, and it is not a particle system: a fragment shader has no particle list, it has a ray and a hash, so the moths ARE a three-dimensional LATTICE filling the volume around the lamp - one moth per cell - and the swarming is a FLOW FIELD applied to that lattice. To find which moth is at a sample point, the point is pushed BACKWARD through the flow and the lattice is read where it lands. Every moth in the volume is therefore carried coherently by the same vortex, for the cost of one inverse rotation per sample, and the population is set by the CELL SIZE rather than by any loop bound - which is the whole reason the count can be five thousand per lamp instead of the dozen a splat loop would afford. The flow has to be exactly invertible for this to be legal, so it is built only from operations that preserve the radius it is parameterised by: a rotation about the lamp's vertical axis whose rate is a function of that radius, and a vertical circulation that does not touch it. The rate falls with radius, so the inner moths lap the outer ones and the swarm SHEARS rather than turning like a plate, which is the difference between a swarm and a carousel. Once a moth is found in lattice space it is pushed FORWARD again into the world, so that it can be splatted against the true perpendicular distance from the ray - the along-ray separation is thrown away, because the extent of a blob along the view direction is invisible, and keeping it would force the march step down to the size of a moth and cost eighty samples where twenty-six will do. A moth smaller than a pixel widens to the pixel and DIMS by the ratio of the areas, so a distant swarm resolves to a haze around the lamp instead of aliasing into crawling sparkle. The grass is a marched height field, stepped by vertical clearance divided by the ray's descent rate rather than by a fixed increment, because a ray aimed at the horizon has to cross two hundred metres and a ray aimed at the verge has to resolve a leaf. Its detail is band-limited by distance from the camera - the blade octaves fade out with range while the mean height does not - so the marcher can never step over a blade it could not have resolved in the first place, which is the cheap way to buy an anti-aliased silhouette. The lamps are a z-repeated distance field with a bounding-box short circuit, and BOTH nearest periods are tested rather than one, because the alternating-sides mode puts consecutive lamps on opposite kerbs and the nearest lamp on the far side is then never the nearest period. Their light is a cobra-head distribution - a downward-weighted lobe rather than a point - gathered over the six nearest fittings, so the pools on the tarmac overlap the way real ones do and the gaps between them go properly black. The sky is a night gradient with a warm town glow sitting on the horizon, stars occluded by a domain-warped cloud layer whose coverage is a threshold rather than a fade, so the clouds have EDGES the way painted clouds do; wires between the utility poles are drawn analytically as closest-approach to a segment, because a three-millimetre catenary in a distance field is a hundred wasted steps. The grade is cel-banded and palette-driven - four anime night palettes - and the whole thing is aimed at one particular shot: a dark, empty road, lit at intervals, with somebody walking down it. Forty controls: walk, lens, yaw and pitch, position across the road, eye height, sway, road width, shoulder, markings, wear, grass length, patchiness, wind, lamp spacing, WHICH SIDES the lamps stand on, lamp height, brightness, colour temperature, dead lamps, light cone, MOTH COUNT, swarm radius, swarm spin, moth size, CLOUD COVER, cloud drift, stars, moon, town glow, utility poles, wires, treeline, four palettes, fog, cel banding, bloom, grain, vignette and contrast.\",\n  \"CREDIT\": \"CC0. Original. Value noise constants after Dave Hoskins.\",\n  \"CATEGORIES\": [\"generator\", \"raymarch\", \"night\", \"road\", \"anime\", \"moths\", \"swarm\", \"particles\", \"procedural\", \"3d\"],\n  \"INPUTS\": [\n    { \"NAME\": \"uSpeed\",     \"TYPE\": \"float\", \"DEFAULT\": 1.10,  \"MIN\": 0.0,   \"MAX\": 6.0 },\n    { \"NAME\": \"uLens\",      \"TYPE\": \"float\", \"DEFAULT\": 1.35,  \"MIN\": 0.7,   \"MAX\": 3.0 },\n    { \"NAME\": \"uYaw\",       \"TYPE\": \"float\", \"DEFAULT\": 0.0,   \"MIN\": -1.57, \"MAX\": 1.57 },\n    { \"NAME\": \"uPitch\",     \"TYPE\": \"float\", \"DEFAULT\": 0.02,  \"MIN\": -0.5,  \"MAX\": 0.5 },\n    { \"NAME\": \"uCamX\",      \"TYPE\": \"float\", \"DEFAULT\": 1.30,  \"MIN\": -6.0,  \"MAX\": 6.0 },\n    { \"NAME\": \"uCamY\",      \"TYPE\": \"float\", \"DEFAULT\": 1.55,  \"MIN\": 0.30,  \"MAX\": 4.0 },\n    { \"NAME\": \"uBob\",       \"TYPE\": \"float\", \"DEFAULT\": 1.0,   \"MIN\": 0.0,   \"MAX\": 2.0 },\n    { \"NAME\": \"uRoadW\",     \"TYPE\": \"float\", \"DEFAULT\": 3.10,  \"MIN\": 1.6,   \"MAX\": 7.0 },\n    { \"NAME\": \"uShoulder\",  \"TYPE\": \"float\", \"DEFAULT\": 0.75,  \"MIN\": 0.10,  \"MAX\": 2.5 },\n    { \"NAME\": \"uMarks\",     \"TYPE\": \"float\", \"DEFAULT\": 0.85,  \"MIN\": 0.0,   \"MAX\": 1.0 },\n    { \"NAME\": \"uWear\",      \"TYPE\": \"float\", \"DEFAULT\": 0.45,  \"MIN\": 0.0,   \"MAX\": 1.0 },\n    { \"NAME\": \"uGrass\",     \"TYPE\": \"float\", \"DEFAULT\": 0.34,  \"MIN\": 0.0,   \"MAX\": 1.30 },\n    { \"NAME\": \"uPatch\",     \"TYPE\": \"float\", \"DEFAULT\": 0.60,  \"MIN\": 0.0,   \"MAX\": 1.0 },\n    { \"NAME\": \"uWind\",      \"TYPE\": \"float\", \"DEFAULT\": 0.70,  \"MIN\": 0.0,   \"MAX\": 2.0 },\n    { \"NAME\": \"uSpacing\",   \"TYPE\": \"float\", \"DEFAULT\": 34.0,  \"MIN\": 10.0,  \"MAX\": 90.0 },\n    { \"NAME\": \"uSide\",      \"TYPE\": \"float\", \"DEFAULT\": 1.0,   \"MIN\": 0.0,   \"MAX\": 3.0 },\n    { \"NAME\": \"uLampH\",     \"TYPE\": \"float\", \"DEFAULT\": 8.20,  \"MIN\": 3.5,   \"MAX\": 13.0 },\n    { \"NAME\": \"uBright\",    \"TYPE\": \"float\", \"DEFAULT\": 1.45,  \"MIN\": 0.0,   \"MAX\": 3.0 },\n    { \"NAME\": \"uTemp\",      \"TYPE\": \"float\", \"DEFAULT\": 2150.0,\"MIN\": 1700.0,\"MAX\": 5200.0 },\n    { \"NAME\": \"uLampOut\",   \"TYPE\": \"float\", \"DEFAULT\": 0.12,  \"MIN\": 0.0,   \"MAX\": 1.0 },\n    { \"NAME\": \"uCone\",      \"TYPE\": \"float\", \"DEFAULT\": 0.85,  \"MIN\": 0.0,   \"MAX\": 2.5 },\n    { \"NAME\": \"uMothN\",     \"TYPE\": \"float\", \"DEFAULT\": 0.55,  \"MIN\": 0.0,   \"MAX\": 1.0 },\n    { \"NAME\": \"uSwarmR\",    \"TYPE\": \"float\", \"DEFAULT\": 1.15,  \"MIN\": 0.30,  \"MAX\": 3.5 },\n    { \"NAME\": \"uSpin\",      \"TYPE\": \"float\", \"DEFAULT\": 1.0,   \"MIN\": 0.0,   \"MAX\": 3.0 },\n    { \"NAME\": \"uMothSize\",  \"TYPE\": \"float\", \"DEFAULT\": 0.034, \"MIN\": 0.010, \"MAX\": 0.090 },\n    { \"NAME\": \"uClouds\",    \"TYPE\": \"float\", \"DEFAULT\": 0.45,  \"MIN\": 0.0,   \"MAX\": 1.0 },\n    { \"NAME\": \"uCloudSpd\",  \"TYPE\": \"float\", \"DEFAULT\": 0.60,  \"MIN\": 0.0,   \"MAX\": 3.0 },\n    { \"NAME\": \"uStars\",     \"TYPE\": \"float\", \"DEFAULT\": 0.70,  \"MIN\": 0.0,   \"MAX\": 1.0 },\n    { \"NAME\": \"uMoon\",      \"TYPE\": \"float\", \"DEFAULT\": 0.35,  \"MIN\": 0.0,   \"MAX\": 1.0 },\n    { \"NAME\": \"uTown\",      \"TYPE\": \"float\", \"DEFAULT\": 0.50,  \"MIN\": 0.0,   \"MAX\": 1.0 },\n    { \"NAME\": \"uPoles\",     \"TYPE\": \"float\", \"DEFAULT\": 0.85,  \"MIN\": 0.0,   \"MAX\": 1.0 },\n    { \"NAME\": \"uWires\",     \"TYPE\": \"float\", \"DEFAULT\": 0.90,  \"MIN\": 0.0,   \"MAX\": 1.0 },\n    { \"NAME\": \"uTrees\",     \"TYPE\": \"float\", \"DEFAULT\": 0.70,  \"MIN\": 0.0,   \"MAX\": 1.0 },\n    { \"NAME\": \"uPalette\",   \"TYPE\": \"float\", \"DEFAULT\": 0.0,   \"MIN\": 0.0,   \"MAX\": 3.0 },\n    { \"NAME\": \"uFog\",       \"TYPE\": \"float\", \"DEFAULT\": 0.014, \"MIN\": 0.0,   \"MAX\": 0.070 },\n    { \"NAME\": \"uCel\",       \"TYPE\": \"float\", \"DEFAULT\": 0.45,  \"MIN\": 0.0,   \"MAX\": 1.0 },\n    { \"NAME\": \"uBloom\",     \"TYPE\": \"float\", \"DEFAULT\": 1.0,   \"MIN\": 0.0,   \"MAX\": 2.5 },\n    { \"NAME\": \"uGrain\",     \"TYPE\": \"float\", \"DEFAULT\": 0.35,  \"MIN\": 0.0,   \"MAX\": 1.0 },\n    { \"NAME\": \"uVignette\",  \"TYPE\": \"float\", \"DEFAULT\": 0.40,  \"MIN\": 0.0,   \"MAX\": 1.0 },\n    { \"NAME\": \"uContrast\",  \"TYPE\": \"float\", \"DEFAULT\": 0.80,  \"MIN\": 0.0,   \"MAX\": 1.5 }\n  ]\n}*/\n\n// THE ROAD AT NIGHT - ISF / GLSL ES 1.00 (gl_FragColor, TIME, RENDERSIZE).\n//\n// uSide: 0 = left kerb, 1 = right kerb, 2 = both, 3 = alternating.\n// uPalette: 0 = prussian night, 1 = deep cyan, 2 = mercury green, 3 = violet dusk.\n\n#define PI  3.14159265359\n#define FAR 200.0\n\nfloat gRoadH;      // road half width\nfloat gShoW;       // shoulder width\nfloat gSpc;        // lamp spacing\nfloat gLampB;      // |x| of the lamp bases\nfloat gPoleB;      // |x| of the utility poles\nfloat gPoleS;      // utility pole spacing\nfloat gLampH;\nfloat gPX;         // world size of one pixel at unit distance\nfloat gT;          // clock\nvec2  gCam;        // camera plan position, for the grass level of detail\n\nvec3 gLamp;        // lamp colour\nvec3 pZen, pHor, pTown, pGrassA, pGrassB, pRoad, pLine, pCloud, pMoon;\n\n// ---------------------------------------------------------------\n// hashes and value noise (Dave Hoskins' constants)\n// ---------------------------------------------------------------\nfloat hash11(float p){ p = fract(p*0.1031); p *= p + 33.33; p *= p + p; return fract(p); }\n\nfloat hash12(vec2 p){\n    vec3 q = fract(vec3(p.xyx)*0.1031);\n    q += dot(q, q.yzx + 33.33);\n    return fract((q.x + q.y)*q.z);\n}\n\nvec2 hash22(vec2 p){\n    vec3 q = fract(vec3(p.xyx)*vec3(0.1031, 0.1030, 0.0973));\n    q += dot(q, q.yzx + 33.33);\n    return fract((q.xx + q.yz)*q.zy);\n}\n\n// The swarm lives on a 3D lattice, so the moth hash has to be three-dimensional\n// and it has to be good: a weak 3D hash puts visible planes through the swarm,\n// and a swarm with planes in it reads as a texture rather than as insects.\nvec4 hash43(vec3 p){\n    vec4 q = fract(vec4(p.xyzx)*vec4(0.1031, 0.1030, 0.0973, 0.1099));\n    q += dot(q, q.wzxy + 33.33);\n    return fract((q.xxyz + q.yzzw)*q.zywx);\n}\n\nfloat vnoise(vec2 p){\n    vec2 i = floor(p), f = fract(p);\n    f = f*f*(3.0 - 2.0*f);\n    return mix(mix(hash12(i), hash12(i + vec2(1.0, 0.0)), f.x),\n               mix(hash12(i + vec2(0.0, 1.0)), hash12(i + vec2(1.0, 1.0)), f.x), f.y);\n}\n\n// Every octave rotated as well as scaled. Value noise has axis-aligned\n// iso-contours, and unrotated octaves stack their cell edges into a quilt that\n// is perfectly obvious on a flat field seen at a grazing angle.\nfloat fbm(vec2 p, int oct){\n    mat2 R = mat2(0.8040, 0.5946, -0.5946, 0.8040);\n    float s = 0.0, a = 0.5;\n    for (int i = 0; i < 6; i++){\n        if (i >= oct) break;\n        s += a*vnoise(p);\n        p = R*p*2.03 + 17.7;\n        a *= 0.5;\n    }\n    return s;\n}\n\n// ---------------------------------------------------------------\n// blackbody, for the lamps\n// ---------------------------------------------------------------\n// Normalised by its own maximum channel and then pulled back to a fixed\n// luminance, so the temperature slider changes the COLOUR of the sodium and\n// not the exposure of the scene.\nvec3 kelvin(float k){\n    k = clamp(k, 1000.0, 15000.0)*0.01;\n    float r, g, b;\n    if (k <= 66.0){\n        r = 1.0;\n        g = clamp(0.39008158*log(max(k, 1.0)) - 0.63184144, 0.0, 1.0);\n    } else {\n        r = clamp(1.29293619*pow(max(k - 60.0, 0.001), -0.1332047), 0.0, 1.0);\n        g = clamp(1.12989086*pow(max(k - 60.0, 0.001), -0.0755148), 0.0, 1.0);\n    }\n    if (k >= 66.0)      b = 1.0;\n    else if (k <= 19.0) b = 0.0;\n    else                b = clamp(0.54320679*log(max(k - 10.0, 1.0)) - 1.19625408, 0.0, 1.0);\n    vec3 c = vec3(r, g, b)/max(max(r, g), max(b, 1e-3));\n    return c*(0.92/max(dot(c, vec3(0.299, 0.587, 0.114)), 1e-3));\n}\n\nvec3 pick4(vec3 a, vec3 b, vec3 c, vec3 d, float f){\n    float i = clamp(f, 0.0, 3.0);\n    float n = floor(i), k = i - n;\n    vec3 lo = a;\n    lo = mix(lo, b, step(0.5, n)); lo = mix(lo, c, step(1.5, n)); lo = mix(lo, d, step(2.5, n));\n    vec3 hi = b;\n    hi = mix(hi, c, step(0.5, n)); hi = mix(hi, d, step(1.5, n));\n    return mix(lo, hi, k);\n}\n\n// Coverage of the band |x| < r by a pixel w wide. A road line is 12 cm across\n// and a lamp pole is 17 cm; both are under a pixel long before they are out of\n// frame, and a hard test keeps drawing them at full strength wherever they\n// happen to land, which crawls.\nfloat band(float x, float r, float w){\n    float h = 0.5*max(w, 1e-5);\n    return clamp((min(x + h, r) - max(x - h, -r))/(2.0*h), 0.0, 1.0);\n}\n\n// CEL SHADING, but band-limited. Quantising light into steps is what makes a\n// painted frame read as painted; doing it with a bare floor() puts a hard\n// contour across every smooth gradient, and those contours alias horribly once\n// the camera moves. So the step edge is softened by the local derivative of the\n// value itself, which is a one-line approximation to filtering the banding.\nfloat cel(float x, float steps, float soft){\n    float s = max(steps, 1.0);\n    float g = x*s;\n    float f = fract(g);\n    float w = clamp(soft, 0.02, 0.9);\n    return (floor(g) + smoothstep(0.5 - w, 0.5 + w, f))/s;\n}\n\n// ---------------------------------------------------------------\n// primitives\n// ---------------------------------------------------------------\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)/dot(ba, ba), 0.0, 1.0);\n    return length(pa - ba*h) - r;\n}\n\nfloat sdBox3(vec3 p, vec3 b){\n    vec3 q = abs(p) - b;\n    return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);\n}\n\nfloat sdRoundBox(vec3 p, vec3 b, float r){ return sdBox3(p, b) - r; }\n\n// Closest approach between a ray and a segment, in closed form. Returns the\n// separation; `t` comes back as the distance along the ray, so the result can\n// be depth-tested against whatever the ray actually hit.\nfloat raySeg(vec3 ro, vec3 rd, vec3 a, vec3 b, out float t){\n    vec3 ba = b - a, w0 = ro - a;\n    float C = dot(ba, ba);\n    float B = dot(rd, ba);\n    float D = dot(rd, w0);\n    float E = dot(ba, w0);\n    float den = C - B*B;\n    float s = clamp((E - B*D)/max(den, 1e-6), 0.0, 1.0);\n    vec3 q = a + ba*s;\n    t = max(dot(q - ro, rd), 0.0);\n    return length(q - (ro + rd*t));\n}\n\n// ---------------------------------------------------------------\n// the ground\n// ---------------------------------------------------------------\n// A travelling shear rather than a scroll: grass does not slide, it leans, and\n// the lean has to run across the field as a gust or the whole verge breathes\n// in unison like a lung.\nvec2 windOff(vec2 p){\n    float a = sin(p.x*0.26 + p.y*0.17 - gT*0.85) + 0.7*sin(p.y*0.43 + gT*0.61)\n            + 0.4*sin(p.x*0.9 - p.y*0.6 + gT*1.9);\n    return vec2(a, a*0.55)*0.055*uWind;\n}\n\n// THE LEVEL OF DETAIL IS NOT COSMETIC. The blade octaves are faded out with\n// distance from the camera while the mean height is kept, so a ray forty\n// metres out is marching a smooth field and cannot step over a blade it could\n// never have resolved. Leave the detail in and the march either misses grass\n// and shows holes, or costs four times as many steps to stop missing it.\nfloat grassHeight(vec2 p){\n    float d = distance(p, gCam);\n    float fb = exp(-d*0.115);\n    float ft = exp(-d*0.011);\n\n    vec2 q = p + windOff(p);\n    float tuft  = fbm(q*0.55, 3);\n    float blade = vnoise(q*21.0)*0.62 + vnoise(q*52.0 + 7.3)*0.38;\n    float patch = mix(1.0, 0.30 + 1.25*fbm(p*0.105, 2), uPatch);\n    return uGrass*patch*(0.34 + 0.66*mix(0.5, tuft, ft))*mix(0.55, blade, fb);\n}\n\n// 0 on the carriageway, 1 out in the field, with the gravel shoulder between\nfloat grassMask(float x){\n    float a = abs(x);\n    return smoothstep(gRoadH + 0.05, gRoadH + gShoW, a);\n}\n\nfloat terrainH(vec2 p){\n    float a = abs(p.x);\n    // The camber. A road is crowned so it drains, and the crown is the reason\n    // the lamp pools on the near lane are brighter than on the far one.\n    float camber = 0.045*(1.0 - clamp(a/(gRoadH + gShoW), 0.0, 1.0));\n    return camber + grassMask(p.x)*grassHeight(p);\n}\n\nvec3 terrainN(vec2 p, float e){\n    e = max(e, 0.006);\n    float h  = terrainH(p);\n    float hx = terrainH(p + vec2(e, 0.0));\n    float hz = terrainH(p + vec2(0.0, e));\n    return normalize(vec3(h - hx, e, h - hz));\n}\n\n// ---------------------------------------------------------------\n// the lamps\n// ---------------------------------------------------------------\n// Which kerbs carry a fitting at this index. Slot 0 and slot 1; a slot returns\n// 0 when it is empty, otherwise the sign of the side it stands on.\nfloat lampSlot(float zi, float k){\n    float m = floor(uSide + 0.5);\n    if (m < 0.5)      return (k < 0.5) ? -1.0 : 0.0;    // left kerb only\n    else if (m < 1.5) return (k < 0.5) ?  1.0 : 0.0;    // right kerb only\n    else if (m < 2.5) return (k < 0.5) ? -1.0 : 1.0;    // both\n    float s = (mod(zi, 2.0) < 0.5) ? -1.0 : 1.0;        // alternating\n    return (k < 0.5) ? s : 0.0;\n}\n\nfloat poleSide(){ return (floor(uSide + 0.5) < 0.5) ? 1.0 : -1.0; }\n\n// where the light actually comes from: under the cobra head, out over the road\nvec3 lampPos(float zi, float s){\n    return vec3(s*(gLampB - 2.02), gLampH - 0.05, zi*gSpc);\n}\n\n// Dead lamps, and the handful that are on the way out. A flat \"some are off\"\n// is worth having on its own; the ones caught mid-failure, strobing at a few\n// hertz, are worth more than all the rest of the lighting model put together.\nfloat lampLive(float zi, float s){\n    float h = hash12(vec2(zi, s*7.3 + 2.1));\n    float on = step(uLampOut, h);\n    float dying = step(h, uLampOut + 0.09);\n    float f = 1.0 - dying*0.75*smoothstep(0.30, 0.95, 0.5 + 0.5*sin(gT*(2.7 + 11.0*h) + h*40.0));\n    return on*f;\n}\n\n// The fitting, in local coordinates: +x reaches in over the carriageway, y is\n// up, z runs along the kerb.\nfloat lampBody(vec3 q){\n    float H = gLampH;\n    // A bounding box that short-circuits the assembly. Without it every march\n    // step pays for five capsules and a rounded box, and the lamp march\n    // becomes the most expensive thing in the frame by a factor of four.\n    float b = sdBox3(q - vec3(1.05, H*0.5, 0.0), vec3(1.30, H*0.5 + 0.42, 0.26));\n    if (b > 0.26) return b;\n\n    float d = sdCapsule(q, vec3(0.0, 0.0, 0.0), vec3(0.0, H - 0.75, 0.0), 0.086);\n    d = min(d, sdCapsule(q, vec3(0.0, 0.0, 0.0), vec3(0.0, 0.42, 0.0), 0.125));\n    d = min(d, sdCapsule(q, vec3(0.0, H - 0.75, 0.0), vec3(0.44, H - 0.03, 0.0), 0.074));\n    d = min(d, sdCapsule(q, vec3(0.44, H - 0.03, 0.0), vec3(1.60, H + 0.10, 0.0), 0.064));\n    d = min(d, sdRoundBox(q - vec3(2.00, H + 0.015, 0.0), vec3(0.26, 0.040, 0.090), 0.082));\n    return d;\n}\n\nfloat poleBody(vec3 q){\n    float H = gLampH*1.22;\n    float b = sdBox3(q - vec3(0.0, H*0.5, 0.0), vec3(1.00, H*0.5 + 0.55, 0.24));\n    if (b > 0.26) return b;\n\n    float d = sdCapsule(q, vec3(0.0, 0.0, 0.0), vec3(0.05, H, 0.0), 0.100);\n    d = min(d, sdCapsule(q, vec3(-0.88, H - 0.55, 0.0), vec3(0.88, H - 0.55, 0.0), 0.044));\n    d = min(d, sdCapsule(q, vec3(-0.58, H - 1.42, 0.0), vec3(0.58, H - 1.42, 0.0), 0.038));\n    d = min(d, sdRoundBox(q - vec3(0.24, H - 2.55, 0.0), vec3(0.075, 0.24, 0.075), 0.085));\n    return d;\n}\n\n// Everything standing up out of the ground, as one field.\n//\n// BOTH nearest periods are tested, not one. Folding to the single nearest\n// period is exact when every period is identical - but in the alternating mode\n// consecutive lamps stand on opposite kerbs, so the nearest fitting on the far\n// side is never in the nearest period, and a march that only looks at one\n// walks straight through it.\nfloat structures(vec3 p){\n    float d = 1e6;\n\n    float zi = floor(p.z/gSpc + 0.5);\n    float zs = (p.z - zi*gSpc >= 0.0) ? 1.0 : -1.0;\n    for (int n = 0; n < 2; n++){\n        float zz = zi + float(n)*zs;\n        float zl = p.z - zz*gSpc;\n        for (int k = 0; k < 2; k++){\n            float s = lampSlot(zz, float(k));\n            if (abs(s) > 0.5) d = min(d, lampBody(vec3(-s*p.x + gLampB, p.y, zl)));\n        }\n    }\n\n    if (uPoles > 0.02){\n        float ps = poleSide();\n        float pb = floor((p.z - gPoleS*0.5)/gPoleS + 0.5);\n        float ss = (p.z - gPoleS*0.5 - pb*gPoleS >= 0.0) ? 1.0 : -1.0;\n        for (int n = 0; n < 2; n++){\n            float pz = (pb + float(n)*ss)*gPoleS + gPoleS*0.5;\n            d = min(d, poleBody(vec3(-ps*p.x + gPoleB, p.y, p.z - pz)));\n        }\n    }\n    return d;\n}\n\nvec3 structN(vec3 p){\n    vec2 e = vec2(1.0, -1.0)*0.0025;\n    return normalize(e.xyy*structures(p + e.xyy) + e.yyx*structures(p + e.yyx)\n                   + e.yxy*structures(p + e.yxy) + e.xxx*structures(p + e.xxx));\n}\n\n// ---------------------------------------------------------------\n// the sky\n// ---------------------------------------------------------------\nfloat starField(vec3 rd){\n    if (uStars < 0.01 || rd.y < 0.0) return 0.0;\n    vec2 s = vec2(atan(rd.z, rd.x)*3.0, acos(clamp(rd.y, -1.0, 1.0))*6.0)*11.0;\n    vec2 id = floor(s), f = fract(s);\n    vec2 h = hash22(id + 4.7);\n    float d = length(f - (0.2 + 0.6*h));\n    float mag = hash12(id*1.7 + 9.3);\n    float pt = smoothstep(0.13, 0.0, d)*step(0.865, mag);\n    // Scintillation, not a sine: a star twinkles because the column of air in\n    // front of it is turbulent, so the rate has to differ per star or the whole\n    // sky pulses together like a string of fairy lights.\n    float tw = 0.35 + 0.65*(0.5 + 0.5*sin(gT*(1.3 + 5.0*h.x) + h.y*63.0));\n    return pt*tw*(0.45 + 0.75*(mag - 0.865)*7.0);\n}\n\n// A THRESHOLD, not a fade. Painted clouds have edges; a raw fbm ramp reads as\n// fog, and no amount of contrast afterwards puts the edge back in. The warp is\n// what stops the threshold from looking like a contour map of noise.\nfloat cloudField(vec3 rd){\n    if (uClouds < 0.01 || rd.y < 0.004) return 0.0;\n    vec2 p = rd.xz*(1.0/max(rd.y, 0.020))*0.0135 + vec2(gT*uCloudSpd*0.012, gT*uCloudSpd*0.004);\n    vec2 w = vec2(fbm(p*0.75 + 1.3, 3), fbm(p*0.75 + 5.1, 3));\n    float f = fbm(p + w*1.25, 4);\n    float cov = mix(0.74, 0.235, clamp(uClouds, 0.0, 1.0));\n    float c = smoothstep(cov, cov + 0.155, f);\n    // fade the layer out at the horizon, where a plane projection goes singular\n    return c*smoothstep(0.004, 0.075, rd.y);\n}\n\nvec3 skyCol(vec3 rd, float px){\n    float up = clamp(rd.y, 0.0, 1.0);\n    vec3 c = mix(pHor, pZen, pow(up, 0.52));\n\n    // The town over the hill. This is most of what separates a night sky near\n    // people from deep space, and it is the one warm thing in the frame that\n    // is not a lamp.\n    float hz = exp(-up*9.0);\n    float az = 0.55 + 0.45*smoothstep(-0.5, 1.0, rd.z);\n    c += pTown*hz*az*uTown*0.85;\n\n    // the moon, low and small, with the haze it drags around itself\n    if (uMoon > 0.01){\n        vec3 md = normalize(vec3(-0.42, 0.30, 0.86));\n        float ca = dot(rd, md);\n        c += pMoon*uMoon*(0.55*pow(max(ca, 0.0), 900.0) + 0.10*pow(max(ca, 0.0), 14.0));\n    }\n\n    float cl = cloudField(rd);\n    c += vec3(0.80, 0.86, 1.00)*starField(rd)*uStars*0.60*(1.0 - cl);\n\n    // Cloud underlit by the town and topped by the moon. Anime clouds are two\n    // flat values and a rim, not a gradient, so they get the cel treatment too.\n    float shape = cel(clamp(cl, 0.0, 1.0), mix(2.0, 4.0, uCel), 0.22);\n    vec3 cc = mix(pCloud*0.42, pCloud, smoothstep(0.02, 0.30, up));\n    cc += pTown*uTown*1.15*hz*az;\n    c = mix(c, cc, mix(cl, shape, uCel)*0.92);\n    return c;\n}\n\n// A far treeline sitting on the horizon, which is what gives the road\n// somewhere to vanish INTO rather than simply running out of resolution.\nfloat treeLine(vec3 rd, float px){\n    if (uTrees < 0.02) return 0.0;\n    float D = 340.0;\n    float a = atan(rd.x, max(abs(rd.z), 0.02)*sign(rd.z + 1e-6));\n    float hh = 7.0 + 15.0*fbm(vec2(a*7.0, 0.0), 4)\n             + 5.0*vnoise(vec2(a*33.0, 3.1)) + 3.0*vnoise(vec2(a*95.0, 8.7));\n    float e = (hh - 1.6)/D;\n    float w = max(px*1.2, 1.0e-4);\n    return smoothstep(e + w, e - w, rd.y)*step(0.0, rd.y + 0.02)*uTrees;\n}\n\n// ---------------------------------------------------------------\n// the wires\n// ---------------------------------------------------------------\n// Drawn analytically. A three-millimetre catenary in a distance field is a\n// hundred wasted steps and it still crawls; the closest approach between a ray\n// and a segment is a closed form. A wire thinner than a pixel is widened to the\n// pixel and DIMMED by the ratio, which is what a real thin line does and what\n// keeps it from strobing as the camera walks.\nvoid wires(vec3 ro, vec3 rd, float tmax, out vec3 wcol, out float wa){\n    wcol = vec3(0.0); wa = 0.0;\n    if (uWires < 0.02 || uPoles < 0.02) return;\n\n    float ps = poleSide();\n    float H  = gLampH*1.22;\n    float bx = ps*gPoleB;\n    float base = floor((ro.z - gPoleS*0.5)/gPoleS) ;\n\n    for (int i = 0; i < 5; i++){\n        float z0 = (base + float(i))*gPoleS + gPoleS*0.5;\n        float z1 = z0 + gPoleS;\n        for (int k = 0; k < 3; k++){\n            float fk = float(k);\n            // three conductors: two on the top arm, one on the lower\n            float ox = (fk < 2.0) ? (fk*1.52 - 0.76) : 0.0;\n            float hy = (fk < 2.0) ? (H - 0.60) : (H - 1.47);\n            float sag = ((fk < 2.0) ? 0.55 : 0.42)*(gPoleS/34.0);\n            vec3 a = vec3(bx - ps*ox, hy, z0);\n            vec3 b = vec3(bx - ps*ox, hy, z1);\n            vec3 m = 0.5*(a + b) - vec3(0.0, sag, 0.0);\n            // the catenary as two chords; a third would not be visible at any\n            // span this shader can put on screen\n            for (int q = 0; q < 2; q++){\n                vec3 s0 = (q == 0) ? a : m;\n                vec3 s1 = (q == 0) ? m : b;\n                float t;\n                float dd = raySeg(ro, rd, s0, s1, t);\n                if (t > 0.5 && t < tmax){\n                    float rw = 0.019;\n                    float pr = max(rw, t*gPX*0.75);\n                    float cov = clamp(1.0 - dd/pr, 0.0, 1.0);\n                    cov = cov*cov*(3.0 - 2.0*cov)*clamp(rw/pr, 0.0, 1.0)*uWires;\n                    // a wire is a silhouette with one lit edge, from whatever\n                    // lamp happens to be under it\n                    vec3 wc = pZen*0.55 + gLamp*0.10;\n                    wcol = wcol + wc*cov*(1.0 - wa);\n                    wa   = wa + cov*(1.0 - wa);\n                }\n            }\n        }\n    }\n}\n\n// ---------------------------------------------------------------\n// the light\n// ---------------------------------------------------------------\n// A cobra head is not a point source. It throws a lobe DOWNWARD and along the\n// kerb, and the difference matters: a point source lights the far verge as\n// brightly as the tarmac and the road stops reading as a road. `L` points from\n// the lamp toward the surface.\nfloat lampGain(vec3 L){\n    float dn = clamp(-L.y, 0.0, 1.0);\n    float along = 0.55 + 0.45*abs(L.z);\n    return (0.10 + 0.90*pow(dn, 0.70))*along;\n}\n\n// The six nearest fittings, gathered as points, plus one direction to key the\n// specular off. Three periods each side covers a lamp behind, the one you are\n// under, and the one ahead - which is exactly the set that contributes\n// anything at a spacing where the pools do not quite meet.\nvec3 lampLight(vec3 p, vec3 n, out vec3 keyDir, out float keyDist){\n    float zi0 = floor(p.z/gSpc + 0.5);\n    vec3 sum = vec3(0.0), acc = vec3(0.0);\n    float sw = 0.0, accD = 0.0;\n    for (int j = 0; j < 3; j++){\n        float zz = zi0 + float(j) - 1.0;\n        for (int k = 0; k < 2; k++){\n            float s = lampSlot(zz, float(k));\n            if (abs(s) > 0.5){\n                float live = lampLive(zz, s);\n                if (live > 0.002){\n                    vec3 lp = lampPos(zz, s);\n                    vec3 dv = lp - p;\n                    float dl = max(length(dv), 0.30);\n                    vec3 L = dv/dl;\n                    float w = live*lampGain(-L)/(1.0 + 0.020*dl*dl);\n                    float ndl = max(dot(n, L), 0.0);\n                    sum  += gLamp*w*ndl;\n                    acc  += L*w*ndl;\n                    accD += dl*w*ndl;\n                    sw   += w*ndl;\n                }\n            }\n        }\n    }\n    keyDir  = normalize(acc + n*0.001 + vec3(0.0, 0.0001, 0.0));\n    keyDist = accD/max(sw, 1e-4);\n    return sum;\n}\n\n// ---------------------------------------------------------------\n// the road surface\n// ---------------------------------------------------------------\nfloat roadMarks(vec2 p, float foot){\n    if (uMarks < 0.01) return 0.0;\n    // Japanese rural centre line: 5 m of paint, 5 m of nothing.\n    float dash = step(0.5, fract(p.y/10.0));\n    float m = band(p.x, 0.075, foot)*dash;\n    m = max(m, band(abs(p.x) - (gRoadH - 0.30), 0.070, foot));\n    // worn, and worn WHERE THE TYRES GO: the paint survives at the edges of\n    // the lane and is polished away in the wheel tracks\n    float wear = 0.55 + 0.45*fbm(p*vec2(2.2, 0.28) + 3.0, 3);\n    return m*uMarks*clamp(wear, 0.0, 1.0);\n}\n\nvec3 shadeGround(vec3 p, vec3 rd, vec3 n, float foot, float dist){\n    float ax = abs(p.x);\n    float g  = grassMask(p.x);\n    vec3 alb; float gloss; float rough;\n\n    // ---------------- carriageway ----------------\n    float agg = vnoise(p.xz*95.0)*0.55 + vnoise(p.xz*310.0)*0.45;    // aggregate\n    float aggF = smoothstep(1.10, 0.10, foot/0.012);\n    vec3 tar = pRoad*(0.86 + 0.30*mix(0.5, agg, aggF));\n    // the polished wheel tracks, and the coarser strip between them\n    float track = exp(-pow((ax - gRoadH*0.52)/0.55, 2.0));\n    tar *= 1.0 - 0.16*track;\n    // patches, cracks and old repairs\n    float rep = smoothstep(0.56, 0.72, fbm(p.xz*vec2(0.28, 0.10) + 11.0, 3));\n    tar = mix(tar, pRoad*0.72, rep*uWear*smoothstep(1.10, 0.10, foot/0.30));\n    float mk = roadMarks(p.xz, foot);\n    tar = mix(tar, pLine, mk);\n    float tarGloss = mix(0.30, 0.12, uWear) + 0.35*track + 0.45*mk;\n\n    // ---------------- gravel shoulder ----------------\n    float sh = smoothstep(gRoadH - 0.02, gRoadH + 0.22, ax)*(1.0 - g);\n    vec3 grav = pRoad*vec3(1.35, 1.30, 1.20)*(0.72 + 0.55*vnoise(p.xz*46.0));\n    tar = mix(tar, grav, sh);\n    tarGloss = mix(tarGloss, 0.10, sh);\n\n    // ---------------- the field ----------------\n    float blade = vnoise(p.xz*23.0 + windOff(p.xz)*3.0);\n    float clump = fbm(p.xz*0.62 + 5.0, 3);\n    vec3 gr = mix(pGrassA, pGrassB, clamp(0.25 + 0.9*clump + 0.5*(blade - 0.5), 0.0, 1.0));\n    // Grass is dark at its own root. The height field already knows where the\n    // roots are, so the occlusion is free: low ground is shadowed by the blades\n    // standing over it.\n    float rel = clamp(terrainH(p.xz)/max(uGrass, 1e-3), 0.0, 1.0);\n    float gao = mix(0.30, 1.0, pow(rel, 0.65));\n    gr *= mix(0.55, 1.0, gao);\n    // dead straw showing through, and the trodden verge next to the gravel\n    gr = mix(gr, pGrassB*vec3(1.25, 1.10, 0.72),\n             smoothstep(0.62, 0.86, fbm(p.xz*0.9 + 21.0, 3))*0.45);\n\n    alb   = mix(tar, gr, g);\n    gloss = mix(tarGloss, 0.08, g);\n    float ao = mix(1.0, gao, g);\n\n    // ---- light ----\n    vec3 kd; float kdist;\n    vec3 lit = lampLight(p, n, kd, kdist);\n\n    // Cel banding on the LIGHT, never on the albedo. Quantising colour posters\n    // the texture; quantising illumination is what a painted cel actually is -\n    // a flat body tone and a flat shadow tone with a hard edge between them.\n    float lum = dot(lit, vec3(0.299, 0.587, 0.114));\n    float ce = cel(clamp(lum*1.5, 0.0, 1.0), mix(3.0, 5.0, 1.0 - uCel),\n                   mix(0.45, 0.10, uCel));\n    lit = mix(lit, gLamp*ce/1.5, uCel*0.80);\n\n    vec3 sky = mix(pHor, pZen, 0.40)*(0.30 + 0.55*max(n.y, 0.0));\n    vec3 col = alb*(lit*(2.6 + 3.6*uBright) + sky*ao + pTown*uTown*0.075*ao);\n\n    // the sheen off wet-looking tarmac and off paint, which is most of what\n    // makes the road read as a surface at all at this light level\n    if (gloss > 0.02){\n        vec3 hv = normalize(kd - rd);\n        float sp = pow(max(dot(n, hv), 0.0), mix(12.0, 90.0, gloss));\n        col += gLamp*sp*gloss*length(lit)*(0.5 + 0.8*uBright)*0.9;\n    }\n    return col;\n}\n\n// ---------------------------------------------------------------\n// the ironmongery\n// ---------------------------------------------------------------\nvec3 shadeStruct(vec3 p, vec3 rd, vec3 n, float foot){\n    // Is this the underside of a cobra head? If so it is not a surface, it is\n    // the source, and it has to be blown out or the brightest thing in the\n    // frame ends up being the tarmac it is lighting.\n    float zi = floor(p.z/gSpc + 0.5);\n    float best = 1e6, live = 0.0;\n    for (int j = 0; j < 3; j++){\n        float zz = zi + float(j) - 1.0;\n        for (int k = 0; k < 2; k++){\n            float s = lampSlot(zz, float(k));\n            if (abs(s) > 0.5){\n                float d = length(p - lampPos(zz, s));\n                if (d < best){ best = d; live = lampLive(zz, s); }\n            }\n        }\n    }\n    float head = smoothstep(0.34, 0.14, best)*clamp(-n.y*1.6 + 0.35, 0.0, 1.0);\n\n    vec3 alb = mix(vec3(0.19, 0.20, 0.22), vec3(0.26, 0.23, 0.19), 0.5);\n    alb *= 0.85 + 0.30*vnoise(vec2(p.y*30.0, p.x*30.0 + p.z*30.0));\n    vec3 kd; float kdist;\n    vec3 lit = lampLight(p, n, kd, kdist);\n    vec3 sky = mix(pHor, pZen, 0.5)*(0.16 + 0.26*max(n.y, 0.0));\n    vec3 col = alb*(lit*(2.0 + 2.6*uBright) + sky + pTown*uTown*0.08);\n    col += gLamp*head*live*(3.0 + 9.0*uBright);\n    return col;\n}\n\n// ---------------------------------------------------------------\n// THE SWARM\n// ---------------------------------------------------------------\n// The flow field the whole swarm is carried by. It must be EXACTLY invertible,\n// because the lattice is read by pushing a sample backward through it, so it is\n// built only from operations that preserve the radius it is parameterised by:\n// a rotation about the lamp's axis whose rate is a function of that radius, and\n// a vertical circulation which does not touch it.\n//\n// The rate FALLS with radius, so the inner moths lap the outer ones and the\n// swarm shears. That is the whole difference between a swarm and a carousel.\nvec3 flow(vec3 q, float sgn){\n    float r = length(q.xz) + 0.04;\n    float a = sgn*uSpin*(1.45/(0.40 + r*1.30))*gT;\n    float yb = sgn*0.15*uSpin*sin(gT*0.63 + r*1.85);\n    float c = cos(a), s = sin(a);\n    return vec3(c*q.x - s*q.z, q.y + yb, s*q.x + c*q.z);\n}\n\nvoid swarm(vec3 ro, vec3 rd, float tmax, float jt, out vec3 mcol, out float ma){\n    mcol = vec3(0.0); ma = 0.0;\n    if (uMothN < 0.01 || uSwarmR < 0.05) return;\n\n    float R  = uSwarmR;\n    // The cell size sets the POPULATION - about fifteen cells across the\n    // sphere is three and a half thousand cells, and the occupancy hash keeps\n    // roughly a third of them, so this is a few thousand moths per lamp with\n    // no loop anywhere that knows how many there are.\n    float cs = R/7.5;\n    float zi0 = floor(ro.z/gSpc + 0.5);\n\n    for (int j = 0; j < 3; j++){\n        float zz = zi0 + float(j);\n        for (int k = 0; k < 2; k++){\n            float s = lampSlot(zz, float(k));\n            if (abs(s) > 0.5){\n                float live = lampLive(zz, s);\n                if (live > 0.02){\n                    vec3 LP = lampPos(zz, s);\n                    vec3 C  = LP + vec3(0.0, -0.22*R, 0.0);\n                    vec3 oc = ro - C;\n                    float b = dot(oc, rd);\n                    float cq = dot(oc, oc) - R*R;\n                    float hh = b*b - cq;\n                    if (hh > 0.0){\n                        hh = sqrt(hh);\n                        float t0 = max(-b - hh, 0.10);\n                        float t1 = min(-b + hh, tmax);\n                        if (t1 > t0){\n                            float dt = max(cs, (t1 - t0)/26.0);\n                            for (int i = 0; i < 26; i++){\n                                float t = t0 + (float(i) + jt)*dt;\n                                if (t > t1 || ma > 0.985) break;\n                                vec3 q2 = flow(ro + rd*t - C, -1.0);   // into lattice space\n                                vec3 ci = floor(q2/cs);\n                                vec4 h4 = hash43(ci + 0.5);\n                                vec3 cc = (ci + 0.5)*cs;\n                                float rr = length(cc*vec3(1.0, 1.25, 1.0))/R;\n                                // moths pile up ON the lamp, not around it\n                                float dens = 0.92*uMothN*smoothstep(1.04, 0.04, rr);\n                                if (h4.w < dens){\n                                    vec3 mp = cc + 0.80*cs*(h4.xyz - 0.5);\n                                    mp += 0.32*cs*vec3(sin(gT*9.1 + h4.x*41.0),\n                                                       sin(gT*12.7 + h4.y*33.0),\n                                                       sin(gT*10.3 + h4.z*27.0));\n                                    vec3 mw = flow(mp, 1.0) + C;       // back to the world\n                                    vec3 w = mw - ro;\n                                    float md = dot(w, rd);\n                                    if (md > 0.12 && md < tmax){\n                                        // The along-ray separation is DISCARDED.\n                                        // A blob's extent along the view\n                                        // direction is invisible, and keeping it\n                                        // would force the step down to the size\n                                        // of a moth - eighty samples instead of\n                                        // twenty-six for a picture nobody can\n                                        // tell apart.\n                                        float perp = length(w - rd*md);\n                                        float wb = 0.30 + 0.70*abs(sin(gT*12.0 + h4.x*50.0));\n                                        float ms = uMothSize*(0.70 + 0.65*h4.y)*(0.72 + 0.55*wb);\n                                        float pr = max(ms, md*gPX*0.80);\n                                        float cov = clamp(1.0 - perp/pr, 0.0, 1.0);\n                                        cov = cov*cov*clamp((ms*ms)/(pr*pr), 0.0, 1.0);\n                                        if (cov > 0.001){\n                                            float dl = length(mw - LP);\n                                            float li = live/(1.0 + 1.9*dl*dl);\n                                            vec3 mc = gLamp*(0.20 + 3.4*li)*wb*(0.45 + 0.70*uBright)\n                                                    + pZen*0.55;\n                                            mc *= exp(-uFog*md);\n                                            mcol += mc*cov*(1.0 - ma);\n                                            ma   += cov*(1.0 - ma);\n                                        }\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n\n// ---------------------------------------------------------------\n// the light in the air\n// ---------------------------------------------------------------\n// The cone under each lamp, which on a damp night is half the picture. The\n// window on the 3x3 set has to reach zero before a lamp leaves it, or the sum\n// steps at every lattice plane - and those planes project to straight vertical\n// lines through the vanishing point.\nvec3 volGlow(vec3 ro, vec3 rd, float tmax, float jt){\n    if (uCone < 0.01) return vec3(0.0);\n    float lim = min(tmax, 140.0);\n    vec3 g = vec3(0.0);\n    for (int i = 0; i < 20; i++){\n        float u = (float(i) + jt)/20.0;\n        float t = lim*u*u;\n        float ds = lim*2.0*u/20.0;\n        vec3 q = ro + rd*t;\n        float zi = floor(q.z/gSpc + 0.5);\n        float zs = (q.z - zi*gSpc >= 0.0) ? 1.0 : -1.0;\n        for (int n = 0; n < 2; n++){\n            float zz = zi + float(n)*zs;\n            for (int k = 0; k < 2; k++){\n                float s = lampSlot(zz, float(k));\n                if (abs(s) > 0.5){\n                    vec3 lp = lampPos(zz, s);\n                    vec3 dv = lp - q;\n                    float dl = max(length(dv), 0.35);\n                    float win = smoothstep(1.55*gSpc, 1.05*gSpc, abs(q.z - lp.z));\n                    // damp air lies low, and the cone is only visible in it\n                    float mist = 0.55 + 0.85*exp(-max(q.y, 0.0)*0.30);\n                    g += gLamp*lampLive(zz, s)*lampGain(-dv/dl)*win*mist\n                       * ds*exp(-uFog*1.6*t)/(1.0 + 0.60*dl*dl);\n                }\n            }\n        }\n    }\n    return g*uCone*0.030;\n}\n\n// The halo. A lamp seen directly is a hard little rectangle of geometry; the\n// bloom around it is not a post effect here but a real integral along the ray,\n// so it is occluded correctly by anything standing in front of it.\nvec3 lampHalo(vec3 ro, vec3 rd, float tmax){\n    if (uBloom < 0.01) return vec3(0.0);\n    vec3 g = vec3(0.0);\n    float zi0 = floor(ro.z/gSpc + 0.5);\n    for (int j = 0; j < 5; j++){\n        float zz = zi0 + float(j) - 1.0;\n        for (int k = 0; k < 2; k++){\n            float s = lampSlot(zz, float(k));\n            if (abs(s) > 0.5){\n                float live = lampLive(zz, s);\n                if (live > 0.02){\n                    vec3 lp = lampPos(zz, s);\n                    vec3 w = lp - ro;\n                    float md = dot(w, rd);\n                    if (md > 0.3 && md < tmax){\n                        float perp = length(w - rd*md);\n                        float r0 = 0.30 + 0.55*uBloom;\n                        g += gLamp*live*(r0*r0)/(perp*perp + r0*r0)\n                           * exp(-uFog*md)/(1.0 + 0.010*md*md);\n                    }\n                }\n            }\n        }\n    }\n    return g*uBloom*(0.16 + 0.24*uBright);\n}\n\n// ---------------------------------------------------------------\nvoid main(){\n    vec2 fc = gl_FragCoord.xy;\n    vec2 R  = RENDERSIZE.xy;\n    float T = TIME;\n    gT = T;\n\n    // Four anime night palettes. Every one of them is built the same way: a\n    // near-black zenith, a horizon two stops brighter, and exactly one warm\n    // thing in the frame that is not a lamp - the town over the hill.\n    pZen    = pick4(vec3(0.018,0.030,0.070), vec3(0.020,0.045,0.095), vec3(0.022,0.038,0.055), vec3(0.040,0.028,0.080), uPalette);\n    pHor    = pick4(vec3(0.055,0.085,0.150), vec3(0.045,0.130,0.190), vec3(0.055,0.095,0.105), vec3(0.130,0.075,0.145), uPalette);\n    pTown   = pick4(vec3(0.115,0.055,0.030), vec3(0.130,0.080,0.045), vec3(0.070,0.105,0.060), vec3(0.165,0.075,0.085), uPalette);\n    pGrassA = pick4(vec3(0.130,0.190,0.115), vec3(0.105,0.205,0.160), vec3(0.120,0.180,0.125), vec3(0.150,0.165,0.140), uPalette);\n    pGrassB = pick4(vec3(0.265,0.310,0.165), vec3(0.215,0.330,0.225), vec3(0.220,0.290,0.180), vec3(0.290,0.265,0.190), uPalette);\n    pRoad   = pick4(vec3(0.200,0.212,0.245), vec3(0.170,0.220,0.262), vec3(0.196,0.216,0.208), vec3(0.222,0.196,0.250), uPalette);\n    pLine   = pick4(vec3(0.78,0.77,0.72),    vec3(0.82,0.84,0.80),    vec3(0.76,0.79,0.72),    vec3(0.80,0.76,0.78),    uPalette);\n    pCloud  = pick4(vec3(0.085,0.105,0.155), vec3(0.075,0.140,0.185), vec3(0.080,0.110,0.110), vec3(0.130,0.090,0.150), uPalette);\n    pMoon   = pick4(vec3(0.85,0.88,1.00),    vec3(0.80,0.90,1.00),    vec3(0.85,0.95,0.95),    vec3(0.95,0.88,1.00),    uPalette);\n    gLamp   = kelvin(uTemp);\n\n    gRoadH = uRoadW;\n    gShoW  = uShoulder;\n    gSpc   = uSpacing;\n    gLampH = uLampH;\n    gLampB = gRoadH + gShoW*0.85 + 0.45;\n    gPoleB = gRoadH + gShoW + 1.60;\n    gPoleS = max(gSpc*0.80, 22.0);\n\n    // ---- the walk ----\n    float z = T*uSpeed;\n    vec3 ro = vec3(uCamX + uBob*0.038*sin(z*1.95 + 0.6),\n                   uCamY + uBob*0.028*sin(z*3.90),\n                   z);\n    gCam = ro.xz;\n\n    float yaw  = uYaw   + uBob*0.018*sin(z*0.87 + 1.0);\n    float pit  = uPitch + uBob*0.011*sin(z*1.71);\n    vec3 fw = normalize(vec3(sin(yaw), pit, cos(yaw)));\n    vec3 rt = normalize(cross(fw, vec3(0.0, 1.0, 0.0)));\n    vec3 up = cross(rt, fw);\n    float roll = uBob*0.009*sin(z*1.30 + 0.4);\n    vec3 r2 = rt*cos(roll) + up*sin(roll);\n    up = up*cos(roll) - rt*sin(roll);\n    rt = r2;\n\n    vec2 uv = (fc - 0.5*R)/R.y;\n    vec3 rd = normalize(uv.x*rt + uv.y*up + uLens*fw);\n    gPX = 1.0/(uLens*R.y);\n\n    float jt  = hash12(fc + floor(T*29.0)*vec2(7.1, 3.7));\n    float jt2 = hash12(fc*1.37 + floor(T*29.0)*vec2(11.3, 19.1));\n\n    // ---- the ground, as a marched height field ----\n    //\n    // Stepped by vertical clearance divided by the ray's rate of descent\n    // rather than by a fixed increment: a ray aimed at the horizon has to\n    // cross two hundred metres and a ray aimed at the verge has to resolve a\n    // blade, and one loop has to do both. The clamp at the bottom is what\n    // stops a nearly-level ray from taking an infinite first step.\n    float maxH = 0.06 + uGrass*1.40;\n    float tG = -1.0;\n    if (!(rd.y > 0.0 && ro.y > maxH)){\n        float t = 0.02;\n        if (ro.y > maxH && rd.y < -1e-4) t = max(t, (maxH - ro.y)/rd.y);\n        float pt = t, ph = terrainH((ro + rd*t).xz);\n        for (int i = 0; i < 150; i++){\n            vec3 p = ro + rd*t;\n            float h = terrainH(p.xz);\n            if (p.y < h){\n                float d0 = (ro + rd*pt).y - ph;\n                float d1 = p.y - h;\n                tG = mix(pt, t, clamp(d0/max(d0 - d1, 1e-5), 0.0, 1.0));\n                break;\n            }\n            pt = t; ph = h;\n            t += clamp((p.y - h)*0.55/max(-rd.y, 0.045), 0.030 + 0.009*t, 2.5 + 0.10*t);\n            if (t > FAR) break;\n        }\n    }\n\n    // ---- the ironmongery ----\n    float tS = -1.0;\n    {\n        float t = 0.05;\n        for (int i = 0; i < 96; i++){\n            float d = structures(ro + rd*t);\n            if (d < 0.0018*t + 0.0016){ tS = t; break; }\n            t += d*0.94;\n            if (t > 175.0) break;\n        }\n    }\n\n    float tHit = FAR;\n    int mat = 0;\n    if (tG > 0.0){ tHit = tG; mat = 1; }\n    if (tS > 0.0 && tS < tHit){ tHit = tS; mat = 2; }\n\n    vec3 col;\n    if (mat == 1){\n        vec3 p = ro + rd*tG;\n        // The normal is taken at the PIXEL's epsilon, not at a fixed one, so\n        // the surface it reports is the surface the pixel can actually see -\n        // which is the cheapest anti-aliasing there is on a field of grass.\n        float e0 = max(0.005, tG*gPX*1.3);\n        vec3 n = terrainN(p.xz, e0);\n        float ndv = min(dot(n, rd), -0.02);\n        float foot = tG*gPX/sqrt(ndv*ndv + 0.004);\n        col = shadeGround(p, rd, n, foot, tG);\n    } else if (mat == 2){\n        vec3 p = ro + rd*tS;\n        vec3 n = structN(p);\n        col = shadeStruct(p, rd, n, tS*gPX);\n    } else {\n        col = skyCol(rd, gPX);\n        float tl = treeLine(rd, gPX);\n        vec3 tc = mix(pZen, pHor, 0.30)*0.42 + pTown*uTown*0.10;\n        col = mix(col, tc, tl);\n    }\n\n    // ---- distance ----\n    vec3 fogc = mix(pHor, pHor + pTown*uTown*0.8, 0.45)*0.92;\n    if (tHit < FAR){\n        float f = 1.0 - exp(-uFog*tHit);\n        // the fade has to finish before rays start missing, or the last few\n        // metres of road keep a fifth of their contrast while the ray beside\n        // them keeps none, and that edge is a hard line at the vanishing point\n        col = mix(col, fogc, max(f, smoothstep(FAR*0.55, FAR*0.93, tHit)));\n    }\n\n    // ---- the light in the air, then what is flying through it ----\n    col += volGlow(ro, rd, tHit, jt);\n    col += lampHalo(ro, rd, tHit);\n\n    vec3 wc; float wa;\n    wires(ro, rd, tHit, wc, wa);\n    col = col*(1.0 - wa) + wc;\n\n    vec3 mc; float ma;\n    swarm(ro, rd, tHit, jt2, mc, ma);\n    col = col*(1.0 - ma) + mc;\n\n    // ---- the print ----\n    col = max(col, 0.0);\n    col = col/(1.0 + col*0.55);                    // roll the lamps off\n    col = mix(col, col*col*(3.0 - 2.0*col), 0.55*uContrast);\n    float lum = dot(col, vec3(0.299, 0.587, 0.114));\n    col = mix(vec3(lum), col, 1.08 + 0.30*uContrast);\n    // night stock leans cold in the shadows, which is what leaves the sodium\n    // room to be the only warm thing on screen\n    float sh = (1.0 - lum)*(1.0 - lum);\n    // Weighted by the shadow term and by nothing else. An unconditional cool\n    // multiply also cools the sodium, and a sodium lamp that has come out cyan\n    // is the one mistake this palette cannot survive.\n    col = mix(col, col*vec3(0.88, 0.96, 1.14) + vec3(0.0, 0.003, 0.011)*sh, 0.80*sh);\n\n    vec2 sc = fc/R;\n    col *= 1.0 - uVignette*1.15*dot(sc - 0.5, sc - 0.5);\n\n    // Grain, weighted into the shadows. Film grain lives in the toe; spreading\n    // it evenly is the tell that it was added by a slider.\n    float nz = hash12(fc + floor(T*24.0)*vec2(13.7, 91.3));\n    col += (nz - 0.5)*uGrain*0.075*(0.30 + 1.10*sh);\n\n    // half an LSB, because a night sky is one enormous smooth gradient and\n    // that is exactly where eight bits shows its seams\n    col += (hash12(fc + 0.5) - 0.5)/255.0;\n\n    gl_FragColor = vec4(clamp(col, 0.0, 1.0), 1.0);\n}\n",
    "generator": {
      "model": "opus5",
      "provider": null,
      "prompt": null,
      "params": null
    }
  }
}