<canvas></canvas>
<script type="x-shader/vertex">
precision mediump float;
attribute vec2 position;

void main () {
  gl_Position = vec4(position, 0, 1.0);
}
</script>
<script type="x-shader/fragment">
precision highp float;
uniform float time;
uniform float width;
uniform float height;

const int ITERS = 120;
const float PI = 3.141592654;
const float DEG = PI / 180.0;

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;
}

int gpf(int num) {
  int result = 1;
  int limit = int(sqrt(float(num)));
  for (int i = 0; i < ITERS; i++) {
    int factor = (i == 0) ? 2 : (1 + i * 2); 
    if (factor > limit) {
      break;
    }
    for (int j = 0; j < ITERS; j++) {
      if (int(mod(float(num), float(factor))) != 0) {
        break;
      }
      num = int(num / factor);
      result = factor;
    }
    if (factor > num) {
      break;
    }
  }
  if (num > 1) {
    result = num;
  }
  return result;
}

vec2 complexMul(vec2 a, vec2 b) {
  return vec2(a.x * b.x - a.y * b.y, a.y * b.x + a.x * b.y);
}

vec2 complexPow(vec2 a, int n) {
  vec2 result = vec2(1.0, 0.0);
  for (int i = 0; i < ITERS; i++) {
    if (i == n) {
      break;
    }
    result = complexMul(result, a);
  }
  return result;
}

// exponential generating function EG(gpf; z) = Σn=1∞ gpf(n) z^n / (n+1)!
vec2 exponential(vec2 p) {
  vec2 x = vec2(0.0, 0.0);
  int j = 1;
  for (int i = 0; i < 13; i++) {
    j = j * (i + 2);
    x = x + float(gpf(i + 1)) * complexPow(p * 8.0, int(i + 1)) / float(j);
  }
  return x;
}

vec3 palette(float x) {
  return vec3(.5 + .5 * sin(time * .1+ x * 4.0), sin(time * .2 + x), sin(time *.1 + x + 1.0));
}
  
  
void main () {
  vec2 p00 = coords();
  vec2 p0 = rotate(p00, time *.05);
  vec2 exp = exponential(p0 * .3)*.1;
  vec2 logExp = log(exp);
  vec3 col = palette(
     .5 * sin(log(pow(length(exp), 3.0 + 
                      1.0 * sin(time *.1))) + atan(exp.y, exp.x) + time*.2));
  gl_FragColor = vec4(col, 1.0);
}  
</script>
body {
  margin: 0;
}

canvas {
  display: block;
  width: 100vw;
  height: 100vh;
}
import GLea from 'https://terabaud.github.io/hello-webgl/lib/glea/glea.mjs';

const frag = document.querySelector('[type="x-shader/fragment"]').textContent;
const vert = document.querySelector('[type="x-shader/vertex"]').textContent;
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();

window.addEventListener('resize', () => {
  glea.resize();
});

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);
}

loop(0);

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.