body {
  margin: 0;
}
const scene = new THREE.Scene();
const fov = 75;
const aspect = window.innerWidth / window.innerHeight;
const near = 0.1;
const far = 1000;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
const renderer = new THREE.WebGLRenderer();
const loader = new THREE.TextureLoader();

renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const light = createLight();
scene.add(light);

const flyingWindow = createFlyingWindow();
scene.add(flyingWindow);

camera.position.z = 1;
let rotationDirection = 1;

function animate() {
  requestAnimationFrame(animate);

  if (flyingWindow.rotation.y < -2 || flyingWindow.rotation.y > 2) {
    rotationDirection *= -1;
  }
  
  flyingWindow.rotation.y += 0.01 * rotationDirection;
  
  renderer.render(scene, camera);
}

animate();
window.addEventListener('resize', onWindowResize, false);

function createLight() {
  const color = 0xFFFFFF;
  const intensity = 1;
  const light = new THREE.DirectionalLight(color, intensity);
  light.position.set(-1, 2, 4);
  return light;
}

function createFlyingWindow() {
  // width and height are based on the aspect of the Windows logo image
  const width = 1.235;
  const height = 1;
  // arbitrary depth to make it appear flat enough
  const depth = 0.01;

  const geometry = new THREE.BoxGeometry(width, height, depth);

  const windowImageMaterial = new THREE.MeshBasicMaterial({
    map: loader.load('https://i.imgur.com/mSoYNK0.png'),
    transparent: true,
    side: THREE.FrontSide
  });
  
  const blackMaterial = new THREE.MeshBasicMaterial({
    color: 0x000000,
    side: THREE.DoubleSide,
  });
  
  // put color on both sides so transparent front can show color from inside box
  const colorMaterial = new THREE.MeshBasicMaterial({
    color: 0xff0000,
    side: THREE.BackSide,
  });

  const materials = [
    blackMaterial,
    blackMaterial,
    blackMaterial,
    blackMaterial,
    windowImageMaterial, // front side facing camera
    colorMaterial, // back side facing camera from the inside
  ];

  const flyingWindow = new THREE.Mesh(geometry, materials);
  flyingWindow.position.z = -1;
  
  return flyingWindow;
}

function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/three.js/r125/three.min.js