shader_type canvas_item; render_mode unshaded; uniform float elapsed = 0.0; float hash(vec2 p) { return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453); } float noise(vec2 p) { vec2 i = floor(p); vec2 f = fract(p); f = f * f * (3.0 - 2.0 * f); return mix(mix(hash(i), hash(i + vec2(1, 0)), f.x), mix(hash(i + vec2(0, 1)), hash(i + vec2(1, 1)), f.x), f.y); } float turbulence(vec2 p) { return noise(p) * 0.55 + noise(p * 2.07) * 0.28 + noise(p * 4.13) * 0.17; } void fragment() { vec2 p = (UV - 0.5) * 2.0; float r = length(p); float a = atan(p.y, p.x); float t = elapsed; float reveal = smoothstep(0.0, 1.2, t); float pulse = 1.0 + 0.012 * sin(t * 2.1); float radius = r / pulse; // Use circular coordinates for seamless turbulent filaments. float twist = a + 2.6 * log(max(radius, 0.035)) - t * 0.65; vec2 flow = vec2(cos(twist), sin(twist)); float clouds = turbulence(flow * 5.0 + vec2(radius * 13.0, -t * 0.3)); float filaments = pow(max(0.0, sin(twist * 7.0 + clouds * 5.0)), 5.0); float disc = exp(-pow((radius - 0.46) / 0.125, 2.0)); float rim_r = 0.432 + 0.008 * sin(a * 6.0 - t * 1.4) + (clouds - 0.5) * 0.017; float rim = exp(-abs(radius - rim_r) * 170.0); float bloom = exp(-abs(radius - rim_r) * 25.0); float halo = exp(-pow(radius / 0.66, 4.0)); vec3 cyan = vec3(0.16, 0.73, 1.0); vec3 violet = vec3(0.40, 0.15, 0.93); vec3 tint = mix(violet, cyan, 0.5 + 0.5 * sin(twist * 2.0 + t * 0.3)); vec3 color = tint * disc * (0.18 + clouds * 0.55 + filaments * 0.85); color += cyan * bloom * 0.3 + vec3(0.63, 0.92, 1.0) * rim * 1.5; color += violet * halo * 0.055; // A dark throat with contracting spiral bands suggests a deep tunnel. float inside = 1.0 - smoothstep(0.37, 0.425, radius); float depth = -log(max(radius / 0.425, 0.015)); float tunnel = pow(max(0.0, sin(depth * 16.0 - t * 3.3 + a * 2.0)), 12.0); float throat_fade = smoothstep(0.035, 0.3, radius); vec3 throat = vec3(0.003, 0.006, 0.026); throat += mix(violet, cyan, radius / 0.425) * tunnel * throat_fade * 0.22; throat += cyan * pow(max(0.0, sin(twist * 5.0 + clouds * 2.0)), 14.0) * throat_fade * 0.11; color = mix(color, throat, inside); // Orbiting pinpoints and their short luminous trails, outside the event horizon. float orbit_angle = a - t * 0.24; vec2 orbit = vec2(cos(orbit_angle), sin(orbit_angle)) * radius * 43.0; float sparks = pow(turbulence(orbit), 18.0) * 32.0; sparks *= smoothstep(0.45, 0.52, radius) * (1.0 - smoothstep(0.62, 0.86, radius)); color += vec3(0.56, 0.83, 1.0) * sparks; float alpha = max(inside, max(disc * (0.5 + clouds * 0.5), bloom * 0.8)); alpha = max(alpha, halo * 0.1 + sparks); alpha *= (1.0 - smoothstep(0.84, 0.98, radius)) * reveal; COLOR = vec4(color, clamp(alpha, 0.0, 1.0)); }