await visibility(), bnbShader(`
uniform vec2 u_resolution;
uniform float u_frame;
uniform sampler2D u_framebuffer;
void main() {
vec2 uv = gl_FragCoord.xy / u_resolution;
vec2 pos = (gl_FragCoord.xy * 2. - u_resolution) / u_resolution.y;
vec3 color = vec3(0);
// initialize first frame
if(u_frame == 0.) {
color = vec3(step(.05, uv.x) * step(uv.x, .95) * step(.45, uv.y) * step(uv.y, .55));
color += vec3(step(.45, uv.x) * step(uv.x, .55) * step(.05, uv.y) * step(uv.y, .95));
}
else {
uv.y = 1. - uv.y;
float alive = texture2D(u_framebuffer, uv).r;
vec2 delta = vec2(1.) / u_resolution;
float sum = 0.;
for(float i = -1.; i <= 1.; i++) {
for(float j = -1.; j <= 1.; j++) {
if(i == 0. && j == 0.) continue;
sum += texture2D(u_framebuffer, uv + vec2(i, j) * delta).r;
}
}
if(alive == 1.) {
// Any live cell with fewer than two live neighbours dies, as if by underpopulation.
if(sum < 2.) color = vec3(0.);
// Any live cell with two or three live neighbours lives on to the next generation.
else if(sum <= 3.) color = vec3(1.);
// Any live cell with more than three live neighbours dies, as if by overpopulation.
else color = vec3(0.);
}
else {
// Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
if(sum == 3.) color = vec3(1.);
}
// can be resumed to:
// if(sum == 3. || (alive == 1. && sum == 2.)) color = vec3(1.);
}
gl_FragColor = vec4(color, 1);
}
`, {
w: 540, h: 540,
numFrames: 200,
record: true,
video: true,
chromaticAberration: .2,
})