JSFiddle - React, Tailwind, and code Playground

by Cody Bennett

CSS

body {
  margin: 0;
}

canvas {
  display: block;
}

JavaScript

import * as THREE from 'https://unpkg.com/three/build/three.module.js';

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(2);
document.body.appendChild(renderer.domElement);

const camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 10);
camera.position.z = 1;

const scene = new THREE.Scene();

const url = 'https://krpano.com/releases/1.20.9/viewer/examples/chromakey/video.mp4';
const keyColor = 0x238E54;

const video = document.createElement('video');
video.src = url;
video.load();

const videoTexture = new THREE.Texture(video);
videoTexture.minFilter = THREE.LinearFilter;
videoTexture.magFilter = THREE.LinearFilter;

const chromaKeyMaterial = new THREE.ShaderMaterial({
  uniforms: {
    texture: {
      type: 't',
      value: videoTexture
    },
    color: {
      type: 'c',
      value: new THREE.Color(keyColor)
    }
  },
  vertexShader: `
    varying mediump vec2 vUv;

    void main(void) {
      vUv = uv;

      mediump vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
      gl_Position = projectionMatrix * mvPosition;
    }
  `,
  fragmentShader: `
    uniform mediump sampler2D texture;
    uniform mediump vec3 color;
    varying mediump vec2 vUv;

    void main(void) {
      mediump vec3 tColor = texture2D( texture, vUv ).rgb;
      mediump float a = (length(tColor - color) - 0.5) * 7.0;

      gl_FragColor = vec4(tColor, a);
    }
  `,
  transparent: true
});

const chromaKeyGeometry = new THREE.PlaneBufferGeometry(5, 5);
const chromaKeyPlane = new THREE.Mesh(chromaKeyGeometry, chromaKeyMaterial);
scene.add(chromaKeyPlane);

renderer.setAnimationLoop(() => {
  if (video.readyState === video.HAVE_ENOUGH_DATA) {
    videoTexture.needsUpdate = true;
  }

  renderer.render(scene, camera);
});