Deep fried math

GLSL shader by merrypranxter · created 2026-02-14 · 10s loop · 2 passes

Layered Julia set iterations warped through 5-octave domain folding, overlaid with animated Voronoi crystal edges and distance-field isolines. Three palettes, supersampled. It goes pretty deep.

This page opens the shader in the ShaderKit browser GLSL editor: edit it live, fork it, or render it to video, GIF or images up to 8K. Also available as a full-screen view and an embeddable player.

Shader source (GLSL)

Common

#define pi acos(-1.)
#define deg pi/180.  //1 degree
#define time iTime*2.*pi/10. //sin(time) loops 10 seconds
#define R iResolution.xy //shorthand
#define ar R.x/R.y //aspect ratio
#define M iMouse //shorthand
#define xm (M.xy/R) //normalized mouse
#define nm ((xm.xy-0.5)*vec2(ar,1.)+0.5) //aspect ratio correction
vec3 cs = vec3(1.,2.,3.);
mat2 r2d(float a) {
    return mat2(cos(a),sin(a),-sin(a),cos(a));
}

Buffer A (iChannel0)

// ============================================================
//  MATH TEXTURE v1.1 — compiler-safe
// ============================================================

const float PI  = 3.14159265359;
const float TAU = 6.28318530718;

const float speed      = 0.15;
const float zoom       = 2.2;
const float warpAmt    = 0.55;
const float iterGain   = 1.0;
const float edgeGlow   = 3.0;
const float brightness = 1.5;

vec3 lfPalette(float t) {
    vec3 a = vec3(0.5, 0.3, 0.6);
    vec3 b = vec3(0.5, 0.5, 0.5);
    vec3 c = vec3(1.0, 1.3, 0.9);
    vec3 d = vec3(0.0, 0.25, 0.6);
    return a + b * cos(TAU * (c * t + d));
}
vec3 neonPalette(float t) {
    vec3 a = vec3(0.4, 0.2, 0.5);
    vec3 b = vec3(0.5, 0.5, 0.4);
    vec3 c = vec3(2.1, 1.5, 0.8);
    vec3 d = vec3(0.1, 0.4, 0.9);
    return a + b * cos(TAU * (c * t + d));
}
vec3 hotPalette(float t) {
    vec3 a = vec3(0.6, 0.4, 0.3);
    vec3 b = vec3(0.4, 0.5, 0.5);
    vec3 c = vec3(0.5, 1.0, 2.0);
    vec3 d = vec3(0.8, 0.2, 0.5);
    return a + b * cos(TAU * (c * t + d));
}

vec2 cMul(vec2 a, vec2 b) {
    return vec2(a.x*b.x - a.y*b.y, a.x*b.y + a.y*b.x);
}
vec2 cPow(vec2 z, float n) {
    float r = length(z);
    float a = atan(z.y, z.x);
    return pow(max(r, 0.0001), n) * vec2(cos(a*n), sin(a*n));
}

// safe cSin — no cosh/sinh, use definitions directly
vec2 cSin(vec2 z) {
    float ep = exp(z.y);
    float em = exp(-z.y);
    return vec2(sin(z.x) * (ep + em) * 0.5,
                cos(z.x) * (ep - em) * 0.5);
}

float hash21(vec2 p) {
    p = fract(p * vec2(127.1, 311.7));
    p += dot(p, p + 19.19);
    return fract(p.x * p.y);
}
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);
}

float vnoise(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)), u.x),
               mix(hash21(i + vec2(0,1)), hash21(i + vec2(1,1)), u.x), u.y);
}

vec2 domainWarp(vec2 p, float t) {
    float s = 1.0;
    vec2  r = vec2(0.0);
    for(int i = 0; i < 5; i++) {
        float fi = float(i);
        vec2 q = p * s + t * (0.1 + fi * 0.07) * vec2(1.0, -0.7);
        r += (vec2(vnoise(q), vnoise(q + vec2(5.2, 1.3))) * 2.0 - 1.0)
             / s * warpAmt;
        s *= 2.1;
    }
    return p + r;
}

vec3 voronoi(vec2 p) {
    vec2  ig = floor(p);
    vec2  fg = fract(p);
    float md  = 8.0;
    float md2 = 8.0;
    vec2  mo  = vec2(0.0);
    for(int j = -2; j <= 2; j++)
    for(int i = -2; i <= 2; i++) {
        vec2 g = vec2(float(i), float(j));
        vec2 o = hash22(ig + g);
        o = 0.5 + 0.5 * sin(o * TAU + p * 0.3 + vec2(0.0, 1.5));
        vec2 r2 = g + o - fg;
        float d = dot(r2, r2);
        if(d < md)       { md2 = md; md = d; mo = r2; }
        else if(d < md2) { md2 = d; }
    }
    return vec3(sqrt(md), sqrt(md2), dot(mo, mo));
}

vec3 complexField(vec2 z, float t) {
    float cx = 0.355 + sin(t * 0.23) * 0.12;
    float cy = 0.355 + cos(t * 0.31) * 0.08;
    vec2  c  = vec2(cx, cy);

    float escape = 0.0;
    float trap   = 1e5;
    vec2  dz     = vec2(1.0, 0.0);

    for(int i = 0; i < 96; i++) {
        if(dot(z, z) > 64.0) break;
        dz = 2.0 * cMul(z, dz) + vec2(1.0, 0.0);
        z  = cPow(z, 2.0) + c;
        z += cSin(z * 0.4 + t * 0.1) * 0.08;
        trap   = min(trap, abs(dot(z, vec2(1.0, 0.0))));
        escape += exp(-length(z) * iterGain);
    }

    float dist = length(z) * log(max(length(z), 1.0001)) 
                 / max(length(dz), 0.0001);
    return vec3(escape, trap, dist);
}

vec3 sampleScene(vec2 uv, float t) {
    vec2 wp = domainWarp(uv * zoom, t);

    vec3 f1 = complexField(wp, t);
    vec3 f2 = complexField(wp * 1.618 + vec2(1.3, 0.7), t * 1.1);
    vec3 f3 = complexField(wp * 0.8 + vec2(0.4, 0.9),   t * 0.9);

    float esc  = f1.x * 0.5 + f2.x * 0.3 + f3.x * 0.2;
    float trap = f1.y * 0.6 + f2.y * 0.4;
    float dist = f1.z;

    vec3  vor  = voronoi(wp * 3.5 + t * 0.05);
    float edge = 1.0 - smoothstep(0.0, 0.06, vor.y - vor.x);

    float film  = fract(esc  * 0.4  + t * 0.08);
    float film2 = fract(trap * 1.2  + t * 0.05);

    vec3 col = vec3(0.01, 0.005, 0.02);

    col = mix(col, lfPalette(film + esc * 0.03),
              smoothstep(0.0, 0.5, esc * 0.15));

    col += neonPalette(film2 + trap * 0.4 + t * 0.06)
           * smoothstep(0.8, 0.0, trap) * 0.7;

    col += hotPalette(f2.x * 0.08 + film * 0.5 - t * 0.04) * f2.x * 0.04;

    float iso = abs(sin(dist * 80.0 + t * 2.0));
    col += lfPalette(dist * 2.0 + t * 0.1) * iso * 0.3;

    col += neonPalette(vor.x * 0.8 + t * 0.07) * edge * edgeGlow * 0.4;
    col += hotPalette(film + vor.x)              * edge * edgeGlow * 0.25;

    return col;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    vec2  uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;
    float t  = iTime * speed;

    vec2 px = 1.0 / iResolution.xy;
    vec3 col  = vec3(0.0);
    col += sampleScene(uv + px * vec2(-0.25, -0.25), t);
    col += sampleScene(uv + px * vec2( 0.25, -0.25), t);
    col += sampleScene(uv + px * vec2(-0.25,  0.25), t);
    col += sampleScene(uv + px * vec2( 0.25,  0.25), t);
    col *= 0.25;

    col *= 1.0 - dot(uv, uv) * 0.4;
    col  = pow(clamp(col * brightness, 0.0, 1.0), vec3(0.8));
    col *= col * 1.5;

    fragColor = vec4(col, 1.0);
}

Image

Not used

More shaders by merrypranxter

Browse all public shaders · All shaders by merrypranxter · ShaderKit home

Vibe Mode BETA
💰 ~0 credits
Uniforms
FPS: 0
Time: 0
Resolution: 0 x 0

Account

FPS: -- Time: -- --×-- 1x