HTML
<canvas></canvas>
<script id="vertexShader" type="x-shader/x-vertex">
attribute vec2 aPosition;
uniform vec2 uResolution;
void main() {
gl_Position = vec4(((aPosition / uResolution * 2.0) - 1.0) * vec2(1, -1), 0, 1);
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
precision highp float;
uniform vec2 uResolution;
uniform vec3 ue;
uniform vec2 ucs;
void main() {
const float Z = 3.0;
const float IZ = 1.0 / Z;
vec2 uv = (gl_FragCoord.xy - 0.5 * uResolution.xy) / min(uResolution.y, uResolution.x);
float rx = 1.0;
float ry = uv.x;
float rz = uv.y;
float d = 1.0;
float ex = ue.x;
float ey = ue.y;
float ez = ue.z;
float tx = ex;
float ty = ey;
float tz = ez;
float cn = ucs.x;
float sn = ucs.y;
float gx = cn * rx + sn * rz;
float gy = ry;
float gz = cn * rz - sn * rx;
rx = gx;
ry = gz;
rz = gy;
gx = cn * rx + sn * rz;
gy = ry;
gz = cn * rz - sn * rx;
rx = gx;
ry = gz;
rz = gy;
float irx = 1.0 / rx;
float iry = 1.0 / ry;
float irz = 1.0 / rz;
for (int i = 20; i > 0 ;i--) {
if (d < 0.0125) break;
d *= IZ;
tx = fract(tx) * Z;
ty = fract(ty) * Z;
tz = fract(tz);
tz = (tz < 0.0) ? (1.0 + tz) : tz;
tz *= Z;
float ix = floor(tx);
float iy = floor(ty);
float iz = floor(tz);
float j = mod(ix * ix + iy * iy + iz * iz, 4.0);
if (j >= 2.0) {
float fx = (rx > 0.0) ? 1.0 : 0.0;
float fy = (ry > 0.0) ? 1.0 : 0.0;
float fz = (rz > 0.0) ? 1.0 : 0.0;
tx = (fx - fract(tx)) * irx;
ty = (fy - fract(ty)) * iry;
tz = (fz - fract(tz)) * irz;
float n = tx;
n = (ty < n) ? ty : n;
n = (tz < n) ? tz : n;
ex += rx * (n * d + 0.001);
ey += ry * (n * d + 0.001);
ez += rz * (n * d + 0.001);
tx = ex;
ty = ey;
tz = ez;
d = 1.0;
}
}
ex -= ue.x;
ey -= ue.y;
ez -= ue.z;
float c = ex*ex + ey*ey + ez*ez;
gl_FragColor = vec4(0.3 * sn * uv.x + c * 0.75, c * 0.5, c * 0.25, 1.0);
}
</script>
CSS
body,
html {
position: absolute;
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
background: #000;
user-select: none;
}
canvas {
position: absolute;
width: 100%;
height: 100%;
user-select: none;
touch-action: none;
content-zooming: none;
background: #000;
}
JAVASCRIPT
// Menger Sponge
// ported to GSLS from http://wa.zozuar.org/code.php?c=x23O
"use strict";
{
const canvas = document.querySelector("canvas");
let gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, document.getElementById("vertexShader").text);
gl.compileShader(vertexShader);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, document.getElementById("fragmentShader").text);
gl.compileShader(fragmentShader);
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
const uResolution = gl.getUniformLocation(program, "uResolution");
const ue = gl.getUniformLocation(program, "ue");
const ucs = gl.getUniformLocation(program, "ucs");
const aPosition = gl.getAttribLocation(program, "aPosition");
const buffer = gl.createBuffer();
const resize = () => {
const WIDTH = (canvas.width = canvas.offsetWidth);
const HEIGHT = (canvas.height = canvas.offsetHeight);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.enableVertexAttribArray(aPosition);
gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([
0,
0,
WIDTH,
0,
0,
HEIGHT,
0,
HEIGHT,
WIDTH,
0,
WIDTH,
HEIGHT
]),
gl.STATIC_DRAW
);
gl.uniform2f(uResolution, WIDTH, HEIGHT);
gl.viewport(0, 0, WIDTH, HEIGHT);
};
window.addEventListener("resize", _ => resize(), false);
resize();
////////////////////////////////////////////////////////
let time = 10;
const update = () => {
requestAnimationFrame(update);
time += 0.01;
gl.uniform2f(ucs, Math.cos(time * 0.1), Math.sin(time * 0.1));
gl.uniform3f(
ue,
0.5 + Math.sin(time * 0.5) * 0.1,
0.5 + Math.cos(time * 0.47) * 0.1,
-time * 0.3 + Math.sin(time * 0.3 - 0.01)
);
gl.drawArrays(gl.TRIANGLES, 0, 6);
};
update();
}