<main>
  <video id="video" playsinline></video>
  <button id="access">Access Camera</button>
  <canvas id="canvas"></canvas>
  <div id="buttons">
  <button data-shader="gl_FragColor = vec4(color, 1.0);">Default</button>
  <button data-shader="gl_FragColor = vec4(color * vec3(0.9, 0.0, 1.0), 1.0);">Purple</button>
  <button data-shader="gl_FragColor = vec4(color * vec3(1.5, 1.5, 0.0), 1.0);">Yellow</button>
  <button data-shader="color = smoothstep(vec3(0.2), vec3(0.8), color); gl_FragColor = vec4(color, 1.0);">High Contrast</button>
  <button data-shader="gl_FragColor = vec4(vec3(1.0) - color, 1.0);">Invert</button>
  <button data-shader="color += vec3(sin(4.5 * u_time), sin(3.1 * u_time + 1.0), sin(2.7 * u_time)); gl_FragColor = vec4(color, 1.0);">Rave</button>
</div>
</main>
main {
  align-items: center;
  display: flex;
  height: 100vh;
  justify-content: center;
  width: 100vw;
}

#canvas,
#video,
#buttons { 
  display: none; 
}

button {
  color: #558;
  cursor: pointer;
  border: 0.3em solid #558;
  font-weight: bold;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 0.35em 1em;
  transition: 0.2s;
}

button:hover,
button:active {
  background: #558;
  box-shadow: 0 0 3px #000;
  color: #fff;
}

#canvas,
#buttons {
  float: left;
}

#buttons {
  max-width: 400px;
}

#buttons button {
  display: block;
  margin: 10px 0 0 10px;
  text-align: center;
  width: 200px;
}

#access {
  display: block;
  font-size: 1.5em;
}

canvas {
  height: auto;
  max-width: 400px;
}
const video = document.getElementById('video');
const buffer = document.createElement('canvas');
const canvas = document.getElementById('canvas');
let glslCanvas;

let fragColor = `gl_FragColor = vec4(color, 1.0);`;

function init() {
  window.navigator.mediaDevices.getUserMedia({
    audio: false,
    video: {
      facing: 'user'
    }
  })
  .then(setup)
  .catch((err) => console.log('There was an error 😱', err));
}

function setup(stream) {
  
  canvas.style.display = 'block';
  document.getElementById('access').style.display = 'none';
  document.getElementById('buttons').style.display = 'block';
  
  video.srcObject = stream;
  video.play();
    
  window.devicePixelRatio = 1;
  update();
}

function render() {

  buffer.width = video.videoWidth;
  buffer.height = video.videoHeight;
  buffer.getContext('2d').drawImage(video, 0, 0);

  canvas.width = buffer.width;
  canvas.height = buffer.height;

  if (!glslCanvas) {
    glslCanvas = new GlslCanvas(canvas);
    update();
  }

  var dataURL = buffer.toDataURL();
  glslCanvas.setUniform('u_texture', dataURL);
  window.requestAnimationFrame(render);
}

function update() {

  const vertexShader = `
    #ifdef GL_ES
    precision mediump float;
    #endif
    uniform sampler2D u_texture;
    uniform vec2 u_resolution;
    uniform float u_time;
    void main() {
      vec2 st = gl_FragCoord.xy / u_resolution.xy;
      float x = gl_FragCoord.x;
      float y = gl_FragCoord.y;
      vec3 color = texture2D(u_texture, st).rgb;
      ${fragColor}
    }
  `;

  if (glslCanvas) glslCanvas.load(vertexShader);
}

function toggle() {
  fragColor = this.getAttribute('data-shader');
  update();
}

document.getElementById('access').addEventListener('click', init);
video.addEventListener('canplay', render);

[...document.getElementById('buttons').children].forEach(button => {
  button.addEventListener('click', toggle);
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://rawgit.com/patriciogonzalezvivo/glslCanvas/master/dist/GlslCanvas.js
  2. https://webrtc.github.io/adapter/adapter-latest.js