{
  "license": "CC0-1.0",
  "shader": {
    "id": "8dymr411",
    "title": "Stick Figure v4",
    "license": "CC0-1.0",
    "provenance_type": "bred",
    "made_with": "glslop",
    "status": "active",
    "compile_ok": true,
    "render_hash": "0018181818181400",
    "tags": [],
    "parents": [
      "73abx4ak"
    ],
    "author": "jab6zg50vals",
    "author_name": "ogcraig",
    "author_url": "/u/ogcraig",
    "created_at": "2026-10-22T20:29:30.398Z",
    "poster_url": "/posters/8dymr411.webp",
    "stats": {
      "slops": 0,
      "views": 5,
      "forks": 0
    },
    "supersedes": "73abx4ak",
    "self": "/api/v1/shaders/8dymr411",
    "isf": "/*{\n  \"DESCRIPTION\": \"Restroom-sign pictogram: white standing figure on a rounded black tile, with a Motion Mode dropdown: Wave, Walk and Run (the figure turns to a side-view profile), Dance (Groove, Hip-Hop Bounce, Running Man, Robot, Arm Wave, and breaking: Toprock, Six-Step, Windmill, Headspin, Freezes and an auto Breaking Combo), Jumping Jacks and Stand Still. Dance mode is driven by a 3D skeleton and drawn as a side-view pictogram (like Walk/Run, with depth-layered limbs and black gaps), the classic front view, or a shaded 3D mannequin; the camera can be turned or orbited. Fully jointed figure (shoulders, elbows, rounded nub ends, knees) with body bounce, sway and head follow. Moves lock to a BPM. Also color cycle, glow, outline and pulse for live use.\",\n  \"CREDIT\": \"Craig\",\n  \"ISFVSN\": \"2\",\n  \"CATEGORIES\": [\"generator\"],\n  \"INPUTS\": [\n    { \"NAME\": \"motionMode\",  \"LABEL\": \"Motion Mode\",  \"TYPE\": \"long\",  \"DEFAULT\": 0,\n      \"VALUES\": [0, 1, 2, 3, 4, 5],\n      \"LABELS\": [\"Wave\", \"Walk (Side View)\", \"Run (Side View)\", \"Dance (see Dance Style)\", \"Jumping Jacks\", \"Stand Still\"] },\n    { \"NAME\": \"danceStyle\",  \"LABEL\": \"Dance Style\",  \"TYPE\": \"long\",  \"DEFAULT\": 0,\n      \"VALUES\": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],\n      \"LABELS\": [\"Groove\", \"Hip-Hop Bounce\", \"Running Man\", \"Robot / Popping\", \"Arm Wave\",\n                 \"Toprock (Breaking)\", \"Six-Step (Breaking)\", \"Windmill (Breaking)\",\n                 \"Headspin (Breaking)\", \"Freezes (Breaking)\", \"Breaking Combo (Auto)\"] },\n    { \"NAME\": \"spinSpeed\",   \"LABEL\": \"Power Move Speed\", \"TYPE\": \"float\", \"DEFAULT\": 1.0, \"MIN\": 0.25, \"MAX\": 3.0 },\n    { \"NAME\": \"danceView\",   \"LABEL\": \"Dance View\",   \"TYPE\": \"long\",  \"DEFAULT\": 0,\n      \"VALUES\": [0, 1, 2], \"LABELS\": [\"Side View (pictogram)\", \"Front View (pictogram)\", \"Shaded 3D\"] },\n    { \"NAME\": \"cam3DAngle\",  \"LABEL\": \"Dance Camera Turn\",   \"TYPE\": \"float\", \"DEFAULT\": 0.75, \"MIN\": -3.1416, \"MAX\": 3.1416 },\n    { \"NAME\": \"cam3DOrbit\",  \"LABEL\": \"Dance Camera Orbit\",  \"TYPE\": \"float\", \"DEFAULT\": 0.0, \"MIN\": -2.0, \"MAX\": 2.0 },\n    { \"NAME\": \"cam3DHeight\", \"LABEL\": \"Dance Camera Height\", \"TYPE\": \"float\", \"DEFAULT\": 0.0, \"MIN\": -0.3, \"MAX\": 0.9 },\n    { \"NAME\": \"floor3D\",     \"LABEL\": \"Floor Light (Shaded 3D)\", \"TYPE\": \"float\", \"DEFAULT\": 0.5, \"MIN\": 0.0, \"MAX\": 1.0 },\n    { \"NAME\": \"bpm\",         \"LABEL\": \"Tempo (BPM)\",  \"TYPE\": \"float\", \"DEFAULT\": 120.0, \"MIN\": 60.0, \"MAX\": 200.0 },\n    { \"NAME\": \"moveAmount\",  \"LABEL\": \"Move Amount\",  \"TYPE\": \"float\", \"DEFAULT\": 1.0, \"MIN\": 0.0, \"MAX\": 1.0 },\n    { \"NAME\": \"speed\",       \"TYPE\": \"float\", \"DEFAULT\": 1.0, \"MIN\": 0.0,  \"MAX\": 4.0 },\n    { \"NAME\": \"groundDashes\",\"LABEL\": \"Ground Dashes (Walk/Run)\", \"TYPE\": \"bool\", \"DEFAULT\": 0 },\n\n    { \"NAME\": \"hue\",         \"TYPE\": \"float\", \"DEFAULT\": 0.5, \"MIN\": 0.0,  \"MAX\": 1.0 },\n    { \"NAME\": \"colorCycle\",  \"LABEL\": \"Color Cycle\",  \"TYPE\": \"float\", \"DEFAULT\": 0.0, \"MIN\": 0.0, \"MAX\": 1.0 },\n    { \"NAME\": \"figureColor\", \"LABEL\": \"Figure Color\", \"TYPE\": \"color\", \"DEFAULT\": [1.0, 1.0, 1.0, 1.0] },\n    { \"NAME\": \"tileColor\",   \"LABEL\": \"Tile Color\",   \"TYPE\": \"color\", \"DEFAULT\": [0.0, 0.0, 0.0, 1.0] },\n    { \"NAME\": \"outerColor\",  \"LABEL\": \"Outer Color\",  \"TYPE\": \"color\", \"DEFAULT\": [1.0, 1.0, 1.0, 1.0] },\n    { \"NAME\": \"showTile\",    \"LABEL\": \"Show Tile\",    \"TYPE\": \"bool\",  \"DEFAULT\": 1 },\n    { \"NAME\": \"zoom\",        \"TYPE\": \"float\", \"DEFAULT\": 1.0, \"MIN\": 0.25, \"MAX\": 3.0 },\n\n    { \"NAME\": \"waveAuto\",    \"LABEL\": \"Auto Wave Loop\", \"TYPE\": \"bool\",  \"DEFAULT\": 1 },\n    { \"NAME\": \"waveStyle\",   \"LABEL\": \"Wave Style\",     \"TYPE\": \"long\",  \"DEFAULT\": 0,\n      \"VALUES\": [0, 1, 2], \"LABELS\": [\"Elbow Wave\", \"Wrist Flick\", \"Big Wave\"] },\n    { \"NAME\": \"waveRaise\",   \"LABEL\": \"Arm Raise\",      \"TYPE\": \"float\", \"DEFAULT\": 1.0, \"MIN\": 0.0, \"MAX\": 1.0 },\n    { \"NAME\": \"waveCycle\",   \"LABEL\": \"Loop Length (s)\",\"TYPE\": \"float\", \"DEFAULT\": 6.0, \"MIN\": 2.0, \"MAX\": 20.0 },\n    { \"NAME\": \"waveSpeed\",   \"LABEL\": \"Wave Speed\",     \"TYPE\": \"float\", \"DEFAULT\": 1.6, \"MIN\": 0.0, \"MAX\": 5.0 },\n    { \"NAME\": \"waveAmount\",  \"LABEL\": \"Wave Amount\",    \"TYPE\": \"float\", \"DEFAULT\": 0.6, \"MIN\": 0.0, \"MAX\": 1.0 },\n    { \"NAME\": \"bodyFollow\",  \"LABEL\": \"Head Follow\",    \"TYPE\": \"float\", \"DEFAULT\": 0.5, \"MIN\": 0.0, \"MAX\": 1.0 },\n    { \"NAME\": \"waveLeft\",    \"LABEL\": \"Mirror Figure\",  \"TYPE\": \"bool\",  \"DEFAULT\": 0 },\n\n    { \"NAME\": \"pulse\",       \"TYPE\": \"float\", \"DEFAULT\": 0.0, \"MIN\": 0.0,  \"MAX\": 1.0 },\n    { \"NAME\": \"glow\",        \"TYPE\": \"float\", \"DEFAULT\": 0.0, \"MIN\": 0.0,  \"MAX\": 1.0 },\n    { \"NAME\": \"outlineMix\",  \"LABEL\": \"Outline Only\", \"TYPE\": \"float\", \"DEFAULT\": 0.0, \"MIN\": 0.0, \"MAX\": 1.0 },\n    { \"NAME\": \"lineWidth\",   \"LABEL\": \"Line Width\",   \"TYPE\": \"float\", \"DEFAULT\": 0.3, \"MIN\": 0.0, \"MAX\": 1.0 }\n  ]\n}*/\n\n// All geometry is measured off the 1000x1000 reference, in a y-up pixel frame\n// (Y = 1000 - imageY), so the numbers map straight back to the photo.\n// Every motion mode returns to the exact reference silhouette at rest.\n// \"Mirror Figure\" flips the sample point about the figure's centre line (x = 491),\n// which also moves the wave to the other arm, or turns the side-view walker to face left.\n\n#define PI      3.14159265\n#define HALF_PI 1.5707963\n\n// Reference rest geometry\n#define PELVIS   vec2(491.0, 452.0)\n#define HIP_L    vec2(445.5, 470.0)\n#define HIP_R    vec2(537.0, 470.0)\n#define FOOT_L   vec2(445.5, 153.5)\n#define FOOT_R   vec2(537.0, 153.5)\n#define LEG_SEG  158.25            // thigh = shin, so the rest leg is exactly straight\n\nbool g3D = false;                  // set in main: dance poses rendered as the 3D figure\n\nmat2 rot(float a) {\n    float c = cos(a), s = sin(a);\n    return mat2(c, -s, s, c);\n}\n\n// iq rounded box with per-corner radii: r = (topRight, bottomRight, topLeft, bottomLeft)\nfloat sdRoundBox(vec2 p, vec2 b, vec4 r) {\n    r.xy = (p.x > 0.0) ? r.xy : r.zw;\n    r.x  = (p.y > 0.0) ? r.x  : r.y;\n    vec2 q = abs(p) - b + r.x;\n    return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r.x;\n}\n\n// Box defined by min/max corners\nfloat boxMM(vec2 p, vec2 mn, vec2 mx, vec4 r) {\n    vec2 c = 0.5 * (mn + mx);\n    vec2 h = 0.5 * (mx - mn);\n    return sdRoundBox(p - c, h, r);\n}\n\nfloat sdSeg(vec2 p, vec2 a, vec2 b) {\n    vec2 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);\n}\n\nfloat dot2(vec2 v) { return dot(v, v); }\n\n// iq exact distance to a quadratic Bezier (A -> C, control B)\nfloat sdBezier(vec2 pos, vec2 A, vec2 B, vec2 C) {\n    vec2 a = B - A;\n    vec2 b = A - 2.0 * B + C;\n    vec2 c = a * 2.0;\n    vec2 d = A - pos;\n    float kk = 1.0 / dot(b, b);\n    float kx = kk * dot(a, b);\n    float ky = kk * (2.0 * dot(a, a) + dot(d, b)) / 3.0;\n    float kz = kk * dot(d, a);\n    float res;\n    float pp = ky - kx * kx;\n    float p3 = pp * pp * pp;\n    float qq = kx * (2.0 * kx * kx - 3.0 * ky) + kz;\n    float h = qq * qq + 4.0 * p3;\n    if (h >= 0.0) {\n        h = sqrt(h);\n        vec2 x = (vec2(h, -h) - qq) / 2.0;\n        vec2 uv = sign(x) * pow(abs(x), vec2(1.0 / 3.0));\n        float t = clamp(uv.x + uv.y - kx, 0.0, 1.0);\n        res = dot2(d + (c + b * t) * t);\n    } else {\n        float z = sqrt(-pp);\n        float v = acos(qq / (pp * z * 2.0)) / 3.0;\n        float m = cos(v);\n        float n = sin(v) * 1.732050808;\n        vec3 t = clamp(vec3(m + m, -n - m, n - m) * z - kx, 0.0, 1.0);\n        res = min(dot2(d + (c + b * t.x) * t.x), dot2(d + (c + b * t.y) * t.y));\n    }\n    return sqrt(res);\n}\n\nfloat smin(float a, float b, float k) {\n    k = max(k, 0.001);\n    float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0);\n    return mix(b, a, h) - k * h * (1.0 - h);\n}\n\n// Arm angle convention, per side: 0 = pointing outward from the body,\n// -PI/2 = hanging down, +PI/2 = straight up. sx = +1 screen right, -1 screen left.\nvec2 aDir(float a, float sx) {\n    return vec2(sx * cos(a), sin(a));\n}\n\n// How far an arm is lifted (drives the shoulder tuck and joint slide)\nfloat liftOf(float upper) {\n    return clamp((upper + HALF_PI) / (HALF_PI + 0.16), 0.0, 1.0);\n}\n\n// Ease with a small late overshoot, so the waving arm \"arrives\" instead of stopping dead\nfloat liftCurve(float x) {\n    x = clamp(x, 0.0, 1.0);\n    return smoothstep(0.0, 0.8, x) + 0.07 * sin(PI * clamp((x - 0.6) / 0.4, 0.0, 1.0));\n}\n\n// ---------------------------------------------------------------------------\n// Pose: everything the figure needs for one frame\n// ---------------------------------------------------------------------------\nstruct Pose {\n    vec2  body;      // upper-body offset (bounce / sway)\n    float tilt;      // upper-body roll around the pelvis (+ = counter-clockwise)\n    float headTilt;  // extra head roll around the neck\n    vec3  armL;      // left arm angles: (upper, forearm, nub)\n    vec2  lenL;      // left arm lengths: (forearm, nub)\n    vec3  armR;      // right arm angles\n    vec2  lenR;      // right arm lengths\n    vec2  footL;     // foot targets (world space)\n    vec2  footR;\n    float splay;     // how far knees bow outward when the legs bend (0..1)\n    // Whole-body transform (power moves, freezes)\n    vec2  gOff;      // whole-body offset\n    float gRot;      // whole-body rotation around the centre (+ = counter-clockwise)\n    float gScale;    // whole-body scale\n    float gSx;       // horizontal squash/flip, fakes spinning around the vertical axis (2D)\n    float gPitch;    // 3D: whole-body rotation about the screen-horizontal axis\n    float gYaw;      // 3D: whole-body rotation about the vertical axis (real spins)\n    float legFront;  // +1 right leg drawn in front, -1 left leg in front, 0 none\n    float grounded;  // 1 = drop/centre the whole body so its lowest point rests on the floor\n};\n\nvoid restPose(inout Pose P) {\n    P.body = vec2(0.0);\n    P.tilt = 0.0;\n    P.headTilt = 0.0;\n    P.armL = vec3(-HALF_PI);\n    P.armR = vec3(-HALF_PI);\n    P.lenL = vec2(103.0, 0.0);\n    P.lenR = vec2(103.0, 0.0);\n    P.footL = FOOT_L;\n    P.footR = FOOT_R;\n    P.splay = 0.45;\n    P.gOff = vec2(0.0);\n    P.gRot = 0.0;\n    P.gScale = 1.0;\n    P.gSx = 1.0;\n    P.gPitch = 0.0;\n    P.gYaw = 0.0;\n    P.legFront = 0.0;\n    P.grounded = 0.0;\n}\n\nPose mixPose(Pose A, Pose B, float t) {\n    Pose P;\n    P.body = mix(A.body, B.body, t);\n    P.tilt = mix(A.tilt, B.tilt, t);\n    P.headTilt = mix(A.headTilt, B.headTilt, t);\n    P.armL = mix(A.armL, B.armL, t);\n    P.lenL = mix(A.lenL, B.lenL, t);\n    P.armR = mix(A.armR, B.armR, t);\n    P.lenR = mix(A.lenR, B.lenR, t);\n    P.footL = mix(A.footL, B.footL, t);\n    P.footR = mix(A.footR, B.footR, t);\n    P.splay = mix(A.splay, B.splay, t);\n    P.gOff = mix(A.gOff, B.gOff, t);\n    P.gRot = mix(A.gRot, B.gRot, t);\n    P.gScale = mix(A.gScale, B.gScale, t);\n    P.gSx = mix(A.gSx, B.gSx, t);\n    P.gPitch = mix(A.gPitch, B.gPitch, t);\n    P.gYaw = mix(A.gYaw, B.gYaw, t);\n    P.legFront = (t < 0.5) ? A.legFront : B.legFront;\n    P.grounded = mix(A.grounded, B.grounded, t);\n    return P;\n}\n\n// Even-width arm tube: straight upper arm, then forearm + rounded nub as one\n// smooth Bezier curve (so a trailing nub bends the forearm instead of kinking).\n// With nub length 0 it is a plain straight capsule, identical to the reference arm.\nfloat armTube(vec2 p, vec2 S, float sx, float r, vec3 ang, vec2 len) {\n    vec2 E = S + 115.0 * aDir(ang.x, sx);\n    vec2 W = E + len.x * aDir(ang.y, sx);\n    vec2 T = W + len.y * aDir(ang.z, sx);\n    float dU = sdSeg(p, S, E) - r;\n    float dF = sdBezier(p, E, W, T) - r;\n    return smin(dU, dF, 4.0 * clamp(len.y / 30.0, 0.0, 1.0) + 0.001);\n}\n\n// Same arm, also returning just the forearm + nub part (used to carve a thin\n// black gap where a forearm crosses in front of the body)\nfloat armParts(vec2 p, vec2 S, float sx, float r, vec3 ang, vec2 len, out float dFore) {\n    vec2 E = S + 115.0 * aDir(ang.x, sx);\n    vec2 W = E + len.x * aDir(ang.y, sx);\n    vec2 T = W + len.y * aDir(ang.z, sx);\n    float dU = sdSeg(p, S, E) - r;\n    dFore = sdBezier(p, E, W, T) - r;\n    return smin(dU, dFore, 4.0 * clamp(len.y / 30.0, 0.0, 1.0) + 0.001);\n}\n\n// Knee position for the IK leg below (shared with the floor solver)\nvec2 kneeOf(vec2 H, vec2 F, float side, float splay, out vec2 Fp) {\n    vec2 d = F - H;\n    float len = max(length(d), 0.001);\n    vec2 dir = d / len;\n    float reach = min(len, 2.0 * LEG_SEG);\n    Fp = H + dir * reach;\n    float h = sqrt(max(LEG_SEG * LEG_SEG - 0.25 * reach * reach, 0.0));\n    vec2 perp = vec2(-dir.y, dir.x);\n    return H + dir * (0.5 * reach) + perp * h * splay * side;\n}\n\n// Two-bone leg with simple IK: hip H reaches for foot target F.\n// If F is out of reach the leg straightens toward it. side = -1 left, +1 right.\nfloat legTube(vec2 p, vec2 H, vec2 F, float r, float side, float splay) {\n    vec2 d = F - H;\n    float len = max(length(d), 0.001);\n    vec2 dir = d / len;\n    float reach = min(len, 2.0 * LEG_SEG);\n    vec2 Fp = H + dir * reach;\n    float h = sqrt(max(LEG_SEG * LEG_SEG - 0.25 * reach * reach, 0.0));\n    vec2 perp = vec2(-dir.y, dir.x);              // pointing +x for a leg hanging down\n    vec2 K = H + dir * (0.5 * reach) + perp * h * splay * side;\n    return min(sdSeg(p, H, K), sdSeg(p, K, Fp)) - r;\n}\n\nfloat figure(vec2 p, Pose P) {\n    // Upper-body space: undo the bounce/sway and roll around the pelvis\n    vec2 pu = rot(P.tilt) * (p - PELVIS - P.body) + PELVIS;\n\n    // Head, rolled around the neck\n    vec2 N = vec2(491.0, 772.0);\n    vec2 hp = rot(P.headTilt) * (pu - N) + N;\n    float head = length(hp - vec2(491.0, 854.0)) - 67.0;\n\n    // Shoulder yoke with rounded top corners. On a lifted side the shoulder cap\n    // tucks in and tightens, so the raised arm becomes the shoulder line.\n    float liftL = liftOf(P.armL.x);\n    float liftR = liftOf(P.armR.x);\n    float xL = mix(333.0, 407.0, liftL), rL = mix(80.0, 34.0, liftL);\n    float xR = mix(648.0, 576.0, liftR), rR = mix(80.0, 34.0, liftR);\n    float yoke = boxMM(pu, vec2(xL, 600.0), vec2(xR, 772.0), vec4(rR, 0.0, rL, 0.0));\n\n    // Below the armpit line outside the torso the arms own the space;\n    // the cut rises on a lifted side to make room for a clean armpit.\n    float cutL = boxMM(pu, vec2(-1000.0, -1000.0), vec2(407.0, 668.0 + 40.0 * liftL), vec4(0.0));\n    float cutR = boxMM(pu, vec2(576.0, -1000.0),  vec2(2000.0, 668.0 + 40.0 * liftR), vec4(0.0));\n    yoke = max(yoke, -min(cutL, cutR));\n\n    // Torso block down to the crotch\n    float torso = boxMM(pu, vec2(407.0, 452.0), vec2(576.0, 700.0), vec4(0.0));\n    float body = min(yoke, torso);\n\n    // Arms. Shoulder joints slide up and in as each arm lifts, so a raised arm\n    // comes out of the top of the shoulder instead of the armpit.\n    vec2 SL = mix(vec2(363.0, 700.0), vec2(404.0, 744.0), smoothstep(0.0, 0.6, liftL));\n    vec2 SR = mix(vec2(619.0, 700.0), vec2(578.0, 744.0), smoothstep(0.0, 0.6, liftR));\n    float foreL, foreR;\n    float armL = armParts(pu, SL, -1.0, 30.0, P.armL, P.lenL, foreL);\n    float armR = armParts(pu, SR,  1.0, 29.0, P.armR, P.lenR, foreR);\n\n    // Legs: hips ride with the upper body, feet go where the pose puts them\n    mat2 back = rot(-P.tilt);\n    vec2 HL = back * (HIP_L - PELVIS) + PELVIS + P.body;\n    vec2 HR = back * (HIP_R - PELVIS) + PELVIS + P.body;\n    float legL = legTube(p, HL, P.footL, 38.5, -1.0, P.splay);\n    float legR = legTube(p, HR, P.footR, 39.0,  1.0, P.splay);\n\n    // Pictogram layering: a forearm crossing in front of the chest, head, legs\n    // or the other arm is separated by a thin black gap (no effect at rest).\n    float gap = 10.0;\n    float fore = min(foreL, foreR) - gap;\n    body = max(body, -fore);\n    head = max(head, -fore);\n    legL = max(legL, -fore);\n    legR = max(legR, -fore);\n    armL = max(armL, -(foreR - gap));            // right forearm passes in front of the left arm\n    if (P.legFront > 0.5)  legL = max(legL, -(legR - gap));\n    if (P.legFront < -0.5) legR = max(legR, -(legL - gap));\n\n    // Blend lifted arms into the shoulder/armpit; razor sharp at rest\n    float d = smin(body, armR, 0.5 + 24.0 * liftR);\n    d = smin(d, armL, 0.5 + 24.0 * liftL);\n    d = min(d, head);\n    d = min(d, min(legL, legR));\n    return d;\n}\n\n// Whole-body transform: rotate / scale / squash the figure around its centre\n#define GPIV vec2(491.0, 500.0)\nfloat figureG(vec2 p, Pose P) {\n    float sx = sign(P.gSx) * max(abs(P.gSx), 0.12);\n    vec2 lp = rot(P.gRot) * (p - GPIV - P.gOff);\n    lp.x /= sx;\n    lp = lp / P.gScale + GPIV;\n    return figure(lp, P) * P.gScale * min(abs(sx), 1.0);\n}\n\n// Figure-local point -> world\nvec2 toWorld(vec2 L, Pose P) {\n    float sx = sign(P.gSx) * max(abs(P.gSx), 0.12);\n    vec2 v = (L - GPIV) * P.gScale;\n    v.x *= sx;\n    return GPIV + P.gOff + rot(-P.gRot) * v;\n}\n\nvoid addPt(vec2 L, float r, Pose P, inout vec4 box) {\n    vec2 w = toWorld(L, P);\n    float rr = r * P.gScale;\n    box.x = min(box.x, w.x - rr); box.y = min(box.y, w.y - rr);\n    box.z = max(box.z, w.x + rr); box.w = max(box.w, w.y + rr);\n}\n\n// Bounding box of the posed body's key joints (head, hands, elbows, knees, feet)\nvec4 bodyBox(Pose P) {\n    vec4 box = vec4(1e5, 1e5, -1e5, -1e5);\n    mat2 back = rot(-P.tilt);\n    vec2 N = vec2(491.0, 772.0);\n    vec2 hc = rot(-P.headTilt) * (vec2(491.0, 854.0) - N) + N;\n    addPt(back * (hc - PELVIS) + PELVIS + P.body, 67.0, P, box);\n\n    float liftL = liftOf(P.armL.x), liftR = liftOf(P.armR.x);\n    vec2 SL = mix(vec2(363.0, 700.0), vec2(404.0, 744.0), smoothstep(0.0, 0.6, liftL));\n    vec2 SR = mix(vec2(619.0, 700.0), vec2(578.0, 744.0), smoothstep(0.0, 0.6, liftR));\n    for (int i = 0; i < 2; i++) {\n        float sx = (i == 0) ? -1.0 : 1.0;\n        vec2 S = (i == 0) ? SL : SR;\n        vec3 a = (i == 0) ? P.armL : P.armR;\n        vec2 l = (i == 0) ? P.lenL : P.lenR;\n        vec2 E = S + 115.0 * aDir(a.x, sx);\n        vec2 W = E + l.x * aDir(a.y, sx);\n        vec2 T = W + l.y * aDir(a.z, sx);\n        addPt(back * (E - PELVIS) + PELVIS + P.body, 29.0, P, box);\n        addPt(back * (W - PELVIS) + PELVIS + P.body, 29.0, P, box);\n        addPt(back * (T - PELVIS) + PELVIS + P.body, 29.0, P, box);\n    }\n    vec2 HL = back * (HIP_L - PELVIS) + PELVIS + P.body;\n    vec2 HR = back * (HIP_R - PELVIS) + PELVIS + P.body;\n    vec2 FpL, FpR;\n    vec2 KL = kneeOf(HL, P.footL, -1.0, P.splay, FpL);\n    vec2 KR = kneeOf(HR, P.footR,  1.0, P.splay, FpR);\n    addPt(KL, 38.5, P, box); addPt(FpL, 38.5, P, box);\n    addPt(KR, 39.0, P, box); addPt(FpR, 39.0, P, box);\n    addPt(HL, 38.5, P, box); addPt(HR, 39.0, P, box);\n    return box;\n}\n\n// Floor solver: drop the whole figure so its lowest point rests on the floor\n// (Y 115), centred in the tile\nvoid groundPose(inout Pose P) {\n    if (P.grounded < 0.001) return;\n    vec4 box = bodyBox(P);\n    vec2 shift = vec2(491.0 - 0.5 * (box.x + box.z), 115.0 - box.y);\n    P.gOff += shift * P.grounded;\n}\n\n// Only push the figure back up if a blend has dipped it through the floor\nvoid floorClamp(inout Pose P) {\n    vec4 box = bodyBox(P);\n    P.gOff.y += max(0.0, 115.0 - box.y);\n}\n\n// ---------------------------------------------------------------------------\n// Motion modes\n// ---------------------------------------------------------------------------\n\n// Wave: elbow-led lift, forearm wave with trailing nub, auto loop or manual\nvoid poseWave(inout Pose P, float t) {\n    float ph = fract(t / waveCycle);\n    float autoRaise = smoothstep(0.06, 0.24, ph) * (1.0 - smoothstep(0.80, 0.96, ph));\n    float raise = waveAuto ? autoRaise * waveRaise : waveRaise;\n\n    float lift = liftCurve(raise);\n    float fold = smoothstep(0.35, 1.0, raise);\n    float env  = smoothstep(0.78, 1.0, raise);\n\n    // Style presets: pose = (upper angle, elbow bend), amp = (forearm, nub flick, shoulder)\n    float style = float(waveStyle);\n    vec2 pose = vec2(0.16, 1.22);\n    vec3 amp  = vec3(0.75, 0.30, 0.00);\n    if (style > 0.5 && style < 1.5) {\n        pose = vec2(0.22, 1.12); amp = vec3(0.08, 0.60, 0.00);\n    } else if (style > 1.5) {\n        pose = vec2(0.08, 0.86); amp = vec3(0.10, 0.30, 0.27);\n    }\n\n    float w   = t * waveSpeed * 2.0 * PI;\n    float A   = waveAmount * env;\n    float osc = sin(w);\n    float lag = sin(w - 1.1);\n\n    float upper = mix(-HALF_PI, pose.x, lift) + A * (amp.z - 0.25 * amp.x) * osc;\n    float foreHang = min(upper, -HALF_PI + 0.3);\n    float foreUp   = upper + pose.y + A * amp.x * osc;\n    float fore = mix(foreHang, foreUp, fold);\n    float nub  = fore - 0.12 * fold + A * amp.y * lag;\n\n    P.armR = vec3(upper, fore, nub);\n    P.lenR = vec2(mix(103.0, 84.0, fold), 30.0 * fold);\n    P.headTilt = bodyFollow * (0.09 * clamp(lift, 0.0, 1.0) + 0.035 * A * sin(w - 1.8));\n}\n\n// ---------------------------------------------------------------------------\n// Side view (Walk / Run): the figure turns to profile, facing screen right.\n// Angles here are measured from straight down, + = forward (toward +x).\n// ---------------------------------------------------------------------------\nstruct Side {\n    float lean;      // torso lean from the hip (+ = forward)\n    float hipY;      // hip joint height (feet are planted from this)\n    float headTilt;  // head nod\n    vec3  armN;      // near arm: (upper, forearm, nub) angles, relative to the torso\n    vec3  armF;      // far arm\n    float nubLen;    // trailing nub length (0 = plain round end like the reference)\n    float farBack;   // how far back the far shoulder sits\n    vec2  legN;      // near leg: (thigh angle, knee bend; + bends the shin back)\n    vec2  legF;      // far leg\n};\n\nvec2 dDown(float a) { return vec2(sin(a), -cos(a)); }\n\n// iq uneven capsule: p relative to the bottom centre, axis +y, radii r1 (bottom) / r2 (top)\nfloat sdUnevenCapsule(vec2 p, float r1, float r2, float h) {\n    p.x = abs(p.x);\n    float b = (r1 - r2) / h;\n    float a = sqrt(1.0 - b * b);\n    float k = dot(p, vec2(-b, a));\n    if (k < 0.0) return length(p) - r1;\n    if (k > a * h) return length(p - vec2(0.0, h)) - r2;\n    return dot(p, vec2(a, b)) - r1;\n}\n\n// Vertical reach of a leg from hip to ankle\nfloat legDrop(vec2 leg) {\n    return LEG_SEG * (cos(leg.x) + cos(leg.x - leg.y));\n}\n\n// Profile leg: thigh, shin, and a rounded shoe toe so the foot reads in profile.\n// The toe sits flush with the sole of the round heel so the outline stays clean.\nfloat sideLeg(vec2 p, vec2 H, vec2 leg, float r) {\n    vec2 K = H + LEG_SEG * dDown(leg.x);\n    float shin = leg.x - leg.y;\n    vec2 A = K + LEG_SEG * dDown(shin);\n    vec2 fwd = vec2(cos(shin), sin(shin));              // 90deg forward of the shin\n    vec2 t0 = A + dDown(shin) * (r - 30.0) + fwd * 6.0;\n    // Never let the toe dig into the ground (Y 115): near the floor the foot\n    // pivots flat on its toe as the heel lifts.\n    float minY = (145.0 - t0.y) / 40.0;\n    if (fwd.y < minY) {\n        fwd.y = clamp(minY, -1.0, 1.0);\n        fwd.x = sqrt(max(1.0 - fwd.y * fwd.y, 0.0));\n    }\n    float d = min(sdSeg(p, H, K), sdSeg(p, K, A)) - r;\n    return smin(d, sdSeg(p, t0, t0 + fwd * 40.0) - 30.0, 16.0);\n}\n\n// Profile arm: same even-width tube and rounded nub as the front-view arm\nfloat sideArm(vec2 p, vec2 S, vec3 ang, float nubLen) {\n    vec2 E = S + 115.0 * dDown(ang.x);\n    vec2 W = E + 103.0 * dDown(ang.y);\n    vec2 T = W + nubLen * dDown(ang.z);\n    float dU = sdSeg(p, S, E) - 29.0;\n    float dF = sdBezier(p, E, W, T) - 29.0;\n    return smin(dU, dF, 4.0 * clamp(nubLen / 30.0, 0.0, 1.0) + 0.001);\n}\n\nfloat figureSide(vec2 p, Side P) {\n    vec2 H = vec2(491.0, P.hipY);\n    vec2 u = vec2(sin(P.lean), cos(P.lean));      // torso axis\n    vec2 n = vec2(u.y, -u.x);\n\n    // Torso: profile chest/back, a little fuller at the chest than the hips\n    vec2 B = H + u * 30.0;\n    vec2 tp = vec2(dot(p - B, n), dot(p - B, u));\n    float torso = sdUnevenCapsule(tp, 60.0, 70.0, 210.0);\n\n    // Head rides the torso, nodding around the neck\n    vec2 neck = H + u * 300.0;\n    vec2 hc = neck + 84.0 * vec2(sin(P.lean * 0.6 + P.headTilt), cos(P.lean * 0.6 + P.headTilt));\n    float head = length(p - hc) - 67.0;\n\n    // Limbs. Arm angles are relative to the torso, so a lean carries them forward.\n    // The far shoulder can sit a touch back, so a far arm swung behind shows as a\n    // clear shape instead of slivers along the torso edge.\n    vec2 S  = H + u * 236.0;\n    vec2 SF = S - n * P.farBack + u * 6.0;\n    float armN = sideArm(p, S,  P.armN + P.lean * 0.6, P.nubLen);\n    float armF = sideArm(p, SF, P.armF + P.lean * 0.6, P.nubLen);\n    float legN = sideLeg(p, H, P.legN, 38.5);\n    float legF = sideLeg(p, H, P.legF, 38.5);\n\n    // Pictogram layering: far limbs sit behind, separated by a thin black gap\n    float gap = 10.0;\n    float back = min(armF, legF);\n    back = max(back, -(legN - gap));             // near leg in front of far leg\n    back = max(back, -(torso - gap));            // far arm and far hip tuck behind the torso\n    float d = min(min(torso, head), legN);\n    d = smin(d, back, 0.5);\n    // Near arm on top of everything with its own gap\n    d = max(d, -(armN - gap));\n    d = min(d, armN);\n    return d;\n}\n\n// Walk: profile gait. Thigh swing, knee folds in early swing, a little flex on\n// landing; the hip height is solved so the standing foot stays on the ground.\nvoid poseWalkSide(inout Side P, float beats, float E) {\n    float ph = PI * beats;                         // one step per beat, stride every 2\n    for (int i = 0; i < 2; i++) {\n        float f = ph + float(i) * PI;\n        float th = 0.08 + 0.36 * sin(f);\n        float kn = 0.08 + 0.95 * pow(max(0.0, cos(f + 0.35)), 2.0)\n                        + 0.18 * pow(max(0.0, cos(f - 2.1)), 4.0);\n        vec2 leg = vec2(th, kn) * E;\n        float sw = -0.38 * sin(f);                 // arm swings opposite its leg\n        vec3 arm = vec3(sw, sw + 0.22 + 0.25 * max(0.0, -sin(f)), 0.0) * E;\n        arm.z = arm.y;\n        if (i == 0) { P.legN = leg; P.armF = arm; } else { P.legF = leg; P.armN = arm; }\n    }\n    P.hipY = FOOT_L.y + max(legDrop(P.legN), legDrop(P.legF));\n    P.lean = 0.05 * E;\n    P.headTilt = bodyFollow * 0.05 * E * sin(2.0 * ph + 0.6);\n    P.nubLen = 0.0;\n    P.farBack = 0.0;                               // far arm hides behind the body at mid-swing\n}\n\n// Run: longer stride, high heel kick, bent pumping arms, forward lean and a\n// short flight phase as stance switches feet.\nvoid poseRunSide(inout Side P, float beats, float E) {\n    float ph = 2.0 * PI * beats;                   // one stride (two steps) per beat\n    for (int i = 0; i < 2; i++) {\n        float f = ph + float(i) * PI;\n        float th = 0.10 + 0.55 * sin(f) + 0.22 * sin(2.0 * f);\n        float kn = 0.30 + 1.75 * pow(max(0.0, cos(f + 0.45)), 1.6)\n                        + 0.35 * pow(max(0.0, cos(f - 2.9)), 2.0);\n        vec2 leg = vec2(th, kn) * E;\n        float sw = -0.80 * sin(f);\n        vec3 arm = vec3(sw, sw + 1.55 + 0.20 * sin(f), 0.0);\n        arm = mix(vec3(0.0), arm, E);\n        arm.z = arm.y + 0.25 * E * cos(f);         // nub trails the pump\n        if (i == 0) { P.legN = leg; P.armF = arm; } else { P.legF = leg; P.armN = arm; }\n    }\n    float dn = legDrop(P.legN), df = legDrop(P.legF);\n    float flight = 24.0 * E * pow(clamp(1.0 - abs(dn - df) / 70.0, 0.0, 1.0), 2.0);\n    P.hipY = FOOT_L.y + max(dn, df) + flight;\n    P.lean = 0.20 * E;\n    P.headTilt = bodyFollow * (-0.08 * E + 0.05 * E * sin(2.0 * ph));\n    P.nubLen = 18.0 * E;\n    P.farBack = 24.0 * E;\n}\n\n// Dance: side-to-side groove, dip on every beat, heel pops, alternating arm raises\nvoid poseDance(inout Pose P, float beats, float E) {\n    float ph  = PI * beats;                        // full groove every two beats\n    float s   = sin(ph);\n    float dip = 0.5 + 0.5 * cos(2.0 * ph);         // 1 on each beat\n    P.body = vec2(24.0 * E * s, -14.0 * E * dip);\n    P.tilt = -0.07 * E * s;                        // lean into the sway\n    P.headTilt = bodyFollow * 0.12 * E * sin(ph + 0.8);\n\n    // Slightly wider stance, unweighted heel pops up\n    P.footL = FOOT_L + vec2(-20.0 * E, 18.0 * E * pow(max( s, 0.0), 2.0));\n    P.footR = FOOT_R + vec2( 20.0 * E, 18.0 * E * pow(max(-s, 0.0), 2.0));\n    P.splay = 0.6;\n\n    float upR = smoothstep(0.1, 0.9, 0.5 + 0.5 * s);\n    float upL = smoothstep(0.1, 0.9, 0.5 - 0.5 * s);\n    float pump = 0.15 * (dip - 0.5);\n    float lagR = 0.25 * cos(ph), lagL = -lagR;\n\n    float uR = mix(-1.25, 0.45, upR), aR = mix(-0.35, 1.35, upR) + pump;\n    float uL = mix(-1.25, 0.45, upL), aL = mix(-0.35, 1.35, upL) + pump;\n    P.armR = mix(vec3(-HALF_PI), vec3(uR, aR, aR - 0.1 * upR + lagR), E);\n    P.armL = mix(vec3(-HALF_PI), vec3(uL, aL, aL - 0.1 * upL + lagL), E);\n    P.lenR = mix(vec2(103.0, 0.0), vec2(mix(95.0, 84.0, upR), mix(16.0, 30.0, upR)), E);\n    P.lenL = mix(vec2(103.0, 0.0), vec2(mix(95.0, 84.0, upL), mix(16.0, 30.0, upL)), E);\n}\n\n\n// ---------------------------------------------------------------------------\n// Hip-hop and breaking styles (Dance mode -> Dance Style)\n// ---------------------------------------------------------------------------\nfloat gbump(float x) { return exp(-1.4 * x * x); }\nfloat wrapAng(float a) { return mod(a + PI, 2.0 * PI) - PI; }\n\n// Blend two poses, taking the short way round for the whole-body rotation\nPose blendPose(Pose A, Pose B, float t) {\n    B.gRot   = A.gRot   + wrapAng(B.gRot   - A.gRot);\n    B.gPitch = A.gPitch + wrapAng(B.gPitch - A.gPitch);\n    B.gYaw   = A.gYaw   + wrapAng(B.gYaw   - A.gYaw);\n    return mixPose(A, B, t);\n}\n\n// Hip-Hop Bounce: knees drop on every beat, shoulders rock, wide stance,\n// arms swing across the chest one beat at a time\nvoid danceBounce(inout Pose P, float b, float E) {\n    float down = pow(abs(cos(PI * b)), 3.0);      // 1 on every beat\n    float rock = sin(PI * b);                     // alternates each beat\n    float s    = sin(PI * b * 0.5);               // drift side to side over two beats\n    P.body = vec2(26.0 * s, 4.0 - 24.0 * down) * E;\n    P.tilt = 0.08 * E * rock;\n    P.headTilt = bodyFollow * 0.14 * E * sin(PI * b - 0.7);\n    P.footL = FOOT_L + vec2(-32.0 + 18.0 * s, 16.0 * max(0.0,  s) * abs(rock)) * E;\n    P.footR = FOOT_R + vec2( 32.0 + 18.0 * s, 16.0 * max(0.0, -s) * abs(rock)) * E;\n    P.splay = 0.75;\n    float x = 0.5 + 0.5 * rock;                   // right arm crosses on one beat, left on the next\n    vec3 crossA = vec3(-1.40, 2.65, 2.85);\n    vec3 outA   = vec3(-0.90, -0.25, -0.45);\n    P.armR = mix(vec3(-HALF_PI), mix(outA, crossA, x), E);\n    P.armL = mix(vec3(-HALF_PI), mix(outA, crossA, 1.0 - x), E);\n    P.lenR = mix(vec2(103.0, 0.0), vec2(mix(100.0, 92.0, x), 16.0), E);\n    P.lenL = mix(vec2(103.0, 0.0), vec2(mix(100.0, 92.0, 1.0 - x), 16.0), E);\n}\n\n// Running Man: knee drives up on each beat while the arms reach forward,\n// then the foot slides back down and the arms push to the floor\nvoid danceRunningMan(inout Pose P, float b, float E) {\n    float k = sin(PI * b);                        // left knee on one beat, right on the next\n    float a = smoothstep(0.0, 1.0, abs(k));\n    P.footL += vec2(-10.0, 105.0 * pow(max( k, 0.0), 1.3)) * E;\n    P.footR += vec2( 10.0, 105.0 * pow(max(-k, 0.0), 1.3)) * E;\n    P.splay = 0.35;\n    P.body = vec2(6.0 * k, -16.0 * (1.0 - abs(k))) * E;\n    P.tilt = -0.03 * E * k;\n    P.headTilt = bodyFollow * 0.08 * E * k;\n    vec3 up   = vec3(-1.10, 2.10, 2.30);\n    vec3 down = vec3(-1.45, -1.55, -1.55);\n    P.armR = mix(vec3(-HALF_PI), mix(down, up, a), E);\n    P.armL = P.armR;\n    P.lenR = mix(vec2(103.0, 0.0), mix(vec2(103.0, 0.0), vec2(58.0, 18.0), a), E);\n    P.lenL = P.lenR;\n}\n\n// Robot key poses: hard right angles, held between hits\nvoid robotKey(float i, inout Pose P) {\n    i = mod(i, 6.0);\n    if (i < 0.5) {\n        P.armR = vec3(0.0, HALF_PI, HALF_PI);     P.armL = vec3(-HALF_PI, 0.0, 0.0);\n        P.headTilt = 0.12;\n    } else if (i < 1.5) {\n        P.armR = vec3(-HALF_PI, 0.0, 0.0);        P.armL = vec3(0.0, HALF_PI, HALF_PI);\n        P.headTilt = -0.12;\n    } else if (i < 2.5) {\n        P.armR = vec3(0.0, -HALF_PI, -HALF_PI);   P.armL = P.armR;\n        P.tilt = 0.05;  P.footR.x += 30.0;\n    } else if (i < 3.5) {\n        P.armR = vec3(0.0, HALF_PI, HALF_PI);     P.armL = P.armR;\n        P.tilt = -0.05; P.footL.x -= 30.0;\n    } else if (i < 4.5) {\n        P.armR = vec3(-0.75, 2.45, 2.45);         P.armL = vec3(-HALF_PI);\n        P.tilt = -0.08; P.headTilt = 0.22;\n    } else {\n        P.armL = vec3(-0.75, 2.45, 2.45);         P.armR = vec3(-HALF_PI);\n        P.tilt = 0.08;  P.headTilt = -0.22;\n    }\n}\n\n// Robot / Popping: snaps into a new key pose right on each beat, with a small\n// 'pop' jitter and dip on the hit, then holds still\nvoid danceRobot(inout Pose P, float b, float E) {\n    float k = floor(b), f = fract(b);\n    Pose A = P, B = P;\n    robotKey(k - 1.0, A);\n    robotKey(k, B);\n    Pose R = mixPose(A, B, smoothstep(0.0, 0.16, f));\n    float hit = exp(-f * 12.0);\n    float buzz = 0.05 * sin(f * 70.0) * hit;\n    R.tilt += buzz;\n    R.headTilt += buzz * 1.5;\n    R.body.y -= 10.0 * hit;\n    P = mixPose(P, R, E);\n}\n\n// Arm Wave: a wave rolls from the left nub through the elbows and shoulders to\n// the right nub, then back, with the shoulders popping as it passes the chest\nvoid danceArmWave(inout Pose P, float b, float E) {\n    float u = fract(b / 4.0) * 2.0;               // across in 2 beats, back in 2\n    float c = (u < 1.0) ? mix(-1.0, 7.0, u) : mix(7.0, -1.0, u - 1.0);\n    float A = 85.0;\n    float hLT = A * gbump(c - 0.0), hLW = A * gbump(c - 0.9), hLE = A * gbump(c - 1.8), hLS = A * gbump(c - 2.7);\n    float hRS = A * gbump(c - 3.3), hRE = A * gbump(c - 4.2), hRW = A * gbump(c - 5.1), hRT = A * gbump(c - 6.0);\n    vec3 aL = vec3(atan(hLE - hLS, 115.0), atan(hLW - hLE, 90.0), atan(hLT - hLW, 30.0));\n    vec3 aR = vec3(atan(hRE - hRS, 115.0), atan(hRW - hRE, 90.0), atan(hRT - hRW, 30.0));\n    P.armL = mix(vec3(-HALF_PI), aL, E);\n    P.armR = mix(vec3(-HALF_PI), aR, E);\n    P.lenL = mix(vec2(103.0, 0.0), vec2(90.0, 30.0), E);\n    P.lenR = P.lenL;\n    float pop = gbump(c - 3.3) - gbump(c - 2.7);\n    P.tilt = 0.10 * E * pop;\n    P.headTilt = bodyFollow * 0.10 * E * pop;\n    P.body = vec2(0.0, -8.0 * pow(abs(cos(PI * b)), 2.0) + 12.0 * gbump(c - 3.0)) * E;\n    P.splay = 0.6;\n}\n\n// Toprock (Indian step): the right foot kicks across in front, arms open wide,\n// back to centre with the arms folded, then the left foot crosses\nvoid danceToprock(inout Pose P, float b, float E) {\n    float s  = sin(PI * b * 0.5);\n    float cR = smoothstep(0.0, 1.0, max( s, 0.0));\n    float cL = smoothstep(0.0, 1.0, max(-s, 0.0));\n    float bounce = pow(abs(cos(PI * b)), 2.0);\n    P.body = vec2(-30.0 * cR + 30.0 * cL, 6.0 - 14.0 * bounce) * E;\n    P.tilt = (0.12 * cR - 0.12 * cL) * E;\n    // the kicking foot crosses well past the standing one, which steps out a touch\n    P.footR = FOOT_R + vec2(10.0 - 230.0 * cR + 30.0 * cL, 30.0 * cR * (1.0 - bounce)) * E;\n    P.footL = FOOT_L + vec2(230.0 * cL - 10.0 - 30.0 * cR, 30.0 * cL * (1.0 - bounce)) * E;\n    P.legFront = (s > 0.0) ? 1.0 : -1.0;\n    P.splay = 0.4;\n    P.headTilt = bodyFollow * 0.10 * E * s;\n    float o = max(cR, cL);\n    vec3 arm = mix(vec3(-1.25, 2.55, 2.75), vec3(0.25, 0.65, 0.85), o);\n    P.armR = mix(vec3(-HALF_PI), arm, E);\n    P.armL = P.armR;\n    P.lenR = mix(vec2(103.0, 0.0), vec2(95.0, 26.0), E);\n    P.lenL = P.lenR;\n}\n\n// Six-Step: dropped low on the floor, one hand planted, the feet circling\n// around and crossing through; the planted hand switches as the feet come round\nvoid danceSixStep(inout Pose P, float b, float E) {\n    float a = PI * b * 0.5 * spinSpeed;           // one circuit every 4 beats\n    float c = cos(a), s = sin(a);\n    float tau = 0.52 * c;                         // lean onto the planted hand\n    P.body = vec2(0.0, -250.0) * E;\n    P.tilt = tau * E;\n    vec2 fl = vec2(491.0 - 210.0 * c + 60.0 * s, 158.0 + 55.0 * max(0.0,  s));\n    vec2 fr = vec2(491.0 + 210.0 * c + 60.0 * s, 158.0 + 55.0 * max(0.0, -s));\n    P.footL = mix(FOOT_L, fl, E);\n    P.footR = mix(FOOT_R, fr, E);\n    P.legFront = (s > 0.0) ? -1.0 : 1.0;\n    P.splay = 0.9;\n    float plantL = smoothstep(-0.35, 0.35, c);    // left hand down while leaning left\n    vec3 plant = vec3(-HALF_PI + abs(tau));       // straight down to the floor once leaning\n    vec3 free  = vec3(0.25, 1.45, 1.75);\n    P.armL = mix(vec3(-HALF_PI), mix(free, plant, plantL), E);\n    P.armR = mix(vec3(-HALF_PI), mix(plant, free, plantL), E);\n    P.lenL = mix(vec2(103.0, 0.0), vec2(103.0, mix(24.0, 0.0, plantL)), E);\n    P.lenR = mix(vec2(103.0, 0.0), vec2(103.0, mix(0.0, 24.0, plantL)), E);\n    P.headTilt = bodyFollow * 0.12 * E * c;\n    P.grounded = E;\n}\n\n// Windmill: the body rolls around on the floor with the legs out in a wide V,\n// scissoring open and closed, one arm tucked across the chest\nvoid danceWindmill(inout Pose P, float b, float E) {\n    float ang = -PI * b * spinSpeed;              // one full roll every 2 beats\n    float v = 1.0 + 0.25 * sin(2.0 * ang);\n    P.footL = mix(FOOT_L, vec2(491.0 - 230.0 * v, 205.0), E);\n    P.footR = mix(FOOT_R, vec2(491.0 + 230.0 * v, 205.0), E);\n    P.splay = 0.2;\n    P.armR = mix(vec3(-HALF_PI), vec3(-1.25, 2.50, 2.70), E);\n    P.armL = mix(vec3(-HALF_PI), vec3(-0.20, 0.60, 0.90), E);\n    P.lenR = mix(vec2(103.0, 0.0), vec2(85.0, 20.0), E);\n    P.lenL = P.lenR;\n    P.gRot = wrapAng(ang) * E;\n    P.gScale = mix(1.0, 0.70, E);\n    P.grounded = E;\n    if (g3D) {\n        // 3D: lying across the floor, rolling over the back and shoulders while\n        // the V of the legs sweeps round, tipped so the circle reads in depth\n        P.gRot   = -1.35 * E;\n        P.gPitch = wrapAng(ang) * E;\n        P.gYaw   = 0.25 * E * sin(ang);\n        P.gScale = mix(1.0, 0.78, E);\n    }\n}\n\n// Headspin: upside down on the head, arms out for balance, one leg out and\n// one tucked so the spin reads as the figure flips round\nvoid danceHeadspin(inout Pose P, float b, float E) {\n    float spin = 2.0 * PI * b * spinSpeed;        // one revolution per beat\n    P.gRot = PI * E;\n    P.gSx = mix(1.0, cos(spin), E);\n    P.gScale = mix(1.0, 0.78, E);\n    P.footL = mix(FOOT_L, vec2(250.0, 225.0), E);\n    P.footR = mix(FOOT_R, vec2(560.0, 330.0), E);\n    P.splay = 0.9;\n    P.legFront = 1.0;\n    P.armR = mix(vec3(-HALF_PI), vec3(0.05, 0.25, 0.35), E);\n    P.armL = mix(vec3(-HALF_PI), vec3(0.05, 0.25, 0.35), E);\n    P.lenR = mix(vec2(103.0, 0.0), vec2(95.0, 20.0), E);\n    P.lenL = P.lenR;\n    P.tilt = 0.05 * E * sin(spin);\n    P.grounded = E;\n    if (g3D) {\n        // 3D: a real spin around the vertical axis while balanced on the head\n        P.gSx = 1.0;\n        P.gYaw = wrapAng(spin) * E;\n        P.tilt = 0.04 * E * sin(spin * 0.5);\n    }\n}\n\n// Freeze key poses (held, the floor solver plants whichever part is lowest)\nvoid freezeKey(float i, inout Pose P) {\n    i = mod(i, 4.0);\n    P.grounded = 1.0;\n    P.gScale = 0.78;\n    if (i < 0.5) {                                // handstand split\n        P.gRot = PI;\n        P.armR = vec3(HALF_PI - 0.15);  P.armL = P.armR;\n        P.lenR = vec2(103.0, 0.0);      P.lenL = P.lenR;\n        P.footL = vec2(230.0, 260.0);   P.footR = vec2(752.0, 260.0);\n        P.splay = 0.0;\n    } else if (i < 1.5) {                         // chair freeze: tipped onto one straight arm, knees tucked\n        P.gRot = -1.15;\n        P.armR = vec3(-0.15);\n        P.armL = vec3(0.9, 1.9, 2.1);   P.lenL = vec2(90.0, 24.0);\n        P.footL = vec2(400.0, 330.0);   P.footR = vec2(600.0, 360.0);\n        P.splay = 1.0;\n        P.headTilt = 0.25;\n    } else if (i < 2.5) {                         // baby freeze: on its side, knees tucked, one leg out\n        P.gRot = 1.95;\n        P.armL = vec3(0.2);\n        P.armR = vec3(-1.3, 2.4, 2.6);  P.lenR = vec2(85.0, 20.0);\n        P.footL = vec2(330.0, 230.0);   P.footR = vec2(560.0, 360.0);\n        P.splay = 0.8;\n        P.headTilt = -0.2;\n    } else {                                      // one-arm pike hold: inverted, legs together and angled\n        P.gRot = PI - 0.45;\n        P.armR = vec3(HALF_PI - 0.1);\n        P.armL = vec3(0.3, 0.9, 1.0);   P.lenL = vec2(95.0, 26.0);\n        P.footL = vec2(470.0, 150.0);   P.footR = vec2(520.0, 150.0);\n        P.legFront = 1.0;\n        P.splay = 0.2;\n    }\n}\n\n// Freezes: hit a new freeze every two beats and hold it, with a little pop on the hit\nvoid danceFreezes(inout Pose P, float b, float E) {\n    float k = floor(b * 0.5), f = fract(b * 0.5);\n    Pose A = P, B = P;\n    freezeKey(k - 1.0, A);\n    freezeKey(k, B);\n    Pose R = blendPose(A, B, smoothstep(0.0, 0.14, f));\n    R.gScale *= 1.0 + 0.04 * exp(-f * 14.0) * sin(f * 40.0);\n    P = blendPose(P, R, E);\n}\n\nvoid danceStyleN(float st, inout Pose P, float b, float E) {\n    if (st < 0.5)      poseDance(P, b, E);\n    else if (st < 1.5) danceBounce(P, b, E);\n    else if (st < 2.5) danceRunningMan(P, b, E);\n    else if (st < 3.5) danceRobot(P, b, E);\n    else if (st < 4.5) danceArmWave(P, b, E);\n    else if (st < 5.5) danceToprock(P, b, E);\n    else if (st < 6.5) danceSixStep(P, b, E);\n    else if (st < 7.5) danceWindmill(P, b, E);\n    else if (st < 8.5) danceHeadspin(P, b, E);\n    else               danceFreezes(P, b, E);\n}\n\n// Breaking Combo: a 16-beat routine that flows Toprock (8) -> drop into\n// Six-Step (4) -> Windmill (2) -> hit a freeze (2), then back up to Toprock\nvoid danceCombo(inout Pose P, float b, float E) {\n    float c = mod(b, 16.0);\n    float cur = 5.0, prev = 9.0, t0 = 0.0;\n    if (c >= 8.0 && c < 12.0)  { cur = 6.0; prev = 5.0; t0 = 8.0;  }\n    else if (c >= 12.0 && c < 14.0) { cur = 7.0; prev = 6.0; t0 = 12.0; }\n    else if (c >= 14.0) { cur = 9.0; prev = 7.0; t0 = 14.0; }\n\n    Pose A = P, B = P;\n    if (prev > 8.5) { freezeKey(3.0, A); A = mixPose(P, A, E); } else danceStyleN(prev, A, b, E);\n    if (cur  > 8.5) { freezeKey(3.0, B); B = mixPose(P, B, E); } else danceStyleN(cur,  B, b, E);\n    if (g3D) {                                    // the 3D rig plants itself after blending\n        P = blendPose(A, B, smoothstep(t0, t0 + 0.6, c));\n        return;\n    }\n    groundPose(A);\n    groundPose(B);\n    A.grounded = 0.0;                             // already planted\n    B.grounded = 0.0;\n    P = blendPose(A, B, smoothstep(t0, t0 + 0.6, c));\n    floorClamp(P);\n}\n\nvoid poseDanceStyle(inout Pose P, float b, float E) {\n    float st = float(danceStyle);\n    if (st > 9.5) danceCombo(P, b, E);\n    else danceStyleN(st, P, b, E);\n}\n\n// Jumping jacks: hop on each switch, land open (arms up, feet wide) then closed\nvoid poseJacks(inout Pose P, float beats, float E) {\n    float ph  = PI * beats;                        // open on one beat, closed on the next\n    float j   = (0.5 - 0.5 * cos(ph)) * E;         // 0 closed .. 1 open\n    float hop = 24.0 * E * abs(sin(ph));           // airborne between positions\n    P.body = vec2(0.0, hop - 9.0 * j);             // sink a touch when landing wide\n    P.footL = FOOT_L + vec2(-75.0 * j, hop);\n    P.footR = FOOT_R + vec2( 75.0 * j, hop);\n    P.splay = 0.3;\n\n    float u = mix(-HALF_PI, 0.85, j);\n    float a = mix(-HALF_PI, 0.95, j);\n    float trail = 0.15 * E * sin(ph);\n    P.armR = vec3(u, a, a - trail);\n    P.armL = vec3(u, a, a - trail);\n    P.lenR = vec2(mix(103.0, 84.0, j), 30.0 * j);\n    P.lenL = P.lenR;\n}\n\n// Stand still: just a slow breath\nvoid poseStand(inout Pose P, float t, float E) {\n    P.body = vec2(0.0, 2.5 * E * sin(t * 1.3));\n}\n\n// ===========================================================================\n// 3D figure (Dance mode). The same Pose drives a raymarched mannequin built in\n// the reference's 1000-unit frame (x right, y up, z toward the camera).\n// ===========================================================================\n#define PIV3 vec3(491.0, 500.0, 0.0)\n#define PEL3 vec3(491.0, 452.0, 0.0)\n#define FLOOR_Y 115.0\n#define CAM_D 2400.0\n\nvec3 rotX(vec3 v, float a) { float c = cos(a), s = sin(a); return vec3(v.x, c * v.y - s * v.z, s * v.y + c * v.z); }\nvec3 rotY(vec3 v, float a) { float c = cos(a), s = sin(a); return vec3(c * v.x + s * v.z, v.y, -s * v.x + c * v.z); }\nvec3 rotZ(vec3 v, float a) { float c = cos(a), s = sin(a); return vec3(c * v.x - s * v.y, s * v.x + c * v.y, v.z); }\n\n// Rig joints in figure space (before the whole-body transform), built once per pixel\nvec3 jHead, jNeckA, jNeckB;\nvec3 jSL, jEL, jWL, jTL, jSR, jER, jWR, jTR;\nvec3 jHL, jKL, jAL, jFL, jHR, jKR, jAR, jFR;\nvec3 gBody3, gOff3;\nfloat gTilt3, gRZ, gRX, gRY, gSc;\nvec3 bCen; float bRad;\n\nvec3 gFwd(vec3 v) { return rotY(rotX(rotZ(v, gRZ), gRX), gRY); }\nvec3 gInv(vec3 v) { return rotZ(rotX(rotY(v, -gRY), -gRX), -gRZ); }\nvec3 toW3(vec3 x) { return PIV3 + gSc * gFwd(x - PIV3) + gOff3; }\nvec3 upToFig(vec3 x) { return PEL3 + gBody3 + rotZ(x - PEL3, gTilt3); }\n\nfloat sdCap3(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-4), 0.0, 1.0);\n    return length(pa - ba * h) - r;\n}\n// iq ellipsoid (bound-corrected approximation)\nfloat sdEll3(vec3 p, vec3 r) {\n    float k0 = length(p / r);\n    float k1 = length(p / (r * r));\n    return k0 * (k0 - 1.0) / max(k1, 1e-5);\n}\nfloat sdRB3(vec3 p, vec3 b, float r) {\n    vec3 q = abs(p) - b + r;\n    return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0) - r;\n}\n\n// 2D arm angle (out/down/up in the frontal plane) tipped toward the camera by 'fwd'\nvec3 dir3(float e, float side, float fwd) {\n    vec3 d2 = vec3(side * cos(e), sin(e), 0.0);\n    return normalize(d2 * sqrt(max(1.0 - fwd * fwd, 0.0)) + vec3(0.0, 0.0, fwd));\n}\n\n// A 2D pose's foreshortened forearm becomes a real forearm pointing at the camera;\n// forearms swung across the body also come forward so they pass in front of it.\nvoid arm3(vec3 S, float side, vec3 ang, vec2 len, out vec3 E, out vec3 W, out vec3 T) {\n    float c = clamp(len.x / 103.0, 0.0, 1.0);\n    float fwd = sqrt(max(1.0 - c * c, 0.0));\n    fwd = max(fwd, 0.55 * smoothstep(-0.05, -0.5, cos(ang.y)));\n    E = S + 115.0 * dir3(ang.x, side, 0.0);\n    W = E + 103.0 * dir3(ang.y, side, fwd);\n    T = W + len.y * dir3(ang.z, side, fwd);\n}\n\n// Two-bone IK with the knee bending forward (and outward with splay)\nvoid leg3(vec3 H, vec3 F, float side, float splay, out vec3 K, out vec3 A) {\n    vec3 d = F - H;\n    float len = max(length(d), 0.001);\n    vec3 dir = d / len;\n    float reach = min(len, 2.0 * LEG_SEG);\n    A = H + dir * reach;\n    float h = sqrt(max(LEG_SEG * LEG_SEG - 0.25 * reach * reach, 0.0));\n    vec3 pole = normalize(vec3(side * splay * 0.9, 0.0, 1.0));\n    vec3 pv = pole - dir * dot(pole, dir);\n    pv = dot(pv, pv) > 1e-6 ? normalize(pv) : vec3(0.0, 0.0, 1.0);\n    K = H + dir * (0.5 * reach) + pv * h;\n}\n\nvoid addW(vec3 x, float r, inout float minY, inout vec3 mn, inout vec3 mx) {\n    vec3 w = toW3(x);\n    float rr = r * gSc;\n    minY = min(minY, w.y - rr);\n    mn = min(mn, w - rr);\n    mx = max(mx, w + rr);\n}\n\nvoid buildRig3(Pose P, float sc) {\n    gBody3 = vec3(P.body, 0.0);\n    gTilt3 = P.tilt;\n    gRZ = P.gRot; gRX = P.gPitch; gRY = P.gYaw;\n    gSc = P.gScale * sc;\n    gOff3 = vec3(0.0);\n\n    vec3 N0 = vec3(491.0, 772.0, 0.0);\n    jHead  = upToFig(N0 + rotZ(vec3(0.0, 82.0, 0.0), P.headTilt));\n    jNeckA = upToFig(vec3(491.0, 735.0, 0.0));\n    jNeckB = upToFig(N0 + rotZ(vec3(0.0, 34.0, 0.0), P.headTilt));\n\n    vec3 E, W, T;\n    vec3 SL = vec3(363.0, 700.0, 0.0), SR = vec3(619.0, 700.0, 0.0);\n    arm3(SL, -1.0, P.armL, P.lenL, E, W, T);\n    jSL = upToFig(SL); jEL = upToFig(E); jWL = upToFig(W); jTL = upToFig(T);\n    arm3(SR,  1.0, P.armR, P.lenR, E, W, T);\n    jSR = upToFig(SR); jER = upToFig(E); jWR = upToFig(W); jTR = upToFig(T);\n\n    jHL = upToFig(vec3(HIP_L, 0.0));\n    jHR = upToFig(vec3(HIP_R, 0.0));\n    // a foot crossing over the other one steps in front of it\n    float zL = 70.0 * smoothstep(10.0, 140.0, P.footL.x - FOOT_L.x);\n    float zR = 70.0 * smoothstep(10.0, 140.0, FOOT_R.x - P.footR.x);\n    leg3(jHL, vec3(P.footL, zL), -1.0, P.splay, jKL, jAL);\n    leg3(jHR, vec3(P.footR, zR),  1.0, P.splay, jKR, jAR);\n    jFL = jAL + vec3(0.0, -8.0, 42.0);\n    jFR = jAR + vec3(0.0, -8.0, 42.0);\n\n    // Floor solver: rest the lowest part on the floor (and centre it) when the\n    // pose asks for it; otherwise only stop anything sinking through the floor\n    float minY = 1e5; vec3 mn = vec3(1e5), mx = vec3(-1e5);\n    addW(jHead, 67.0, minY, mn, mx);\n    addW(upToFig(vec3(491.0, 688.0, 0.0)), 60.0, minY, mn, mx);\n    addW(upToFig(vec3(491.0, 482.0, 0.0)), 55.0, minY, mn, mx);\n    addW(jSL, 36.0, minY, mn, mx); addW(jSR, 36.0, minY, mn, mx);\n    addW(jEL, 30.0, minY, mn, mx); addW(jWL, 30.0, minY, mn, mx); addW(jTL, 30.0, minY, mn, mx);\n    addW(jER, 30.0, minY, mn, mx); addW(jWR, 30.0, minY, mn, mx); addW(jTR, 30.0, minY, mn, mx);\n    addW(jHL, 41.0, minY, mn, mx); addW(jKL, 37.0, minY, mn, mx); addW(jAL, 35.0, minY, mn, mx); addW(jFL, 27.0, minY, mn, mx);\n    addW(jHR, 41.0, minY, mn, mx); addW(jKR, 37.0, minY, mn, mx); addW(jAR, 35.0, minY, mn, mx); addW(jFR, 27.0, minY, mn, mx);\n    float g = clamp(P.grounded, 0.0, 1.0);\n    vec3 cen = 0.5 * (mn + mx);\n    gOff3 = vec3((491.0 - cen.x) * g,\n                 mix(max(0.0, FLOOR_Y - minY), FLOOR_Y - minY, g),\n                 -cen.z * g);\n    bCen = 0.5 * (mn + mx) + gOff3;\n    bRad = 0.5 * length(mx - mn) + 40.0;\n}\n\n\n// ---------------------------------------------------------------------------\n// Side-view pictogram of the 3D rig: every body part is projected flat onto the\n// screen and drawn in depth order, with the same thin black gap the Walk/Run\n// side view uses wherever a nearer part passes over a farther one.\n// ---------------------------------------------------------------------------\nvec3 cRt, cUp, cFw, cTgt;\n\nvec2 prj(vec3 fig) { vec3 w = toW3(fig) - cTgt; return vec2(491.0 + dot(w, cRt), 480.0 + dot(w, cUp)); }\nfloat dep(vec3 fig) { return -dot(toW3(fig) - cTgt, cFw); }       // bigger = nearer the camera\n\n// Carve a gap into part i wherever a nearer part j covers it (fades in with depth difference)\nfloat carveBy(float di, float dj, float zi, float zj) {\n    float g = 10.0 * smoothstep(3.0, 25.0, zj - zi);\n    return (g > 0.01) ? max(di, -(dj - g)) : di;\n}\n\nfloat flatSeg(vec2 p, vec3 a, vec3 b) { return sdSeg(p, prj(a), prj(b)); }\n\nfloat figureFlat(vec2 p) {\n    float sc = gSc;\n    // --- head ---\n    float dHead = length(p - prj(jHead)) - 67.0 * sc;\n    float zHead = dep(jHead);\n\n    // --- torso: tapered capsule whose width depends on how it faces the camera ---\n    vec3 tb = upToFig(vec3(491.0, 500.0, 0.0)), tt = upToFig(vec3(491.0, 710.0, 0.0));\n    vec2 pb = prj(tb), pt = prj(tt);\n    vec2 ax = pt - pb;\n    float h = length(ax);\n    vec2 u2 = (h > 1.0) ? ax / h : vec2(0.0, 1.0);\n    vec2 n2 = vec2(u2.y, -u2.x);\n    vec3 ex = gFwd(rotZ(vec3(1.0, 0.0, 0.0), gTilt3)), ez = gFwd(rotZ(vec3(0.0, 0.0, 1.0), gTilt3));\n    float kx = dot(vec2(dot(ex, cRt), dot(ex, cUp)), n2);\n    float kz = dot(vec2(dot(ez, cRt), dot(ez, cUp)), n2);\n    float rBot = sqrt(kx * kx * 88.0 * 88.0 + kz * kz * 60.0 * 60.0) * sc;\n    float rTop = sqrt(kx * kx * 105.0 * 105.0 + kz * kz * 70.0 * 70.0) * sc;\n    vec2 tp = vec2(dot(p - pb, n2), dot(p - pb, u2));\n    float dTor = sdUnevenCapsule(tp, rBot, rTop, max(h, 1.0));\n    float zTor = 0.5 * (dep(tb) + dep(tt));\n\n    // --- arms: even tubes ending in the rounded nub ---\n    float r = 29.0 * sc;\n    float dAL = smin(flatSeg(p, jSL, jEL), flatSeg(p, jEL, jWL), 4.0) - r;\n    dAL = smin(dAL, flatSeg(p, jWL, jTL) - r, 6.0);\n    float dAR = smin(flatSeg(p, jSR, jER), flatSeg(p, jER, jWR), 4.0) - r;\n    dAR = smin(dAR, flatSeg(p, jWR, jTR) - r, 6.0);\n    float zAL = (dep(jEL) + dep(jWL) + dep(jTL)) / 3.0;\n    float zAR = (dep(jER) + dep(jWR) + dep(jTR)) / 3.0;\n\n    // --- legs with the rounded shoe, like the Walk/Run profile ---\n    float rl = 38.5 * sc;\n    float dLL = min(flatSeg(p, jHL, jKL), flatSeg(p, jKL, jAL)) - rl;\n    dLL = smin(dLL, flatSeg(p, jAL + vec3(0.0, -8.0, 6.0), jFL + vec3(0.0, -2.0, 4.0)) - 30.0 * sc, 16.0);\n    float dLR = min(flatSeg(p, jHR, jKR), flatSeg(p, jKR, jAR)) - rl;\n    dLR = smin(dLR, flatSeg(p, jAR + vec3(0.0, -8.0, 6.0), jFR + vec3(0.0, -2.0, 4.0)) - 30.0 * sc, 16.0);\n    float zLL = 0.5 * (dep(jKL) + dep(jAL));\n    float zLR = 0.5 * (dep(jKR) + dep(jAR));\n\n    // --- depth layering ---\n    // arms: gap against anything nearer, and they cut a gap into anything behind\n    float aL = dAL, aR = dAR;\n    aL = carveBy(aL, dAR, zAL, zAR);  aR = carveBy(aR, dAL, zAR, zAL);\n    aL = carveBy(aL, dTor, zAL, zTor); aR = carveBy(aR, dTor, zAR, zTor);\n    aL = carveBy(aL, dHead, zAL, zHead); aR = carveBy(aR, dHead, zAR, zHead);\n    aL = carveBy(aL, dLL, zAL, zLL);  aL = carveBy(aL, dLR, zAL, zLR);\n    aR = carveBy(aR, dLL, zAR, zLL);  aR = carveBy(aR, dLR, zAR, zLR);\n\n    float tor = dTor, hd = dHead;\n    tor = carveBy(tor, dAL, zTor, zAL); tor = carveBy(tor, dAR, zTor, zAR);\n    hd  = carveBy(hd,  dAL, zHead, zAL); hd = carveBy(hd, dAR, zHead, zAR);\n    hd  = carveBy(hd,  dLL, zHead, zLL); hd = carveBy(hd, dLR, zHead, zLR);\n\n    // legs: the far leg tucks behind the near one and behind the torso; a near\n    // leg joins the torso at the hip without a gap (as in the Walk/Run view)\n    float lL = dLL, lR = dLR;\n    lL = carveBy(lL, dLR, zLL, zLR);  lR = carveBy(lR, dLL, zLR, zLL);\n    lL = carveBy(lL, dTor, zLL, zTor); lR = carveBy(lR, dTor, zLR, zTor);\n    lL = carveBy(lL, dAL, zLL, zAL);  lL = carveBy(lL, dAR, zLL, zAR);\n    lR = carveBy(lR, dAL, zLR, zAL);  lR = carveBy(lR, dAR, zLR, zAR);\n    lL = carveBy(lL, dHead, zLL, zHead); lR = carveBy(lR, dHead, zLR, zHead);\n\n    return min(min(min(tor, hd), min(aL, aR)), min(lL, lR));\n}\n\nvoid flatCamera(float t) {\n    // Camera Turn 0 = pure profile facing right; the default 0.75 is a three-quarter\n    // side view, which keeps the pictogram look but shows arm and leg moves more clearly\n    float yaw = -HALF_PI + cam3DAngle + cam3DOrbit * t;\n    float pit = cam3DHeight;\n    cTgt = vec3(491.0, 480.0, 0.0);\n    vec3 ro = cTgt + vec3(sin(yaw) * cos(pit), sin(pit), cos(yaw) * cos(pit));\n    cFw = normalize(cTgt - ro);\n    cRt = normalize(cross(cFw, vec3(0.0, 1.0, 0.0)));\n    cUp = cross(cRt, cFw);\n}\n\nfloat map3(vec3 p) {\n    vec3 q = PIV3 + gInv((p - gOff3 - PIV3) / gSc);\n    vec3 u = PEL3 + rotZ(q - PEL3 - gBody3, -gTilt3);\n\n    // torso: chest, waist and pelvis blended into one smooth mannequin trunk\n    float tor = smin(sdEll3(u - vec3(491.0, 682.0, 0.0), vec3(124.0, 84.0, 64.0)),\n                     sdEll3(u - vec3(491.0, 570.0, 0.0), vec3( 86.0, 112.0, 56.0)), 40.0);\n    tor = smin(tor, sdEll3(u - vec3(491.0, 482.0, 0.0), vec3(96.0, 58.0, 60.0)), 40.0);\n    float d = smin(tor, sdCap3(q, jNeckA, jNeckB, 30.0), 22.0);\n    d = smin(d, length(q - jHead) - 67.0, 14.0);\n    d = smin(d, min(length(q - jSL), length(q - jSR)) - 36.0, 24.0);     // shoulder caps\n\n    // arms with rounded nubs\n    float aL = smin(sdCap3(q, jSL, jEL, 30.0), sdCap3(q, jEL, jWL, 28.0), 6.0);\n    aL = smin(aL, sdCap3(q, jWL, jTL, 30.0), 8.0);\n    float aR = smin(sdCap3(q, jSR, jER, 30.0), sdCap3(q, jER, jWR, 28.0), 6.0);\n    aR = smin(aR, sdCap3(q, jWR, jTR, 30.0), 8.0);\n\n    // legs with a short rounded shoe\n    float lL = smin(sdCap3(q, jHL, jKL, 41.0), sdCap3(q, jKL, jAL, 35.0), 10.0);\n    lL = smin(lL, sdCap3(q, jAL, jFL, 27.0), 16.0);\n    float lR = smin(sdCap3(q, jHR, jKR, 41.0), sdCap3(q, jKR, jAR, 35.0), 10.0);\n    lR = smin(lR, sdCap3(q, jAR, jFR, 27.0), 16.0);\n\n    d = min(d, min(aL, aR));\n    d = smin(d, min(lL, lR), 14.0);\n    return d * gSc;\n}\n\nvec3 normal3(vec3 p) {\n    vec2 e = vec2(1.0, -1.0) * 0.8;\n    return normalize(e.xyy * map3(p + e.xyy) + e.yyx * map3(p + e.yyx) +\n                     e.yxy * map3(p + e.yxy) + e.xxx * map3(p + e.xxx));\n}\n\nfloat shadow3(vec3 ro, vec3 rd) {\n    float res = 1.0, t = 6.0;\n    for (int i = 0; i < 32; i++) {\n        float h = map3(ro + rd * t);\n        res = min(res, 9.0 * h / t);\n        t += clamp(h, 6.0, 90.0);\n        if (res < 0.005 || t > 1600.0) break;\n    }\n    return clamp(res, 0.0, 1.0);\n}\n\n// Renders the 3D figure for one pixel. Returns the tile-interior colour.\nvec3 render3D(vec2 q, float upp, float t) {\n    float yaw = -0.25 + cam3DAngle + cam3DOrbit * t;\n    float pit = 0.12 + cam3DHeight;\n    vec3 tgt = vec3(491.0, 480.0, 0.0);\n    vec3 ro = tgt + CAM_D * vec3(sin(yaw) * cos(pit), sin(pit), cos(yaw) * cos(pit));\n    vec3 fw = normalize(tgt - ro);\n    vec3 rt = normalize(cross(fw, vec3(0.0, 1.0, 0.0)));\n    vec3 up = cross(rt, fw);\n    vec3 rd = normalize(fw * CAM_D + rt * (q.x - 491.0) + up * (q.y - 480.0));\n    if (waveLeft) { ro.x = 982.0 - ro.x; rd.x = -rd.x; }\n\n    vec3 L = normalize(vec3(-0.55, 0.85, 0.45));      // key light: high, front-left\n    vec3 bg = tileColor.rgb;\n    vec3 col = bg;\n\n    // --- figure: march only inside its bounding sphere ---\n    vec3 oc = ro - bCen;\n    float rad = bRad + 300.0 * glow;                  // wider when glowing so the halo fades out smoothly\n    float bb = dot(oc, rd), cc = dot(oc, oc) - rad * rad, hh = bb * bb - cc;\n    float tHit = -1.0, dmin = 1e5, tdm = 0.0;\n    if (hh > 0.0) {\n        hh = sqrt(hh);\n        float tt = max(-bb - hh, 0.0), tEnd = -bb + hh;\n        for (int i = 0; i < 110; i++) {\n            float d = map3(ro + rd * tt);\n            if (d < dmin) { dmin = d; tdm = tt; }\n            if (d < 0.25 * upp * tt / CAM_D) { tHit = tt; break; }\n            tt += d;\n            if (tt > tEnd) break;\n        }\n    }\n\n    // --- floor: a soft pool of light under the figure, with its shadow ---\n    float tF = (rd.y < 0.0) ? (FLOOR_Y - ro.y) / rd.y : -1.0;\n    if (tF > 0.0 && (tHit < 0.0 || tF < tHit) && floor3D > 0.0) {\n        vec3 fp = ro + rd * tF;\n        vec2 dxz = fp.xz - bCen.xz;\n        float pool = exp(-dot(dxz, dxz) / (2.0 * 330.0 * 330.0));\n        float sh = shadow3(fp + vec3(0.0, 1.0, 0.0), L);\n        float ao = clamp(map3(fp) / 90.0, 0.0, 1.0);\n        vec3 fl = figureColor.rgb * floor3D * 0.30 * pool * mix(0.25, 1.0, sh) * mix(0.35, 1.0, ao);\n        col = bg + fl;\n    }\n\n    // colour for the figure (solid, or the cosine palette)\n    vec3 hitP = ro + rd * (tHit > 0.0 ? tHit : tdm);\n    vec3 pal = 0.5 + 0.5 * cos(t + hitP.y * 0.006 + hitP.x * 0.002 + vec3(0.0, 2.0, 4.0) + hue * 6.2831);\n    vec3 base = mix(figureColor.rgb, pal, colorCycle);\n\n    // shade the hit (or the closest near-miss, for anti-aliased edges)\n    float pix = upp * max(tdm, 1.0) / CAM_D;\n    float cover = (tHit > 0.0) ? 1.0 : clamp(0.5 - dmin / pix, 0.0, 1.0);\n    float rimEdge = 0.0;\n    if (cover > 0.0) {\n        vec3 n = normal3(hitP);\n        float dif = max(dot(n, L), 0.0);\n        float sh = (dif > 0.0) ? shadow3(hitP + n * 3.0, L) : 0.0;\n        float hemi = 0.5 + 0.5 * n.y;\n        float ao = clamp(0.35 + map3(hitP + n * 24.0) / 24.0 * 0.65, 0.0, 1.0);\n        float fres = pow(1.0 - max(dot(n, -rd), 0.0), 3.0);\n        float spec = pow(max(dot(reflect(rd, n), L), 0.0), 28.0);\n        float fill = max(dot(n, normalize(vec3(0.8, 0.2, 0.6))), 0.0);   // soft fill from the right\n        vec3 lit = base * (0.30 * hemi * ao + 0.85 * dif * sh + 0.22 * fill * ao)\n                 + vec3(0.35 * spec * sh) + base * fres * 0.50;\n        vec3 sc = lit;\n        col = mix(col, sc, cover);\n        rimEdge = smoothstep(0.55, 0.85, 1.0 - max(dot(n, -rd), 0.0)) * cover;\n    }\n\n    // glow halo and outline-only look\n    float gl = glow * exp(-max(dmin, 0.0) / 60.0) * 0.8 * (1.0 - cover);\n    col += base * gl;\n    if (outlineMix > 0.0) {\n        float lw = mix(3.0, 40.0, lineWidth) * 0.5;\n        float lineOut = (tHit > 0.0) ? rimEdge : clamp(0.5 - (dmin - lw) / pix, 0.0, 1.0) * step(0.0, dmin);\n        vec3 oCol = bg + base * gl;\n        oCol = mix(oCol, base, max(lineOut, (tHit > 0.0) ? rimEdge : 0.0));\n        col = mix(col, oCol, outlineMix);\n    }\n    return col;\n}\n\nvoid main() {\n    float t = TIME * speed;\n    float beats = t * bpm / 60.0;\n    float E = moveAmount;\n\n    // Aspect-correct coords, mapped into the reference's 1000-unit frame\n    vec2 p = isf_FragNormCoord - 0.5;\n    p.x *= RENDERSIZE.x / RENDERSIZE.y;\n    float upp = 1000.0 / (RENDERSIZE.y * zoom);   // reference units per screen pixel (for AA)\n    vec2 q = p * 1000.0 / zoom + 500.0;\n\n    // Rounded black tile\n    float dTile = sdRoundBox(q - vec2(500.0), vec2(468.0), vec4(95.0));\n    float tileM = showTile ? clamp(0.5 - dTile / upp, 0.0, 1.0) : 1.0;\n\n    // ---------------- Pose for the selected motion ----------------\n    float mode = float(motionMode);\n    bool sideView = mode > 0.5 && mode < 2.5;      // Walk and Run turn to profile\n    float view = float(danceView);\n    bool isDance = mode > 2.5 && mode < 3.5;\n    bool danceFlat = isDance && view < 0.5;        // side-view pictogram from the 3D rig\n    bool dance3D   = isDance && view > 1.5;        // shaded 3D mannequin\n    g3D = danceFlat || dance3D;\n\n    Pose P;\n    restPose(P);\n    if (mode < 0.5)      poseWave(P, t);\n    else if (mode < 3.5) poseDanceStyle(P, beats, E);\n    else if (mode < 4.5) poseJacks(P, beats, E);\n    else                 poseStand(P, t, E);\n    if (!g3D) groundPose(P);                       // power moves / freezes rest on the floor\n\n    Side SP;\n    SP.lean = 0.0; SP.hipY = HIP_L.y; SP.headTilt = 0.0; SP.nubLen = 0.0; SP.farBack = 0.0;\n    SP.armN = vec3(0.0); SP.armF = vec3(0.0); SP.legN = vec2(0.0); SP.legF = vec2(0.0);\n    if (mode > 0.5 && mode < 1.5) poseWalkSide(SP, beats, E);\n    else if (mode > 1.5 && mode < 2.5) poseRunSide(SP, beats, E);\n\n    // ---------------- Figure ----------------\n    float s = 1.0 + pulse * 0.08 * sin(t * 3.0);\n\n    if (dance3D) {\n        buildRig3(P, s);\n        vec3 inside3 = render3D(q, upp, t);\n        gl_FragColor = vec4(mix(outerColor.rgb, inside3, tileM), 1.0);\n        return;\n    }\n    if (danceFlat) buildRig3(P, s);\n    flatCamera(t);\n\n    vec2 c = vec2(491.0, 500.0);\n    vec2 fq = (q - c) / s + c;\n    if (waveLeft) fq.x = 982.0 - fq.x;             // mirror about the figure's centre line\n\n    float dFig;\n    if (danceFlat) {\n        vec2 fp = q;\n        if (waveLeft) fp.x = 982.0 - fp.x;         // mirror: face the other way\n        dFig = figureFlat(fp);\n    } else {\n        dFig = (sideView ? figureSide(fq, SP) : figureG(fq, P)) * s;\n    }\n\n    // Optional ground dashes that scroll under the feet in Walk / Run\n    if (sideView && groundDashes) {\n        float scroll = beats * (mode < 1.5 ? 210.0 : 470.0);\n        float gx = mod(fq.x + scroll, 110.0) - 55.0;\n        float dash = boxMM(vec2(gx, fq.y), vec2(-30.0, 92.0), vec2(30.0, 102.0), vec4(5.0));\n        dash = max(dash, abs(fq.x - 491.0) - 380.0);\n        dFig = min(dFig, dash * s);\n    }\n\n    // Fill vs outline\n    float lw    = mix(3.0, 40.0, lineWidth);\n    float mFill = clamp(0.5 - dFig / upp, 0.0, 1.0);\n    float mLine = clamp(0.5 - (abs(dFig) - lw * 0.5) / upp, 0.0, 1.0);\n    float m     = mix(mFill, mLine, outlineMix);\n\n    // Color: solid figure color blended toward the reference cosine palette\n    vec3 pal = 0.5 + 0.5 * cos(t + q.y * 0.006 + q.x * 0.002 + vec3(0.0, 2.0, 4.0) + hue * 6.2831);\n    vec3 fig = mix(figureColor.rgb, pal, colorCycle);\n\n    // Soft halo around the figure\n    float g = glow * exp(-max(dFig, 0.0) / 60.0) * 0.8;\n\n    vec3 inside = tileColor.rgb + fig * g;\n    inside = mix(inside, fig, m);\n\n    vec3 col = mix(outerColor.rgb, inside, tileM);\n    gl_FragColor = vec4(col, 1.0);\n}"
  }
}