Back to shaders
Shader test bench
20250813
runnable fragment
Complete GLSL fragment shader. Stronghold runs it directly when the browser can compile it.
Code
precision mediump float;
// ✴︎ MONO MANDALA QUASICRYSTAL — v2 (ultra clean B/W) ✴︎
uniform float u_time;
uniform vec2 u_resolution;
#define fragColor gl_FragColor
const float PI = 3.14159265359;
const float TAU = 6.28318530718;
const float PHI = 1.61803398875;
// ---------- utils
mat2 rotate2D(float a){ float s=sin(a), c=cos(a); return mat2(c,-s,s,c); }
float hash21(vec2 p){
p = fract(p*vec2(123.34, 345.45));
p += dot(p, p+34.345);
return fract(p.x*p.y);
}
float noise(vec2 x){
vec2 i = floor(x), f = fract(x);
f = f*f*(3.0-2.0*f);
float a = hash21(i);
float b = hash21(i+vec2(1,0));
float c = hash21(i+vec2(0,1));
float d = hash21(i+vec2(1,1));
return mix(mix(a,b,f.x), mix(c,d,f.x), f.y);
}
float fbm(vec2 x){
float v = 0.0, a = 0.5;
for(int i=0;i<4;i++){ v += a*noise(x); x*=2.0; a*=0.5; }
return v;
}
// from your sample
vec2 sacredGrid(vec2 p){
vec2 q = vec2(p.x*2.0, p.y*1.73205);
vec2 r = vec2(q.x+q.y, q.y-q.x)*0.5;
return fract(r)-0.5;
}
float mandala(vec2 p, float segments){
float ang = atan(p.y,p.x), rad = length(p);
return abs(cos(ang*segments)*0.5+0.5)*smoothstep(0.35,0.0,rad);
}
float smoothBreath(float t){ return 0.5 + 0.5*sin(t); }
float stars(vec2 uv, float time){
vec2 g = fract(uv*80.0);
float d = length(g-0.5);
float tw = sin(dot(uv*120.0, vec2(12.9898,78.233))+time*6.0)*0.5+0.5;
return smoothstep(0.03,0.005,d)*tw;
}
// kaleidoscope fold
vec2 kaleid(vec2 p, float seg){
float a = atan(p.y,p.x), r=length(p), w = TAU/seg;
a = mod(a, w); a = abs(a - w*0.5);
return vec2(cos(a), sin(a))*r;
}
// AA line helper
float lineAA(float d, float w){ return smoothstep(w, 0.0, abs(d)); }
// 5-fold quasicrystal
float quasicrystal(vec2 p, float t){
float s=0.0, rot=0.22*sin(t*0.3);
for(int i=0;i<5;i++){
float a = float(i)*PI/5.0 + rot;
s += cos(dot(p, vec2(cos(a),sin(a)))*14.0);
}
return s/5.0; // [-1,1]
}
// rose-curve (rosette) field around a target radius
float roseField(float r, float theta, float k, float target){
// r ≈ cos(k*θ) style petals remapped to line distance
float ro = abs(cos(theta*k));
float d = (r - ro*target);
return lineAA(d, 0.06);
}
void main(){
// -------- coords & gentle camera
vec2 fc = gl_FragCoord.xy;
vec2 uv = fc / u_resolution;
vec2 asp = vec2(u_resolution.x/u_resolution.y, 1.0);
vec2 p = (uv - 0.5) * asp * 2.0;
float t = u_time;
float camBob = sin(t*0.3)*0.05;
float camZoom = 1.0 + sin(t*0.2)*0.10;
p.y += camBob;
p = rotate2D(t*0.05)*p;
p *= camZoom;
// -------- symmetry & subtle lens warp
float seg = mix(10.0, 16.0, 0.5+0.5*sin(t*0.15)); // breathe segment count
vec2 pk = kaleid(p, seg);
// soft radial “lens” warp for silky flow
float r0 = length(pk);
float lens = 1.0 + 0.12*sin(r0*4.0 - t*0.7);
pk *= lens;
// micro displacement for living surface
vec2 warp = 0.06*vec2(fbm(pk*3.0+t*0.15), fbm(pk*3.0-t*0.12));
pk += warp;
float r = length(pk);
float th = atan(pk.y, pk.x);
// -------- core line fields (grayscale components)
// crisp concentric rings
float rings = lineAA(sin(r*40.0 - t*1.6), 0.05);
// petal spokes with falloff
float spokes = lineAA(sin(th*seg + t*0.6), 0.10) * smoothstep(1.2, 0.0, r);
// rosette around mid-radius
float rose = roseField(r, th, floor(seg*0.5), 0.75);
// quasicrystal shards
float qc = quasicrystal(pk, t);
float shards= lineAA(qc, 0.11);
// sacred hex edges
float hexEdge = lineAA(length(sacredGrid(pk*3.2)), 0.16);
// mandala mask (soft add)
float mand = mandala(pk, seg);
// -------- composition (luminance)
float L = 0.0;
L += rings * 0.55;
L += spokes * 0.35;
L += rose * 0.45;
L += shards * 0.40;
L += hexEdge * 0.22;
L += mand * 0.35;
// center bloom & breathing
float bloom = exp(-r*1.25)*5.0 + smoothstep(0.25, 0.0, r)*0.5;
float breath = smoothBreath(t*0.8)*0.5 + 0.5;
L *= bloom * breath;
// delicate star sparkle (keep subtle)
L += stars((p+1.0)*0.5, t) * 0.18;
// scanline shimmer
L *= (1.0 - 0.06 * sin(fc.y*3.0 + t*12.0));
// vignette
float vignette = smoothstep(1.55, 0.32, r);
L *= vignette;
// soft bloom lift on highlights
float soft = smoothstep(0.55, 0.95, L);
L += soft*0.28;
// subpixel dual-sample (cheap AA): average two tiny offsets
vec2 j = vec2(0.5, -0.5) / u_resolution.y;
float L2= 0.0;
{
vec2 pk2 = kaleid((p+j)*lens, seg);
pk2 += 0.06*vec2(fbm(pk2*3.0+t*0.15), fbm(pk2*3.0-t*0.12));
float r2=length(pk2), th2=atan(pk2.y,pk2.x);
float rings2 = lineAA(sin(r2*40.0 - t*1.6), 0.05);
float spokes2= lineAA(sin(th2*seg + t*0.6), 0.10)*smoothstep(1.2,0.0,r2);
float rose2 = roseField(r2, th2, floor(seg*0.5), 0.75);
float shards2= lineAA(quasicrystal(pk2,t), 0.11);
float hex2 = lineAA(length(sacredGrid(pk2*3.2)), 0.16);
float mand2 = mandala(pk2, seg);
float Ls = rings2*0.55 + spokes2*0.35 + rose2*0.45 + shards2*0.40 + hex2*0.22 + mand2*0.35;
float bloom2 = exp(-r2*1.25)*5.0 + smoothstep(0.25,0.0,r2)*0.5;
L2 = Ls*bloom2*breath;
}
L = mix(L, L2, 0.5);
// paper grain (true mono)
float grain = (hash21(fc + t*60.0) - 0.5)*0.06;
L += grain;
// tone curve for creamy whites / deep blacks
float exposure = 2.3;
float mono = 1.0 - exp(-max(L,0.0)*exposure);
mono = pow(clamp(mono, 0.0, 1.0), 1.0/1.7);
fragColor = vec4(vec3(mono), 1.0);
}