Back to shaders

Shader test bench

20260403

glsl-daily-practice generative glsl runnable fragment MIT
Source
runnable fragment

Complete GLSL fragment shader. Stronghold runs it directly when the browser can compile it.

Code

precision mediump float;
// ============================================================
// Babylonian Fibonacci — Sacred Geometry + Pink Dots Edition
// TouchDesigner GLSL TOP
// ============================================================

uniform float iTime;
uniform vec2  iResolution;

layout(location = 0) #define fragColor gl_FragColor

// --- Color Palette (mandatory) ---
const vec3 cBg1    = vec3(0.161, 0.188, 0.224);
const vec3 cBg2    = vec3(0.157, 0.212, 0.192);
const vec3 cDeep1  = vec3(0.051, 0.122, 0.176);
const vec3 cDeep2  = vec3(0.039, 0.239, 0.180);
const vec3 cGreen  = vec3(0.000, 1.000, 0.529);
const vec3 cCyan   = vec3(0.000, 0.831, 1.000);
const vec3 cPurple = vec3(0.482, 0.184, 1.000);
const vec3 cPink   = vec3(1.000, 0.176, 0.478);
const vec3 cMint   = vec3(0.690, 1.000, 0.910);
const vec3 cIce    = vec3(0.769, 0.941, 1.000);

const float PI           = 3.14159265359;
const float TAU          = 6.28318530718;
const float PHI          = 1.61803398875;
const float GOLDEN_ANGLE = 2.39996323;

// ─────────────────────────────────────────────
//  Utilities
// ─────────────────────────────────────────────

mat2 rot(float a) { float c=cos(a),s=sin(a); return mat2(c,-s,s,c); }

vec3 pal(float t) {
    t = fract(t);
    if (t < 0.2) return mix(cCyan,   cGreen,  t / 0.2);
    if (t < 0.4) return mix(cGreen,  cMint,  (t - 0.2) / 0.2);
    if (t < 0.6) return mix(cMint,   cIce,   (t - 0.4) / 0.2);
    if (t < 0.8) return mix(cIce,    cPurple,(t - 0.6) / 0.2);
                 return mix(cPurple, cPink,  (t - 0.8) / 0.2);
}

float sdSeg(vec2 p, vec2 a, vec2 b) {
    vec2 pa=p-a, ba=b-a;
    return length(pa - ba*clamp(dot(pa,ba)/dot(ba,ba),0.0,1.0));
}
float sdRing(vec2 p, vec2 c, float r) { return abs(length(p-c)-r); }
float glow(float d, float w, float bloom) {
    return smoothstep(w, 0.0, d) + bloom*exp(-d*d*180.0);
}

// Deterministic hash for sparkles
float hash(float n) { return fract(sin(n*127.1+311.7)*43758.5453); }

// ─────────────────────────────────────────────
//  Sacred Geometry Primitives
// ─────────────────────────────────────────────

float flowerOfLife(vec2 uv, float R, float w) {
    float d = sdRing(uv, vec2(0.0), R);
    for (int i = 0; i < 6; i++) {
        float a = float(i)*TAU/6.0;
        d = min(d, sdRing(uv, vec2(cos(a),sin(a))*R, R));
    }
    return glow(d, w, 0.35);
}

float sdPolyLine(vec2 uv, int n, float r, float angle, float w) {
    float d = 1e9;
    for (int i = 0; i < n; i++) {
        float a0 = float(i)  *TAU/float(n) + angle;
        float a1 = float(i+1)*TAU/float(n) + angle;
        d = min(d, sdSeg(uv, vec2(cos(a0),sin(a0))*r, vec2(cos(a1),sin(a1))*r));
    }
    return glow(d, w, 0.20);
}

float hexagram(vec2 uv, float r, float angle, float w) {
    float d1=1e9, d2=1e9;
    for (int i = 0; i < 3; i++) {
        float a0=float(i)*TAU/3.0+angle, a1=float(i+1)*TAU/3.0+angle;
        d1 = min(d1, sdSeg(uv, vec2(cos(a0),sin(a0))*r, vec2(cos(a1),sin(a1))*r));
        float b0=a0+TAU/6.0, b1=a1+TAU/6.0;
        d2 = min(d2, sdSeg(uv, vec2(cos(b0),sin(b0))*r, vec2(cos(b1),sin(b1))*r));
    }
    return glow(min(d1,d2), w, 0.28);
}

float pentagram(vec2 uv, float r, float angle, float w) {
    vec2 v[5];
    for (int i=0;i<5;i++){float a=float(i)*TAU/5.0+angle; v[i]=vec2(cos(a),sin(a))*r;}
    int ord[5]; ord[0]=0;ord[1]=2;ord[2]=4;ord[3]=1;ord[4]=3;
    float d=1e9;
    for (int i=0;i<5;i++) d=min(d, sdSeg(uv,v[ord[i]],v[ord[(i+1)%5]]));
    return glow(d, w, 0.22);
}

float vesica(vec2 uv, float R, float angle, float w) {
    vec2 c1=rot(angle)*vec2(R*0.5,0.0), c2=rot(angle)*vec2(-R*0.5,0.0);
    return glow(min(sdRing(uv,c1,R),sdRing(uv,c2,R)), w, 0.18);
}

float rays(vec2 uv, int n, float angle, float spread) {
    float a = atan(uv.y,uv.x)+PI;
    float sec = TAU/float(n);
    a = abs(mod(a-angle, sec) - sec*0.5);
    float r = length(uv);
    return smoothstep(spread,0.0,a)*smoothstep(0.88,0.08,r)*smoothstep(0.0,0.05,r);
}

float babylonRing(vec2 uv, float radius, float rotOff) {
    float r=length(uv), a=atan(uv.y,uv.x)+rotOff;
    float ring   = smoothstep(0.006,0.0,abs(r-radius));
    float minorPh= abs(fract(a/TAU*60.0+0.5)-0.5);
    float majorPh= abs(fract(a/TAU*6.0 +0.5)-0.5);
    float minor  = smoothstep(0.010,0.0,minorPh)*step(radius,r)*smoothstep(radius+0.022,radius+0.006,r);
    float major  = smoothstep(0.013,0.0,majorPh)*step(radius,r)*smoothstep(radius+0.042,radius+0.006,r);
    return ring + minor*0.50 + major*0.85;
}

float spiralArm(vec2 uv, float k, float offset, float spread) {
    float r=length(uv);
    if (r<0.001) return 0.0;
    float a=atan(uv.y,uv.x)+offset;
    float phase=fract((log(r)/k - a)/TAU)-0.5;
    return smoothstep(spread,0.0,abs(phase)/(1.0+r*2.2));
}

// ─────────────────────────────────────────────
//  NEW: Pink Comet Beads
//  count beads orbit a ring, each leaving a fading angular trail
// ─────────────────────────────────────────────
float pinkCometBeads(vec2 uv, float radius, int count, float speed, float trailLen) {
    float r       = length(uv);
    float uvAngle = atan(uv.y, uv.x) + PI;   // pixel angle [0, TAU]
    float nearRing= smoothstep(0.028, 0.0, abs(r - radius)); // ring proximity mask

    float result = 0.0;
    for (int i = 0; i < count; i++) {
        float beadAngle = mod(float(i)*TAU/float(count) + speed, TAU);

        // ── Dot core + bloom halo ──
        vec2  pos  = vec2(cos(beadAngle), sin(beadAngle)) * radius;
        float d    = length(uv - pos);
        float sz   = 0.014 + 0.005*sin(speed*2.2 + float(i)*1.1);
        result    += smoothstep(sz, 0.0, d);
        result    += 0.40 * exp(-d*d*380.0);

        // ── Comet tail (angular arc behind bead) ──
        float angDiff = mod(beadAngle - uvAngle + TAU, TAU);
        float tail    = smoothstep(trailLen, 0.0, angDiff)   // fade with distance
                      * pow(1.0 - angDiff/trailLen, 1.8)     // sharper near head
                      * nearRing;                             // only on ring surface
        result += tail * 0.70;
    }
    return clamp(result, 0.0, 1.0);
}

// ─────────────────────────────────────────────
//  NEW: Twinkling sparkle field (fixed positions, oscillating brightness)
// ─────────────────────────────────────────────
float sparkleField(vec2 uv, float t, int count, float spread) {
    float result = 0.0;
    for (int i = 0; i < count; i++) {
        float fi     = float(i);
        float angle  = hash(fi)       * TAU;
        float radius = 0.06 + hash(fi+0.1) * spread;
        vec2  pos    = vec2(cos(angle), sin(angle)) * radius;
        float twinkle= 0.5 + 0.5*sin(t*(1.8+hash(fi+0.5)*2.5) + hash(fi+0.7)*TAU);
        float d      = length(uv - pos);
        float sz     = 0.004 + 0.003*twinkle;
        result      += smoothstep(sz, 0.0, d) * twinkle;
        result      += 0.18 * exp(-d*d*1800.0) * twinkle;
    }
    return clamp(result, 0.0, 1.0);
}

// ─────────────────────────────────────────────
//  NEW: Concentric wave ripples from center
// ─────────────────────────────────────────────
float rippleWaves(vec2 uv, float t) {
    float r = length(uv);
    float w = 0.0;
    for (int i = 0; i < 4; i++) {
        float fi = float(i);
        w += sin(r*32.0 - t*(1.3+fi*0.55) - fi*1.4) * exp(-r*(2.2+fi*0.9));
    }
    return w * 0.25;
}

// ─────────────────────────────────────────────
//  NEW: Aurora nebula background bands
// ─────────────────────────────────────────────
float auroraField(vec2 uv, float t) {
    float val = 0.0;
    for (int i = 0; i < 5; i++) {
        float fi = float(i) * PHI;
        val += sin(uv.x*(2.0+fi*0.9) + t*(0.22+fi*0.06) + fi*1.2)
             * cos(uv.y*(1.7+fi*0.7) + t*(0.18+fi*0.04) + fi*0.8)
             * (1.0/float(i+1));
    }
    return 0.5 + 0.38*val;
}

// ─────────────────────────────────────────────
//  Main
// ─────────────────────────────────────────────
void main() {
    float mn = min(iResolution.x, iResolution.y);
    vec2  uv = (gl_FragCoord.xy - 0.5*iResolution.xy) / mn;
    float t  = iTime * 0.18;

    // Breathing UV warp — the whole field pulses slowly
    float breathAmt = 0.013*sin(t*1.55);
    vec2  wuv = uv + breathAmt*vec2(sin(uv.y*5.2+t*1.0), cos(uv.x*5.2+t*0.85));

    // ── 1. Background ─────────────────────────────────────
    float bgPulse = 0.5+0.5*sin(length(uv)*3.8 - t*1.8);
    vec3  col     = mix(cDeep1, cDeep2, bgPulse);
    col           = mix(col, mix(cBg1,cBg2,bgPulse), 0.50);

    // Aurora color wash (slow, subtle)
    float aur1 = auroraField(uv*0.9,  t);
    float aur2 = auroraField(uv*1.2, -t*0.7 + 3.14);
    col = mix(col, cPurple*0.35, aur1*0.18);
    col = mix(col, cPink  *0.25, aur2*0.14);

    // Clay tablet micro-grid
    float gx=abs(fract(uv.x*22.0+0.5)-0.5), gy=abs(fract(uv.y*22.0+0.5)-0.5);
    col += cDeep2*smoothstep(0.48,0.43,max(gx,gy))*0.055;

    // Concentric ripple waves
    float rip = rippleWaves(uv, iTime);
    col += cCyan * rip * 0.055;
    col += cPink * rip * 0.038;

    // ── 2. Radial rays ────────────────────────────────────
    float rr = rays(uv,24, t*0.55, 0.016)*0.5 + rays(uv,8, t*0.18, 0.028)*0.4;
    col = mix(col, cGreen, clamp(rr,0.0,1.0)*0.18);

    // ── 3. Vesica Piscis ──────────────────────────────────
    col = mix(col, cDeep2+cCyan*0.4, clamp(vesica(uv,0.72,t*0.06,0.005),0.0,1.0)*0.35);

    // ── 4. Nested spinning polygons (breathing scale) ─────
    float breath = 1.0 + 0.04*sin(t*TAU*0.52);
    col = mix(col, cIce   *1.2, clamp(sdPolyLine(uv,7,0.68*breath, t*0.055,       0.004),0.0,1.0)*0.32);
    col = mix(col, cMint  *1.2, clamp(sdPolyLine(uv,6,0.56*breath,-t*0.075,       0.004),0.0,1.0)*0.34);
    col = mix(col, cCyan  *1.3, clamp(sdPolyLine(uv,5,0.45*breath, t*0.110+0.30,  0.004),0.0,1.0)*0.36);
    col = mix(col, cPurple*1.3, clamp(sdPolyLine(uv,4,0.36*breath,-t*0.150,       0.004),0.0,1.0)*0.38);
    col = mix(col, cPink  *1.2, clamp(sdPolyLine(uv,3,0.28*breath, t*0.200,       0.004),0.0,1.0)*0.38);

    // ── 5. Flower of Life ─────────────────────────────────
    col = mix(col, cMint*1.5, clamp(flowerOfLife(rot( t*0.07)*uv, 0.160, 0.005),0.0,1.0)*0.50);
    col = mix(col, cCyan*1.3, clamp(flowerOfLife(rot(-t*0.04)*uv, 0.335, 0.004),0.0,1.0)*0.38);

    // ── 6. Hexagram (Star of Ishtar) ─────────────────────
    col = mix(col, cCyan*1.6, clamp(hexagram(uv,0.230, t*0.14,        0.005),0.0,1.0)*0.55);
    col = mix(col, cIce *1.4, clamp(hexagram(uv,0.115,-t*0.19+PI*0.1, 0.004),0.0,1.0)*0.48);

    // ── 7. Pentagram (φ geometry) ─────────────────────────
    col = mix(col, cPurple*1.7, clamp(pentagram(uv,0.190,-t*0.17,        0.005),0.0,1.0)*0.55);
    col = mix(col, cPink  *1.4, clamp(pentagram(uv,0.095, t*0.24+PI*0.2, 0.004),0.0,1.0)*0.45);

    // ── 8. Logarithmic spiral arms 8 + 13 ────────────────
    float k=0.30614, arms8=0.0, arms13=0.0;
    for (int i=0;i<8; i++) arms8  += spiralArm(uv,k,float(i)*TAU/8.0 + t*0.25,0.080);
    for (int i=0;i<13;i++) arms13 += spiralArm(uv,k,float(i)*TAU/13.0- t*0.16,0.062);
    col = mix(col, cPurple*1.2, clamp(arms8, 0.0,1.0)*0.20);
    col = mix(col, cCyan  *1.1, clamp(arms13,0.0,1.0)*0.17);

    // ── 9. Fibonacci phyllotaxis (233 seeds) ──────────────
    float fibLayer=0.0, fibHue=0.0;
    for (int n=1;n<=233;n++) {
        float fn=float(n), angle=fn*GOLDEN_ANGLE+t*0.38, rad=sqrt(fn)*0.058;
        vec2  pos=vec2(cos(angle),sin(angle))*rad;
        float sz=0.0075+0.003*sin(t*1.9+fn*0.38);
        float d=smoothstep(sz,0.0,length(wuv-pos));
        fibLayer+=d; fibHue=mix(fibHue,fn/233.0,d);
    }
    col = mix(col, pal(fibHue+t*0.10), clamp(fibLayer,0.0,1.0));

    // ── 10. Pink secondary phyllotaxis ───────────────────
    //  Same golden angle, offset by π — fills the inter-seed gaps with pink
    float pinkFib = 0.0;
    for (int n=1;n<=144;n++) {
        float fn=float(n), angle=fn*GOLDEN_ANGLE+PI+t*0.50, rad=sqrt(fn)*0.062;
        vec2  pos=vec2(cos(angle),sin(angle))*rad;
        float sz=0.007+0.003*sin(t*2.1+fn*0.52);
        pinkFib += smoothstep(sz, 0.0, length(wuv-pos));
    }
    pinkFib = clamp(pinkFib,0.0,1.0);
    col  = mix(col, cPink*1.6, pinkFib*0.72);
    col += cPink * pinkFib * 0.12;   // additive bloom

    // ── 11. Fibonacci node highlights + orbit trails ──────
    int fibSeq[11];
    fibSeq[0]=1;fibSeq[1]=1;fibSeq[2]=2; fibSeq[3]=3;
    fibSeq[4]=5;fibSeq[5]=8;fibSeq[6]=13;fibSeq[7]=21;
    fibSeq[8]=34;fibSeq[9]=55;fibSeq[10]=89;
    for (int i=0;i<11;i++) {
        float fn=float(fibSeq[i]);
        float angle=fn*GOLDEN_ANGLE+t*0.38, rad=sqrt(fn)*0.058;
        vec2  pos=vec2(cos(angle),sin(angle))*rad;
        float pulse=0.012+0.006*sin(t*3.0+fn*0.9);
        float dist=length(uv-pos);
        float prevA=fn*GOLDEN_ANGLE+(t-0.4)*0.38;
        vec2  prev=vec2(cos(prevA),sin(prevA))*rad;
        col = mix(col, cPink *1.6, exp(-dist*dist*280.0)*0.42);
        col = mix(col, cGreen*1.4, smoothstep(0.018,0.0,sdSeg(uv,pos,prev))*0.30);
        col = mix(col, cIce,       smoothstep(pulse,0.0,dist));
    }

    // ── 12. PINK COMET BEADS orbiting Babylonian rings ───
    //        Bead counts: 12, 8, 5 — all Fibonacci numbers
    //        Orbit speeds differ → create clock-hand effect
    float beads1 = pinkCometBeads(uv, 0.210, 12, iTime*0.42, 0.58);
    float beads2 = pinkCometBeads(uv, 0.460,  8, iTime*0.26, 0.48);
    float beads3 = pinkCometBeads(uv, 0.750,  5, iTime*0.15, 0.38);
    col  = mix(col, cPink*2.0, beads1*0.82);
    col  = mix(col, cPink*1.8, beads2*0.72);
    col  = mix(col, cPink*1.6, beads3*0.62);
    col += cPink * beads1 * 0.18;   // extra additive glow on inner ring
    col += cPink * beads2 * 0.12;

    // ── 13. Babylonian base-60 rings (rotating dials) ─────
    col = mix(col, cMint, clamp(babylonRing(uv,0.210, t*0.30),0.0,1.0)*0.65);
    col = mix(col, cCyan, clamp(babylonRing(uv,0.460,-t*0.18),0.0,1.0)*0.52);
    col = mix(col, cIce,  clamp(babylonRing(uv,0.750, t*0.10),0.0,1.0)*0.40);

    // ── 14. Twinkling sparkle field ───────────────────────
    //        Two layers: white stars + pink stars at different radii
    col += cIce  * sparkleField(uv,       iTime,    55, 0.82) * 0.38;
    col += cPink * sparkleField(uv*0.85,  iTime+7.0,30, 0.78) * 0.32;

    // ── 15. Shimmer spokes (21 Fibonacci) ─────────────────
    col = mix(col, cMint*1.3, clamp(rays(uv,21,t*0.08,0.007),0.0,1.0)*0.12);

    // ── 16. Center glow (static) ──────────────────────────
    col += cGreen * exp(-length(uv)*8.5) * 0.55;
    col += cCyan  * exp(-length(uv)*17.0) * 0.30;

    // ── 17. Vignette + ACES tone map + gamma ─────────────
    col *= 1.0 - smoothstep(0.52, 1.05, length(uv));
    col  = (col*(2.51*col+0.03)) / (col*(2.43*col+0.59)+0.14);
    col  = pow(max(col,vec3(0.0)), vec3(1.0/1.08));

    fragColor = vec4(col, 1.0);
}