Matrix
Seven parallax layers of falling-glyph streams over a slowly drifting camera. Each layer runs its own column grid, its own scroll speed, and its own palette offset; depth-fog dims the far ones. The glyphs are a 32-symbol procedural font built out of signed distance fields — bars, crosses, arcs, dots, a smiley, a dog, a heart, a music note, and a couple of random-grid patterns for filler.
Every stream is periodic: each column carries a (streamLen, gapLen)
pair, and the y-position is mod(cell.y + speed * time, period) — a
seamless tile, so the “infinite” scroll never seams.
[glsl]: shader source
// Multi-layer falling-glyph rain over a drifting camera. Seven parallax
// depths, each with its own column grid and palette offset.
// @slider tempo 0.1 3.0 1.0 0.05
uniform float tempo;
float hash(vec2 p){
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
}
// smooth stroke — 1 inside a signed distance w, fading to 0 outside
float strokeLine(float d, float w){
return 1.0 - smoothstep(w - 0.02, w + 0.03, d);
}
// procedural glyph: cellUV in [0,1], seed picks one of 32 shapes
float glyph(vec2 cellUV, float seed){
vec2 p = cellUV - 0.5;
float w = 0.065;
int tt = int(floor(fract(seed * 7.31) * 32.0));
float s = 0.0;
if(tt == 0){ // vertical bar
s = strokeLine(abs(p.x), w);
} else if(tt == 1){ // horizontal bar
s = strokeLine(abs(p.y), w);
} else if(tt == 2){ // plus
s = strokeLine(min(abs(p.x), abs(p.y)), w);
} else if(tt == 3){ // X cross
s = strokeLine(min(abs(p.x - p.y), abs(p.x + p.y)) * 0.7071, w);
} else if(tt == 4){ // circle
s = strokeLine(abs(length(p) - 0.28), w);
} else if(tt == 5){ // filled dot
s = 1.0 - smoothstep(0.15, 0.19, length(p));
} else if(tt == 6){ // square outline
float bx = max(abs(p.x), abs(p.y));
s = strokeLine(abs(bx - 0.28), w);
} else if(tt == 7){ // three horizontal bars
float d = min(min(abs(p.y - 0.22), abs(p.y)), abs(p.y + 0.22));
s = strokeLine(d, w * 0.55);
} else if(tt == 8){ // double vertical bars
s = strokeLine(min(abs(p.x - 0.14), abs(p.x + 0.14)), w);
} else if(tt == 9){ // diamond outline
float dd = abs(p.x) + abs(p.y);
s = strokeLine(abs(dd - 0.32), w);
} else if(tt == 10){ // asterisk (plus + X)
float d1 = min(abs(p.x), abs(p.y));
float d2 = min(abs(p.x - p.y), abs(p.x + p.y)) * 0.7071;
s = strokeLine(min(d1, d2), w * 0.75);
} else if(tt == 11){ // equals
float d = min(abs(p.y - 0.12), abs(p.y + 0.12));
s = strokeLine(d, w);
} else if(tt == 12){ // top arc
float cd = abs(length(p) - 0.3);
s = strokeLine(cd, w) * smoothstep(-0.05, 0.05, p.y);
} else if(tt == 13){ // L (bottom-left corner)
float vert = strokeLine(abs(p.x + 0.15), w) * step(0.0, p.y);
float horiz = strokeLine(abs(p.y), w) * step(-0.15, p.x);
s = max(vert, horiz);
} else if(tt == 14){ // reverse-L
float vert = strokeLine(abs(p.x - 0.15), w) * step(p.y, 0.0);
float horiz = strokeLine(abs(p.y), w) * step(p.x, 0.15);
s = max(vert, horiz);
} else if(tt == 15){ // smiley
float head = strokeLine(abs(length(p) - 0.35), w * 0.7);
float eyeL = 1.0 - smoothstep(0.03, 0.06, length(p - vec2(-0.12, 0.1)));
float eyeR = 1.0 - smoothstep(0.03, 0.06, length(p - vec2( 0.12, 0.1)));
float smile = strokeLine(abs(length(p - vec2(0.0, 0.04)) - 0.16), w * 0.5)
* step(p.y, 0.04);
s = max(head, max(max(eyeL, eyeR), smile));
} else if(tt == 16){ // dog face
float head = strokeLine(abs(length(p * vec2(1.0, 1.1)) - 0.24), w * 0.7);
float earL = 1.0 - smoothstep(0.06, 0.09, length(p - vec2(-0.2, 0.25)));
float earR = 1.0 - smoothstep(0.06, 0.09, length(p - vec2( 0.2, 0.25)));
float eyeL = 1.0 - smoothstep(0.02, 0.04, length(p - vec2(-0.09, 0.06)));
float eyeR = 1.0 - smoothstep(0.02, 0.04, length(p - vec2( 0.09, 0.06)));
float nose = 1.0 - smoothstep(0.03, 0.05, length(p - vec2( 0.0, -0.06)));
float tongue = strokeLine(abs(p.x), w * 0.4) * step(-0.22, p.y) * step(p.y, -0.13);
s = max(head, max(max(earL, earR), max(max(eyeL, eyeR), max(nose, tongue))));
} else if(tt == 17){ // heart (filled)
vec2 hp = (p + vec2(0.0, 0.35)) * 1.5;
hp.x = abs(hp.x);
float hd;
if(hp.y + hp.x > 1.0){
hd = length(hp - vec2(0.25, 0.75)) - 0.3536;
} else {
float a = length(hp - vec2(0.0, 1.0));
float b = length(hp - vec2(0.5 * max(hp.x + hp.y, 0.0)));
hd = min(a, b) * sign(hp.x - hp.y);
}
s = 1.0 - smoothstep(-0.02, 0.08, hd);
} else if(tt == 18){ // triangle up outline
vec2 tp = vec2(abs(p.x), p.y + 0.05);
float tri = max(-tp.y - 0.2, tp.x * 0.866 + tp.y * 0.5 - 0.22);
s = strokeLine(abs(tri), w);
} else if(tt == 19){ // triangle down outline
vec2 tp = vec2(abs(p.x), -p.y + 0.05);
float tri = max(-tp.y - 0.2, tp.x * 0.866 + tp.y * 0.5 - 0.22);
s = strokeLine(abs(tri), w);
} else if(tt == 20){ // arrow up
float stem = strokeLine(abs(p.x), w) * step(p.y, 0.15);
float chevron = strokeLine(abs(abs(p.x) + p.y - 0.35) * 0.707, w)
* step(0.12, p.y) * step(p.y, 0.4);
s = max(stem, chevron);
} else if(tt == 21){ // arrow right
float stem = strokeLine(abs(p.y), w) * step(p.x, 0.15);
float chevron = strokeLine(abs(abs(p.y) + p.x - 0.35) * 0.707, w)
* step(0.12, p.x) * step(p.x, 0.4);
s = max(stem, chevron);
} else if(tt == 22){ // music note
float nh = 1.0 - smoothstep(0.08, 0.12, length((p - vec2(-0.05, -0.2)) * vec2(1.0, 1.5)));
float stem = strokeLine(abs(p.x - 0.07), w * 0.6) * step(-0.2, p.y) * step(p.y, 0.3);
float flag = strokeLine(abs(length(p - vec2(0.18, 0.2)) - 0.14), w * 0.5)
* step(0.07, p.x) * step(0.12, p.y);
s = max(nh, max(stem, flag));
} else if(tt == 23){ // crescent moon
float outer = length(p) - 0.3;
float inner = length(p - vec2(0.13, 0.0)) - 0.26;
s = 1.0 - smoothstep(-0.02, 0.04, max(outer, -inner));
} else if(tt == 24){ // circle with plus
float circ = strokeLine(abs(length(p) - 0.28), w * 0.7);
float pl = strokeLine(min(abs(p.x), abs(p.y)), w * 0.5);
s = max(circ, pl);
} else if(tt == 25){ // square with cross
float bx = max(abs(p.x), abs(p.y));
float sq = strokeLine(abs(bx - 0.3), w * 0.7);
float cr = strokeLine(min(abs(p.x), abs(p.y)), w * 0.5) * step(bx, 0.33);
s = max(sq, cr);
} else if(tt == 26){ // T
float vert = strokeLine(abs(p.x), w) * step(p.y, 0.25);
float horiz = strokeLine(abs(p.y - 0.25), w);
s = max(vert, horiz);
} else if(tt == 27){ // Z
float topBar = strokeLine(abs(p.y - 0.25), w);
float botBar = strokeLine(abs(p.y + 0.25), w);
float diag = strokeLine(abs(p.x + p.y) * 0.707, w) * step(abs(p.y), 0.28);
s = max(max(topBar, botBar), diag);
} else if(tt == 28){ // sine wave
float wave = abs(p.y - 0.15 * sin(p.x * 10.0));
s = strokeLine(wave, w);
} else if(tt == 29){ // bottom arc
float cd = abs(length(p) - 0.3);
s = strokeLine(cd, w) * smoothstep(0.05, -0.05, p.y);
} else if(tt == 30){ // dense 4×6 hash grid
vec2 g = floor(cellUV * vec2(4.0, 6.0));
float on = step(0.4, hash(g + seed * 23.7));
vec2 f = fract(cellUV * vec2(4.0, 6.0));
float mask = smoothstep(0.0, 0.18, f.x) * smoothstep(1.0, 0.82, f.x)
* smoothstep(0.0, 0.18, f.y) * smoothstep(1.0, 0.82, f.y);
s = on * mask;
} else { // 3×5 katakana-ish
vec2 g = floor(cellUV * vec2(3.0, 5.0));
float on = step(0.45, hash(g + seed * 17.3));
vec2 f = fract(cellUV * vec2(3.0, 5.0));
float mask = smoothstep(0.0, 0.15, f.x) * smoothstep(1.0, 0.85, f.x)
* smoothstep(0.0, 0.15, f.y) * smoothstep(1.0, 0.85, f.y);
s = on * mask;
}
// margin so glyphs never touch cell walls
float margin = smoothstep(0.0, 0.08, cellUV.x) * smoothstep(1.0, 0.92, cellUV.x)
* smoothstep(0.0, 0.08, cellUV.y) * smoothstep(1.0, 0.92, cellUV.y);
return s * margin;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
float syncTime = iTime * tempo;
float beatPulse = exp(-fract(syncTime) * 4.0);
// cinematic camera drift + tiny rotation
float camX = syncTime * 15.0 + sin(syncTime * 0.2) * 60.0;
float camY = sin(syncTime * 0.15) * 30.0 + cos(syncTime * 0.1) * 20.0;
float angle = sin(syncTime * 0.09) * 0.04;
vec3 c1 = iAccent;
vec3 c2 = vec3(0.35, 0.75, 1.00);
vec3 c3 = vec3(1.00, 0.35, 0.55);
vec3 c4 = vec3(0.55, 0.25, 0.85);
vec3 totalColor = vec3(0.0);
for(int i = 0; i < 7; i++){
float fi = float(i);
float depth = 0.4 + fi * 0.45;
float invDepth = 1.0 / depth;
float fog = 1.0 / (1.0 + fi * 0.5);
// more columns (smaller glyphs) at farther depths
float cols = 14.0 + fi * 4.0;
float cellW = iResolution.x / cols;
float cellH = cellW * 1.6;
// parallax offset + per-layer rotation about screen center
vec2 offset = vec2(camX, camY) * invDepth;
float a = angle * invDepth;
vec2 centered = fragCoord - iResolution.xy * 0.5;
vec2 rotated = vec2(
centered.x * cos(a) - centered.y * sin(a),
centered.x * sin(a) + centered.y * cos(a));
vec2 fragPos = rotated + iResolution.xy * 0.5 + offset;
vec2 cell = vec2(floor(fragPos.x / cellW), floor(fragPos.y / cellH));
vec2 cellUV = vec2(fract(fragPos.x / cellW), fract(fragPos.y / cellH));
// per-column stream: length, gap, speed, phase — all hash-derived
float colSeed = hash(vec2(cell.x, fi * 73.13));
float speed = (1.5 + colSeed * 2.5) * tempo;
float phase = colSeed * 100.0;
float streamLen = 4.0 + colSeed * 8.0;
float gapLen = 14.0 + colSeed * 20.0;
float period = streamLen + gapLen;
// seamless tile: y-position wraps every (streamLen + gapLen)
float cyclePos = mod(cell.y + syncTime * speed + phase, period);
if(cyclePos >= streamLen) continue;
float dist = cyclePos;
// glyph flickers on a hashed clock
float charSeed = hash(cell + vec2(fi * 37.0, floor(syncTime * (2.0 + colSeed * 3.0) * tempo)));
float g = glyph(cellUV, charSeed);
// head white-hot, tail fades quadratically
float brightness;
if(dist < 1.0){
brightness = 1.0;
} else {
brightness = max(0.05, 1.0 - (dist - 1.0) / (streamLen - 1.0));
brightness *= brightness;
}
// palette per column, offset per layer
int colorIdx = int(mod(cell.x + fi, 4.0));
vec3 baseColor;
if(colorIdx == 0) baseColor = c1;
else if(colorIdx == 1) baseColor = c2;
else if(colorIdx == 2) baseColor = c3;
else baseColor = c4;
vec3 neon = baseColor * 1.5;
vec3 col = dist < 1.0 ? mix(neon, vec3(1.0), 0.7) : neon * brightness;
totalColor += col * g * fog;
}
// beat-ish brightness + filmic tone map
totalColor *= 1.0 + beatPulse * 0.15;
totalColor = 1.0 - exp(-totalColor * 1.5);
fragColor = vec4(totalColor, 1.0);
}