#version 300 es
precision highp float;

uniform vec2 u_resolution;
uniform float u_time;
uniform vec2 u_pointer;   // 0–1, eased; drifts by itself while nobody is pointing
uniform vec3 u_click;     // xy = last press (0–1), z = seconds since that press
uniform float u_seed;
out vec4 outColor;

// Integer hash: a given seed renders the same work on every GPU.
uint hashu(uint x) {
    x ^= x >> 16; x *= 0x7feb352dU;
    x ^= x >> 15; x *= 0x846ca68bU;
    x ^= x >> 16;
    return x;
}

float seeded(uint k) {
    return float(hashu(uint(u_seed) * 0x9e3779b9U + k)) / 4294967295.0;
}

vec2 toField(vec2 q) {
    return (2.0 * q - 1.0) * u_resolution / min(u_resolution.x, u_resolution.y);
}

float dither(vec2 p) {
    return (fract(52.9829189 * fract(dot(p, vec2(0.06711056, 0.00583715)))) - 0.5) / 255.0;
}

void main() {
    vec2 uv = toField(gl_FragCoord.xy / u_resolution.xy);
    vec2 pointer = toField(u_pointer);
    // The aperture leans toward the pointer and opens as it rises.
    vec2 q = uv - 0.12 * pointer;
    float folds = 4.0 + floor(seeded(1u) * 6.0);
    float rayCount = 12.0 + 2.0 * floor(seeded(2u) * 7.0);
    float spiral = 2.0 + 1.4 * seeded(3u);
    float spin = seeded(4u) < 0.5 ? -0.055 : 0.055;

    float radius = length(q) + 0.0001;
    float angle = atan(q.y, q.x) + u_time * spin;
    float crease = abs(sin(angle * folds + log(radius) * spiral));
    float opening = 0.54 + 0.1 * (u_pointer.y - 0.5);
    float aperture = abs(radius - opening - 0.16 * crease);
    float rim = 1.0 - smoothstep(0.018, 0.09, aperture);
    float rays = pow(0.5 + 0.5 * cos(angle * rayCount - radius * 14.0), 7.0);
    float flare = 1.0 + 2.2 * exp(-2.5 * u_click.z);
    float halo = exp(-3.2 * radius / flare) * (0.55 + 0.45 * crease);

    int pick = int(floor(seeded(5u) * 3.0));
    vec3 shade = vec3(0.10, 0.025, 0.16), ember = vec3(0.92, 0.24, 0.06), cream = vec3(1.0, 0.83, 0.54);
    if (pick == 1) { shade = vec3(0.01, 0.07, 0.09); ember = vec3(0.86, 0.58, 0.12); cream = vec3(0.98, 0.95, 0.80); }
    if (pick == 2) { shade = vec3(0.04, 0.03, 0.08); ember = vec3(0.86, 0.22, 0.38); cream = vec3(0.96, 0.88, 0.92); }

    vec3 color = mix(shade, ember, min(1.0, halo + rays * 0.3));
    color = mix(color, cream, rim * (0.55 + 0.45 * rays));
    color *= 1.0 - 0.45 * smoothstep(0.85, 1.55, length(uv));
    outColor = vec4(color + dither(gl_FragCoord.xy), 1.0);
}
