How to Autoplay and Loop Three.js VideoTexture

To display autoplaying video in Three.js, you must configure the underlying HTML5 <video> element to comply with modern browser autoplay policies. Browsers block autoplaying videos with audio to prevent intrusive user experiences. By programmatically setting the video element to be muted, loop, and play inline, you can seamlessly initialize a Three.js VideoTexture that plays automatically upon loading without throwing console errors or being blocked by the browser.

1. Configure the HTML5 Video Element

Three.js relies on a standard HTML5 <video> element to source its video frames. Before passing this element to Three.js, you must define the properties required by modern browsers (such as Chrome, Safari, and iOS) to allow autoplay.

Create and configure the video element in your JavaScript file:

// Create the HTML5 video element
const video = document.createElement('video');

// Set the video source path
video.src = 'path/to/your/video.mp4';

// Required properties for autoplay compliance
video.muted = true;        // Must be muted to bypass autoplay restrictions
video.loop = true;         // Ensures the video loops continuously
video.playsInline = true;  // Required for iOS/Safari mobile compatibility
video.autoplay = true;     // Instructs the browser to start playback immediately

// Load the video source
video.load();

// Trigger playback programmatically
video.play().catch((error) => {
    console.error("Autoplay was prevented by the browser. Waiting for user interaction.", error);
});

2. Create and Apply the Three.js VideoTexture

Once the video element is configured, pass it directly into the THREE.VideoTexture constructor. This specialized texture class automatically updates the WebGL texture map every time a new video frame is ready.

import * as THREE from 'three';

// Initialize the VideoTexture
const videoTexture = new THREE.VideoTexture(video);

// Optional: Set texture filtering and color space for better quality
videoTexture.minFilter = THREE.LinearFilter;
videoTexture.magFilter = THREE.LinearFilter;
videoTexture.colorSpace = THREE.SRGBColorSpace; 

// Create a material using the video texture
const material = new THREE.MeshBasicMaterial({ 
    map: videoTexture,
    side: THREE.DoubleSide 
});

// Apply the material to a mesh (e.g., a screen plane)
const geometry = new THREE.PlaneGeometry(16 / 9, 1); // 16:9 aspect ratio
const screenMesh = new THREE.Mesh(geometry, material);

scene.add(screenMesh);

3. Handling Strict Browser Restrictions

While setting video.muted = true satisfies standard autoplay policies, some strict browser environments may still block video playback until a user interaction occurs. To guarantee your video texture plays, you can add a global event listener that triggers playback on the first user click or touch.

const startVideoOnInteraction = () => {
    if (video.paused) {
        video.play();
    }
    // Remove listeners once the video is successfully playing
    window.removeEventListener('click', startVideoOnInteraction);
    window.removeEventListener('touchstart', startVideoOnInteraction);
};

window.addEventListener('click', startVideoOnInteraction);
window.addEventListener('touchstart', startVideoOnInteraction);