// geocities.glsl — a tribute to the golden age of blinking, tiled, // under-construction personal homepages. Caution-stripe wallpaper, // a rainbow sparkle field with hard blink (not a gentle twinkle), // a scrolling pixel-font "UNDER CONSTRUCTION" marquee, and a bouncing // rotating star badge, DVD-logo style. // transparent background const bool transparent = true; // terminal contents luminance threshold to be considered background (0.0 to 1.0) const float threshold = 0.02; // show/hide individual gimmicks const bool showStripes = true; const bool showSparkles = true; const bool showMarquee = true; const bool showBadge = true; // caution-stripe wallpaper opacity (0.0 to 1.0) const float stripeOpacity = 0.02; // sparkle field brightness const float sparkleIntensity = 0.1; // marquee scroll speed, in pixels per second const float scrollSpeed = 90.0; // --------------------------------------------------------------- // helpers // --------------------------------------------------------------- float luminance(vec3 color) { return dot(color, vec3(0.2126, 0.7152, 0.0722)); } vec3 hsv2rgb(vec3 c) { vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); } float hash21(vec2 p) { p = fract(p * vec2(233.34, 851.73)); p += dot(p, p + 23.45); return fract(p.x * p.y); } // 0 -> 1 -> 0 triangle wave, used to ping-pong the bouncing badge float triangleWave(float x, float period) { float t = fract(x / period); return 1.0 - abs(2.0 * t - 1.0); } // --------------------------------------------------------------- // tiny 5x7 pixel font, just enough glyphs to spell "UNDER CONSTRUCTION" // each row is packed as a 5-bit value, bit weight 16 = leftmost column // --------------------------------------------------------------- const int FONT_ROWS = 7; const int FONT[77] = int[77]( 0, 0, 0, 0, 0, 0, 0, // 0: space 17, 17, 17, 17, 17, 17, 14, // 1: U 17, 25, 21, 21, 19, 17, 17, // 2: N 30, 17, 17, 17, 17, 17, 30, // 3: D 31, 16, 16, 30, 16, 16, 31, // 4: E 30, 17, 17, 30, 20, 18, 17, // 5: R 15, 16, 16, 16, 16, 16, 15, // 6: C 14, 17, 17, 17, 17, 17, 14, // 7: O 15, 16, 16, 14, 1, 1, 30, // 8: S 31, 4, 4, 4, 4, 4, 4, // 9: T 31, 4, 4, 4, 4, 4, 31 // 10: I ); // "UNDER CONSTRUCTION" as indices into the glyph table above const int MSG_LEN = 18; const int MSG[18] = int[18](1, 2, 3, 4, 5, 0, 6, 7, 2, 8, 9, 5, 1, 6, 9, 10, 7, 2); float fontBit(int code, int row, int col) { int rowVal = FONT[code * FONT_ROWS + row]; float shifted = floor(float(rowVal) / pow(2.0, float(4 - col))); return mod(shifted, 2.0); } // --------------------------------------------------------------- // background gimmicks // --------------------------------------------------------------- vec3 hazardStripes(vec2 fragCoord) { float stripeWidth = 18.0; float diag = (fragCoord.x + fragCoord.y) + iTime * 40.0; float m = mod(diag, stripeWidth * 2.0); vec3 yellow = vec3(1.0, 0.82, 0.0); vec3 blk = vec3(0.05); return m < stripeWidth ? yellow : blk; } vec3 sparkleStars(vec2 uv, vec2 resolution) { vec2 gridUV = uv; gridUV.x *= resolution.x / resolution.y; gridUV *= 26.0; vec2 ipos = floor(gridUV); vec2 fpos = fract(gridUV); // only a fraction of cells host a star float rnd = hash21(ipos); if (rnd > 0.12) return vec3(0.0); vec2 center = vec2(hash21(ipos + 3.1), hash21(ipos + 7.7)); float d = length(fpos - center); // hard on/off blink rather than a smooth twinkle, tacky on purpose float phase = hash21(ipos + 11.0) * 10.0; float blink = step(0.5, fract(iTime * (1.5 + rnd * 4.0) + phase)); float glow = smoothstep(0.12, 0.0, d); vec3 hue = hsv2rgb(vec3(fract(rnd * 4.0 + iTime * 0.1), 1.0, 1.0)); return hue * glow * blink; } vec3 starBadge(vec2 fragCoord, vec2 resolution) { float radius = 26.0; float px = mix(radius, resolution.x - radius, triangleWave(iTime * 0.09, 1.0)); float py = mix(radius, resolution.y - radius, triangleWave(iTime * 0.13 + 0.37, 1.0)); vec2 p = fragCoord - vec2(px, py); float d = length(p); float a = atan(p.y, p.x) - iTime * 2.0; float starR = radius * (0.55 + 0.45 * cos(a * 5.0)); float shape = smoothstep(1.5, -1.5, d - starR); vec3 hue = hsv2rgb(vec3(fract(iTime * 0.3), 1.0, 1.0)); return hue * shape; } // returns rgb + coverage alpha for the scrolling marquee ticker vec4 marquee(vec2 fragCoord, vec2 resolution) { float scale = clamp(resolution.y / 220.0, 2.0, 6.0); float charW = 6.0 * scale; // 5 columns + 1 spacing column float charH = 8.0 * scale; // 7 rows + 1 spacing row int gap = 6; // blank characters between loops of the message int totalChars = MSG_LEN + gap; // band hugs the bottom edge of the terminal float bandY0 = resolution.y - charH - scale * 2.0; float localY = fragCoord.y - bandY0; if (localY < 0.0 || localY >= charH) return vec4(0.0); int row = int(floor(localY / scale)); if (row >= FONT_ROWS) return vec4(0.0); float scrollX = fragCoord.x + iTime * scrollSpeed; float totalWidth = float(totalChars) * charW; float wrapped = mod(scrollX, totalWidth); int charIndex = int(floor(wrapped / charW)); if (charIndex >= MSG_LEN) return vec4(0.0); // in the gap, blank float localX = mod(wrapped, charW); int col = int(floor(localX / scale)); if (col >= 5) return vec4(0.0); int code = MSG[charIndex]; if (fontBit(code, row, col) < 0.5) return vec4(0.0); vec3 color = hsv2rgb(vec3(fract(float(charIndex) / float(MSG_LEN) + iTime * 0.15), 1.0, 1.0)); return vec4(color, 1.0); } // --------------------------------------------------------------- // main // --------------------------------------------------------------- void mainImage(out vec4 fragColor, in vec2 fragCoord) { vec2 uv = fragCoord / iResolution.xy; vec4 terminalColor = texture(iChannel0, uv); vec3 deco = vec3(0.0); if (showStripes) { deco += hazardStripes(fragCoord) * stripeOpacity; } if (showSparkles) { deco += sparkleStars(uv, iResolution.xy) * sparkleIntensity; } if (showBadge) { deco = max(deco, starBadge(fragCoord, iResolution.xy)); } if (showMarquee) { vec4 marq = marquee(fragCoord, iResolution.xy); deco = mix(deco, marq.rgb, marq.a); } if (transparent) { deco += terminalColor.rgb; } // only show the effect where the terminal is background (not text) float mask = 1.0 - step(threshold, luminance(terminalColor.rgb)); vec3 blended = mix(terminalColor.rgb, deco, mask); fragColor = vec4(blended, terminalColor.a); }