OffscreenCanvas 15fps

by Gregg Tavares

HTML

<canvas></canvas>

<div id="no-offscreencanvas" style="display: none;">
  <div>Sorry but your browser doesn't appear to support OffscreenCanvas</div>
</div>

CSS

body { margin: 0; }
canvas { width: 100vw; height: 100vh; }

#no-webgl, #no-offscreencanvas {
  position: absolute;
  left: 0;
  top: 0;
  background: red;
  color: white;
  width: 100vw;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}

JavaScript

const wsrc = `
const appInfo = {
  clientWidth: 300,
  clientHeight: 150,
};

function main(gl) {
  const vs = \`
  attribute vec4 position;
  uniform mat4 matrix;
  void main(){
    gl_Position = matrix * position;
  }
  \`;

  const fs = \`
  precision mediump float;
  uniform vec4 color;
  void main() {
    gl_FragColor = color;
  }
  \`;

  const p = createProgram(gl, [vs, fs]);
  gl.useProgram(p);
  const posLoc = gl.getAttribLocation(p, "position");
  const matLoc = gl.getUniformLocation(p, "matrix");
  const colorLoc = gl.getUniformLocation(p, "color");

  const b = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, b);
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
    -1, -1,  1, -1,
     1,  1, -1,  1,
  ]), gl.STATIC_DRAW);

  gl.enableVertexAttribArray(posLoc);
  gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);

  function render() {
    time = performance.now() * 0.001;
    
    const clientWidth = appInfo.clientWidth;
    const clientHeight = appInfo.clientHeight;

    // Make the canvas match its display size
    if (gl.canvas.width !== clientWidth || gl.canvas.height !== clientHeight) {
      gl.canvas.width = clientWidth;
      gl.canvas.height = clientHeight;
    }

    gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
    
    gl.clearColor(0, 0, time % 1, 1);
    gl.clear(gl.COLOR_BUFFER_BIT);
    
    const aspect = clientWidth / clientHeight;
    gl.uniformMatrix4fv(matLoc, false, [
      .5 / aspect, 0, 0, 0,
      0, .5, 0, 0,
      0, 0, 1, 0,
      0, 0, 0, 1,
    ]);
    gl.uniform4f(colorLoc, 1, time % 1, 0, 1);
    gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
  }
  
  let then = -1000;
  function loop(time) {
    time *= 0.001;
    const elapsed = time - then;
    if (elapsed > 1 / 15) {
      then = time;
      render();
      gl.commit();
    }
    requestAnimationFrame(loop);
  }
  requestAnimationFrame(loop);

  function createShader(gl, type, src) {
    const s = gl.createShader(type);
    gl.shaderSource(s, src);
   ...