import GLea from 'https://terabaud.github.io/glea/dist/glea.js'; // this is just for code highlighting in VSCode // via the glsl-literal extension const glsl = x => x; const frag = glsl` precision highp float; uniform float time; uniform float width; uniform float height; uniform sampler2D texture; const float PI = 3.141592654; const float DEG = PI / 180.0; const int ITERS = 10000; vec2 coords() { float vmin = min(width, height); return vec2((gl_FragCoord.x - width * .5) / vmin, (gl_FragCoord.y - height * .5) / vmin); } vec2 rotate(vec2 p, float a) { return vec2(p.x * cos(a) - p.y * sin(a), p.x * sin(a) + p.y * cos(a)); } vec2 repeat(in vec2 p, in vec2 c) { return mod(p, c) - 0.5 * c; } // Distance functions by Inigo Quilez // https://iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm float circle(in vec2 p, in vec2 pos, float radius) { return length((p - pos)) - radius; } float distanceField(vec2 p) { float d = 10000.0; for (int i = 0; i < 250; i++) { vec2 point = vec2(cos(float(i)) * float(i), sin(float(i)) * float(i)); d = min(d, circle(p, point, 3.0)); } return d; } // check if is prime, works for numbers 1 .. 900 bool isPrime(int n) { if (n <= 3) { return (n > 1) ? true : false; } if (mod(float(n), 2.0) == 0.0 || mod(float(n), 3.0) == 0.0) { return false; } int i = 5; for (int j = 0; j < 30; j++) { if (i * i > n) { return true; } if (mod(float(n), float(i)) == 0.0 || mod(float(n), float(i + 2)) == 0.0) { return false; } i += 6; } return false; } float primeDistanceField(vec2 p) { float d = 10000.0; for (int i = 0; i < 250; i++) { if (isPrime(i)) { vec2 point = vec2(cos(float(i)) * float(i), sin(float(i)) * float(i)); d = min(d, circle(p, point, 3.0)); } } return d; } vec3 shade(in vec2 p) { vec3 background = vec3(.1, .3, .7); vec3 foreground = vec3(.7, .3, .1); float sdf = distanceField(p); if (sdf < 0.0) { return foreground; } vec3 col = background; // Darken around surface col = mix(col, col*1.0-exp(-2.0 * abs(sdf)), 0.4); // repeating lines col *= 0.8 + 0.2*cos(1.25*sdf - time * .5); return col; } void main () { vec2 p0 = coords(); float zoom = 150.0 + sin(time * .05)*100.0; vec2 p1 = rotate(p0 * zoom, time * DEG); vec3 col = shade(p1); gl_FragColor = vec4(col, 1.0); } ` const vert = glsl` precision mediump float; attribute vec2 position; void main () { gl_Position = vec4(position, 0, 1.0); } ` let texture = null; const glea = new GLea({ shaders: [ GLea.fragmentShader(frag), GLea.vertexShader(vert) ], buffers: { 'position': GLea.buffer(2, [1, 1, -1, 1, 1,-1, -1,-1]) } }).create(); function loop(time) { const { gl } = glea; glea.clear(); glea.uni('width', glea.width); glea.uni('height', glea.height); glea.uni('time', time * .005); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); requestAnimationFrame(loop); } function setup() { const { gl } = glea; window.addEventListener('resize', () => { glea.resize(); }); loop(0); } setup();