Spiral Nebula Nocturne
GLSL shader by scry · created 2026-10-13 · 10s loop · 2 passes
Tags: 2d, Animation, Noise, Abstract, Layers, Symmetry
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)
float hash21(vec2 p){
p = fract(p*vec2(123.34,456.21));
p += dot(p,p+45.32);
return fract(p.x*p.y);
}
vec2 hash22(vec2 p){
float n = sin(dot(p, vec2(41.0,289.0)));
vec2 v = vec2(n*43758.5453, n*28001.8384);
return fract(v);
}
float noise(vec2 p){
vec2 i = floor(p);
vec2 f = fract(p);
float a = hash21(i);
float b = hash21(i+vec2(1.0,0.0));
float c = hash21(i+vec2(0.0,1.0));
float d = hash21(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;
}
float fbm(vec2 p){
float v = 0.0;
float amp = 0.5;
for(int i=0;i<3;i++){
v += amp*noise(p);
p *= 2.02;
amp *= 0.5;
}
return v;
}
vec3 starColor(float h){
if(h<0.15) return vec3(1.0,0.95,0.85);
else if(h<0.4) return vec3(1.0,0.55,0.2);
else if(h<0.55) return vec3(1.0,0.3,0.1);
else if(h<0.8) return vec3(0.4,0.7,1.0);
else if(h<0.9) return vec3(0.3,0.9,0.8);
return vec3(0.9,0.95,1.0);
}
float starShape(vec2 p, float size){
float d = length(p);
float core = size*0.03/(d+0.004);
core = core*core*0.15;
float spikeX = size*0.006/(abs(p.x)+0.002);
float spikeY = size*0.006/(abs(p.y)+0.002);
return core + (spikeX+spikeY)*0.4*size;
}
// animated, organic twinkle: layered sine flicker + rare bright flares
float twinkle(float h, float speed){
float base = 0.6 + 0.22*sin(iTime*speed + h*123.0) + 0.18*sin(iTime*speed*2.63 + h*57.0 + 1.3);
float flare = pow(max(sin(iTime*speed*0.37 + h*31.4),0.0), 10.0)*1.8;
return base + flare;
}
vec3 starLayer(vec2 p, float density, float seed, float twinkleSpeed, vec2 drift, float rotSpeed){
vec3 col = vec3(0.0);
p = r2d(iTime*rotSpeed)*p + drift;
vec2 guv = p*density;
vec2 gi = floor(guv);
for(int y=-1;y<=1;y++){
for(int x=-1;x<=1;x++){
vec2 cell = gi+vec2(float(x),float(y));
vec2 rnd = hash22(cell+seed);
vec2 starPos = cell+rnd;
vec2 cp = starPos-guv;
float h = hash21(cell+seed+1.7);
float sizeSel = pow(h,9.0);
float size = 0.3+2.2*sizeSel;
float tw = twinkle(h, twinkleSpeed);
vec3 c = starColor(hash21(cell+seed+3.3));
float br = starShape(cp, size)*tw;
col += c*br;
}
}
return col;
}
vec3 nebulaCore(vec2 p){
float r = length(p);
float a = atan(p.y,p.x);
float n = fbm(p*3.5 + vec2(time*0.12,-time*0.09));
float warp = n*0.9 - 0.45;
float spiral = a*2.0 + r*6.0 - time*0.5 + warp;
float arms = pow(max(sin(spiral*3.0),0.0), 3.0);
float arms2 = pow(max(sin(spiral*5.0+1.3),0.0),6.0);
float turb = 0.6+0.6*n;
float streak = (arms*0.6+arms2*0.8) * exp(-r*2.2) * turb;
float pulse = 1.0 + 0.12*sin(time*2.0);
float glowCore = (exp(-r*6.0)*1.5 + exp(-r*18.0)*2.0) * pulse;
vec3 colBase = mix(vec3(0.3,0.6,1.0), vec3(1.0,0.5,0.15), smoothstep(0.05,0.5,r));
vec3 result = colBase*streak;
result += vec3(0.6,0.8,1.0)*glowCore;
return result;
}
// rare shooting stars streaking across the frame
vec3 shootingStars(vec2 p, float t){
vec3 col = vec3(0.0);
for(int i=0;i<2;i++){
float period = 5.3+float(i)*2.7;
float seed = floor(t/period)+float(i)*17.0;
float r0 = hash21(vec2(seed,1.0+float(i)));
float r1 = hash21(vec2(seed,2.0+float(i)));
float r2 = hash21(vec2(seed,3.0+float(i)));
float t0 = mod(t, period);
float dur = 0.45+0.35*r2;
if(t0 > dur) continue;
vec2 start = vec2(mix(-0.9,0.9,r0), mix(0.25,0.95,r1));
vec2 dir = normalize(vec2(-1.0, -0.4-0.5*r2));
float prog = t0/dur;
vec2 pos = start + dir*prog*1.3;
vec2 d = p-pos;
float along = dot(d,dir);
vec2 perpVec = d-along*dir;
float perp = length(perpVec);
float fade = smoothstep(1.0,0.0,prog);
float trail = exp(-perp*220.0)*exp(-max(along,0.0)*7.0)*fade;
float head = exp(-length(d)*110.0)*fade;
col += vec3(1.0,0.95,0.85)*(trail*1.1+head*2.2);
}
return col;
}
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord/R;
vec2 p = uv-0.5;
p.x *= ar;
vec3 col = vec3(0.035,0.028,0.07);
vec2 coreDrift = vec2(sin(iTime*0.037), cos(iTime*0.029))*0.015;
vec2 corePos = p - vec2(0.02,-0.03) - coreDrift;
col += nebulaCore(corePos)*1.3;
vec2 drift = vec2(sin(iTime*0.05), cos(iTime*0.04))*0.01;
col += starLayer(p, 15.0, 0.0, 1.3, drift*1.0, 0.004)*1.2;
col += starLayer(p, 35.0, 5.0, 2.0, drift*1.7, 0.007)*0.65;
col += starLayer(p, 70.0, 11.0, 3.0, drift*2.4, 0.011)*0.38;
col += shootingStars(p, iTime);
float lum = dot(col, vec3(0.299,0.587,0.114));
vec2 dotUV = fract(fragCoord/3.0)-0.5;
float dotR = clamp(lum,0.05,0.9)*0.45;
float dmask = smoothstep(dotR, dotR-0.35, length(dotUV));
col = mix(col*0.35, col, dmask);
fragColor = vec4(col, 1.0);
}
Image
Not used
More shaders by scry
- Iridescent Ground Ritual
- Project_2026-08-15_18-22-06
- Project_2026-08-14_16-45-00
- Project_2026-07-24_15-10-23
- Project_2026-07-15_03-18-26
- Glass of Orange Juice (raymarched)
- Project_2026-07-13_00-53-50
- Project_2026-07-10_16-39-54
- Popcorn ceiling
- Project_2026-06-20_15-32-19
- Project_2026-06-25_12-22-43
- Visual Enhancer
Browse all public shaders · All shaders by scry · ShaderKit home
Unread comments
×Projects with new comments. Click to open and read.