Skip to content

Instantly share code, notes, and snippets.

@AKST
Last active December 8, 2025 07:46
Show Gist options
  • Select an option

  • Save AKST/2b6a0bfda0917846955f9cf1c26f8f18 to your computer and use it in GitHub Desktop.

Select an option

Save AKST/2b6a0bfda0917846955f9cf1c26f8f18 to your computer and use it in GitHub Desktop.
const float DITHER_SCALE = 4.0;
const float TARGET_FPS = 30.0;
const float SCANLINE_FPS = 60.0;
const vec3 LUM_VECTOR = vec3(0.299, 0.587, 0.114);
const mat4 BAYER_MATRIX = mat4(
0.0/16.0, 8.0/16.0, 2.0/16.0, 10.0/16.0,
12.0/16.0, 4.0/16.0, 14.0/16.0, 6.0/16.0,
3.0/16.0, 11.0/16.0, 1.0/16.0, 9.0/16.0,
15.0/16.0, 7.0/16.0, 13.0/16.0, 5.0/16.0
);
vec2 square_coord(vec2 frag_coord) {
return floor(frag_coord / DITHER_SCALE) * DITHER_SCALE + DITHER_SCALE * 0.5;
}
/**
* This is based on this guys tweet, with some changes.
*
* https://x.com/XorDev/status/1995634971030196401
*/
vec3 colour_fn(vec2 coord, float time) {
vec2 p = coord * 6.0 / iResolution.y;
for (float i = 1.0; i <= 32.0; i++) {
p += sin(p.yx * i + i * i + time * i + iResolution.xy) / i;
}
vec4 fragColor = tanh(0.2 / tan(p.y + vec4(0.0, 0.1, 0.3, 0.0)));
return (fragColor * fragColor).xyz;
}
const vec3 DARK_BLUE = vec3(0.0, 0.0, 0.2);
const vec3 CYAN = vec3(0.0, 0.2, 0.8);
const vec3 YELLOW = vec3(1.0, 0.9, 0.0);
const vec3 WHITE = vec3(1.0, 1.0, 1.0);
vec3 gradient_map(float t) {
if (t < 0.33) {
return mix(DARK_BLUE, CYAN, t / 0.33);
} else if (t < 0.66) {
return mix(CYAN, YELLOW, (t - 0.33) / 0.33);
} else {
return mix(YELLOW, WHITE, (t - 0.66) / 0.34);
}
}
vec3 render_cell(vec2 coord, float time) {
float wave = sin(coord.y * 0.02 + time / 16.0) * 0.5 + 0.5;
vec2 coord_dist = vec2(coord.x + 200.0 * wave, coord.y);
vec3 col_base = colour_fn(square_coord(coord_dist), 2.0 * time);
ivec2 pixelPos = ivec2(coord / DITHER_SCALE) % 4;
float threshold = BAYER_MATRIX[pixelPos.x][pixelPos.y];
float lum = dot(col_base, LUM_VECTOR);
vec3 mapped_col = gradient_map(lum);
return step(threshold, mapped_col);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
float quantized_time = floor(iTime * TARGET_FPS) / TARGET_FPS;
float scanline_time = floor(iTime * SCANLINE_FPS) / SCANLINE_FPS;
float is_even_frame = mod(scanline_time, 2.0);
float a = mod(fragCoord.y, DITHER_SCALE * 2.0);
float b = DITHER_SCALE;
float refresh = mix(step(a, b), step(b, a), is_even_frame);
if (refresh == 1.0) {
float time_in_frame = fract(iTime * SCANLINE_FPS);
float decay = mix(0.5, 1.0, time_in_frame);
vec3 cell_base = render_cell(fragCoord, quantized_time);
fragColor = vec4(cell_base * time_in_frame, 1.0);
} else {
float time_in_frame = fract(iTime * SCANLINE_FPS);
float last_frame = (floor(iTime * TARGET_FPS) - 1.0) / TARGET_FPS;
vec3 cell_base = render_cell(fragCoord, last_frame);
vec2 coord_u = fragCoord - vec2(0.0, DITHER_SCALE);
vec2 coord_b = fragCoord + vec2(0.0, DITHER_SCALE);
vec3 col_u = render_cell(coord_u, quantized_time);
vec3 col_b = render_cell(coord_b, quantized_time);
vec3 col_bleed = mix(col_u, col_b, 0.5);
fragColor = vec4(mix(col_bleed * 0.9, cell_base * 0.75, 0.6 * (1.0 - time_in_frame)), 1.0);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment