Back to shaders

Shader test bench

20250225

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;
uniform float u_time;
uniform vec2 u_resolution;

#define fragColor gl_FragColor

// 2D rotation matrix helper
mat2 rotate(float angle) {
    float s = sin(angle);
    float c = cos(angle);
    return mat2(c, -s, s, c);
}

// Basic hash-based noise
float hash(vec2 p) {
    p = fract(p * vec2(5.3983, 5.4427));
    p += dot(p, p + 3.45);
    return fract(p.x * p.y);
}

// Simple noise function
float noise(vec2 p) {
    vec2 i = floor(p);
    vec2 f = fract(p);
    float a = hash(i);
    float b = hash(i + vec2(1.0, 0.0));
    float c = hash(i + vec2(0.0, 1.0));
    float d = hash(i + vec2(1.0, 1.0));
    vec2 u = f * f * (3.0 - 2.0 * f);
    return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
}

// Fractal Brownian Motion for nebula texture
float fbm(vec2 p) {
    float value = 0.0;
    float amplitude = 0.5;
    for (int i = 0; i < 5; i++) {
        value += amplitude * noise(p);
        p *= 2.0;
        amplitude *= 0.5;
    }
    return value;
}

void main() {
    // Normalize and center coordinates
    vec2 uv = (gl_FragCoord.xy - 0.5 * u_resolution) / u_resolution.y;
    
    // Add liquid, time-based distortion for dynamic motion
    uv += 0.015 * vec2(sin(uv.y * 10.0 + u_time * 2.0),
                        cos(uv.x * 10.0 + u_time * 2.0));
    
    // Compute distance from center and add a spiritual swirl
    float len = length(uv);
    float swirlAngle = 0.7 * len * sin(u_time * 0.5);
    uv = rotate(swirlAngle) * uv;
    len = length(uv);
    
    // Background: a radial gradient modulated with time
    float radial = smoothstep(0.9, 0.2, len + 0.1 * sin(u_time * 0.3));
    
    // Nebula texture from fractal noise for cosmic complexity
    float nebula = fbm(uv * 3.0 + u_time * 0.2) * 0.25;
    
    // Sacred geometry: a meditative flower pattern
    float sacred = 0.0;
    float numCircles = 12.0;
    for (float i = 0.0; i < numCircles; i++) {
        float angle = (i / numCircles) * 6.28318 + u_time * 0.25;
        vec2 offset = vec2(cos(angle), sin(angle)) * 0.4;
        offset += 0.02 * vec2(sin(u_time * 2.0 + i), cos(u_time * 2.0 - i));
        float d = length(uv - offset);
        sacred += smoothstep(0.025, 0.005, d);
    }
    float centralSacred = smoothstep(0.025, 0.005, len);
    sacred += centralSacred;
    
    // Luminous beams radiating from the center
    float ang = atan(uv.y, uv.x);
    float beams = smoothstep(0.0, 0.1, abs(sin(10.0 * ang - u_time)));
    
    // Animated ripples: expanding circular waves
    float ripple = sin(20.0 * (len - u_time * 0.5)) * 0.02;
    
    // Twinkling star-like sparkles using noise
    float sparkle = step(0.95, fract(sin(dot(uv * 50.0, vec2(12.9898, 78.233))) * 43758.5453 + u_time));
    sparkle *= 0.05;
    
    // Aurora overlay: a drifting color gradient based on UV and time
    float auroraFactor = smoothstep(0.3, 0.0, abs(uv.x + 0.2 * sin(u_time * 1.0)));
    vec3 auroraColor = mix(vec3(0.8, 0.5, 1.0), vec3(1.0, 0.7, 0.3), auroraFactor);
    
    // Spiritual color palette: mystical purples, pinks, blues, and gentle golds
    vec3 baseColor = vec3(0.4, 0.3, 0.6);
    baseColor = mix(baseColor, vec3(0.9, 0.6, 0.4), 0.3 + 0.3 * sin(u_time * 0.2));
    
    // Combine layers: geometry, nebula, beams, ripples, sparkles, and aurora
    vec3 color = baseColor * sacred * radial;
    color += vec3(1.0, 0.8, 0.5) * beams * 0.5;
    color += nebula;
    color += vec3(ripple);
    color += sparkle;
    color = mix(color, auroraColor, 0.3);
    
    // Add a subtle, expanding aura glow near the center
    float aura = 0.25 / (len + 0.1);
    color += vec3(aura * 0.8, aura * 0.7, aura * 1.0);
    
    // Overall pulsation to simulate a gentle, spiritual heartbeat
    color *= 1.0 + 0.1 * sin(u_time * 1.5);
    
    // Final boost: enhance vibrancy and luminance
    color = pow(color, vec3(1.3));
    color *= 1.8;
    
    fragColor = vec4(color, 1.0);
}