OffscreenCanvas rAF+commit loop fetch image

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 = \`
  void main(){
    gl_Position = vec4(0, 0, 0, 1);
    gl_PointSize = 200.0;
  }
  \`;

  const fs = \`
  precision mediump float;
  uniform sampler2D tex;
  void main() {
    gl_FragColor = texture2D(tex, gl_PointCoord.xy);
  }
  \`;

  const p = createProgram(gl, [vs, fs]);
  gl.useProgram(p);

  const tex = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, tex);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([255, 0, 0, 255]));
  
  fetch('https://i.imgur.com/ZKMnXce.png', {mode:'cors'}).then(function(response) {
    if (!response.ok) {
      console.error(response);
    }
    return response.blob();
  }).then(function(blob) {
    return createImageBitmap(blob, {
      premultiplyAlpha: 'none',
      colorSpaceConversion: 'none',
    });
  }).then(function(bitmap) {
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, bitmap);
    gl.generateMipmap(gl.TEXTURE_2D);
  }).catch(function(e) {
    console.error(e);
  });

  function render(time) {
    time *= 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);
    
    gl.drawArrays(gl.POINTS, 0, 1);

    gl.commit();
    requestAnimationFrame(render);
  }
  requestAnimationFrame(render);

  function createShader(gl, type, src) {
    const s = gl.createShader(type);
    gl.shaderSource(s, src);
    gl.compileShader(s);
    if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {
      throw new Error(gl.getShaderInfoLog(s));
    }
    return s;
  }

 ...