Fun
Shader Collection
50 fragment shaders drafted with generative AI and tuned by hand, running live in WebGL2 — one fullscreen triangle, three uniforms, no libraries. Every tile goes fullscreen, where the source is editable and recompiles as you type. Each shader has its own link. For music underneath, open the Mod Music File Museum and press Random shader there.
In fullscreen: ← → browse · R random · T tour ·E edit GLSL · S save PNG · C copy link · Space pause · Esc close
Afterburn
#tunnelPolar remap · 16 neon lanes · a nod to Radial Afterburn
GLSL source
// Afterburn — a neon tube tunnel, a nod to Radial Afterburn. // Polar remap of the screen into (angle, depth), 16 glowing lanes around the rim, // rings marching toward the viewer, fogged toward the vanishing point. #define TAU 6.28318530718 vec3 palette(float t) { return mix(vec3(0.70, 0.15, 0.12), vec3(0.94, 0.41, 0.36), t); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; float r = length(p); float angle = atan(p.y, p.x); float depth = 0.25 / max(r, 1e-3) + iTime * 0.6; float twist = angle + 0.35 * sin(depth * 0.8 + iTime * 0.5); float lanes = abs(fract(twist / TAU * 16.0) - 0.5); float rings = abs(fract(depth * 2.0) - 0.5); float laneGlow = 0.02 / (lanes + 0.015); float ringGlow = 0.03 / (rings + 0.025); float pulse = 0.6 + 0.4 * sin(depth * 3.0 - iTime * 4.0); float fog = smoothstep(0.02, 0.6, r); vec3 col = vec3(0.03, 0.015, 0.02); col += palette(0.5 + 0.5 * sin(depth + iTime)) * laneGlow * fog * 0.6; col += palette(fract(depth * 0.5)) * ringGlow * fog * pulse; col += vec3(1.0, 0.9, 0.85) * laneGlow * ringGlow * fog * 0.15; col += vec3(1.0, 0.85, 0.8) * 0.02 / (r + 0.02); col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Raymarched SDFs · soft shadows · drag to orbit
GLSL source
// Still life — raymarched signed distance fields. // A sphere melted into a torus over a ground plane, key light with soft shadows, // rim light in the site accent. Drag horizontally to orbit the camera. float sdSphere(vec3 p, float r) { return length(p) - r; } float sdTorus(vec3 p, vec2 t) { vec2 q = vec2(length(p.xz) - t.x, p.y); return length(q) - t.y; } float smin(float a, float b, float k) { float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0); return mix(b, a, h) - k * h * (1.0 - h); } float map(vec3 p) { float ground = p.y + 1.0; float sphere = sdSphere(p - vec3(0.0, 0.2 * sin(iTime * 1.3), 0.0), 0.8); float torus = sdTorus(p - vec3(0.0, -0.3, 0.0), vec2(1.5, 0.22)); return min(ground, smin(sphere, torus, 0.4)); } vec3 normalAt(vec3 p) { vec2 e = vec2(0.001, 0.0); return normalize(vec3( map(p + e.xyy) - map(p - e.xyy), map(p + e.yxy) - map(p - e.yxy), map(p + e.yyx) - map(p - e.yyx))); } float softShadow(vec3 origin, vec3 dir) { float shade = 1.0; float t = 0.05; for (int i = 0; i < 24; i++) { float h = map(origin + dir * t); shade = min(shade, 10.0 * h / t); if (h < 0.001) break; t += clamp(h, 0.02, 0.3); } return clamp(shade, 0.0, 1.0); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; float drag = iMouse.z > 0.0 ? (iMouse.x - iMouse.z) / iResolution.x * 4.0 : 0.0; float orbit = iTime * 0.3 + drag; vec3 ro = vec3(3.5 * sin(orbit), 1.2, 3.5 * cos(orbit)); vec3 fwd = normalize(vec3(0.0, -0.2, 0.0) - ro); vec3 right = normalize(cross(vec3(0.0, 1.0, 0.0), fwd)); vec3 up = cross(fwd, right); vec3 rd = normalize(uv.x * right + uv.y * up + 1.6 * fwd); float t = 0.0; float d = 0.0; for (int i = 0; i < 80; i++) { d = map(ro + rd * t); if (d < 0.001 || t > 20.0) break; t += d; } vec3 sky = vec3(0.04, 0.03, 0.035); vec3 col = sky; if (d < 0.001) { vec3 p = ro + rd * t; vec3 n = normalAt(p); vec3 key = normalize(vec3(0.6, 0.8, 0.3)); float diffuse = max(dot(n, key), 0.0) * softShadow(p + n * 0.01, key); float rim = pow(1.0 - max(dot(n, -rd), 0.0), 3.0); float ao = clamp(map(p + n * 0.2) / 0.2, 0.0, 1.0); vec3 albedo = p.y < -0.99 ? vec3(0.10, 0.10, 0.11) : vec3(0.70, 0.15, 0.12); col = albedo * (0.15 + diffuse) * ao + vec3(0.94, 0.41, 0.36) * rim * 0.4; col = mix(col, sky, 1.0 - exp(-0.0025 * t * t)); } col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Ember
#plasmaDomain-warped fbm · cosine palette
GLSL source
// Ember — domain-warped fractal noise. // Value noise stacked into fbm, then fed back into itself twice (Quilez's warp), // shaded with a cosine palette in the site's ember reds. #define TAU 6.28318530718 float hash21(vec2 p) { p = fract(p * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } float noise(vec2 p) { vec2 i = floor(p); vec2 f = fract(p); vec2 u = f * f * (3.0 - 2.0 * f); return mix( mix(hash21(i), hash21(i + vec2(1.0, 0.0)), u.x), mix(hash21(i + vec2(0.0, 1.0)), hash21(i + vec2(1.0, 1.0)), u.x), u.y); } float fbm(vec2 p) { float value = 0.0; float amplitude = 0.5; mat2 rotate = mat2(0.8, 0.6, -0.6, 0.8); for (int i = 0; i < 5; i++) { value += amplitude * noise(p); p = rotate * p * 2.0 + 10.0; amplitude *= 0.5; } return value; } vec3 palette(float t) { return vec3(0.32, 0.10, 0.08) + vec3(0.60, 0.26, 0.16) * cos(TAU * (0.8 * t + vec3(0.0, 0.08, 0.12))); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * 2.5; float t = iTime * 0.15; vec2 q = vec2(fbm(p + t), fbm(p + vec2(5.2, 1.3) - t)); vec2 r = vec2( fbm(p + 4.0 * q + vec2(1.7, 9.2) + 0.3 * t), fbm(p + 4.0 * q + vec2(8.3, 2.8) - 0.2 * t)); float f = fbm(p + 4.0 * r); vec3 col = palette(f + 0.2 * length(q)); col *= 0.4 + 0.9 * f * f; col += vec3(0.94, 0.41, 0.36) * pow(clamp(length(r) - 0.6, 0.0, 1.0), 2.0) * 0.6; col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Menger
#mengerRaymarched Menger sponge · three folds
GLSL source
// Menger — a raymarched Menger sponge, three subdivisions deep, slowly tumbling. // The distance field is a box carved by a repeating cross at each scale. float sdBox(vec3 p, vec3 b) { vec3 q = abs(p) - b; return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0); } mat2 rot(float a) { float c = cos(a); float s = sin(a); return mat2(c, -s, s, c); } float map(vec3 p) { p.xz *= rot(iTime * 0.25); p.xy *= rot(iTime * 0.17); float d = sdBox(p, vec3(1.0)); float s = 1.0; for (int i = 0; i < 3; i++) { vec3 a = mod(p * s, 2.0) - 1.0; s *= 3.0; vec3 r = abs(1.0 - 3.0 * abs(a)); float da = max(r.x, r.y); float db = max(r.y, r.z); float dc = max(r.z, r.x); d = max(d, (min(da, min(db, dc)) - 1.0) / s); } return d; } vec3 normalAt(vec3 p) { vec2 e = vec2(0.0005, 0.0); return normalize(vec3(map(p + e.xyy) - map(p - e.xyy), map(p + e.yxy) - map(p - e.yxy), map(p + e.yyx) - map(p - e.yyx))); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; vec3 ro = vec3(0.0, 0.0, 3.4); vec3 rd = normalize(vec3(uv, -1.6)); float t = 0.0; float d = 0.0; int steps = 0; for (int i = 0; i < 72; i++) { d = map(ro + rd * t); steps = i; if (d < 0.001 || t > 8.0) break; t += d; } vec3 col = vec3(0.03, 0.015, 0.02); if (d < 0.001) { vec3 p = ro + rd * t; vec3 n = normalAt(p); float diffuse = max(dot(n, normalize(vec3(0.5, 0.8, 0.6))), 0.0); float ao = 1.0 - float(steps) / 72.0; float rim = pow(1.0 - max(dot(n, -rd), 0.0), 3.0); col = vec3(0.70, 0.15, 0.12) * (0.2 + diffuse) * ao + vec3(0.94, 0.41, 0.36) * rim * 0.5; } col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Cells
#cellsAnimated Voronoi · glowing borders
GLSL source
// Cells — animated Voronoi. One feature point jitters inside each grid square; // distance to the nearest and second-nearest point gives cell shading and glowing borders. vec2 hash22(vec2 p) { p = vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3))); return fract(sin(p) * 43758.5453); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * 6.0; vec2 cell = floor(p); vec2 f = fract(p); float d1 = 8.0; float d2 = 8.0; vec2 nearest = vec2(0.0); for (int y = -1; y <= 1; y++) { for (int x = -1; x <= 1; x++) { vec2 offset = vec2(float(x), float(y)); vec2 h = hash22(cell + offset); vec2 point = offset + 0.5 + 0.4 * sin(iTime * 0.8 + 6.2831 * h); float d = length(point - f); if (d < d1) { d2 = d1; d1 = d; nearest = h; } else if (d < d2) { d2 = d; } } } float border = d2 - d1; vec3 base = mix(vec3(0.04, 0.02, 0.03), vec3(0.70, 0.15, 0.12), nearest.x * 0.6); vec3 col = base * (1.0 - d1 * 0.5); col += vec3(0.94, 0.41, 0.36) * smoothstep(0.08, 0.0, border) * 0.9; col += vec3(1.0, 0.9, 0.85) * smoothstep(0.06, 0.0, d1) * 0.5; col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Julia
#juliaJulia set · smooth escape time · orbit trap
GLSL source
// Julia — the quadratic Julia set for a constant that drifts around the // Mandelbrot cardioid. Outside: smooth escape time. Inside: an orbit trap. const int STEPS = 120; void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 z = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * 3.0; float t = iTime * 0.15; vec2 c = vec2(-0.745 + 0.11 * cos(t), 0.186 + 0.11 * sin(t * 1.3)); float trap = 1e9; int i = 0; for (; i < STEPS; i++) { z = vec2(z.x * z.x - z.y * z.y, 2.0 * z.x * z.y) + c; trap = min(trap, abs(z.y)); if (dot(z, z) > 64.0) break; } vec3 col; if (i >= STEPS) { col = vec3(0.02, 0.01, 0.015) + vec3(0.70, 0.15, 0.12) * exp(-trap * 6.0); } else { float s = (float(i) - log2(max(log2(dot(z, z)), 1.0))) / 40.0; col = vec3(0.32, 0.10, 0.08) + vec3(0.60, 0.28, 0.18) * cos(6.2831 * (s * 1.5 + vec3(0.0, 0.08, 0.14))); } col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Warp
#warpLog-polar starfield · six layers
GLSL source
// Warp — a starfield streaking past the camera. The screen is mapped to // (angle, log radius); each layer is a hashed grid of streaks sliding outward. float hash21(vec2 p) { p = fract(p * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; float angle = atan(p.y, p.x); float r = length(p); vec3 col = vec3(0.02, 0.01, 0.015); for (int layer = 0; layer < 6; layer++) { float fl = float(layer); vec2 uv = vec2(angle / 6.2831 * 24.0, log(max(r, 0.001)) * 5.0 - iTime * (1.5 + fl * 0.4) - fl * 7.3); vec2 cell = floor(uv); vec2 f = fract(uv) - 0.5; float h = hash21(cell + fl * 13.7); float present = step(h, 0.14); float sx = (hash21(cell + 3.1 + fl) - 0.5) * 0.6; float streak = smoothstep(0.08, 0.0, abs(f.x - sx)) * smoothstep(0.5, 0.0, abs(f.y)); vec3 tint = mix(vec3(0.94, 0.41, 0.36), vec3(1.0, 0.9, 0.85), h * 6.0); col += present * streak * tint * smoothstep(0.0, 0.5, r) * 0.9; } col += vec3(0.70, 0.15, 0.12) * 0.03 / (r + 0.05); col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Metaballs
#metaballsInverse-square field · iso-contours
GLSL source
// Metaballs — five wandering charges summed as r²/d². A threshold makes the // blobs merge and split; iso-contours below the threshold show the field. void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * 2.0; float field = 0.0; for (int i = 0; i < 5; i++) { float fi = float(i); vec2 c = 0.7 * vec2(sin(iTime * (0.5 + fi * 0.13) + fi * 1.7), cos(iTime * (0.4 + fi * 0.11) + fi * 2.3)); float radius = 0.12 + 0.05 * fi; field += radius * radius / dot(p - c, p - c); } float blob = smoothstep(0.9, 1.1, field); float rings = 0.5 + 0.5 * sin(field * 20.0 - iTime * 2.0); vec3 col = vec3(0.03, 0.015, 0.02); col += vec3(0.70, 0.15, 0.12) * (1.0 - blob) * pow(rings, 8.0) * smoothstep(0.1, 0.9, field) * 0.8; col = mix(col, vec3(0.94, 0.41, 0.36), blob); col += vec3(1.0, 0.9, 0.85) * smoothstep(1.1, 2.5, field) * 0.5; col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Truchet
#truchetQuarter-circle tiles · hashed mirroring
GLSL source
// Truchet — quarter-circle arcs on a grid, each tile mirrored by a hash, so // random tiles join into endless loops. Light flows along the arcs. float hash21(vec2 p) { p = fract(p * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * 7.0 + vec2(iTime * 0.3, 0.0); vec2 cell = floor(p); vec2 f = fract(p); float h = hash21(cell); if (h < 0.5) f.x = 1.0 - f.x; float d = min(abs(length(f) - 0.5), abs(length(f - 1.0) - 0.5)); float line = smoothstep(0.08, 0.02, d); float glow = 0.02 / (d + 0.05); float flow = 0.5 + 0.5 * sin((length(f) + length(f - 1.0)) * 6.0 - iTime * 3.0 + h * 6.2831); vec3 col = vec3(0.03, 0.015, 0.02); col += vec3(0.70, 0.15, 0.12) * glow * 0.6; col += mix(vec3(0.94, 0.41, 0.36), vec3(1.0, 0.9, 0.85), flow) * line; col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Hex
#hexHexagonal grid · per-cell pulse
GLSL source
// Hex — a hexagonal grid. Every cell pulses on its own phase, offset by its // distance from the center so waves ripple outward; edges glow. float hash21(vec2 p) { p = fract(p * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } float hexDist(vec2 p) { p = abs(p); return max(dot(p, normalize(vec2(1.0, 1.7320508))), p.x); } // Returns (distance to edge, cell id). vec3 hexCell(vec2 uv) { vec2 r = vec2(1.0, 1.7320508); vec2 h = r * 0.5; vec2 a = mod(uv, r) - h; vec2 b = mod(uv - h, r) - h; vec2 gv = dot(a, a) < dot(b, b) ? a : b; return vec3(0.5 - hexDist(gv), uv - gv); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * 8.0; vec3 cell = hexCell(p); float h = hash21(cell.yz); float pulse = 0.5 + 0.5 * sin(iTime * 1.5 + h * 6.2831 - length(cell.yz) * 0.6); float edge = smoothstep(0.06, 0.0, cell.x); vec3 col = vec3(0.03, 0.015, 0.02) + vec3(0.70, 0.15, 0.12) * pulse * pulse * 0.7; col += vec3(0.94, 0.41, 0.36) * edge * 0.8; col += vec3(1.0, 0.9, 0.85) * smoothstep(0.9, 1.0, pulse) * smoothstep(0.0, 0.2, cell.x) * 0.3; col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Kaleidoscope
#kaleidoEight-way polar fold · fbm
GLSL source
// Kaleidoscope — the plane folded into eight mirrored wedges, then fractal // noise painted through the folded coordinates so every wedge matches its neighbors. float hash21(vec2 p) { p = fract(p * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } float noise(vec2 p) { vec2 i = floor(p); vec2 f = fract(p); vec2 u = f * f * (3.0 - 2.0 * f); return mix( mix(hash21(i), hash21(i + vec2(1.0, 0.0)), u.x), mix(hash21(i + vec2(0.0, 1.0)), hash21(i + vec2(1.0, 1.0)), u.x), u.y); } float fbm(vec2 p) { float value = 0.0; float amplitude = 0.5; for (int i = 0; i < 5; i++) { value += amplitude * noise(p); p = p * 2.1 + 7.0; amplitude *= 0.5; } return value; } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; float r = length(p); const float WEDGES = 8.0; float a = abs(mod(atan(p.y, p.x), 6.2831 / WEDGES) - 3.14159 / WEDGES); vec2 q = vec2(cos(a), sin(a)) * r * 4.0; float n = fbm(q + vec2(iTime * 0.2, -iTime * 0.15)); float n2 = fbm(q * 2.0 - iTime * 0.1); vec3 col = vec3(0.32, 0.10, 0.08) + vec3(0.60, 0.26, 0.16) * cos(6.2831 * (n * 1.2 + vec3(0.0, 0.08, 0.12))); col *= 0.3 + n2; col *= smoothstep(1.0, 0.3, r); col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Waves
#wavesTwelve sine lines · additive glow
GLSL source
// Waves — a stack of sine curves with drifting phase and amplitude, each drawn // as a thin glowing line. Reads like an oscilloscope left running. void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; vec3 col = vec3(0.03, 0.015, 0.02); for (int i = 0; i < 12; i++) { float fi = float(i); float baseline = -0.4 + fi * 0.07; float amplitude = 0.05 + 0.03 * sin(iTime * 0.7 + fi); float wave = baseline + amplitude * sin(p.x * (4.0 + fi * 0.5) + iTime * (1.0 + fi * 0.1) + fi) + 0.02 * sin(p.x * 20.0 - iTime * 3.0 + fi * 2.0); float d = abs(p.y - wave); float line = 0.004 / (d + 0.004); col += mix(vec3(0.70, 0.15, 0.12), vec3(0.94, 0.41, 0.36), fi / 11.0) * line * 0.6; } col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Interference
#ringsThree ring sources · moiré
GLSL source
// Interference — three ring sources wander around; their waves add and cancel // into a moiré that never repeats. void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; float sum = 0.0; for (int i = 0; i < 3; i++) { float fi = float(i); vec2 c = 0.45 * vec2(cos(iTime * 0.3 + fi * 2.094), sin(iTime * 0.23 + fi * 2.094)); sum += sin(length(p - c) * 60.0 - iTime * 2.0); } float v = sum / 3.0; vec3 col = vec3(0.32, 0.10, 0.08) + vec3(0.60, 0.26, 0.16) * cos(6.2831 * (v * 0.5 + vec3(0.0, 0.08, 0.12))); col *= 0.35 + 0.65 * smoothstep(-0.2, 1.0, v); col += vec3(1.0, 0.9, 0.85) * smoothstep(0.85, 1.0, v) * 0.4; col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Seahorse
#mandelbrotEscape-time Mandelbrot · smooth iteration count · cosine palette
GLSL source
// Mandelbrot — a breathing zoom into the seahorse valley at (-0.745, 0.186). // Escape time is smoothed with the log-log of the bailout radius so bands blend, // then fed through a cosine palette in ember reds; the interior stays dark. const int MAX_ITER = 100; vec3 palette(float t) { return vec3(0.42, 0.16, 0.13) + vec3(0.40, 0.15, 0.12) * cos(6.2831853 * (t + vec3(0.0, 0.10, 0.18))); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; float depth = 11.0 * (0.5 - 0.5 * cos(iTime * 0.05)); float scale = 2.6 * exp2(-depth); vec2 c = vec2(-0.745, 0.186) + p * scale; vec2 z = vec2(0.0); float smoothIter = 0.0; bool escaped = false; for (int i = 0; i < MAX_ITER; i++) { z = vec2(z.x * z.x - z.y * z.y, 2.0 * z.x * z.y) + c; float r2 = dot(z, z); if (r2 > 256.0) { smoothIter = float(i) + 1.0 - log2(log2(r2) * 0.5); escaped = true; break; } } vec3 col = vec3(0.03, 0.015, 0.02); if (escaped) { float t = sqrt(max(smoothIter, 0.0) / float(MAX_ITER)); col = palette(t * 3.0 - iTime * 0.04) * (0.25 + 0.75 * t); col += vec3(1.0, 0.9, 0.85) * t * t * t * t * 0.5; } col = max(col, 0.0); col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Gasket
#sierpinskiKaleidoscopic fold IFS · per-level edge SDF · pulsing hierarchy
GLSL source
// Sierpinski — the gasket by kaleidoscopic folding. Each pass reflects the plane // into the wedge nearest the apex and doubles it about that vertex; every level's // triangle outline is accumulated as glow, so the whole hierarchy shows at once. float sdTriangle(vec2 p) { float bottom = -p.y - 0.5; float right = dot(p, vec2(0.8660254, 0.5)) - 0.5; float left = dot(p, vec2(-0.8660254, 0.5)) - 0.5; return max(bottom, max(right, left)); } mat2 rotate(float a) { float c = cos(a); float s = sin(a); return mat2(c, s, -s, c); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { float zoom = 2.3 - 0.3 * sin(iTime * 0.2); vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * zoom; p = rotate(iTime * 0.1) * p; float pixel = zoom / iResolution.y; vec2 mirrorA = vec2(0.5, 0.8660254); vec2 mirrorB = vec2(-0.5, 0.8660254); vec2 apex = vec2(0.0, 1.0); float scale = 1.0; float edges = 0.0; float d = 0.0; for (int i = 0; i < 8; i++) { d = sdTriangle(p) / scale; float pulse = 0.55 + 0.45 * sin(iTime * 1.2 - float(i) * 1.1); edges += smoothstep(pixel * 2.0, 0.0, abs(d)) * pulse; if (scale * 14.0 > iResolution.y) break; p -= 2.0 * min(0.0, dot(p, mirrorA)) * mirrorA; p -= 2.0 * min(0.0, dot(p, mirrorB)) * mirrorB; p = p * 2.0 - apex; scale *= 2.0; } float fill = smoothstep(pixel, -pixel, d); vec3 col = vec3(0.03, 0.015, 0.02); col += vec3(0.70, 0.15, 0.12) * fill * 0.45; col += vec3(0.94, 0.41, 0.36) * edges * 0.7; col += vec3(1.0, 0.9, 0.85) * edges * edges * 0.12; col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Kaleidoscopic IFS · abs/rotate/scale folds · orbit-trap color
GLSL source
// KIFS — a kaleidoscopic iterated function system. Every pass mirrors the plane // across both axes, shifts it off-center, then rotates and scales it; orbit traps // (closest approach to the origin and to the x-axis) drive the coloring. mat2 rotate(float a) { float c = cos(a); float s = sin(a); return mat2(c, s, -s, c); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * 2.4; float t = iTime * 0.15; float mouseTurn = iMouse.z > 0.0 ? (iMouse.x / iResolution.x - 0.5) * 3.0 : 0.0; mat2 twist = rotate(0.55 + 0.3 * sin(t * 0.9) + mouseTurn); vec2 offset = vec2(0.9 + 0.15 * sin(t * 1.3), 0.35 + 0.1 * cos(t * 0.7)); p = rotate(t) * p; float trapOrigin = 1e5; float trapAxis = 1e5; for (int i = 0; i < 8; i++) { p = abs(p) - offset; p = twist * p; p *= 1.35; trapOrigin = min(trapOrigin, dot(p, p)); trapAxis = min(trapAxis, abs(p.y)); } float glow = exp(-trapOrigin * 2.5); float lines = exp(-trapAxis * 9.0); float band = 0.5 + 0.5 * cos(trapOrigin * 3.0 - iTime * 0.6); vec3 col = vec3(0.03, 0.015, 0.02); col += vec3(0.70, 0.15, 0.12) * band * 0.55; col += vec3(0.94, 0.41, 0.36) * glow * 0.9; col += vec3(0.55, 0.35, 0.95) * lines * 0.6; col += vec3(1.0, 0.9, 0.85) * glow * lines * 0.6; col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Vortex arms
#spiralLog-polar spirals · three arm layers · radial falloff
GLSL source
// Spiral — logarithmic spiral arms. In (angle, log radius) a log spiral is a straight // line, so cos(n * (theta - pitch * log r)) draws n arms at once; three layers with // different arm counts, pitches and speeds are summed under a radial falloff. void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * 2.0; float r = max(length(p), 1e-4); float theta = atan(p.y, p.x); float logR = log(r); float t = iTime; float armsTwo = pow(0.5 + 0.5 * cos(2.0 * (theta - 0.9 * logR) + t * 0.2), 3.0); float armsThree = pow(0.5 + 0.5 * cos(3.0 * (theta - 1.6 * logR) - t * 0.5), 6.0); float armsFive = pow(0.5 + 0.5 * cos(5.0 * (theta + 2.2 * logR) + t * 0.35), 10.0); float fade = smoothstep(0.0, 0.25, r) * exp(-r * 1.1); vec3 col = vec3(0.03, 0.015, 0.02); col += vec3(0.70, 0.15, 0.12) * armsTwo * fade * 0.8; col += vec3(0.94, 0.41, 0.36) * armsThree * fade * 1.2; col += vec3(1.0, 0.75, 0.3) * armsFive * fade * 0.7; col += vec3(1.0, 0.9, 0.85) * armsThree * armsFive * fade * 1.5; col += vec3(0.70, 0.15, 0.12) * exp(-r * 5.0) * 0.6; col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Rhodonea
#rosePolar rose curves · implicit-function SDF · k crossfade
GLSL source
// Rose — polar roses r = cos(k * theta), drawn as glowing lines from the implicit // form |r - |cos(k theta)|| divided by its gradient. k steps through 2..6 with a // crossfade between neighbours; a counter-rotating teal rose and ring grid sit below. mat2 rotate(float a) { float c = cos(a); float s = sin(a); return mat2(c, s, -s, c); } float roseDist(vec2 p, float k) { float r = length(p); float theta = atan(p.y, p.x); float f = r - abs(cos(k * theta)); float slope = k * sin(k * theta) / max(r, 0.02); return abs(f) / sqrt(1.0 + slope * slope); } float glowLine(float d, float pixel) { return smoothstep(pixel * 2.5, 0.0, d) + 0.35 * 0.02 / (d + 0.02); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * 2.3; float pixel = 2.3 / iResolution.y; float s = iTime * 0.12; float kNow = 2.0 + mod(floor(s), 5.0); float kNext = 2.0 + mod(floor(s) + 1.0, 5.0); float blend = smoothstep(0.6, 0.95, fract(s)); vec2 q = rotate(iTime * 0.08) * p; float outer = mix(glowLine(roseDist(q, kNow), pixel), glowLine(roseDist(q, kNext), pixel), blend); vec2 inner = rotate(-iTime * 0.2) * p / 0.45; float innerRose = glowLine(roseDist(inner, 3.0) * 0.45, pixel); float r = length(p); float ringDist = abs(fract(r * 5.0 + 0.5) - 0.5) / 5.0; float rings = smoothstep(pixel * 1.5, 0.0, ringDist) * smoothstep(1.25, 0.4, r); vec3 col = vec3(0.03, 0.015, 0.02); col += vec3(0.70, 0.15, 0.12) * rings * 0.35; col += vec3(0.94, 0.41, 0.36) * outer * 0.9; col += vec3(1.0, 0.9, 0.85) * outer * outer * 0.25; col += vec3(0.2, 0.8, 0.75) * innerRose * 0.6; col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Sevenfold
#quasicrystalSeven summed plane waves · aperiodic interference · contour banding
GLSL source
// Quasicrystal — seven plane waves with evenly spaced directions summed together. // Seven-fold symmetry cannot tile the plane, so the interference never repeats; // phases drift with time and contours of the sum are banded in ember. const float PI = 3.14159265; void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; float spin = iTime * 0.03; float freq = 36.0 + 8.0 * sin(iTime * 0.07); float sum = 0.0; for (int i = 0; i < 7; i++) { float a = float(i) * PI / 7.0 + spin; vec2 dir = vec2(cos(a), sin(a)); sum += cos(dot(p, dir) * freq + iTime * (0.35 + 0.05 * float(i))); } float v = 0.5 + 0.5 * sum / 7.0; float band = 0.5 + 0.5 * cos(sum * 1.6 - iTime * 0.5); float vignette = 1.0 - 0.35 * dot(p, p); vec3 col = vec3(0.03, 0.015, 0.02); col += vec3(0.70, 0.15, 0.12) * band * 0.45; col += vec3(0.94, 0.41, 0.36) * smoothstep(0.6, 0.85, v); col += vec3(1.0, 0.9, 0.85) * smoothstep(0.82, 1.0, v) * 0.8; col *= vignette; col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Dazzle
#opartPolar checkerboard · drifting lens warp · fwidth anti-aliasing
GLSL source
// Op-art — a warped dartboard. Concentric rings crossed with angular sectors make a // polar checkerboard; a lens drifting around the frame pushes and pulls the grid // beneath it while the rings creep outward. Screen-space derivatives anti-alias. void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * 2.0; float t = iTime; vec2 lensCenter = vec2(0.7 * sin(t * 0.23), 0.4 * cos(t * 0.31)); vec2 delta = p - lensCenter; float lens = exp(-dot(delta, delta) * 4.0); float bulge = 0.45 * sin(t * 0.45); vec2 q = p + delta * bulge * lens; float r = length(q); float theta = atan(q.y, q.x); float checker = sin(r * 26.0 - t * 0.5) * sin(theta * 12.0); float aa = max(fwidth(checker), 1e-4); float v = smoothstep(-aa, aa, checker); vec3 light = mix(vec3(1.0, 0.9, 0.85), vec3(0.94, 0.41, 0.36), lens * 0.85) * 2.4; vec3 dark = mix(vec3(0.03, 0.015, 0.02), vec3(0.70, 0.15, 0.12) * 0.35, lens); vec3 col = mix(dark, light, v); col *= 0.75 + 0.25 * smoothstep(1.3, 0.3, r); col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Phosphor
#lissajousLissajous polylines · 48-segment SDF trails · additive glow
GLSL source
// Lissajous — four curves x = sin(a s + phi), y = sin(b s) traced like a phosphor // scope: 48 samples trail behind a moving head, the distance to each segment adds // glow, and the weight fades toward the tail so the trace has persistence. float segmentDist(vec2 p, vec2 a, vec2 b) { vec2 pa = p - a; vec2 ba = b - a; float h = clamp(dot(pa, ba) / max(dot(ba, ba), 1e-6), 0.0, 1.0); return length(pa - ba * h); } // k = (a, b, phi, amplitude) vec2 curvePoint(float s, vec4 k) { return k.w * vec2(1.45 * sin(k.x * s + k.z), 0.85 * sin(k.y * s)); } float trace(vec2 p, vec4 k, float head, float span, float pixel) { float glow = 0.0; vec2 prev = curvePoint(head, k); for (int i = 1; i <= 48; i++) { float f = float(i) / 48.0; vec2 next = curvePoint(head - f * span, k); float d = segmentDist(p, prev, next); float weight = (1.0 - f) * (1.0 - f); glow += weight * (smoothstep(pixel * 2.0, 0.0, d) + 0.5 * 0.0015 / (d * d + 0.0015)); prev = next; } vec2 headPoint = curvePoint(head, k); glow += 0.004 / (dot(p - headPoint, p - headPoint) + 0.004); return glow; } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * 2.2; float pixel = 2.2 / iResolution.y; float t = iTime * 0.45; float traceA = trace(p, vec4(3.0, 2.0, 1.5708, 1.0), t, 1.3, pixel); float traceB = trace(p, vec4(1.0, 3.0, 0.7854, 0.8), t * 0.85 + 2.0, 2.2, pixel); float traceC = trace(p, vec4(5.0, 4.0, 0.0, 0.92), t * 0.6 + 4.0, 0.8, pixel); float traceD = trace(p, vec4(2.0, 3.0, 0.5, 0.6), t * 0.7 + 1.0, 3.0, pixel); vec3 col = vec3(0.03, 0.015, 0.02); col += vec3(0.70, 0.15, 0.12) * traceA * 0.9; col += vec3(0.94, 0.41, 0.36) * traceB * 0.8; col += vec3(0.94, 0.41, 0.36) * traceC * 0.45; col += vec3(0.70, 0.15, 0.12) * traceD * 0.7; col += vec3(1.0, 0.9, 0.85) * (traceA + traceB + traceC + traceD) * 0.12; col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Hypercube
#tesseract4D bit-indexed vertices · xw/yz rotation · double perspective
GLSL source
// Tesseract — a hypercube turning in the xw and yz planes. The 16 vertices come // from the bits of their index, the 32 edges join vertices one bit apart; each is // projected 4D -> 3D -> 2D with perspective and drawn as a glowing segment. float segmentDist(vec2 p, vec2 a, vec2 b) { vec2 pa = p - a; vec2 ba = b - a; float h = clamp(dot(pa, ba) / max(dot(ba, ba), 1e-6), 0.0, 1.0); return length(pa - ba * h); } // Returns (screen x, screen y, nearness in [0, 1]). vec3 project(int index, mat4 rot4, mat3 rot3) { vec4 v = vec4( float(index & 1), float((index >> 1) & 1), float((index >> 2) & 1), float((index >> 3) & 1)) * 2.0 - 1.0; v = rot4 * v; float depth4 = 1.0 / (2.6 - v.w); vec3 q = rot3 * (v.xyz * depth4); float depth3 = 1.0 / (4.0 - q.z); return vec3(q.xy * depth3 * 2.4, clamp(0.5 + 0.35 * v.w, 0.0, 1.0)); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * 2.0; float pixel = 2.0 / iResolution.y; float ca = cos(iTime * 0.35); float sa = sin(iTime * 0.35); float cb = cos(iTime * 0.22); float sb = sin(iTime * 0.22); float cc = cos(iTime * 0.1); float sc = sin(iTime * 0.1); mat4 rotXW = mat4(vec4(ca, 0.0, 0.0, sa), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(-sa, 0.0, 0.0, ca)); mat4 rotYZ = mat4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, cb, sb, 0.0), vec4(0.0, -sb, cb, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); mat3 rotY = mat3(vec3(cc, 0.0, -sc), vec3(0.0, 1.0, 0.0), vec3(sc, 0.0, cc)); mat3 tilt = mat3(vec3(1.0, 0.0, 0.0), vec3(0.0, 0.92, 0.39), vec3(0.0, -0.39, 0.92)); mat4 rot4 = rotYZ * rotXW; mat3 rot3 = tilt * rotY; vec3 col = vec3(0.03, 0.015, 0.02); for (int i = 0; i < 16; i++) { vec3 from = project(i, rot4, rot3); vec2 toVertex = p - from.xy; col += vec3(1.0, 0.9, 0.85) * (0.0004 / (dot(toVertex, toVertex) + 0.0004)) * (0.3 + 0.7 * from.z) * 0.5; for (int bit = 0; bit < 4; bit++) { if (((i >> bit) & 1) == 1) continue; vec3 to = project(i | (1 << bit), rot4, rot3); float d = segmentDist(p, from.xy, to.xy); float nearness = 0.5 * (from.z + to.z); float line = smoothstep(pixel * 1.5, 0.0, d) + 0.4 * 0.0006 / (d * d + 0.0006); col += mix(vec3(0.70, 0.15, 0.12), vec3(0.94, 0.41, 0.36), nearness) * line * (0.35 + 0.9 * nearness); } } col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Clockwork
#gearsSDF spur gears · solved mesh phases · gradient-bevel shading
GLSL source
// Gears — three meshing spur gears as 2D SDFs. Each is a circle whose radius follows // a squared-off cosine of the angle for teeth, minus a hub hole and a groove; they // share a tooth pitch and turn at inverse ratios with phases solved so teeth interleave. const float PI = 3.14159265; float gearShape(vec2 q, float radius, float teeth, float phase) { float r = length(q); float theta = atan(q.y, q.x); float tooth = smoothstep(-0.45, 0.45, 1.5 * cos(teeth * (theta - phase))); float d = r - (radius - 0.045 + 0.09 * tooth); d = max(d, 0.28 * radius - r); return max(d, -(abs(r - 0.62 * radius) - 0.012)); } float scene(vec2 q, float angle) { float teethA = 12.0; float teethB = 8.0; float teethC = 18.0; float radiusA = 0.42; float pitch = radiusA / teethA; float radiusB = pitch * teethB; float radiusC = pitch * teethC; float dirB = 2.6; float dirC = -0.5; vec2 centerB = (radiusA + radiusB) * vec2(cos(dirB), sin(dirB)); vec2 centerC = (radiusA + radiusC) * vec2(cos(dirC), sin(dirC)); float phaseB = (dirB * (teethA + teethB) + (teethB - 1.0) * PI) / teethB - angle * teethA / teethB; float phaseC = (dirC * (teethA + teethC) + (teethC - 1.0) * PI) / teethC - angle * teethA / teethC; float d = gearShape(q, radiusA, teethA, angle); d = min(d, gearShape(q - centerB, radiusB, teethB, phaseB)); d = min(d, gearShape(q - centerC, radiusC, teethC, phaseC)); return d; } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * 2.2; vec2 q = p + vec2(0.33, -0.25); float angle = iTime * 0.4; float eps = 0.006; float d = scene(q, angle); vec2 grad = vec2(scene(q + vec2(eps, 0.0), angle) - d, scene(q + vec2(0.0, eps), angle) - d) / eps; float bevel = smoothstep(-0.05, 0.0, d); vec3 normal = normalize(vec3(grad * bevel * 1.5, 1.0)); vec3 lightDir = normalize(vec3(cos(iTime * 0.3), sin(iTime * 0.3) + 0.5, 0.8)); float diffuse = max(dot(normal, lightDir), 0.0); float spec = pow(max(dot(reflect(-lightDir, normal), vec3(0.0, 0.0, 1.0)), 0.0), 20.0); float inside = smoothstep(0.004, -0.004, d); float brush = 0.92 + 0.08 * sin(d * 220.0); vec3 metal = vec3(0.70, 0.15, 0.12) * 0.55 + vec3(0.94, 0.41, 0.36) * 0.25; vec3 col = vec3(0.03, 0.015, 0.02) + vec3(0.70, 0.15, 0.12) * 0.12 * exp(-dot(q, q) * 0.8); col = mix(col, metal * brush * (0.3 + 0.9 * diffuse) + vec3(1.0, 0.9, 0.85) * spec * 0.7, inside); col += vec3(0.94, 0.41, 0.36) * smoothstep(0.01, 0.0, abs(d)) * 0.5; col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Rain
#matrixHashed 3×5 bit-glyphs · per-column scroll speed · head/trail falloff
GLSL source
// Rain — digital rain in ember. Each column scrolls at its own hashed speed; // glyphs are 3x5 bit patterns pulled from a hash and drawn as small squares, // the head burns bright, the tail fades to ember, and the bits flicker over time. float hash21(vec2 p) { p = fract(p * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } // A 3x5 grid of squares inside the unit cell, each bit set by hash. float glyph(vec2 cellUv, vec2 id, float seed) { vec2 grid = (cellUv - 0.1) / 0.8 * vec2(3.0, 5.0); if (grid.x < 0.0 || grid.y < 0.0 || grid.x >= 3.0 || grid.y >= 5.0) return 0.0; vec2 bit = floor(grid); vec2 f = fract(grid); float on = step(0.45, hash21(id * 3.1 + bit * 0.7 + seed * 0.13)); float square = step(0.12, f.x) * step(f.x, 0.88) * step(0.12, f.y) * step(f.y, 0.88); return on * square; } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 uv = fragCoord / iResolution.y; vec2 cellSize = vec2(0.7, 1.0) / 20.0; vec2 cell = floor(uv / cellSize); vec2 cellUv = fract(uv / cellSize); float speed = 3.0 + 8.0 * hash21(vec2(cell.x, 7.0)); float trailLen = 8.0 + floor(14.0 * hash21(vec2(cell.x, 11.0))); float row = cell.y + floor(iTime * speed + hash21(vec2(cell.x, 3.0)) * 100.0); float pos = mod(row, trailLen); float alive = step(0.25, hash21(vec2(cell.x, floor(row / trailLen)))); float fade = 1.0 - pos / trailLen; float isHead = 1.0 - step(0.5, pos); float flickerRate = 1.5 + 5.0 * hash21(cell + 0.5); float seed = floor(iTime * flickerRate + hash21(cell) * 10.0); float g = glyph(cellUv, cell, seed) * alive; vec3 col = vec3(0.03, 0.015, 0.02); col += vec3(0.70, 0.15, 0.12) * g * fade * fade * 1.6; col += vec3(0.94, 0.41, 0.36) * g * fade * fade * fade * 0.8; col += vec3(1.0, 0.9, 0.85) * g * isHead * 1.5; col += vec3(0.70, 0.15, 0.12) * 0.12 * fade * alive; col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Test card
#crtBarrel distortion · curved scanlines · RGB subpixel mask · roll bar
GLSL source
// Test card — a CRT test pattern in ember: colour bars, gradient bands, a // grid, circle and crosshair, then barrel distortion, curved scanlines, RGB // subpixel stripes, a rolling dark bar, vignette and per-frame noise flicker. float hash21(vec2 p) { p = fract(p * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } vec3 ramp(float t) { t = clamp(t, 0.0, 1.0); vec3 col = mix(vec3(0.03, 0.015, 0.02), vec3(0.70, 0.15, 0.12), smoothstep(0.0, 0.35, t)); col = mix(col, vec3(0.94, 0.41, 0.36), smoothstep(0.35, 0.7, t)); return mix(col, vec3(1.0, 0.9, 0.85), smoothstep(0.7, 1.0, t)); } vec3 testCard(vec2 uv, float aspect) { vec3 col; if (uv.y > 0.66) { float bar = floor(uv.x * 8.0); col = ramp(fract(bar * 0.618 + iTime * 0.04)); } else if (uv.y > 0.42) { float t = uv.x < 0.5 ? uv.x * 2.0 : floor(uv.x * 16.0 - 8.0) / 7.0; col = ramp(t); } else { vec2 grid = abs(fract(uv * vec2(aspect, 1.0) * 6.0) - 0.5); float line = smoothstep(0.46, 0.5, max(grid.x, grid.y)); col = vec3(0.03, 0.015, 0.02) + vec3(0.70, 0.15, 0.12) * line * 0.8; } vec2 p = (uv - 0.5) * vec2(aspect, 1.0); float r = length(p); float ring = smoothstep(0.012, 0.004, abs(r - 0.4)); float crosshair = smoothstep(0.008, 0.002, min(abs(p.x), abs(p.y))) * step(r, 0.4); return mix(col, vec3(1.0, 0.9, 0.85), max(ring, crosshair) * 0.9); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 uv = fragCoord / iResolution.xy; float aspect = iResolution.x / iResolution.y; vec2 c = uv * 2.0 - 1.0; float r2 = dot(c, c); c *= 1.0 + 0.1 * r2; vec2 warped = c * 0.5 + 0.5; vec2 edge = smoothstep(vec2(0.0), vec2(0.008), warped) * smoothstep(vec2(0.0), vec2(0.008), 1.0 - warped); float inside = edge.x * edge.y; vec3 col = testCard(warped, aspect); float scan = 0.8 + 0.2 * sin(warped.y * iResolution.y * 2.0); float sub = mod(fragCoord.x, 3.0); vec3 mask = vec3(step(sub, 1.0), step(1.0, sub) * step(sub, 2.0), step(2.0, sub)) * 0.5 + 0.65; float roll = 1.0 - smoothstep(0.0, 0.1, abs(fract(warped.y + iTime * 0.08) - 0.5)); float grain = 0.85 + 0.3 * hash21(fragCoord + fract(iTime * 7.0) * 100.0); float flicker = 0.94 + 0.08 * hash21(vec2(mod(floor(iTime * 24.0), 256.0), 3.0)); float vig = 16.0 * warped.x * warped.y * (1.0 - warped.x) * (1.0 - warped.y); vig = pow(clamp(vig, 0.0, 1.0), 0.35); col *= scan * mask * (1.0 - 0.35 * roll) * grain * flicker * vig * inside; col += vec3(0.70, 0.15, 0.12) * 0.03 * (1.0 - inside); col = max(col, 0.0); col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Copper
#circuitTruchet routes with 45° jogs · hashed corner pads · phase-hashed pulses
GLSL source
// Circuit — a printed circuit board. Each grid cell picks a hashed copper // route (straight, a 45-degree jog to a neighbouring edge, or a dead end on a // pad); pads sit on hashed corners and light pulses travel along the traces. float hash21(vec2 p) { p = fract(p * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } float segDist(vec2 p, vec2 a, vec2 b) { vec2 ab = b - a; float h = clamp(dot(p - a, ab) / dot(ab, ab), 0.0, 1.0); return length(p - a - ab * h); } // Returns (distance to the trace, position along it 0..1) for the cell's route. vec2 route(vec2 p, float variant) { if (variant < 1.0) return vec2(abs(p.y), p.x + 0.5); if (variant < 2.0) return vec2(abs(p.x), p.y + 0.5); if (variant < 6.0) { vec2 q = p * vec2(variant < 4.0 ? 1.0 : -1.0, mod(variant, 2.0) < 1.0 ? 1.0 : -1.0); float d = min(segDist(q, vec2(-0.5, 0.0), vec2(-0.2, 0.0)), segDist(q, vec2(-0.2, 0.0), vec2(0.0, 0.2))); d = min(d, segDist(q, vec2(0.0, 0.2), vec2(0.0, 0.5))); return vec2(d, clamp(q.x + 0.5 + q.y, 0.0, 1.0)); } vec2 r = variant < 7.0 ? p : p.yx; return vec2(segDist(r, vec2(-0.5, 0.0), vec2(0.0, 0.0)), (r.x + 0.5) * 2.0); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * 7.0; p.x += iTime * 0.15; vec2 id = floor(p); vec2 f = fract(p) - 0.5; float variant = floor(hash21(id) * 8.0); vec2 tr = route(f, variant); float trace = smoothstep(0.07, 0.04, tr.x); float traceEdge = smoothstep(0.1, 0.07, tr.x) - trace; vec2 cornerId = id + step(0.0, f); float padOn = step(0.7, hash21(cornerId + 0.37)); float dc = length(abs(f) - 0.5); float pad = padOn * smoothstep(0.02, 0.0, abs(dc - 0.1) - 0.05); float centerPad = step(6.0, variant) * smoothstep(0.02, 0.0, abs(length(f) - 0.09) - 0.045); float speed = 0.4 + 0.6 * hash21(id + 0.11); float spot = fract(iTime * speed + hash21(id + 0.23)); float pulse = step(0.55, hash21(id + 0.31)) * smoothstep(0.15, 0.0, abs(tr.y - spot)) * trace; float weave = 0.5 + 0.5 * sin(p.x * 60.0) * sin(p.y * 60.0); vec3 col = vec3(0.03, 0.015, 0.02) + vec3(0.70, 0.15, 0.12) * (0.06 + 0.05 * weave); col += vec3(0.70, 0.15, 0.12) * 0.15 * traceEdge; col += vec3(0.94, 0.41, 0.36) * 0.55 * trace; col += vec3(0.94, 0.41, 0.36) * 0.7 * max(pad, centerPad); col += vec3(1.0, 0.9, 0.85) * pulse * 1.5; col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Helix
#dnaSine strands ordered by cos depth · slope-corrected tubes · fixed-interval rungs
GLSL source
// Helix — a double helix. Two sine strands half a turn apart, drawn as tubes // shaded by depth (cos decides which is in front), rungs at a fixed interval, // the whole thing rotating; a fainter second helix drifts behind. float cover(float d, float w) { return smoothstep(w, w * 0.7, d); } float shade(float d, float w) { float x = clamp(d / w, 0.0, 1.0); return sqrt(1.0 - x * x); } vec3 helix(vec2 p, float t, float amp, float w, float gain, vec3 bg) { vec3 ember = vec3(0.70, 0.15, 0.12); vec3 accent = vec3(0.94, 0.41, 0.36); vec3 highlight = vec3(1.0, 0.9, 0.85); float k = 3.0; float a = p.y * k + t; float x1 = amp * sin(a); float z1 = cos(a); float slope = amp * k * cos(a); float foreshorten = 1.0 / sqrt(1.0 + slope * slope); float d1 = abs(p.x - x1) * foreshorten; float d2 = abs(p.x + x1) * foreshorten; float depth1 = 0.5 + 0.5 * z1; float depth2 = 1.0 - depth1; float s1 = shade(d1, w); float s2 = shade(d2, w); vec3 c1 = mix(ember, accent, depth1) * (0.3 + 0.7 * s1) + highlight * smoothstep(0.75, 1.0, s1) * depth1 * 0.7; vec3 c2 = mix(ember, accent, depth2) * (0.3 + 0.7 * s2) + highlight * smoothstep(0.75, 1.0, s2) * depth2 * 0.7; float spacing = 0.3; float yn = (floor(p.y / spacing) + 0.5) * spacing; float xr = amp * sin(yn * k + t); float dx = max(abs(p.x) - abs(xr), 0.0); float dr = length(vec2(dx, p.y - yn)); vec3 cr = mix(ember, accent, 0.4) * (0.25 + 0.6 * shade(dr, w * 0.55)); float front = step(z1, 0.0); vec3 col = mix(bg, mix(c2, c1, front), cover(mix(d2, d1, front), w) * gain); col = mix(col, cr, cover(dr, w * 0.55) * gain); col = mix(col, mix(c1, c2, front), cover(mix(d1, d2, front), w) * gain); return col; } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * 2.4; float tilt = 0.45; p = mat2(cos(tilt), -sin(tilt), sin(tilt), cos(tilt)) * p; float t = iTime * 1.1; vec3 col = vec3(0.03, 0.015, 0.02); col += vec3(0.70, 0.15, 0.12) * 0.1 * (1.0 - smoothstep(0.2, 1.4, abs(p.x))); col = helix(p + vec2(1.25, 0.6), t * 0.6 + 2.0, 0.3, 0.05, 0.4, col); col = helix(p, t, 0.45, 0.08, 1.0, col); col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Angle-periodic fbm fibres · ember-to-gold bands · breathing pupil
GLSL source
// Iris — a procedural eye. Radial fibres from fbm that wraps seamlessly around // the angle, colour bands from ember out to gold, a pupil breathing on a slow // sine (it dilates and glances toward the mouse when pressed), limbal ring, glint. float hash21(vec2 p) { p = fract(p * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } // Value noise whose lattice wraps in x every `period`, so it tiles around the angle. float noise(vec2 p, float period) { vec2 i = floor(p); vec2 f = fract(p); vec2 u = f * f * (3.0 - 2.0 * f); float x0 = mod(i.x, period); float x1 = mod(i.x + 1.0, period); return mix( mix(hash21(vec2(x0, i.y)), hash21(vec2(x1, i.y)), u.x), mix(hash21(vec2(x0, i.y + 1.0)), hash21(vec2(x1, i.y + 1.0)), u.x), u.y); } float fbm(vec2 p, float period) { float value = 0.0; float amplitude = 0.5; for (int i = 0; i < 4; i++) { value += amplitude * noise(p, period); p = p * 2.0 + 7.3; period *= 2.0; amplitude *= 0.5; } return value; } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * 2.2; float dilate = 0.0; if (iMouse.z > 0.0) { vec2 m = (iMouse.xy - 0.5 * iResolution.xy) / iResolution.y * 2.2; p -= m * 0.12; dilate = 0.08; } float r = length(p); float ang = (atan(p.y, p.x) / 6.28318530718 + 0.5) * 48.0 + iTime * 0.15; float fibre = fbm(vec2(ang, r * 2.5), 48.0); float fine = noise(vec2(ang * 4.0 + 3.0, r * 9.0), 192.0); float pupilR = mix(0.24, 0.36, 0.5 + 0.5 * sin(iTime * 0.5)) + dilate; float rw = r + 0.03 * (fibre - 0.5); float pupil = smoothstep(pupilR, pupilR + 0.025, rw); float band = smoothstep(pupilR, 1.0, r); vec3 col = mix(vec3(0.70, 0.15, 0.12), vec3(1.0, 0.75, 0.3), band * band); col = mix(col, vec3(0.94, 0.41, 0.36), smoothstep(0.2, 0.5, band) * (1.0 - smoothstep(0.5, 0.85, band))); col *= 0.35 + 1.3 * fibre * fibre + 0.5 * fine; col *= 0.75 + 0.25 * sin(r * 26.0 + fibre * 7.0); col += vec3(0.94, 0.41, 0.36) * 0.5 * smoothstep(pupilR + 0.02, pupilR + 0.1, rw) * (1.0 - smoothstep(pupilR + 0.1, pupilR + 0.28, rw)); col *= pupil * smoothstep(1.0, 0.8, r); vec3 outside = vec3(0.03, 0.015, 0.02) + vec3(0.70, 0.15, 0.12) * 0.08 * (1.0 - smoothstep(1.0, 1.7, r)); col = mix(outside, col, smoothstep(1.03, 0.99, r)); vec2 glint = vec2(-0.36, 0.42) + 0.03 * vec2(sin(iTime * 0.7), cos(iTime * 0.5)); col += vec3(1.0, 0.9, 0.85) * smoothstep(0.22, 0.0, length(p - glint)); col += vec3(1.0, 0.9, 0.85) * 0.35 * smoothstep(0.1, 0.0, length(p - vec2(0.3, -0.28))); col = max(col, 0.0); col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Rising
#bubblesFour hashed grid layers · rim + refractive gradient · pixel-aware AA
GLSL source
// Bubbles — rising bubbles. Four layers of hashed grid cells, each holding one // bubble that drifts upward with a sine wobble: a thin teal rim, a refractive // inner gradient and a specular dot; the big front bubbles rise faster and brighter. float hash21(vec2 p) { p = fract(p * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } vec3 layer(vec2 p, float scale, float speed, float strength, float seed) { vec2 g = p * scale + vec2(0.0, -iTime * speed); vec2 id = floor(g) + seed; vec2 f = fract(g) - 0.5; float h1 = hash21(id); float h2 = hash21(id + 0.37); float h3 = hash21(id + 0.71); float alive = step(0.3, hash21(id + 1.13)); float radius = 0.1 + 0.18 * h1; vec2 center = (vec2(h2, h3) - 0.5) * (0.86 - 2.0 * radius); center.x += 0.04 * sin(iTime * (1.0 + h1) + h2 * 6.2832); vec2 q = (f - center) / radius; float d = length(q); float aa = 2.0 * scale / (iResolution.y * radius); float rim = smoothstep(0.08 + aa, 0.0, abs(d - 1.0)); float inside = smoothstep(1.0 + aa, 1.0 - aa, d); float inner = inside * (0.05 + 0.3 * smoothstep(0.45, 1.0, d) * (0.5 - 0.5 * q.y)); float spec = smoothstep(0.3, 0.0, length(q - vec2(-0.38, 0.4))); vec3 col = vec3(0.2, 0.8, 0.75) * (rim * 0.8 + inner); col += vec3(1.0, 0.9, 0.85) * (spec * 0.8 + rim * 0.2 * (0.5 - 0.5 * q.y)); return col * alive * strength; } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y * 2.0; float depth = smoothstep(-1.0, 1.0, p.y); vec3 col = vec3(0.03, 0.015, 0.02) + vec3(0.70, 0.15, 0.12) * (0.1 + 0.2 * depth); col += vec3(0.2, 0.8, 0.75) * 0.04 * depth; for (int i = 0; i < 4; i++) { float fi = float(i); float scale = 6.5 - fi * 1.55; float speed = 0.5 + fi * 0.35; float strength = 0.35 + fi * 0.22; col += layer(p, scale, speed, strength, fi * 17.0); } col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Datamosh
#glitchHash-shifted bands · RGB split · block corruption · burst schedule
GLSL source
// Glitch — datamosh. A striped ember gradient sliced into horizontal bands that // hash-shift sideways, RGB channels split, block corruption rectangles and // scanline noise; the glitch bursts on a hashed schedule and then calms down. float hash21(vec2 p) { p = fract(p * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } vec3 base(vec2 uv, float aspect) { float t = iTime; float grad = clamp(uv.y * 0.8 + 0.25 * sin(uv.x * 4.0 + t * 0.5), 0.0, 1.0); float stripes = smoothstep(0.35, 0.65, 0.5 + 0.5 * sin((uv.x * aspect + uv.y * 0.6) * 30.0 - t * 1.2)); vec3 col = mix(vec3(0.03, 0.015, 0.02), vec3(0.70, 0.15, 0.12), grad); col = mix(col, vec3(0.94, 0.41, 0.36), stripes * (0.3 + 0.4 * grad)); vec2 c = (uv - 0.5) * vec2(aspect, 1.0); float ring = smoothstep(0.025, 0.0, abs(length(c) - 0.3 - 0.03 * sin(t * 0.8))); col += vec3(1.0, 0.9, 0.85) * ring * 0.8; col += vec3(1.0, 0.9, 0.85) * 0.25 * smoothstep(0.9, 1.0, grad); return col; } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 uv = fragCoord / iResolution.xy; float aspect = iResolution.x / iResolution.y; float frame = mod(floor(iTime * 18.0), 997.0); float slot = floor(iTime * 0.7); float within = fract(iTime * 0.7); float burst = step(0.45, hash21(vec2(slot, 5.0))) * (1.0 - within) * (1.0 - within); float intensity = 0.05 + 0.95 * burst; uv.y = fract(uv.y + step(0.92, hash21(vec2(frame, 4.0))) * intensity * 0.2); float band = floor(uv.y * 20.0 + hash21(vec2(frame, 1.0)) * 5.0); float shift = (hash21(vec2(band, frame)) - 0.5) * step(0.55, hash21(vec2(band, frame + 0.5))) * 0.3 * intensity; float band2 = floor(uv.y * 90.0); shift += (hash21(vec2(band2, frame + 3.0)) - 0.5) * step(0.7, hash21(vec2(band2, frame + 7.0))) * 0.06 * intensity; vec2 guv = vec2(fract(uv.x + shift), uv.y); float split = 0.003 + 0.02 * intensity; vec3 col = vec3( base(guv + vec2(split, 0.0), aspect).r, base(guv, aspect).g, base(guv - vec2(split, 0.0), aspect).b); vec2 blockId = floor(uv * vec2(12.0, 7.0) + hash21(vec2(frame, 2.0)) * 3.0); float blockOn = step(0.97 - 0.2 * intensity, hash21(blockId + frame * 0.1)); vec2 moshOffset = vec2(hash21(blockId + 0.5), hash21(blockId + 0.9)) * 0.4; vec3 moshed = base(fract(uv + moshOffset), aspect) * vec3(1.3, 0.9, 1.1); col = mix(col, moshed, blockOn); float line = hash21(vec2(floor(fragCoord.y), frame)); col += (line - 0.5) * 0.15 * (0.2 + intensity); col *= 0.92 + 0.16 * hash21(fragCoord * 0.37 + frame); col = max(col, 0.0); col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Cumulus
#cloudsLayered fbm density · one-sided light · horizon gradient
GLSL source
// Clouds — drifting cumulus. Two fbm layers stack into a density field with a // horizon gradient, then the same field is re-sampled a step toward the sun: // the difference lights each puff from one side over a warm ember sky. float hash21(vec2 p) { p = fract(mod(p, 289.0) * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } float noise(vec2 p) { vec2 i = floor(p); vec2 f = fract(p); vec2 u = f * f * (3.0 - 2.0 * f); return mix( mix(hash21(i), hash21(i + vec2(1.0, 0.0)), u.x), mix(hash21(i + vec2(0.0, 1.0)), hash21(i + vec2(1.0, 1.0)), u.x), u.y); } float fbm(vec2 p) { float value = 0.0; float amplitude = 0.5; mat2 rotate = mat2(0.8, 0.6, -0.6, 0.8); for (int i = 0; i < 5; i++) { value += amplitude * noise(p); p = rotate * p * 2.0 + 10.0; amplitude *= 0.5; } return value; } float cloudDensity(vec2 p) { float drift = iTime * 0.05; vec2 q = p * vec2(1.0, 1.7) + vec2(drift, 0.0); float shape = fbm(q * 1.6); float detail = fbm(q * 4.5 + vec2(drift * 1.5, 0.3)); float horizon = smoothstep(-0.5, 0.3, p.y); float density = shape * 0.8 + detail * 0.3 - 0.62 + 0.28 * horizon; return clamp(density * 3.0, 0.0, 1.0); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; vec3 dark = vec3(0.03, 0.015, 0.02); vec3 ember = vec3(0.70, 0.15, 0.12); vec3 accent = vec3(0.94, 0.41, 0.36); vec3 highlight = vec3(1.0, 0.9, 0.85); vec2 sunPos = vec2(-0.55, -0.3); float sunDist = length(p - sunPos); vec3 col = mix(ember * 0.5, dark, smoothstep(-0.5, 0.5, p.y)); col += accent * 0.5 * exp(-sunDist * 2.5); col += highlight * 0.6 * exp(-sunDist * 14.0); float density = cloudDensity(p); vec2 toSun = normalize(vec2(-0.75, -0.5)) * 0.03; float towardSun = cloudDensity(p + toSun); float lit = clamp(0.45 + (density - towardSun) * 5.0, 0.0, 1.0); vec3 cloudCol = mix(dark + ember * 0.35, mix(accent, highlight, lit), lit); cloudCol += highlight * 0.35 * lit * exp(-sunDist * 1.5); col = mix(col, cloudCol, density); col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Curtains
#aurora1D fbm streaks · three bands · teal→violet→ember by altitude
GLSL source
// Aurora — curtains over a star field. Each layer is a 1D fbm profile along x // stretched into vertical streaks, hung from a wavy base and fading upward; // three layers at different heights and speeds, tinted teal → violet → ember. float hash21(vec2 p) { p = fract(mod(p, 289.0) * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } float noise(vec2 p) { vec2 i = floor(p); vec2 f = fract(p); vec2 u = f * f * (3.0 - 2.0 * f); return mix( mix(hash21(i), hash21(i + vec2(1.0, 0.0)), u.x), mix(hash21(i + vec2(0.0, 1.0)), hash21(i + vec2(1.0, 1.0)), u.x), u.y); } float fbm(vec2 p) { float value = 0.0; float amplitude = 0.5; for (int i = 0; i < 4; i++) { value += amplitude * noise(p); p = p * 2.0 + 17.0; amplitude *= 0.5; } return value; } float curtain(vec2 p, float seed, float speed, float base) { float t = iTime * speed; float x = p.x * 2.0 + seed + 0.5 * (p.y - base); float intensity = smoothstep(0.25, 0.85, fbm(vec2(x * 1.5 + t, seed))); intensity *= intensity; float streak = 0.55 + 0.45 * noise(vec2(x * 16.0 - t * 4.0, seed + 5.0)); float bottom = base + 0.25 * (noise(vec2(x * 1.3 + t * 0.7, seed + 9.0)) - 0.5); float h = p.y - bottom; float band = smoothstep(-0.06, 0.1, h) * exp(-max(h, 0.0) * 3.0); return band * intensity * streak; } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; vec3 dark = vec3(0.03, 0.015, 0.02); vec3 teal = vec3(0.2, 0.8, 0.75); vec3 violet = vec3(0.55, 0.35, 0.95); vec3 ember = vec3(0.70, 0.15, 0.12); vec3 highlight = vec3(1.0, 0.9, 0.85); vec2 grid = p * 40.0; vec2 cellId = floor(grid); float starHash = hash21(cellId); vec2 starOffset = vec2(hash21(cellId + 3.1), hash21(cellId + 7.7)) - 0.5; float starDist = length(fract(grid) - 0.5 - starOffset * 0.6) / 40.0; float twinkle = 0.6 + 0.4 * sin(iTime * 3.0 + starHash * 50.0); float star = smoothstep(2.5 / iResolution.y, 0.0, starDist) * step(0.88, starHash) * twinkle; vec3 col = dark + highlight * star * 0.8; float glow = curtain(p, 1.0, 0.12, -0.32) * 0.9; glow += curtain(p, 4.0, 0.2, -0.12) * 0.7; glow += curtain(p, 9.0, 0.3, 0.08) * 0.5; vec3 tint = mix(teal, violet, smoothstep(-0.25, 0.2, p.y)); tint = mix(tint, ember, smoothstep(0.2, 0.55, p.y)); col += tint * glow * 2.0; col += highlight * glow * glow * 0.3; col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Bonfire
#fireUpward-scrolling fbm · height-shaped heat · black→ember→highlight ramp
GLSL source
// Fire — the classic demo flame. fbm scrolls upward through a heat field that // is hot at the base and thins toward the tips, a second faster noise tears // the edges, and heat indexes a black → ember → accent → highlight ramp. float hash21(vec2 p) { p = fract(mod(p, 289.0) * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } float noise(vec2 p) { vec2 i = floor(p); vec2 f = fract(p); vec2 u = f * f * (3.0 - 2.0 * f); return mix( mix(hash21(i), hash21(i + vec2(1.0, 0.0)), u.x), mix(hash21(i + vec2(0.0, 1.0)), hash21(i + vec2(1.0, 1.0)), u.x), u.y); } float fbm(vec2 p) { float value = 0.0; float amplitude = 0.5; mat2 rotate = mat2(0.8, 0.6, -0.6, 0.8); for (int i = 0; i < 5; i++) { value += amplitude * noise(p); p = rotate * p * 2.0 + 10.0; amplitude *= 0.5; } return value; } vec3 heatRamp(float heat) { vec3 col = mix(vec3(0.03, 0.015, 0.02), vec3(0.70, 0.15, 0.12), smoothstep(0.0, 0.4, heat)); col = mix(col, vec3(0.94, 0.41, 0.36), smoothstep(0.4, 0.75, heat)); col = mix(col, vec3(1.0, 0.9, 0.85), smoothstep(0.75, 1.05, heat)); return col; } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; float t = iTime; float rise = p.y + 0.5; float sway = (noise(vec2(rise * 3.0 - t * 1.5, p.x * 2.0)) - 0.5) * 0.4 * rise; vec2 q = vec2((p.x + sway) * 4.5, rise * 2.5 - t * 2.0); float body = fbm(q); float edge = fbm(q * 2.3 + vec2(t * 0.4, -t * 2.5)); float heat = (1.0 - rise) * 1.5 - 0.45 + (body - 0.5) * 2.2 + (edge - 0.5) * 0.7; heat -= abs(p.x) * 0.3 * rise; heat = clamp(heat, 0.0, 1.0); vec3 col = heatRamp(heat); col += vec3(0.70, 0.15, 0.12) * 0.25 * exp(-rise * 4.0); col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Strike
#lightningNoise-offset channel · fixed-height branches · core + glow · hashed strobe
GLSL source
// Lightning — a strike every second or so. The main channel is x = f(y) from // three octaves of value noise; branches fork at fixed heights to alternating // sides. Distance to each channel gives a white core with ember glow, and a // hashed strobe lights the clouds behind. float hash21(vec2 p) { p = fract(mod(p, 289.0) * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } float hash11(float n) { return hash21(vec2(n, n * 0.37 + 1.3)); } float noise(vec2 p) { vec2 i = floor(p); vec2 f = fract(p); vec2 u = f * f * (3.0 - 2.0 * f); return mix( mix(hash21(i), hash21(i + vec2(1.0, 0.0)), u.x), mix(hash21(i + vec2(0.0, 1.0)), hash21(i + vec2(1.0, 1.0)), u.x), u.y); } float boltX(float y, float seed) { float x = (noise(vec2(y * 1.2, seed)) - 0.5) * 0.9; x += (noise(vec2(y * 5.0, seed + 3.0)) - 0.5) * 0.25; x += (noise(vec2(y * 20.0, seed + 6.0)) - 0.5) * 0.07; return x; } // Core plus glow of a near-vertical channel at xPath, alive for y in [yMin, yMax]. float channel(vec2 p, float xPath, float yMin, float yMax, float width) { float alive = step(yMin, p.y) * step(p.y, yMax); float d = abs(p.x - xPath); return alive * (smoothstep(width, 0.0, d) + 0.01 / (d + 0.02)); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; vec3 dark = vec3(0.03, 0.015, 0.02); vec3 ember = vec3(0.70, 0.15, 0.12); vec3 highlight = vec3(1.0, 0.9, 0.85); float period = 1.2; float cycle = floor(iTime / period); float phase = fract(iTime / period); float seed = hash11(cycle) * 40.0; float flicker = 0.6 + 0.4 * step(0.5, hash11(floor(iTime * 30.0))); float strike = exp(-phase * 3.0) * flicker; float flash = 0.12 * step(0.8, hash11(floor(iTime * 7.0) + 0.5)) + 0.2 * exp(-phase * 10.0); float cloud = 0.6 * noise(p * 3.0 + vec2(iTime * 0.05, 0.0)) + 0.4 * noise(p * 7.0 - vec2(iTime * 0.1, 0.0)); vec3 col = dark + ember * cloud * (0.15 + flash * 2.5) * smoothstep(-0.3, 0.5, p.y); col += ember * flash; float jitter = (noise(vec2(p.y * 40.0, iTime * 25.0)) - 0.5) * 0.015; float energy = channel(p, boltX(p.y, seed) + jitter, -0.6, 0.6, 0.007); for (int i = 0; i < 3; i++) { float fi = float(i); float yBranch = 0.32 - fi * 0.24; float side = 1.0 - 2.0 * mod(fi, 2.0); float wiggle = (noise(vec2(p.y * 9.0, seed + fi + 20.0)) - noise(vec2(yBranch * 9.0, seed + fi + 20.0))) * 0.12; float xBranch = boltX(yBranch, seed) + (yBranch - p.y) * side * (0.5 + 0.4 * hash11(seed + fi)) + wiggle; energy += 0.6 * channel(p, xBranch, yBranch - 0.3, yBranch, 0.004); } energy *= strike; col += ember * energy * 1.2 + highlight * energy * energy; col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Poolside
#causticsAnimated Voronoi F2−F1 ridges · three scales · additive teal
GLSL source
// Caustics — light on a pool floor. Three animated Voronoi layers at different // scales, each reduced to its F2 − F1 cell edges so only the thin bright // ridges survive, summed additively in teal over an ember-tinted floor. vec2 hash22(vec2 p) { vec3 q = fract(vec3(p.xyx) * vec3(0.1031, 0.1030, 0.0973)); q += dot(q, q.yzx + 33.33); return fract((q.xx + q.yz) * q.zy); } float voronoiEdge(vec2 p, float t) { vec2 cell = floor(p); vec2 f = fract(p); float first = 8.0; float second = 8.0; for (int y = -1; y <= 1; y++) { for (int x = -1; x <= 1; x++) { vec2 offset = vec2(float(x), float(y)); vec2 h = hash22(cell + offset); vec2 point = offset + 0.5 + 0.4 * sin(t + 6.2831 * h); float d = length(point - f); if (d < first) { second = first; first = d; } else if (d < second) { second = d; } } } return second - first; } float ridge(vec2 p, float t) { float edge = voronoiEdge(p, t); float r = smoothstep(0.15, 0.0, edge); return r * r; } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; vec3 dark = vec3(0.03, 0.015, 0.02); vec3 ember = vec3(0.70, 0.15, 0.12); vec3 teal = vec3(0.2, 0.8, 0.75); vec3 highlight = vec3(1.0, 0.9, 0.85); float t = iTime * 0.5; float light = ridge(p * 4.0 + vec2(t * 0.15, 0.0), t); light += 0.7 * ridge(p * 6.5 + vec2(3.0, -t * 0.1), t * 1.3 + 2.0); light += 0.5 * ridge(p * 10.0 + vec2(7.0 + t * 0.08, 7.0), t * 0.8 + 4.0); float floorShade = 0.7 + 0.3 * sin(p.x * 2.0 + p.y * 3.0 + t * 0.4); vec3 col = dark + ember * 0.18 * floorShade / (1.0 + 0.5 * dot(p, p)); col += teal * light * 0.8; col += highlight * light * light * 0.4; col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Rainfall
#ripplesHashed drop timing · analytic ring gradients → normal · fake specular
GLSL source
// Ripples — rain on still water. Every grid cell drops once per hashed period; // each ring is a windowed sine whose analytic gradient is summed over the 5×5 // neighborhood into a surface normal, then lit with a fake specular ember sky. float hash21(vec2 p) { p = fract(mod(p, 289.0) * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } vec2 rippleGradient(vec2 p, float t) { vec2 grad = vec2(0.0); vec2 cell = floor(p); for (int y = -2; y <= 2; y++) { for (int x = -2; x <= 2; x++) { vec2 id = cell + vec2(float(x), float(y)); float h = hash21(id); vec2 center = id + 0.5 + 0.7 * (vec2(hash21(id + 1.3), hash21(id + 2.7)) - 0.5); float period = 3.0 + 3.0 * h; float age = mod(t + h * 17.0, period); vec2 toP = p - center; float r = length(toP); float phase = r * 20.0 - age * 8.0; float window = smoothstep(1.0, -3.0, phase) * smoothstep(-15.0, -7.0, phase); float amplitude = 0.6 * exp(-age * 0.8) * window; grad += amplitude * cos(phase) * toP / max(r, 0.001); } } return grad; } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; vec3 dark = vec3(0.03, 0.015, 0.02); vec3 ember = vec3(0.70, 0.15, 0.12); vec3 accent = vec3(0.94, 0.41, 0.36); vec3 highlight = vec3(1.0, 0.9, 0.85); vec2 grad = rippleGradient(p * 3.0, iTime); vec3 normal = normalize(vec3(-grad, 1.0)); vec3 lightDir = normalize(vec3(-0.4, 0.6, 0.7)); vec3 halfVec = normalize(lightDir + vec3(0.0, 0.0, 1.0)); float spec = pow(max(dot(normal, halfVec), 0.0), 48.0); float diffuse = max(dot(normal, lightDir), 0.0); float tilt = 1.0 - normal.z; float skyReflect = smoothstep(-0.7, 0.9, p.y + normal.y * 1.5); vec3 col = dark + ember * (0.1 + 0.3 * skyReflect) * (0.6 + 0.4 * diffuse); col += accent * tilt * 1.5; col += highlight * spec * 0.9; col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Pinwheel
#galaxyLog-spiral warped fbm · dust lanes · gold core · hashed star grid
GLSL source
// Galaxy — a face-on spiral. fbm is sampled through coordinates whose angle is // offset by log(r), so the noise winds into logarithmic arms with dust lanes; // a hot gold core sits in the middle and a hashed grid scatters point stars. float hash21(vec2 p) { p = fract(mod(p, 289.0) * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } float noise(vec2 p) { vec2 i = floor(p); vec2 f = fract(p); vec2 u = f * f * (3.0 - 2.0 * f); return mix( mix(hash21(i), hash21(i + vec2(1.0, 0.0)), u.x), mix(hash21(i + vec2(0.0, 1.0)), hash21(i + vec2(1.0, 1.0)), u.x), u.y); } float fbm(vec2 p) { float value = 0.0; float amplitude = 0.5; mat2 rotate = mat2(0.8, 0.6, -0.6, 0.8); for (int i = 0; i < 4; i++) { value += amplitude * noise(p); p = rotate * p * 2.0 + 10.0; amplitude *= 0.5; } return value; } float starField(vec2 uv, float scale, float chance) { vec2 grid = uv * scale; vec2 id = floor(grid); float h = hash21(id); vec2 offset = (vec2(hash21(id + 0.7), hash21(id + 1.9)) - 0.5) * 0.5; float d = length(fract(grid) - 0.5 - offset) / scale; return smoothstep(1.8 / iResolution.y, 0.0, d) * step(1.0 - chance, h) * (0.4 + 0.6 * h); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; vec3 dark = vec3(0.03, 0.015, 0.02); vec3 ember = vec3(0.70, 0.15, 0.12); vec3 accent = vec3(0.94, 0.41, 0.36); vec3 gold = vec3(1.0, 0.75, 0.3); vec3 highlight = vec3(1.0, 0.9, 0.85); float t = iTime * 0.04; float r = length(p); float angle = atan(p.y, p.x); float spiral = angle - 2.6 * log(max(r, 0.001)) + t * (1.0 + 1.5 * exp(-r * 4.0)); vec2 q = r * vec2(cos(spiral), sin(spiral)); float arms = 0.5 + 0.5 * cos(2.0 * spiral); arms = arms * arms * arms; float clumps = fbm(q * 5.0 + 3.0); float dust = smoothstep(0.55, 0.8, fbm(q * 8.0 - 4.0)) * smoothstep(0.08, 0.25, r); float disc = exp(-r * 3.5); float density = disc * (0.15 + arms * (0.5 + 1.2 * clumps)) * (1.0 - 0.7 * dust); float core = 1.2 * exp(-r * 10.0) + 2.5 * exp(-r * 35.0); vec3 col = dark; col += ember * density * 1.6; col += accent * density * density * 2.0; col += mix(gold, highlight, exp(-r * 20.0)) * core; mat2 spin = mat2(cos(t), sin(t), -sin(t), cos(t)); col += highlight * starField(spin * p, 90.0, 0.1 + 0.5 * density) * (0.5 + density); col += highlight * starField(p, 30.0, 0.05) * 0.6; col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Ridgelines
#mountainsFive 1D ridged fbm layers · depth haze · low sun · parallax drift
GLSL source
// Mountains — parallax ridgelines under a low sun. Five layers, each a 1D // ridged fbm profile at its own scale and drift speed; nearer layers are // darker and taller, farther ones dissolve into sunlit ember haze. float hash21(vec2 p) { p = fract(mod(p, 289.0) * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } float noise1D(float x, float seed) { float i = floor(x); float f = fract(x); float u = f * f * (3.0 - 2.0 * f); return mix(hash21(vec2(i, seed)), hash21(vec2(i + 1.0, seed)), u); } float ridge(float x, float seed) { float height = 0.0; float amplitude = 0.5; for (int i = 0; i < 5; i++) { float n = noise1D(x, seed + float(i) * 3.7); height += amplitude * (1.0 - abs(2.0 * n - 1.0)); x = x * 2.1 + 7.3; amplitude *= 0.5; } return height; } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; vec3 dark = vec3(0.03, 0.015, 0.02); vec3 ember = vec3(0.70, 0.15, 0.12); vec3 accent = vec3(0.94, 0.41, 0.36); vec3 highlight = vec3(1.0, 0.9, 0.85); vec2 sunPos = vec2(0.3, 0.2); float sunDist = length(p - sunPos); vec3 col = mix(ember * 0.6, dark, smoothstep(0.0, 0.5, p.y)); col += accent * 0.4 * exp(-sunDist * 3.0); col += highlight * smoothstep(0.075, 0.065, sunDist); col += highlight * 0.3 * exp(-sunDist * 12.0); vec3 haze = ember * 0.55 + accent * 0.2; float edge = 1.5 / iResolution.y; for (int i = 0; i < 5; i++) { float layer = float(i); float depth = 1.0 - layer / 4.0; float x = p.x * (1.5 + layer * 0.6) + iTime * (0.01 + layer * 0.015) + layer * 11.0; float baseline = 0.12 - layer * 0.12; float height = baseline + (0.15 + layer * 0.06) * ridge(x, layer * 5.0); float mask = smoothstep(-edge, edge, height - p.y); vec3 layerCol = mix(dark, haze, depth * 0.8); layerCol += accent * 0.3 * depth * exp(-sunDist * 3.0); col = mix(col, layerCol, mask); } col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Maelstrom
#vortexAngle twisted by log(r) · fbm through polar warp · pulsing core
GLSL source
// Vortex — a whirlpool of fbm. Polar coordinates whose angle is twisted by // log(r) and time wind the noise into spiral arms; spinning a log spiral reads // as inward flow, and everything brightens toward a pulsing white core. float hash21(vec2 p) { p = fract(mod(p, 289.0) * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } float noise(vec2 p) { vec2 i = floor(p); vec2 f = fract(p); vec2 u = f * f * (3.0 - 2.0 * f); return mix( mix(hash21(i), hash21(i + vec2(1.0, 0.0)), u.x), mix(hash21(i + vec2(0.0, 1.0)), hash21(i + vec2(1.0, 1.0)), u.x), u.y); } float fbm(vec2 p) { float value = 0.0; float amplitude = 0.5; mat2 rotate = mat2(0.8, 0.6, -0.6, 0.8); for (int i = 0; i < 5; i++) { value += amplitude * noise(p); p = rotate * p * 2.0 + 10.0; amplitude *= 0.5; } return value; } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; vec3 dark = vec3(0.03, 0.015, 0.02); vec3 ember = vec3(0.70, 0.15, 0.12); vec3 accent = vec3(0.94, 0.41, 0.36); vec3 highlight = vec3(1.0, 0.9, 0.85); float t = iTime * 0.25; float r = length(p); float angle = atan(p.y, p.x); float twisted = angle + 3.0 * log(r + 0.03) - t; vec2 q = vec2(cos(twisted), sin(twisted)) * (1.0 + r * 3.0); float swirl = fbm(q * 1.5); float detail = fbm(q * 4.0 + 7.0); float arms = 0.5 + 0.5 * sin(3.0 * twisted + swirl * 5.0 + t * 2.0); float field = swirl * 0.8 + detail * 0.4; float energy = field * (0.4 + 0.6 * arms); float pull = 1.0 / (1.0 + r * 6.0); vec3 col = dark; col += ember * energy * energy * (0.8 + pull * 3.0); col += accent * energy * energy * energy * pull * 3.0; col += highlight * smoothstep(0.7, 1.0, energy * (0.6 + pull)) * 0.5; col += highlight * exp(-r * 14.0) * (0.8 + 0.3 * sin(iTime * 2.0)); col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Streamlines
#flowAnalytic curl of a sine potential · 14-step streamlines · traveling dashes
GLSL source
// Flow — streamlines through a curl field. The velocity is the analytic curl // of a drifting sine potential, so it never diverges; each grid cell seeds a // short streamline that is stepped forward and drawn as a traveling ember dash. float hash21(vec2 p) { p = fract(mod(p, 289.0) * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } // Curl of psi = sin(ax) cos(ay) + 0.5 sin(bx) sin(by): (dpsi/dy, -dpsi/dx). vec2 flowField(vec2 p, float t) { float ax = 1.7 * p.x + 0.3 * t; float ay = 2.1 * p.y - 0.2 * t; float bx = 3.9 * p.x - 0.5 * t + 1.0; float by = 3.3 * p.y + 0.4 * t; vec2 v = vec2(-2.1 * sin(ax) * sin(ay), -1.7 * cos(ax) * cos(ay)); v += vec2(1.65 * sin(bx) * cos(by), -1.95 * cos(bx) * sin(by)); return v; } float segmentDist(vec2 p, vec2 a, vec2 b) { vec2 ab = b - a; vec2 ap = p - a; float h = clamp(dot(ap, ab) / max(dot(ab, ab), 0.000001), 0.0, 1.0); return length(ap - ab * h); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; vec3 dark = vec3(0.03, 0.015, 0.02); vec3 ember = vec3(0.70, 0.15, 0.12); vec3 accent = vec3(0.94, 0.41, 0.36); vec3 highlight = vec3(1.0, 0.9, 0.85); float t = iTime * 0.6; float cellSize = 0.11; float stepLen = cellSize * 0.07; float lineWidth = 1.2 / iResolution.y; vec2 cell = floor(p / cellSize); float glow = 0.0; for (int y = -1; y <= 1; y++) { for (int x = -1; x <= 1; x++) { vec2 id = cell + vec2(float(x), float(y)); vec2 pos = (id + vec2(hash21(id), hash21(id + 5.3))) * cellSize; float phase = fract(iTime * 0.2 + hash21(id + 9.1)); float line = 0.0; for (int i = 0; i < 14; i++) { vec2 v = flowField(pos, t); vec2 next = pos + v / (length(v) + 0.1) * stepLen; float along = (float(i) + 0.5) / 14.0; float dash = smoothstep(0.4, 0.0, abs(along - phase)); line = max(line, smoothstep(lineWidth * 2.0, 0.0, segmentDist(p, pos, next)) * dash); pos = next; } glow += line; } } vec2 here = flowField(p, t); vec3 col = dark + ember * 0.03 * length(here); col += ember * glow * 1.3 + accent * glow * glow * 0.5; col += highlight * smoothstep(1.5, 2.5, glow) * 0.3; col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Twist
#torusRaymarched torus · twisted stripe · rim + specular
GLSL source
// Torus — a raymarched torus with a twisted stripe, tumbling on two axes. // Ember diffuse plus a rim and a tight specular, over a soft floor glow on the dark backdrop. mat2 rot(float a) { float c = cos(a); float s = sin(a); return mat2(c, -s, s, c); } vec3 toObject(vec3 p) { p.xz *= rot(iTime * 0.35); p.yz *= rot(iTime * 0.23); return p; } float map(vec3 p) { vec3 q = toObject(p); vec2 d = vec2(length(q.xz) - 1.0, q.y); return length(d) - 0.38; } vec3 normalAt(vec3 p) { vec2 e = vec2(0.001, 0.0); return normalize(vec3( map(p + e.xyy) - map(p - e.xyy), map(p + e.yxy) - map(p - e.yxy), map(p + e.yyx) - map(p - e.yyx))); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; vec3 ro = vec3(0.0, 0.0, 3.6); vec3 rd = normalize(vec3(uv, -1.5)); float t = 0.0; float d = 0.0; for (int i = 0; i < 64; i++) { d = map(ro + rd * t); if (d < 0.001 || t > 8.0) break; t += d; } vec3 col = vec3(0.03, 0.015, 0.02); col += vec3(0.70, 0.15, 0.12) * 0.35 * exp(-3.0 * length(uv - vec2(0.0, -0.45))); if (d < 0.001) { vec3 p = ro + rd * t; vec3 n = normalAt(p); vec3 q = toObject(p); float major = atan(q.z, q.x); float minor = atan(q.y, length(q.xz) - 1.0); float stripe = smoothstep(-0.2, 0.2, sin(minor * 3.0 + major * 2.0 + iTime)); vec3 lightDir = normalize(vec3(0.6, 0.8, 0.5)); vec3 halfDir = normalize(lightDir - rd); float diffuse = max(dot(n, lightDir), 0.0); float spec = pow(max(dot(n, halfDir), 0.0), 48.0); float rim = pow(1.0 - max(dot(n, -rd), 0.0), 3.0); vec3 base = mix(vec3(0.70, 0.15, 0.12), vec3(0.94, 0.41, 0.36), stripe); col = base * (0.12 + diffuse) + vec3(0.94, 0.41, 0.36) * rim * 0.4 + vec3(1.0, 0.9, 0.85) * spec * 0.8; } col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Tumble
#cubeRaymarched rounded box · soft shadow march · fresnel rim
GLSL source
// Cube — a raymarched rounded cube tumbling above a ground plane. // Faces carry a positional grid and a fresnel rim; a short 24-step march toward the light // drops a soft shadow onto the floor. mat2 rot(float a) { float c = cos(a); float s = sin(a); return mat2(c, -s, s, c); } vec3 toObject(vec3 p) { p.xz *= rot(iTime * 0.4); p.xy *= rot(iTime * 0.27); return p; } float mapCube(vec3 p) { vec3 q = abs(toObject(p)) - vec3(0.6); return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0) - 0.08; } float map(vec3 p) { return min(mapCube(p), p.y + 1.4); } vec3 normalAt(vec3 p) { vec2 e = vec2(0.001, 0.0); return normalize(vec3( map(p + e.xyy) - map(p - e.xyy), map(p + e.yxy) - map(p - e.yxy), map(p + e.yyx) - map(p - e.yyx))); } float shadow(vec3 ro, vec3 rd) { float res = 1.0; float t = 0.05; for (int i = 0; i < 24; i++) { float d = mapCube(ro + rd * t); res = min(res, 8.0 * d / t); t += clamp(d, 0.04, 0.3); if (res < 0.01 || t > 4.0) break; } return clamp(res, 0.0, 1.0); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; vec3 ro = vec3(0.0, 0.9, 3.8); vec3 rd = normalize(vec3(uv, -1.6)); rd.yz *= rot(-0.2); float t = 0.0; float d = 0.0; for (int i = 0; i < 64; i++) { d = map(ro + rd * t); if (d < 0.001 || t > 16.0) break; t += d; } vec3 dark = vec3(0.03, 0.015, 0.02); vec3 col = dark; if (d < 0.001) { vec3 p = ro + rd * t; vec3 n = normalAt(p); vec3 lightDir = normalize(vec3(0.5, 0.9, 0.4)); float diffuse = max(dot(n, lightDir), 0.0) * shadow(p + n * 0.02, lightDir); if (mapCube(p) < 0.005) { vec3 g = abs(fract(toObject(p) * 3.0) - 0.5); float grid = smoothstep(0.40, 0.47, max(g.x, max(g.y, g.z))); float fresnel = pow(1.0 - max(dot(n, -rd), 0.0), 4.0); float spec = pow(max(dot(n, normalize(lightDir - rd)), 0.0), 32.0); vec3 base = mix(vec3(0.70, 0.15, 0.12), vec3(0.94, 0.41, 0.36), grid * 0.6); col = base * (0.12 + diffuse) + vec3(1.0, 0.9, 0.85) * (spec * 0.6 + fresnel * 0.35); } else { float glow = exp(-1.2 * length(p.xz)); col = mix(dark, vec3(0.70, 0.15, 0.12) * 0.45, glow) * (0.35 + 0.65 * diffuse); col = mix(col, dark, smoothstep(4.0, 12.0, t)); } } col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Overflight
#terrainRaymarched fbm heightfield · height fog · ember sun
GLSL source
// Terrain — a raymarched fbm heightfield flown over toward a low ember sun. // Four noise octaves drive the march and five the final shade; the normal comes from // height differences and fog pools in the valleys. float hash21(vec2 p) { p = fract(p * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } float noise(vec2 p) { vec2 i = floor(p); vec2 f = fract(p); vec2 u = f * f * (3.0 - 2.0 * f); return mix( mix(hash21(i), hash21(i + vec2(1.0, 0.0)), u.x), mix(hash21(i + vec2(0.0, 1.0)), hash21(i + vec2(1.0, 1.0)), u.x), u.y); } float height(vec2 p, int octaves) { float value = 0.0; float amplitude = 1.0; mat2 rotate = mat2(0.8, 0.6, -0.6, 0.8); p *= 0.3; for (int i = 0; i < 5; i++) { if (i >= octaves) break; value += amplitude * noise(p); p = rotate * p * 2.0 + 10.0; amplitude *= 0.5; } return value * 1.8 - 1.4; } vec3 skyColor(vec3 rd, vec3 sunDir) { float sunAmount = max(dot(rd, sunDir), 0.0); float horizon = pow(1.0 - clamp(rd.y, 0.0, 1.0), 5.0); vec3 col = mix(vec3(0.03, 0.015, 0.02), vec3(0.70, 0.15, 0.12) * 0.7, horizon); col += vec3(0.94, 0.41, 0.36) * pow(sunAmount, 6.0) * 0.5; col += vec3(1.0, 0.9, 0.85) * pow(sunAmount, 96.0); return col; } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; vec3 sunDir = normalize(vec3(0.5, 0.12, 1.0)); vec3 ro = vec3(0.6 * sin(iTime * 0.2), 0.0, iTime * 1.2); ro.y = height(ro.xz, 2) + 1.5; vec3 rd = normalize(vec3(uv.x, uv.y - 0.12, 1.0)); float t = 0.1; float hit = 0.0; for (int i = 0; i < 80; i++) { vec3 p = ro + rd * t; float h = p.y - height(p.xz, 4); if (h < 0.003 * t) { hit = 1.0; break; } if (t > 40.0) break; t += 0.3 * h + 0.005 * t; } vec3 col = skyColor(rd, sunDir); if (hit > 0.5) { vec3 p = ro + rd * t; float e = 0.02 + 0.003 * t; vec3 n = normalize(vec3( height(p.xz - vec2(e, 0.0), 5) - height(p.xz + vec2(e, 0.0), 5), 2.0 * e, height(p.xz - vec2(0.0, e), 5) - height(p.xz + vec2(0.0, e), 5))); float diffuse = max(dot(n, sunDir), 0.0); float skyLight = 0.5 + 0.5 * n.y; vec3 ground = mix(vec3(0.10, 0.04, 0.035), vec3(0.70, 0.15, 0.12), smoothstep(-0.8, 1.6, p.y)); ground = mix(ground, vec3(0.94, 0.41, 0.36), 0.5 * smoothstep(0.6, 1.0, n.y) * smoothstep(0.8, 2.0, p.y)); col = ground * (0.12 * skyLight + 1.1 * diffuse); float fog = 1.0 - exp(-0.06 * t); fog = max(fog, 0.7 * exp(-1.5 * max(p.y + 0.9, 0.0)) * (1.0 - exp(-0.1 * t))); col = mix(col, skyColor(rd, sunDir), clamp(fog, 0.0, 1.0)); } col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Landfall
#planetAnalytic ray–sphere · 3D fbm continents · atmosphere rim
GLSL source
// Planet — an analytic ray–sphere planet with fbm continents spinning under a thin atmosphere. // No marching: the surface is 3D value noise at the hit point, the seas lean teal, and the // stars behind are a hashed grid that slowly rotates. float hash21(vec2 p) { p = fract(p * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } float hash31(vec3 p) { p = fract(p * vec3(123.34, 456.21, 789.12)); p += dot(p, p.yzx + 45.32); return fract((p.x + p.y) * p.z); } float noise3d(vec3 p) { vec3 i = floor(p); vec3 f = fract(p); vec3 u = f * f * (3.0 - 2.0 * f); float a = mix(hash31(i), hash31(i + vec3(1.0, 0.0, 0.0)), u.x); float b = mix(hash31(i + vec3(0.0, 1.0, 0.0)), hash31(i + vec3(1.0, 1.0, 0.0)), u.x); float c = mix(hash31(i + vec3(0.0, 0.0, 1.0)), hash31(i + vec3(1.0, 0.0, 1.0)), u.x); float d = mix(hash31(i + vec3(0.0, 1.0, 1.0)), hash31(i + vec3(1.0, 1.0, 1.0)), u.x); return mix(mix(a, b, u.y), mix(c, d, u.y), u.z); } float fbm(vec3 p) { float value = 0.0; float amplitude = 0.5; for (int i = 0; i < 5; i++) { value += amplitude * noise3d(p); p = p * 2.1 + 7.3; amplitude *= 0.5; } return value; } float stars(vec2 p) { vec2 cell = floor(p); vec2 f = fract(p) - 0.5; float h = hash21(cell); vec2 offset = vec2(hash21(cell + 1.3), hash21(cell + 2.7)) - 0.5; float d = length(f - offset * 0.7); float twinkle = 0.7 + 0.3 * sin(iTime * 2.0 + h * 60.0); return step(0.93, h) * twinkle * (1.0 - smoothstep(0.0, 0.14, d)); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; vec3 ro = vec3(0.0, 0.0, 4.4); vec3 rd = normalize(vec3(uv, -1.8)); vec3 sunDir = normalize(vec3(-0.7, 0.35, 0.6)); float spin = iTime * 0.04; vec2 starUv = mat2(cos(spin), -sin(spin), sin(spin), cos(spin)) * uv; vec3 col = vec3(0.03, 0.015, 0.02); col += vec3(1.0, 0.9, 0.85) * stars(starUv * 28.0) * 0.8; col += vec3(0.94, 0.41, 0.36) * stars(starUv * 55.0 + 11.0) * 0.35; float b = dot(ro, rd); float c = dot(ro, ro) - 1.0; float h = b * b - c; float closest = sqrt(max(c + 1.0 - b * b, 0.0)); col += vec3(0.94, 0.41, 0.36) * 0.9 * exp(-max(closest - 1.0, 0.0) * 14.0); if (h > 0.0) { float t = -b - sqrt(h); vec3 p = ro + rd * t; float angle = iTime * 0.15; vec3 q = vec3(p.x * cos(angle) - p.z * sin(angle), p.y, p.x * sin(angle) + p.z * cos(angle)); float elevation = fbm(q * 2.4); float land = smoothstep(0.47, 0.51, elevation); vec3 sea = vec3(0.2, 0.8, 0.75) * 0.14; vec3 ground = mix(vec3(0.70, 0.15, 0.12) * 0.7, vec3(0.94, 0.41, 0.36), smoothstep(0.5, 0.72, elevation)); vec3 surface = mix(sea, ground, land); surface = mix(surface, vec3(1.0, 0.9, 0.85) * 0.8, smoothstep(0.8, 0.95, abs(p.y))); float diffuse = max(dot(p, sunDir), 0.0); float spec = pow(max(dot(p, normalize(sunDir - rd)), 0.0), 48.0) * (1.0 - land); float rim = pow(1.0 - max(dot(p, -rd), 0.0), 3.0); col = surface * (0.03 + diffuse) + vec3(1.0, 0.9, 0.85) * spec * 0.5 + vec3(0.94, 0.41, 0.36) * rim * (0.15 + 0.6 * diffuse); } col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Hexfield
#isocubes2D isometric hex tiling · flat-shaded columns · sine bob
GLSL source
// Isocubes — a 2D isometric column field on a pointy-top hex tiling, no raymarching. // Each hex is a cube with three flat-shaded faces; columns bob on a sine of position and time, // and the front-most column covering a pixel wins a five-sample vertical depth test. float hash21(vec2 p) { p = fract(p * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } vec2 hexCenter(vec2 p) { vec2 r = vec2(1.0, 1.7320508); vec2 h = r * 0.5; vec2 a = mod(p, r) - h; vec2 b = mod(p - h, r) - h; return dot(a, a) < dot(b, b) ? p - a : p - b; } float columnHeight(vec2 center) { return 0.25 + 0.22 * sin(iTime * 1.6 + center.x * 0.8 + center.y * 0.5 + hash21(center) * 1.5); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; vec2 p = uv * 6.5 + vec2(iTime * 0.12, iTime * 0.08); vec3 ember = vec3(0.70, 0.15, 0.12); vec3 col = vec3(0.03, 0.015, 0.02); for (int i = 4; i >= 0; i--) { vec2 center = hexCenter(p - vec2(0.0, float(i) * 0.125)); vec2 local = p - center; float h = columnHeight(center); float margin = 1.0 - 1.7320508 * abs(local.x); if (abs(local.x) > 0.5 || local.y < -margin || local.y > h + margin) continue; float topY = local.y - h; bool isTop = topY > 0.57735 * abs(local.x); float lift = 0.75 + 0.7 * h; if (isTop) { col = vec3(0.94, 0.41, 0.36) * lift; } else if (local.x < 0.0) { col = ember * lift; } else { col = ember * 0.4 * lift; } float edge = abs(topY - 0.57735 * abs(local.x)); if (!isTop) edge = min(edge, abs(local.x)); edge = min(edge, 0.5 - abs(local.x)); edge = min(edge, h + margin - local.y); col *= 0.5 + 0.5 * smoothstep(0.0, 0.04, edge); break; } col *= 1.0 - 0.5 * dot(uv, uv); col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Bore
#squaretunnelChebyshev tunnel · angle × 1/r checker · wobbling centre
GLSL source
// Square tunnel — the classic demo tunnel with a Chebyshev radius. // max(|x|,|y|) replaces length() so the bore is square; angle and 1/r index a checker that // scrolls toward the viewer while the centre wobbles and the four corner seams glow. void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; p -= 0.15 * vec2(sin(iTime * 0.7), cos(iTime * 0.9)); float r = max(abs(p.x), abs(p.y)); float angle = atan(p.y, p.x) / 6.28318530718 + iTime * 0.03; float depth = 0.25 / max(r, 0.01); vec2 tex = vec2(angle * 8.0, depth - iTime * 2.5); float checker = mod(floor(tex.x) + floor(tex.y), 2.0); float stripe = 1.0 - smoothstep(0.30, 0.45, abs(fract(tex.y) - 0.5)); float seam = 1.0 - smoothstep(0.0, 0.06, abs(fract(tex.x) - 0.5)); float corner = 1.0 - smoothstep(0.0, 0.02, abs(abs(p.x) - abs(p.y))); vec3 ember = vec3(0.70, 0.15, 0.12); vec3 accent = vec3(0.94, 0.41, 0.36); vec3 col = mix(ember * 0.6, accent, checker); col *= 0.55 + 0.45 * stripe; col += vec3(1.0, 0.9, 0.85) * seam * 0.3; col += accent * corner * 0.5; col *= 1.0 - exp(-r * 4.0); col = max(col, 0.0); col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Spin cycle
#rotozoomRotozoomer · two sine-warped layers · procedural dots
GLSL source
// Rotozoom — the demoscene rotozoomer: a procedural dot-and-checker texture spun and zoomed by time. // Two layers at different speeds, each sine-warped, blend into a plasma-ish ember mix. mat2 rot(float a) { float c = cos(a); float s = sin(a); return mat2(c, -s, s, c); } float pattern(vec2 p) { vec2 cell = fract(p) - 0.5; float checker = mod(floor(p.x) + floor(p.y), 2.0); float dots = 1.0 - smoothstep(0.22, 0.30, length(cell)); return mix(checker, 1.0 - checker, dots); } float layer(vec2 p, float t, float spin, float speed, vec2 drift) { float zoom = 1.5 + sin(t * speed); vec2 q = rot(t * spin) * p * zoom * 3.0 + drift * t; q += 0.18 * sin(q.yx * 1.7 + t); return pattern(q); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; float t = iTime; float a = layer(uv, t, 0.25, 0.6, vec2(0.6, 0.2)); float b = layer(uv, t + 3.0, -0.17, 0.43, vec2(-0.3, 0.5)); vec3 col = mix(vec3(0.03, 0.015, 0.02), vec3(0.70, 0.15, 0.12), a); col = mix(col, vec3(0.94, 0.41, 0.36), b * 0.55); col += vec3(1.0, 0.9, 0.85) * a * b * 0.25; col *= 1.0 - 0.4 * dot(uv, uv); col = max(col, 0.0); col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Outrun
#synthgridPerspective grid · banded sun · 1D-noise ridges
GLSL source
// Synthgrid — a synthwave horizon: a perspective grid scrolling toward the viewer under a // banded setting sun, a violet-to-ember sky, and two ridges of mountains cut from 1D value noise. float hash11(float n) { return fract(sin(n * 127.1) * 43758.5453); } float noise1d(float x) { float i = floor(x); float f = fract(x); float u = f * f * (3.0 - 2.0 * f); return mix(hash11(i), hash11(i + 1.0), u); } float ridge(float x, float seed) { return 0.10 * noise1d(x * 3.0 + seed) + 0.05 * noise1d(x * 7.0 + seed * 2.0) + 0.02 * noise1d(x * 17.0 + seed); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; vec3 dark = vec3(0.03, 0.015, 0.02); vec3 ember = vec3(0.70, 0.15, 0.12); vec3 accent = vec3(0.94, 0.41, 0.36); vec3 highlight = vec3(1.0, 0.9, 0.85); vec3 violet = vec3(0.55, 0.35, 0.95); float horizon = 0.02; vec3 col; if (uv.y < horizon) { float d = horizon - uv.y; float z = 0.35 / d; vec2 g = vec2(uv.x * z, z + iTime * 1.5) / 0.3; vec2 dist = 0.5 - abs(fract(g) - 0.5); vec2 w = fwidth(g) * 1.2 + 0.02; vec2 lines = 1.0 - smoothstep(vec2(0.0), w, dist); float gridLine = max(lines.x, lines.y) * (1.0 - exp(-d * 30.0)); col = dark + ember * 0.12 * exp(-d * 12.0); col += mix(ember, highlight, gridLine * 0.3) * gridLine * 1.3; } else { float sky = smoothstep(horizon, 0.45, uv.y); col = mix(ember * 0.45, violet * 0.12, sky); vec2 sunPos = vec2(0.0, horizon + 0.2); float sd = length(uv - sunPos); float sun = 1.0 - smoothstep(0.20, 0.205, sd); float band = sin((uv.y - horizon) * 90.0 - iTime * 0.8); float threshold = 0.9 - 6.0 * (uv.y - horizon); sun *= smoothstep(-0.08, 0.08, band - threshold); vec3 sunCol = mix(accent, highlight, smoothstep(sunPos.y - 0.2, sunPos.y + 0.2, uv.y)); col += sunCol * sun + accent * 0.35 * exp(-sd * 5.0); float farRidge = horizon + 0.03 + ridge(uv.x + 0.3, 5.0); float nearRidge = horizon + 0.005 + ridge(uv.x, 1.0) * 0.7; if (uv.y < farRidge) col = mix(violet * 0.18, dark, smoothstep(0.0, 0.06, farRidge - uv.y)); if (uv.y < nearRidge) col = dark + ember * 0.15 * (1.0 - smoothstep(0.0, 0.015, nearRidge - uv.y)); } col = max(col, 0.0); col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Singularity
#blackhole2D lensing · hashed starfield · gold accretion ring
GLSL source
// Black hole — gravitational lensing faked in 2D: star lookups are pulled toward the centre by // a 1/r term around a dark event horizon, ringed by a thin ember-and-gold accretion disc whose // front half passes over the hole. float hash21(vec2 p) { p = fract(p * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } float stars(vec2 p) { vec2 cell = floor(p); vec2 f = fract(p) - 0.5; float h = hash21(cell); vec2 offset = vec2(hash21(cell + 1.3), hash21(cell + 2.7)) - 0.5; float d = length(f - offset * 0.7); float twinkle = 0.7 + 0.3 * sin(iTime * 2.0 + h * 60.0); return step(0.92, h) * twinkle * (1.0 - smoothstep(0.0, 0.12, d)); } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; float r = length(uv); vec2 dir = uv / max(r, 0.0001); float horizonR = 0.13; vec2 lensed = uv - dir * 0.022 / max(r - 0.04, 0.02); float spin = iTime * 0.02; lensed = mat2(cos(spin), -sin(spin), sin(spin), cos(spin)) * lensed; vec3 col = vec3(0.03, 0.015, 0.02); col += vec3(1.0, 0.9, 0.85) * stars(lensed * 26.0) * 0.9; col += vec3(0.94, 0.41, 0.36) * stars(lensed * 50.0 + 9.0) * 0.4; col += vec3(0.70, 0.15, 0.12) * 0.08 * exp(-length(lensed) * 2.0); vec2 q = mat2(0.94, -0.34, 0.34, 0.94) * uv; q.y *= 2.6; float rr = length(q); float x = (rr - 0.3) * 22.0; float a = atan(q.y, q.x); float doppler = 0.4 + 0.6 * smoothstep(-1.0, 1.0, cos(a)); float ring = exp(-x * x) * doppler * (0.7 + 0.3 * sin(a * 3.0 - iTime * 2.0)); float haze = exp(-abs(rr - 0.3) * 9.0) * 0.25 * doppler; float hole = 1.0 - smoothstep(horizonR, horizonR + 0.008, r); col *= 1.0 - hole; float photon = (r - horizonR - 0.012) * 90.0; col += vec3(0.94, 0.41, 0.36) * exp(-photon * photon) * 0.8; vec3 ringCol = mix(vec3(0.94, 0.41, 0.36), vec3(1.0, 0.75, 0.3), doppler); float front = step(q.y, 0.0); float visible = 1.0 - hole * (1.0 - front); col += ringCol * (ring * 1.6 + haze) * visible; col = max(col, 0.0); col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }Slow burn
#lavaMetaballs · gradient-shaded field · glass highlight
GLSL source
// Lava lamp — five metaballs drifting on sine paths inside a glass tube. // The summed inverse-square field is thresholded with a soft edge and shaded by its own // gradient for a fake-3D bulge, under a vertical glass highlight and a warm bulb glow below. float field(vec2 p) { float f = 0.0; for (int i = 0; i < 5; i++) { float k = float(i); vec2 c = vec2( 0.26 * sin(iTime * (0.35 + 0.11 * k) + k * 1.7), 0.28 * sin(iTime * (0.22 + 0.07 * k) + k * 2.3) - 0.02); float radius = 0.08 + 0.02 * k; vec2 d = p - c; f += radius * radius / (dot(d, d) + 0.0005); } return f; } void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 p = (fragCoord - 0.5 * iResolution.xy) / iResolution.y; vec3 dark = vec3(0.03, 0.015, 0.02); vec3 ember = vec3(0.70, 0.15, 0.12); vec3 accent = vec3(0.94, 0.41, 0.36); vec3 highlight = vec3(1.0, 0.9, 0.85); float inTube = (1.0 - smoothstep(0.44, 0.46, abs(p.x))) * (1.0 - smoothstep(0.455, 0.475, abs(p.y))); float f = field(p); vec2 e = vec2(0.004, 0.0); vec2 grad = vec2(field(p + e.xy) - field(p - e.xy), field(p + e.yx) - field(p - e.yx)) / (2.0 * e.x); vec3 n = normalize(vec3(-grad * 0.08, 1.0)); vec3 lightDir = normalize(vec3(-0.4, 0.5, 0.75)); float light = max(dot(n, lightDir), 0.0); float spec = pow(max(dot(n, normalize(lightDir + vec3(0.0, 0.0, 1.0))), 0.0), 24.0); float body = smoothstep(0.85, 1.15, f); vec3 blob = mix(ember, accent, light) + highlight * spec * 0.6 + accent * 0.3 * smoothstep(1.5, 4.0, f); vec3 liquid = vec3(0.09, 0.03, 0.03) + ember * 0.3 * exp(-(p.y + 0.5) * 3.0); liquid += ember * 0.25 * smoothstep(0.2, 0.85, f); vec3 col = mix(liquid, blob, body); float stripe = (p.x + 0.28) * 14.0; col += highlight * 0.10 * exp(-stripe * stripe); col = mix(dark + ember * 0.06 * exp(-abs(p.x) * 2.0), col, inTube); col = max(col, 0.0); col = col / (1.0 + col); fragColor = vec4(pow(col, vec3(0.9)), 1.0); }