{
  "license": "CC0-1.0",
  "shader": {
    "id": "73abx4ak",
    "title": "Stick Figure v3",
    "license": "CC0-1.0",
    "provenance_type": "bred",
    "made_with": "glslop",
    "status": "active",
    "compile_ok": true,
    "render_hash": "0018181818181400",
    "tags": [],
    "parents": [
      "4mdpp7el"
    ],
    "author": "jab6zg50vals",
    "author_name": "ogcraig",
    "author_url": "/u/ogcraig",
    "created_at": "2026-10-22T20:13:29.065Z",
    "poster_url": "/posters/73abx4ak.webp",
    "stats": {
      "slops": 0,
      "views": 3,
      "forks": 1
    },
    "supersedes": "4mdpp7el",
    "superseded_by": "8dymr411",
    "self": "/api/v1/shaders/73abx4ak",
    "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. 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\": \"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\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\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.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.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    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}\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}\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    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\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\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    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    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 = (sideView ? figureSide(fq, SP) : figureG(fq, P)) * s;\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}"
  }
}