{
  "license": "CC0-1.0",
  "shader": {
    "id": "4mdpp7el",
    "title": "Stick Figure V2",
    "license": "CC0-1.0",
    "provenance_type": "bred",
    "made_with": "glslop",
    "status": "active",
    "compile_ok": true,
    "render_hash": "0018181818181400",
    "tags": [],
    "parents": [
      "qgi71c8k"
    ],
    "author": "jab6zg50vals",
    "author_name": "ogcraig",
    "author_url": "/u/ogcraig",
    "created_at": "2026-10-22T16:44:32.177Z",
    "poster_url": "/posters/4mdpp7el.webp",
    "stats": {
      "slops": 0,
      "views": 13,
      "forks": 1
    },
    "supersedes": "qgi71c8k",
    "superseded_by": "73abx4ak",
    "self": "/api/v1/shaders/4mdpp7el",
    "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, 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\", \"Jumping Jacks\", \"Stand Still\"] },\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};\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}\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// 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 armL = armTube(pu, SL, -1.0, 30.0, P.armL, P.lenL);\n    float armR = armTube(pu, SR,  1.0, 29.0, P.armR, P.lenR);\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\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    d = min(d, min(legL, legR));\n    return d;\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// 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) poseDance(P, beats, E);\n    else if (mode < 4.5) poseJacks(P, beats, E);\n    else                 poseStand(P, t, E);\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) : figure(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}"
  }
}