|  | <style> | 
        
          |  | body { margin: 0 } | 
        
          |  | video { display: none } | 
        
          |  | </style> | 
        
          |  | <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r75/three.min.js"></script> | 
        
          |  | <script src="https://cdn.rawgit.com/mrdoob/three.js/r75/examples/js/controls/OrbitControls.js"></script> | 
        
          |  | <script> | 
        
          |  | 'use strict' | 
        
          |  |  | 
        
          |  | navigator.mediaDevices.enumerateDevices().then((devices) => { | 
        
          |  | // find the theta uvc blender device | 
        
          |  | let theta = devices.find(device => device.label.match(/THETA UVC Blender/)) | 
        
          |  | return theta ? { optional: [{ sourceId: theta.deviceId }] } : true | 
        
          |  | }).then((video) => { | 
        
          |  | // get the camera | 
        
          |  | return navigator.mediaDevices.getUserMedia({ video }) | 
        
          |  | }).then((stream) => { | 
        
          |  | // create the video tag | 
        
          |  | let video = document.body.appendChild(document.createElement('video')) | 
        
          |  | video.src = window.URL.createObjectURL(stream) | 
        
          |  |  | 
        
          |  | // create a scene | 
        
          |  | let scene = new THREE.Scene() | 
        
          |  |  | 
        
          |  | // attach the video to a texture | 
        
          |  | let videoTexture = new THREE.Texture(video) | 
        
          |  | videoTexture.minFilter = THREE.NearestFilter | 
        
          |  |  | 
        
          |  | // create a sphere at the origin textured on the inside by the video | 
        
          |  | let sphere = new THREE.SphereGeometry(50, 16, 16), | 
        
          |  | material = new THREE.MeshBasicMaterial({ map: videoTexture }) | 
        
          |  | material.side = THREE.BackSide | 
        
          |  | scene.add(new THREE.Mesh(sphere, material)) | 
        
          |  |  | 
        
          |  | // setup a light and camera inside the sphere | 
        
          |  | let { width, height } = document.body.getBoundingClientRect() | 
        
          |  | let light = new THREE.AmbientLight(0xFFFFFF), | 
        
          |  | camera = new THREE.PerspectiveCamera(85, width / height, 1, 1000) | 
        
          |  |  | 
        
          |  | scene.add(light) | 
        
          |  | scene.add(camera) | 
        
          |  |  | 
        
          |  | // controls for rotating around the origin | 
        
          |  | let controls = new THREE.OrbitControls(camera) | 
        
          |  | controls.autoRotate = true | 
        
          |  | // invert rotation because we're inside the sphere | 
        
          |  | controls.rotateSpeed = -1.0 | 
        
          |  | // camera needs to move off origin to see panning effect | 
        
          |  | camera.position.z = 1 | 
        
          |  |  | 
        
          |  | // render | 
        
          |  | let renderer = new THREE.WebGLRenderer() | 
        
          |  | renderer.setSize(width, height, true) | 
        
          |  | document.body.appendChild(renderer.domElement) | 
        
          |  |  | 
        
          |  | ;(function render() { | 
        
          |  | requestAnimationFrame(render) | 
        
          |  |  | 
        
          |  | controls.update() | 
        
          |  |  | 
        
          |  | // update the video texture | 
        
          |  | if (video.readyState === video.HAVE_ENOUGH_DATA) | 
        
          |  | videoTexture.needsUpdate = true | 
        
          |  |  | 
        
          |  | renderer.render(scene, camera) | 
        
          |  | })() | 
        
          |  | }).catch((err) => { | 
        
          |  | console.error(err) | 
        
          |  | }) | 
        
          |  | </script> |