{
  "license": "CC0-1.0",
  "shader": {
    "id": "qm9zjuop",
    "title": "Plate XXIV: Ammonite",
    "license": "CC0-1.0",
    "provenance_type": "witnessed_generation",
    "made_with": "glslop-scaffold1",
    "status": "active",
    "compile_ok": true,
    "render_hash": "ffffe3c7c1d1ffff",
    "tags": [
      "engraving",
      "print",
      "paper",
      "ink",
      "hatching",
      "intaglio",
      "monochrome",
      "shell"
    ],
    "parents": [],
    "author": "zazi5inxhmgi",
    "author_name": "ufffd",
    "author_url": "/u/ufffd",
    "created_at": "2026-08-30T15:33:33.986Z",
    "poster_url": "/posters/qm9zjuop.avif",
    "stats": {
      "slops": 0,
      "views": 106,
      "forks": 0
    },
    "self": "/api/v1/shaders/qm9zjuop",
    "isf": "/*{\n  \"DESCRIPTION\": \"Plate XXIV. An ammonite cut in copperplate and pulled in two inks on warm laid paper. The shell is a real height field - log-spiral whorls with a rounded section, bifurcating ribs and umbilical tubercles - marched under a raking light that sweeps across it. The hatching is laid out on the shell's own coil coordinates: the primary lay is locked to the rib phase, so every stroke runs across the whorl the way a burin follows the sculpture, and it converges into the umbilicus by itself. Line WEIGHT carries the whole value structure; crosshatch, the third diagonal and the lozenge dot enter only where the tone below them has run out of room, and the darks stay open so paper still flecks through. Second plate is a ruled tint screen at its own angle, drifting slowly in and out of registration. Plate mark, wiped plate tone, laid lines, tooth, border rules, caption and scale bar.\",\n  \"CREDIT\": \"\",\n  \"CATEGORIES\": [\"print\", \"engraving\", \"paper\"],\n  \"INPUTS\": [\n    { \"NAME\": \"inkKey\",       \"TYPE\": \"color\", \"DEFAULT\": [0.118, 0.098, 0.092, 1.0] },\n    { \"NAME\": \"inkTint\",      \"TYPE\": \"color\", \"DEFAULT\": [0.596, 0.330, 0.235, 1.0] },\n    { \"NAME\": \"paperCol\",     \"TYPE\": \"color\", \"DEFAULT\": [0.938, 0.902, 0.826, 1.0] },\n    { \"NAME\": \"hatchDensity\", \"TYPE\": \"float\", \"DEFAULT\": 1.0,  \"MIN\": 0.4,  \"MAX\": 2.2 },\n    { \"NAME\": \"lineWeight\",   \"TYPE\": \"float\", \"DEFAULT\": 1.0,  \"MIN\": 0.4,  \"MAX\": 1.7 },\n    { \"NAME\": \"tintInk\",      \"TYPE\": \"float\", \"DEFAULT\": 1.00, \"MIN\": 0.0,  \"MAX\": 1.6 },\n    { \"NAME\": \"registration\", \"TYPE\": \"float\", \"DEFAULT\": 2.6,  \"MIN\": 0.0,  \"MAX\": 7.0 },\n    { \"NAME\": \"paperGrain\",   \"TYPE\": \"float\", \"DEFAULT\": 1.0,  \"MIN\": 0.0,  \"MAX\": 2.0 },\n    { \"NAME\": \"plateTilt\",    \"TYPE\": \"float\", \"DEFAULT\": 0.42, \"MIN\": 0.0,  \"MAX\": 0.85 },\n    { \"NAME\": \"ribDepth\",     \"TYPE\": \"float\", \"DEFAULT\": 0.55, \"MIN\": 0.0,  \"MAX\": 1.6 }\n  ]\n}*/\n\n#ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#endif\n\n#define PI  3.14159265\n#define TAU 6.28318531\n\n/* ---------------------------------------------------------------- shell */\n/* log-spiral coil: r = exp(SB * theta), theta = atan + 2*PI*n, theta <= 0\n   at the aperture. One whorl period in \"S\" space is exactly 1.0, so the\n   across-whorl coordinate e = S - round(S) runs -0.5 .. 0.5 and the coil\n   parameter is continuous everywhere (mod an integer). */\n#define SB     0.163\n#define THMAX  0.0\n#define THMIN -24.0\n#define HAMP   0.440\n#define SUTFL  0.34\n#define RIBN   30.0\n#define HCEIL  0.62\n#define COILC  0.5403   /* cos(1.0) : the coil is turned so the aperture faces lower-right */\n#define COILS  0.8415\n\nfloat h11(float n){ return fract(sin(n * 127.1) * 43758.5453); }\nfloat h21(vec2 p){ return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453); }\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(h21(i), h21(i + vec2(1.0, 0.0)), f.x),\n               mix(h21(i + vec2(0.0, 1.0)), h21(i + vec2(1.0, 1.0)), f.x), f.y);\n}\n\nmat2 rot(float a){ float c = cos(a), s = sin(a); return mat2(c, -s, s, c); }\n\nfloat sdBox(vec2 p, vec2 b){ vec2 d = abs(p) - b; return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)); }\n\nfloat sdSeg(vec2 p, vec2 a, vec2 b){\n    vec2 pa = p - a, ba = b - a;\n    float h = clamp(dot(pa, ba) / max(dot(ba, ba), 1e-9), 0.0, 1.0);\n    return length(pa - ba * h);\n}\n\n/* returns (height, e, theta, rib) */\nvec4 shellEval(vec2 qin){\n    vec4 z = vec4(0.0);\n    vec2 q = mat2(COILC, -COILS, COILS, COILC) * qin;\n    float r = length(q);\n    if (r < 0.016 || r > 1.03) return z;\n    float a  = atan(q.y, q.x);\n    float S  = (log(r) / SB - a) * (1.0 / TAU);\n    float n  = floor(S + 0.5);\n    float e  = S - n;\n    float th = a + TAU * n;\n    if (th > THMAX || th < THMIN) return z;\n\n    float rc  = exp(SB * th);            /* whorl centreline radius */\n    float amp = HAMP * rc;\n\n    /* is there a whorl outside / inside this one? if not, round the flank off */\n    float fo = mix(smoothstep(0.50, 0.30,  e), 1.0, step(th + TAU, THMAX));\n    float fi = mix(smoothstep(0.50, 0.30, -e), 1.0, step(THMIN, th - TAU));\n    float fl = min(fo, fi);\n\n    /* the aperture is a rounded lip, not a cliff */\n    float ga = smoothstep(THMAX + 0.01, THMAX - 0.10, th);\n\n    float t  = max(0.0, 1.0 - 4.0 * e * e);\n    float pr = sqrt(t); pr = pr * (1.36 - 0.36 * pr * pr);   /* rounded whorl, flat crest, steep flanks */\n    float h  = amp * (SUTFL * fl + (1.0 - SUTFL) * pr) * ga;\n\n    /* ribs: swept forward across the flank, bifurcating toward the venter,\n       fading out at the umbilical suture. phase stays continuous across a\n       suture because RIBN is an integer and the sweep is a whole TAU. */\n    float rp2 = th * RIBN + TAU * e;\n    float rib = mix(cos(rp2), 0.5 * cos(rp2) + 0.55 * cos(2.0 * rp2 + 0.7),\n                    smoothstep(-0.12, 0.30, e));\n    float ribM = (0.30 + 0.70 * smoothstep(-0.46, 0.22, e)) * smoothstep(0.50, 0.38, abs(e));\n    h += amp * ribDepth * 0.11 * rib * ribM * pr * fl * ga;\n\n    /* umbilical tubercles on the rib crests */\n    float dn = (e + 0.28) * 6.0;\n    float bn = max(0.0, 1.0 - dn * dn);\n    float rp = max(cos(rp2), 0.0); rp *= rp;\n    h += amp * 0.060 * bn * rp * fl * ga;\n\n    return vec4(h, e, th, rib);\n}\n\nfloat softShadow(vec3 p, vec3 L, float dt){\n    float s = 1.0;\n    for (int i = 1; i <= 12; i++){\n        float k = dt * float(i);\n        vec3 q = p + L * (k + 0.010);\n        if (q.z > HCEIL) break;\n        float h = shellEval(q.xy).x;\n        s = min(s, clamp((q.z - h) * 6.0 / k, 0.0, 1.0));\n    }\n    return clamp(s, 0.0, 1.0);\n}\n\n/* one filtered family of burin lines.\n   phv  : phase (lines sit at integer phase)\n   gpx  : |d(phase)/d(pixel)|\n   wf   : ink fraction of the period                                        */\nfloat hatch(float phv, float gpx, float wf, float jit){\n    if (wf <= 0.0006) return 0.0;\n    float li = floor(phv + 0.5);\n    float o  = phv - li;\n    o += (h11(li * 1.7) - 0.5) * jit;\n    float w  = wf * (0.84 + 0.32 * h11(li * 5.3 + 11.0));\n    float gp = max(gpx, 1e-5);\n    float d  = abs(o) / gp;\n    float hw = 0.5 * w / gp;\n    float cov = clamp(min(d + 0.5, hw) - max(d - 0.5, -hw), 0.0, 1.0);\n    float f = smoothstep(0.26, 0.62, gp);        /* too fine to resolve -> flat tone */\n    return mix(cov, clamp(w, 0.0, 1.0), f);\n}\n\nvoid main(){\n    float mn  = min(RENDERSIZE.x, RENDERSIZE.y);\n    vec2  sp  = (gl_FragCoord.xy - 0.5 * RENDERSIZE) / mn;\n    float pxs = 1.0 / mn;                         /* one pixel in sp units */\n\n    /* ---------------------------------------------------------- motion */\n    float ph = fract(TIME / 32.0);\n    float w1 = TAU * ph;\n    float spin    = 0.048 * sin(w1 + 2.4);\n    float lightAz = 2.32 + 0.62 * sin(w1) - spin;\n    float lightEl = 0.60 + 0.11 * sin(2.0 * w1);\n    float tilt    = clamp(plateTilt + 0.045 * sin(w1 + 1.2), 0.0, 1.1);\n    vec2  regOff  = registration * (mn / 512.0) * vec2(cos(w1), sin(w1));\n\n    /* ---------------------------------------------------------- camera */\n    const float VS = 3.15;                        /* object units across one sp unit */\n    const float CY = 0.050;                       /* specimen sits a touch high */\n    float ct = cos(tilt), st = sin(tilt);\n    vec3 fwd = vec3(0.0, st, -ct);\n    vec3 rgt = vec3(1.0, 0.0, 0.0);\n    vec3 upv = vec3(0.0, ct, st);\n    vec2 spr = rot(spin) * (sp - vec2(0.0, CY));\n    /* the specimen is coiled with its aperture toward the lower right */\n    vec3 ro = rgt * (spr.x * VS) + upv * (spr.y * VS) - fwd * 3.0;\n    vec3 rd = fwd;\n\n    float pxObj = VS / mn;\n\n    /* ------------------------------------------------------ height march */\n    float t1 = ro.z / ct;                         /* ray reaches z = 0 */\n    float t0 = max((ro.z - HCEIL) / ct, 0.0);\n    vec2  A  = (ro + rd * t0).xy;\n    vec2  B  = (ro + rd * t1).xy;\n    vec2  AB = B - A;\n    float uu = clamp(dot(-A, AB) / max(dot(AB, AB), 1e-9), 0.0, 1.0);\n    float dmin = length(A + AB * uu);\n    float rseg = max(length(A), length(B));\n    /* local ceiling: the coil is never taller than ~0.56 of its own radius */\n    t0 = max(t0, (ro.z - min(HCEIL, 0.70 * rseg + 0.02)) / ct);\n\n    float tHit = t1;\n    if (dmin < 1.04){\n        const int NS = 40;\n        float dt = (t1 - t0) / float(NS);\n        float pd = 1.0, pt = t0;\n        for (int i = 1; i <= NS; i++){\n            float t = t0 + dt * float(i);\n            vec3  q = ro + rd * t;\n            float d = q.z - shellEval(q.xy).x;\n            if (d < 0.0){\n                tHit = pt + (t - pt) * (pd / max(pd - d, 1e-6));\n                break;\n            }\n            pd = d; pt = t;\n        }\n    }\n\n    vec3  P  = ro + rd * tHit;\n    vec4  si = shellEval(P.xy);\n    bool  onShell = si.x > 0.0008;\n\n    vec3 Lv = vec3(cos(lightAz) * cos(lightEl), sin(lightAz) * cos(lightEl), sin(lightEl));\n\n    /* --------------------------------------------------- tone + line work */\n    float D    = 0.0;        /* darkness 0..1 */\n    float ink  = 0.0;        /* key-plate coverage */\n    float tint = 0.0;        /* tint-plate tone */\n\n    if (onShell){\n        float ee = max(0.0020, pxObj * 0.75);\n        float hx = shellEval(P.xy + vec2(ee, 0.0)).x - shellEval(P.xy - vec2(ee, 0.0)).x;\n        float hy = shellEval(P.xy + vec2(0.0, ee)).x - shellEval(P.xy - vec2(0.0, ee)).x;\n        vec3  N  = normalize(vec3(-hx, -hy, 2.0 * ee));\n        float slope = length(vec2(hx, hy)) / (2.0 * ee);\n        float r   = max(length(P.xy), 1e-4);\n\n        /* An ammonite laid flat is nearly a disc: physically correct shading\n           gives it no large-scale form at all. Draughtsmen never draw it that\n           way - they read the whole specimen as one convex body and swing the\n           tone right across it. Tilting the normal outward with radius is that\n           reading, and it is what gives the plate a lit side and a dark side. */\n        vec3 Nd = normalize(N + vec3(P.xy * 0.52, 0.0));\n\n        float ndl = max(dot(Nd, Lv), 0.0);\n        float sh  = softShadow(P + N * 0.004, Lv, 0.050);\n\n        float ao = mix(0.26, 1.0, smoothstep(0.50, 0.19, abs(si.y)));\n        ao *= mix(0.34, 1.0, smoothstep(0.035, 0.30, r));\n        float fill = 0.5 + 0.5 * Nd.z;\n\n        float lum = 0.038 * ao + 0.105 * fill * ao + 1.22 * ndl * mix(0.22, 1.0, sh) * ao;\n        float tone = 1.0 - exp(-1.55 * lum);\n        tone = mix(tone, tone * tone * (3.0 - 2.0 * tone), 0.65);  /* the plate contrast curve */\n        D = clamp(1.0 - tone, 0.0, 1.0);\n        /* burin contour: the umbilical walls take a heavier line */\n        D = max(D, smoothstep(3.0, 7.5, slope) * 0.70);\n        /* and the specimen is OUTLINED, the way a plate always is - a line\n           that thickens where it runs into shadow. rimT is the height of the\n           surface relative to the whorl it belongs to, so it falls to zero\n           exactly at the silhouette and at each suture. */\n        float rimT = si.x / (HAMP * max(r, 0.06));\n        D = max(D, smoothstep(0.26, 0.05, rimT) * (0.62 + 0.34 * D));\n\n        /* ---- coil-space hatch frames ----\n           The PRIMARY lay is locked to the rib phase, so every stroke runs\n           across the whorl the way a burin follows the sculpture: the tone\n           changes ACROSS the strokes (rib to rib) and only slowly ALONG them,\n           which is what makes each line swell and taper instead of breaking\n           into dashes. Because the lay is angular, it converges into the\n           umbilicus on its own. The secondary lay is a spiral sheared into a\n           diagonal; C and D are the two diagonals of A x B, deepest darks only.\n           All four phases jump by whole integers at a suture, so fract() stays\n           continuous and there is no seam. */\n        vec2 qr = mat2(COILC, -COILS, COILS, COILC) * P.xy;\n        vec2 rh = qr / r;                         /* radial   unit */\n        vec2 tg = vec2(-rh.y, rh.x);              /* tangent  unit */\n        vec2 gS = (rh / SB - tg) * (1.0 / (TAU * r));   /* grad of coil coord S */\n        vec2 gT = tg / r;                                /* grad of theta       */\n\n        float NM  = 2.0 * max(1.0, floor(2.0 * hatchDensity + 0.5));   /* strokes per rib   */\n        float NSp = 2.0 * max(2.0, floor(8.0 * hatchDensity + 0.5));   /* spiral lay        */\n        float NK  = 2.0 * floor(26.0 * hatchDensity + 0.5);            /* its forward shear */\n\n        vec2 gA = (gT * (RIBN / TAU) + gS) * NM;\n        vec2 gB =  gS * NSp + gT * (NK / TAU);\n        float fp = pxObj / max(dot(N, -rd), 0.22);       /* object units per pixel on surface */\n\n        float pA = (si.z * (RIBN / TAU) + si.y) * NM;\n        float pB =  si.y * NSp + si.z * (NK / TAU);\n        float gpA = length(gA) * fp;\n        float gpB = length(gB) * fp;\n        float gpC = length(gA + gB) * 0.5 * fp;\n        float gpD = length(gA - gB) * 0.5 * fp;\n\n        /* the tonal ladder of a real plate: the primary lay carries everything\n           up to a heavy midtone on its own (swelling from a hairline to half\n           the pitch), and each further lay only enters once the tone below it\n           has genuinely run out of room. */\n        float lw = lineWeight;\n        float wA = (smoothstep(0.035, 0.46, D) * 0.34 + smoothstep(0.40, 0.92, D) * 0.26) * lw;\n        float wB =  smoothstep(0.64, 0.96, D) * 0.40 * lw;\n        float wC =  smoothstep(0.80, 1.00, D) * 0.34 * lw;\n        float wD =  smoothstep(0.93, 1.00, D) * 0.24 * lw;\n\n        float cA = hatch(pA, gpA, wA, 0.10);\n        float cB = hatch(pB, gpB, wB, 0.08);\n        float cC = hatch((pA + pB) * 0.5, gpC, wC, 0.07);\n        float cD = hatch((pA - pB) * 0.5, gpD, wD, 0.07);\n\n        /* the lozenge dot that sits in the white diamond of the deepest crosshatch */\n        float wDot = smoothstep(0.85, 1.00, D) * 0.36;\n        float zA = (fract(pA) - 0.5) / max(gpA, 1e-5);\n        float zB = (fract(pB) - 0.5) / max(gpB, 1e-5);\n        float dd = length(vec2(zA, zB));\n        float rr = wDot * 0.5 / max(max(gpA, gpB), 1e-5);\n        float cE = clamp(min(dd + 0.5, rr) - max(dd - 0.5, -rr), 0.0, 1.0);\n        cE *= 1.0 - smoothstep(0.30, 0.60, max(gpA, gpB));\n\n        ink  = 1.0 - (1.0 - cA) * (1.0 - cB) * (1.0 - cC) * (1.0 - cD) * (1.0 - cE);\n        /* the tint plate carries the mid-shadow, where the key plate is still\n           open enough for the second ink to actually show through */\n        tint = smoothstep(0.16, 0.56, D) * (1.0 - 0.42 * smoothstep(0.74, 1.0, D));\n    } else {\n        /* bare paper: nothing but a short contact shadow to seat the specimen.\n           The umbilical perforation at the very centre of the coil is the one\n           place paper shows THROUGH the specimen, and it has to be solid ink,\n           not a white pinhole. */\n        float cs  = 1.0 - softShadow(vec3(P.xy, 0.003), Lv, 0.017);\n        float umb = smoothstep(0.055, 0.016, length(P.xy));\n        D = max(cs * 0.22, umb * 0.94);\n        float spc = mn / 150.0;\n        float pP  = dot(gl_FragCoord.xy, vec2(0.8192, 0.5736)) / spc;\n        ink  = hatch(pP, 1.0 / spc, smoothstep(0.02, 0.28, cs * 0.22) * 0.34 * lineWeight, 0.12);\n        ink  = max(ink, umb * 0.90);\n        tint = max(cs * 0.30, umb * 0.55);\n    }\n\n    /* registration: the tint plate is pulled a hair off the key plate */\n    vec2 shiftObj = vec2(regOff.x * pxObj, regOff.y * pxObj / max(ct, 0.15));\n    float mShift = step(0.0008, shellEval(P.xy + shiftObj).x);\n    float tintTone = onShell ? tint * mShift : max(tint * 0.7, 0.44 * mShift);\n\n    /* ------------------------------------------------------------- paper */\n    vec2 gp = gl_FragCoord.xy;\n    float tooth  = vnoise(gp * 0.95) * 0.60 + vnoise(gp * 0.22) * 0.40;\n    float mottle = vnoise(gp * (5.0 / mn) * 12.0 + 17.0);\n    float laid   = sin(gp.y * TAU * 46.0 / mn) * 0.5 + 0.5;\n    float chain  = sin(gp.x * TAU * 6.0 / mn) * 0.5 + 0.5;\n\n    vec3 col = paperCol.rgb;\n    col *= 1.0 + ((mottle - 0.5) * 0.045 + (tooth - 0.5) * 0.038\n                 + (laid - 0.5) * 0.016 + (chain - 0.5) * 0.014) * paperGrain;\n    col += vec3(0.014, 0.004, -0.010) * (mottle - 0.5) * paperGrain;\n\n    /* plate mark: the copper's bevelled edge pressed into the sheet */\n    vec2  he = vec2(0.5 * RENDERSIZE.x, 0.5 * RENDERSIZE.y) / mn - 0.032;\n    float dP = sdBox(sp, he);\n    vec2  d2 = abs(sp) - he;\n    vec2  nb = (d2.x > d2.y) ? vec2(sign(sp.x), 0.0) : vec2(0.0, sign(sp.y));\n    float lit = dot(nb, normalize(vec2(-0.6, 0.8)));\n    float bevel = (1.0 - smoothstep(0.0, 3.2 * pxs, abs(dP + 1.6 * pxs))) * (-0.42 * lit)\n                + (1.0 - smoothstep(0.0, 2.6 * pxs, abs(dP - 1.1 * pxs))) * (0.20 * lit);\n    col *= 1.0 + bevel * 0.55;\n\n    /* wiped plate tone inside the mark */\n    float inPlate = smoothstep(1.2 * pxs, -1.2 * pxs, dP);\n    float wipe = vnoise(sp * vec2(7.0, 70.0) + 3.7) * 0.6 + vnoise(sp * vec2(3.0, 16.0)) * 0.4;\n    col = mix(col, mix(col, inkKey.rgb, 0.028 + 0.034 * wipe), inPlate);\n\n    /* --------------------------------------------------------- tint plate */\n    /* A dot screen at this scale beats against the burin pitch and turns the\n       whole midtone to speckle. A RULED tint screen at its own angle is both\n       quieter and the more period-correct thing for a second plate. */\n    float spcT = mn / 176.0;\n    float pT   = dot(gl_FragCoord.xy + regOff, vec2(0.3420, -0.9397)) / spcT;\n    float cT   = hatch(pT, 1.0 / spcT, clamp(tintTone, 0.0, 1.0) * 0.66, 0.06);\n    cT *= 1.0 - 0.12 * tooth;\n    col = mix(col, inkTint.rgb, clamp(cT * tintInk * 0.92, 0.0, 1.0) * inPlate);\n\n    /* ---------------------------------------------------------- key plate */\n    ink = min(ink, 0.90);   /* the darks stay open - paper still flecks through */\n    ink *= 1.0 - 0.075 * tooth * paperGrain;\n    col = mix(col, inkKey.rgb, clamp(ink, 0.0, 1.0) * 0.965 * inPlate);\n\n    /* --------------------------------------------------------- furniture */\n    vec2  be = he - 0.040;\n    float f1 = 1.0 - smoothstep(0.5 * pxs, 1.7 * pxs, abs(sdBox(sp, be)));\n    float f2 = 1.0 - smoothstep(1.4 * pxs, 3.0 * pxs, abs(sdBox(sp, be - 0.012)));\n    float furn = max(f1 * 0.85, f2);\n\n    /* scale bar with divisions */\n    float by = -be.y + 0.030;\n    float bar = 1.0 - smoothstep(0.5 * pxs, 1.6 * pxs, sdSeg(sp, vec2(-0.085, by), vec2(0.085, by)));\n    for (int i = 0; i < 7; i++){\n        float fi = float(i);\n        float x  = mix(-0.085, 0.085, fi / 6.0);\n        float hh = (mod(fi, 3.0) < 0.5) ? 0.016 : 0.009;\n        bar = max(bar, 1.0 - smoothstep(0.5 * pxs, 1.6 * pxs, sdSeg(sp, vec2(x, by), vec2(x, by + hh))));\n    }\n    furn = max(furn, bar);\n\n    /* caption: a line of small marks reading as a set species name */\n    float cy = by + 0.050;\n    float cw = 0.0042;\n    float cx0 = -0.115;\n    if (sp.x > cx0 && sp.x < -cx0 && abs(sp.y - cy) < 0.014){\n        float xg = (sp.x - cx0) / cw;\n        float gi = floor(xg);\n        float gf = fract(xg);\n        float sk = h11(gi * 3.1 + 4.0);\n        float gap = step(0.87, h11(gi * 9.7 + 1.0));\n        float hh = 0.0085 * (0.55 + 0.6 * sk);\n        float asc = (sk > 0.72) ? 0.0055 : 0.0;\n        float m = (1.0 - smoothstep(0.20, 0.30, abs(gf - 0.47)))\n                * (1.0 - smoothstep(hh + asc, hh + asc + 1.2 * pxs, abs(sp.y - cy - asc * 0.5)))\n                * (1.0 - gap);\n        furn = max(furn, m * 0.9);\n    }\n\n    /* plate number, upper right inside the rule */\n    float ny = be.y - 0.026;\n    if (sp.x > be.x - 0.185 && sp.x < be.x - 0.030 && abs(sp.y - ny) < 0.012){\n        float xg = (sp.x - (be.x - 0.185)) / 0.0050;\n        float gi = floor(xg);\n        float gf = fract(xg);\n        float sk = h11(gi * 7.3 + 21.0);\n        float gap = step(0.80, h11(gi * 2.9 + 6.0));\n        float m = (1.0 - smoothstep(0.20, 0.32, abs(gf - 0.45)))\n                * (1.0 - smoothstep(0.0085, 0.0085 + 1.2 * pxs, abs(sp.y - ny)))\n                * (1.0 - gap) * (0.5 + 0.5 * step(0.3, sk));\n        furn = max(furn, m * 0.85);\n    }\n\n    furn *= (1.0 - 0.22 * tooth) * inPlate;\n    col = mix(col, inkKey.rgb, clamp(furn, 0.0, 1.0) * 0.90);\n\n    /* outside the plate mark the sheet is clean and very slightly brighter */\n    col *= mix(1.012, 1.0, inPlate);\n\n    gl_FragColor = vec4(clamp(col, 0.0, 1.0), 1.0);\n}\n",
    "generator": {
      "model": "claude-opus-5",
      "provider": "anthropic",
      "prompt": null,
      "params": null
    }
  }
}