fork a shader
Write or paste an ISF shader (GLSL ES with a /*{ ... }*/ header). It compiles + renders in yer browser. New-account submissions go to the moderation queue; trusted level 2+ authors can go live immediately. Everything is CC0. Got a file first? preview it locally →
A model marks this as witnessed_generation (honest AI provenance). Leave blank if you hand-authored it.
/*{ "DESCRIPTION": "Restroom-sign pictogram: white standing figure on a rounded black tile, with a Motion Mode dropdown: Wave, Walk, Run in Place, 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.", "CREDIT": "Craig", "ISFVSN": "2", "CATEGORIES": ["generator"], "INPUTS": [ { "NAME": "motionMode", "LABEL": "Motion Mode", "TYPE": "long", "DEFAULT": 0, "VALUES": [0, 1, 2, 3, 4, 5], "LABELS": ["Wave", "Walk", "Run in Place", "Dance", "Jumping Jacks", "Stand Still"] }, { "NAME": "bpm", "LABEL": "Tempo (BPM)", "TYPE": "float", "DEFAULT": 120.0, "MIN": 60.0, "MAX": 200.0 }, { "NAME": "moveAmount", "LABEL": "Move Amount", "TYPE": "float", "DEFAULT": 1.0, "MIN": 0.0, "MAX": 1.0 }, { "NAME": "speed", "TYPE": "float", "DEFAULT": 1.0, "MIN": 0.0, "MAX": 4.0 }, { "NAME": "hue", "TYPE": "float", "DEFAULT": 0.5, "MIN": 0.0, "MAX": 1.0 }, { "NAME": "colorCycle", "LABEL": "Color Cycle", "TYPE": "float", "DEFAULT": 0.0, "MIN": 0.0, "MAX": 1.0 }, { "NAME": "figureColor", "LABEL": "Figure Color", "TYPE": "color", "DEFAULT": [1.0, 1.0, 1.0, 1.0] }, { "NAME": "tileColor", "LABEL": "Tile Color", "TYPE": "color", "DEFAULT": [0.0, 0.0, 0.0, 1.0] }, { "NAME": "outerColor", "LABEL": "Outer Color", "TYPE": "color", "DEFAULT": [1.0, 1.0, 1.0, 1.0] }, { "NAME": "showTile", "LABEL": "Show Tile", "TYPE": "bool", "DEFAULT": 1 }, { "NAME": "zoom", "TYPE": "float", "DEFAULT": 1.0, "MIN": 0.25, "MAX": 3.0 }, { "NAME": "waveAuto", "LABEL": "Auto Wave Loop", "TYPE": "bool", "DEFAULT": 1 }, { "NAME": "waveStyle", "LABEL": "Wave Style", "TYPE": "long", "DEFAULT": 0, "VALUES": [0, 1, 2], "LABELS": ["Elbow Wave", "Wrist Flick", "Big Wave"] }, { "NAME": "waveRaise", "LABEL": "Arm Raise", "TYPE": "float", "DEFAULT": 1.0, "MIN": 0.0, "MAX": 1.0 }, { "NAME": "waveCycle", "LABEL": "Loop Length (s)","TYPE": "float", "DEFAULT": 6.0, "MIN": 2.0, "MAX": 20.0 }, { "NAME": "waveSpeed", "LABEL": "Wave Speed", "TYPE": "float", "DEFAULT": 1.6, "MIN": 0.0, "MAX": 5.0 }, { "NAME": "waveAmount", "LABEL": "Wave Amount", "TYPE": "float", "DEFAULT": 0.6, "MIN": 0.0, "MAX": 1.0 }, { "NAME": "bodyFollow", "LABEL": "Head Follow", "TYPE": "float", "DEFAULT": 0.5, "MIN": 0.0, "MAX": 1.0 }, { "NAME": "waveLeft", "LABEL": "Mirror Figure", "TYPE": "bool", "DEFAULT": 0 }, { "NAME": "pulse", "TYPE": "float", "DEFAULT": 0.0, "MIN": 0.0, "MAX": 1.0 }, { "NAME": "glow", "TYPE": "float", "DEFAULT": 0.0, "MIN": 0.0, "MAX": 1.0 }, { "NAME": "outlineMix", "LABEL": "Outline Only", "TYPE": "float", "DEFAULT": 0.0, "MIN": 0.0, "MAX": 1.0 }, { "NAME": "lineWidth", "LABEL": "Line Width", "TYPE": "float", "DEFAULT": 0.3, "MIN": 0.0, "MAX": 1.0 } ] }*/ // All geometry is measured off the 1000x1000 reference, in a y-up pixel frame // (Y = 1000 - imageY), so the numbers map straight back to the photo. // Every motion mode returns to the exact reference silhouette at rest. // "Mirror Figure" flips the sample point about the figure's centre line (x = 491), // which also moves the wave to the other arm. #define PI 3.14159265 #define HALF_PI 1.5707963 // Reference rest geometry #define PELVIS vec2(491.0, 452.0) #define HIP_L vec2(445.5, 470.0) #define HIP_R vec2(537.0, 470.0) #define FOOT_L vec2(445.5, 153.5) #define FOOT_R vec2(537.0, 153.5) #define LEG_SEG 158.25 // thigh = shin, so the rest leg is exactly straight mat2 rot(float a) { float c = cos(a), s = sin(a); return mat2(c, -s, s, c); } // iq rounded box with per-corner radii: r = (topRight, bottomRight, topLeft, bottomLeft) float sdRoundBox(vec2 p, vec2 b, vec4 r) { r.xy = (p.x > 0.0) ? r.xy : r.zw; r.x = (p.y > 0.0) ? r.x : r.y; vec2 q = abs(p) - b + r.x; return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r.x; } // Box defined by min/max corners float boxMM(vec2 p, vec2 mn, vec2 mx, vec4 r) { vec2 c = 0.5 * (mn + mx); vec2 h = 0.5 * (mx - mn); return sdRoundBox(p - c, h, r); } float sdSeg(vec2 p, vec2 a, vec2 b) { vec2 pa = p - a, ba = b - a; float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0); return length(pa - ba * h); } float dot2(vec2 v) { return dot(v, v); } // iq exact distance to a quadratic Bezier (A -> C, control B) float sdBezier(vec2 pos, vec2 A, vec2 B, vec2 C) { vec2 a = B - A; vec2 b = A - 2.0 * B + C; vec2 c = a * 2.0; vec2 d = A - pos; float kk = 1.0 / dot(b, b); float kx = kk * dot(a, b); float ky = kk * (2.0 * dot(a, a) + dot(d, b)) / 3.0; float kz = kk * dot(d, a); float res; float pp = ky - kx * kx; float p3 = pp * pp * pp; float qq = kx * (2.0 * kx * kx - 3.0 * ky) + kz; float h = qq * qq + 4.0 * p3; if (h >= 0.0) { h = sqrt(h); vec2 x = (vec2(h, -h) - qq) / 2.0; vec2 uv = sign(x) * pow(abs(x), vec2(1.0 / 3.0)); float t = clamp(uv.x + uv.y - kx, 0.0, 1.0); res = dot2(d + (c + b * t) * t); } else { float z = sqrt(-pp); float v = acos(qq / (pp * z * 2.0)) / 3.0; float m = cos(v); float n = sin(v) * 1.732050808; vec3 t = clamp(vec3(m + m, -n - m, n - m) * z - kx, 0.0, 1.0); res = min(dot2(d + (c + b * t.x) * t.x), dot2(d + (c + b * t.y) * t.y)); } return sqrt(res); } float smin(float a, float b, float k) { k = max(k, 0.001); float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0); return mix(b, a, h) - k * h * (1.0 - h); } // Arm angle convention, per side: 0 = pointing outward from the body, // -PI/2 = hanging down, +PI/2 = straight up. sx = +1 screen right, -1 screen left. vec2 aDir(float a, float sx) { return vec2(sx * cos(a), sin(a)); } // How far an arm is lifted (drives the shoulder tuck and joint slide) float liftOf(float upper) { return clamp((upper + HALF_PI) / (HALF_PI + 0.16), 0.0, 1.0); } // Ease with a small late overshoot, so the waving arm "arrives" instead of stopping dead float liftCurve(float x) { x = clamp(x, 0.0, 1.0); return smoothstep(0.0, 0.8, x) + 0.07 * sin(PI * clamp((x - 0.6) / 0.4, 0.0, 1.0)); } // --------------------------------------------------------------------------- // Pose: everything the figure needs for one frame // --------------------------------------------------------------------------- struct Pose { vec2 body; // upper-body offset (bounce / sway) float tilt; // upper-body roll around the pelvis (+ = counter-clockwise) float headTilt; // extra head roll around the neck vec3 armL; // left arm angles: (upper, forearm, nub) vec2 lenL; // left arm lengths: (forearm, nub) vec3 armR; // right arm angles vec2 lenR; // right arm lengths vec2 footL; // foot targets (world space) vec2 footR; float splay; // how far knees bow outward when the legs bend (0..1) }; void restPose(inout Pose P) { P.body = vec2(0.0); P.tilt = 0.0; P.headTilt = 0.0; P.armL = vec3(-HALF_PI); P.armR = vec3(-HALF_PI); P.lenL = vec2(103.0, 0.0); P.lenR = vec2(103.0, 0.0); P.footL = FOOT_L; P.footR = FOOT_R; P.splay = 0.45; } // Even-width arm tube: straight upper arm, then forearm + rounded nub as one // smooth Bezier curve (so a trailing nub bends the forearm instead of kinking). // With nub length 0 it is a plain straight capsule, identical to the reference arm. float armTube(vec2 p, vec2 S, float sx, float r, vec3 ang, vec2 len) { vec2 E = S + 115.0 * aDir(ang.x, sx); vec2 W = E + len.x * aDir(ang.y, sx); vec2 T = W + len.y * aDir(ang.z, sx); float dU = sdSeg(p, S, E) - r; float dF = sdBezier(p, E, W, T) - r; return smin(dU, dF, 4.0 * clamp(len.y / 30.0, 0.0, 1.0) + 0.001); } // Two-bone leg with simple IK: hip H reaches for foot target F. // If F is out of reach the leg straightens toward it. side = -1 left, +1 right. float legTube(vec2 p, vec2 H, vec2 F, float r, float side, float splay) { vec2 d = F - H; float len = max(length(d), 0.001); vec2 dir = d / len; float reach = min(len, 2.0 * LEG_SEG); vec2 Fp = H + dir * reach; float h = sqrt(max(LEG_SEG * LEG_SEG - 0.25 * reach * reach, 0.0)); vec2 perp = vec2(-dir.y, dir.x); // pointing +x for a leg hanging down vec2 K = H + dir * (0.5 * reach) + perp * h * splay * side; return min(sdSeg(p, H, K), sdSeg(p, K, Fp)) - r; } float figure(vec2 p, Pose P) { // Upper-body space: undo the bounce/sway and roll around the pelvis vec2 pu = rot(P.tilt) * (p - PELVIS - P.body) + PELVIS; // Head, rolled around the neck vec2 N = vec2(491.0, 772.0); vec2 hp = rot(P.headTilt) * (pu - N) + N; float head = length(hp - vec2(491.0, 854.0)) - 67.0; // Shoulder yoke with rounded top corners. On a lifted side the shoulder cap // tucks in and tightens, so the raised arm becomes the shoulder line. float liftL = liftOf(P.armL.x); float liftR = liftOf(P.armR.x); float xL = mix(333.0, 407.0, liftL), rL = mix(80.0, 34.0, liftL); float xR = mix(648.0, 576.0, liftR), rR = mix(80.0, 34.0, liftR); float yoke = boxMM(pu, vec2(xL, 600.0), vec2(xR, 772.0), vec4(rR, 0.0, rL, 0.0)); // Below the armpit line outside the torso the arms own the space; // the cut rises on a lifted side to make room for a clean armpit. float cutL = boxMM(pu, vec2(-1000.0, -1000.0), vec2(407.0, 668.0 + 40.0 * liftL), vec4(0.0)); float cutR = boxMM(pu, vec2(576.0, -1000.0), vec2(2000.0, 668.0 + 40.0 * liftR), vec4(0.0)); yoke = max(yoke, -min(cutL, cutR)); // Torso block down to the crotch float torso = boxMM(pu, vec2(407.0, 452.0), vec2(576.0, 700.0), vec4(0.0)); float body = min(yoke, torso); // Arms. Shoulder joints slide up and in as each arm lifts, so a raised arm // comes out of the top of the shoulder instead of the armpit. vec2 SL = mix(vec2(363.0, 700.0), vec2(404.0, 744.0), smoothstep(0.0, 0.6, liftL)); vec2 SR = mix(vec2(619.0, 700.0), vec2(578.0, 744.0), smoothstep(0.0, 0.6, liftR)); float armL = armTube(pu, SL, -1.0, 30.0, P.armL, P.lenL); float armR = armTube(pu, SR, 1.0, 29.0, P.armR, P.lenR); // Blend lifted arms into the shoulder/armpit; razor sharp at rest float d = smin(body, armR, 0.5 + 24.0 * liftR); d = smin(d, armL, 0.5 + 24.0 * liftL); d = min(d, head); // Legs: hips ride with the upper body, feet go where the pose puts them mat2 back = rot(-P.tilt); vec2 HL = back * (HIP_L - PELVIS) + PELVIS + P.body; vec2 HR = back * (HIP_R - PELVIS) + PELVIS + P.body; float legL = legTube(p, HL, P.footL, 38.5, -1.0, P.splay); float legR = legTube(p, HR, P.footR, 39.0, 1.0, P.splay); d = min(d, min(legL, legR)); return d; } // --------------------------------------------------------------------------- // Motion modes // --------------------------------------------------------------------------- // Wave: elbow-led lift, forearm wave with trailing nub, auto loop or manual void poseWave(inout Pose P, float t) { float ph = fract(t / waveCycle); float autoRaise = smoothstep(0.06, 0.24, ph) * (1.0 - smoothstep(0.80, 0.96, ph)); float raise = waveAuto ? autoRaise * waveRaise : waveRaise; float lift = liftCurve(raise); float fold = smoothstep(0.35, 1.0, raise); float env = smoothstep(0.78, 1.0, raise); // Style presets: pose = (upper angle, elbow bend), amp = (forearm, nub flick, shoulder) float style = float(waveStyle); vec2 pose = vec2(0.16, 1.22); vec3 amp = vec3(0.75, 0.30, 0.00); if (style > 0.5 && style < 1.5) { pose = vec2(0.22, 1.12); amp = vec3(0.08, 0.60, 0.00); } else if (style > 1.5) { pose = vec2(0.08, 0.86); amp = vec3(0.10, 0.30, 0.27); } float w = t * waveSpeed * 2.0 * PI; float A = waveAmount * env; float osc = sin(w); float lag = sin(w - 1.1); float upper = mix(-HALF_PI, pose.x, lift) + A * (amp.z - 0.25 * amp.x) * osc; float foreHang = min(upper, -HALF_PI + 0.3); float foreUp = upper + pose.y + A * amp.x * osc; float fore = mix(foreHang, foreUp, fold); float nub = fore - 0.12 * fold + A * amp.y * lag; P.armR = vec3(upper, fore, nub); P.lenR = vec2(mix(103.0, 84.0, fold), 30.0 * fold); P.headTilt = bodyFollow * (0.09 * clamp(lift, 0.0, 1.0) + 0.035 * A * sin(w - 1.8)); } // Walk in place: alternating knee lifts, opposite arm swings forward // (shown front-on as the arm foreshortening and the nub rising), weight shift and bob. void poseWalk(inout Pose P, float beats, float E) { float ph = PI * beats; // one step per beat float s = sin(ph); P.footL.y += 62.0 * E * pow(max( s, 0.0), 1.3); P.footR.y += 62.0 * E * pow(max(-s, 0.0), 1.3); P.splay = 0.3; P.body = vec2(8.0 * E * s, -2.0 * E * (1.0 - abs(s))); // tiny settle between steps P.tilt = 0.025 * E * s; float fR = 0.5 + 0.5 * s; // right arm forward while left knee is up float fL = 1.0 - fR; float uR = -HALF_PI + E * mix(0.04, 0.16, fR); float uL = -HALF_PI + E * mix(0.04, 0.16, fL); float aR = uR + E * mix(0.0, 0.30, fR); float aL = uL + E * mix(0.0, 0.30, fL); P.armR = vec3(uR, aR, aR + 0.15 * E * fR); P.armL = vec3(uL, aL, aL + 0.15 * E * fL); P.lenR = vec2(103.0 - 46.0 * E * fR, 14.0 * E * fR); P.lenL = vec2(103.0 - 46.0 * E * fL, 14.0 * E * fL); P.headTilt = bodyFollow * 0.05 * E * sin(ph + 0.6); } // Run in place: high knees, a little flight between steps, and bent arms pumping // the nubs up and down in front of the chest (forearms foreshortened toward camera) void poseRun(inout Pose P, float beats, float E) { float ph = 2.0 * PI * beats; // one stride (two steps) per beat float s = sin(ph); P.footL.y += 120.0 * E * pow(max( s, 0.0), 1.2); P.footR.y += 120.0 * E * pow(max(-s, 0.0), 1.2); P.splay = 0.4; float flight = pow(1.0 - abs(s), 2.0); // airborne as the legs switch P.body = vec2(4.0 * E * s, E * (12.0 * flight - 5.0)); P.tilt = 0.02 * E * s; float fR = 0.5 + 0.5 * s; // arms opposite the legs float fL = 1.0 - fR; float uR = -HALF_PI + E * mix(0.22, 0.82, fR); float uL = -HALF_PI + E * mix(0.22, 0.82, fL); float aR = mix(-HALF_PI, mix(1.95, 2.30, fR), E); float aL = mix(-HALF_PI, mix(1.95, 2.30, fL), E); float trail = 0.2 * E * cos(ph); P.armR = vec3(uR, aR, aR - trail); P.armL = vec3(uL, aL, aL + trail); P.lenR = vec2(mix(103.0, 52.0, E), 18.0 * E); P.lenL = P.lenR; P.headTilt = bodyFollow * 0.05 * E * s; } // Dance: side-to-side groove, dip on every beat, heel pops, alternating arm raises void poseDance(inout Pose P, float beats, float E) { float ph = PI * beats; // full groove every two beats float s = sin(ph); float dip = 0.5 + 0.5 * cos(2.0 * ph); // 1 on each beat P.body = vec2(24.0 * E * s, -14.0 * E * dip); P.tilt = -0.07 * E * s; // lean into the sway P.headTilt = bodyFollow * 0.12 * E * sin(ph + 0.8); // Slightly wider stance, unweighted heel pops up P.footL = FOOT_L + vec2(-20.0 * E, 18.0 * E * pow(max( s, 0.0), 2.0)); P.footR = FOOT_R + vec2( 20.0 * E, 18.0 * E * pow(max(-s, 0.0), 2.0)); P.splay = 0.6; float upR = smoothstep(0.1, 0.9, 0.5 + 0.5 * s); float upL = smoothstep(0.1, 0.9, 0.5 - 0.5 * s); float pump = 0.15 * (dip - 0.5); float lagR = 0.25 * cos(ph), lagL = -lagR; float uR = mix(-1.25, 0.45, upR), aR = mix(-0.35, 1.35, upR) + pump; float uL = mix(-1.25, 0.45, upL), aL = mix(-0.35, 1.35, upL) + pump; P.armR = mix(vec3(-HALF_PI), vec3(uR, aR, aR - 0.1 * upR + lagR), E); P.armL = mix(vec3(-HALF_PI), vec3(uL, aL, aL - 0.1 * upL + lagL), E); P.lenR = mix(vec2(103.0, 0.0), vec2(mix(95.0, 84.0, upR), mix(16.0, 30.0, upR)), E); P.lenL = mix(vec2(103.0, 0.0), vec2(mix(95.0, 84.0, upL), mix(16.0, 30.0, upL)), E); } // Jumping jacks: hop on each switch, land open (arms up, feet wide) then closed void poseJacks(inout Pose P, float beats, float E) { float ph = PI * beats; // open on one beat, closed on the next float j = (0.5 - 0.5 * cos(ph)) * E; // 0 closed .. 1 open float hop = 24.0 * E * abs(sin(ph)); // airborne between positions P.body = vec2(0.0, hop - 9.0 * j); // sink a touch when landing wide P.footL = FOOT_L + vec2(-75.0 * j, hop); P.footR = FOOT_R + vec2( 75.0 * j, hop); P.splay = 0.3; float u = mix(-HALF_PI, 0.85, j); float a = mix(-HALF_PI, 0.95, j); float trail = 0.15 * E * sin(ph); P.armR = vec3(u, a, a - trail); P.armL = vec3(u, a, a - trail); P.lenR = vec2(mix(103.0, 84.0, j), 30.0 * j); P.lenL = P.lenR; } // Stand still: just a slow breath void poseStand(inout Pose P, float t, float E) { P.body = vec2(0.0, 2.5 * E * sin(t * 1.3)); } void main() { float t = TIME * speed; float beats = t * bpm / 60.0; float E = moveAmount; // Aspect-correct coords, mapped into the reference's 1000-unit frame vec2 p = isf_FragNormCoord - 0.5; p.x *= RENDERSIZE.x / RENDERSIZE.y; float upp = 1000.0 / (RENDERSIZE.y * zoom); // reference units per screen pixel (for AA) vec2 q = p * 1000.0 / zoom + 500.0; // Rounded black tile float dTile = sdRoundBox(q - vec2(500.0), vec2(468.0), vec4(95.0)); float tileM = showTile ? clamp(0.5 - dTile / upp, 0.0, 1.0) : 1.0; // ---------------- Pose for the selected motion ---------------- Pose P; restPose(P); float mode = float(motionMode); if (mode < 0.5) poseWave(P, t); else if (mode < 1.5) poseWalk(P, beats, E); else if (mode < 2.5) poseRun(P, beats, E); else if (mode < 3.5) poseDance(P, beats, E); else if (mode < 4.5) poseJacks(P, beats, E); else poseStand(P, t, E); // ---------------- Figure ---------------- float s = 1.0 + pulse * 0.08 * sin(t * 3.0); vec2 c = vec2(491.0, 500.0); vec2 fq = (q - c) / s + c; if (waveLeft) fq.x = 982.0 - fq.x; // mirror about the figure's centre line float dFig = figure(fq, P) * s; // Fill vs outline float lw = mix(3.0, 40.0, lineWidth); float mFill = clamp(0.5 - dFig / upp, 0.0, 1.0); float mLine = clamp(0.5 - (abs(dFig) - lw * 0.5) / upp, 0.0, 1.0); float m = mix(mFill, mLine, outlineMix); // Color: solid figure color blended toward the reference cosine palette 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); vec3 fig = mix(figureColor.rgb, pal, colorCycle); // Soft halo around the figure float g = glow * exp(-max(dFig, 0.0) / 60.0) * 0.8; vec3 inside = tileColor.rgb + fig * g; inside = mix(inside, fig, m); vec3 col = mix(outerColor.rgb, inside, tileM); gl_FragColor = vec4(col, 1.0); }
forking #qgi71c8k — lineage will be recorded.
renders in YOUR browser. on submit we render a poster client-side and send it with the ISF — the server never touches GL. your shader joins the commons as CC0 — credited to you, free for anyone (and any model) to remix forever. that's the whole point. it's permanent: once it's public, CC0 has no take-backs. by submitting you attest you have the right to release it as CC0.