Use HTML Canvas as Dynamic Texture in Three.js

This article explains how to use an HTML <canvas> element as a dynamic, updatable texture within a Three.js 3D scene. You will learn how to initialize the canvas, project it onto a 3D object using THREE.CanvasTexture, and continuously update the texture in real-time to reflect changes drawn on the canvas.

Step 1: Create and Draw on the HTML Canvas

First, create an HTML canvas element in your JavaScript code. You do not need to append this canvas to the DOM if you only want it to exist in memory as a texture.

// Create the canvas element
const canvas = document.createElement('canvas');
canvas.width = 512;
canvas.height = 512;

// Get the 2D rendering context
const ctx = canvas.getContext('2d');

// Draw an initial background and text
ctx.fillStyle = '#1e1e1e';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#ffffff';
ctx.font = '40px Arial';
ctx.fillText('Hello Three.js', 50, 100);

Step 2: Create the CanvasTexture in Three.js

Three.js provides a specialized class called THREE.CanvasTexture designed specifically to handle canvas elements. Pass your canvas instance directly into this constructor.

// Create the texture from the canvas
const texture = new THREE.CanvasTexture(canvas);

Step 3: Apply the Texture to a Material and Mesh

Apply the texture to a material (such as MeshBasicMaterial or MeshStandardMaterial) and map it to a 3D geometry.

// Create a material using the canvas texture
const material = new THREE.MeshBasicMaterial({ map: texture });

// Create a cube geometry and mesh
const geometry = new THREE.BoxGeometry(2, 2, 2);
const cube = new THREE.Mesh(geometry, material);

// Add the cube to your Three.js scene
scene.add(cube);

Step 4: Update the Texture Dynamically

Three.js caches textures for performance reasons. If you modify the HTML canvas inside your rendering loop, you must explicitly inform Three.js that the texture needs to be uploaded to the GPU again. You do this by setting the needsUpdate property of the texture to true.

Here is how to update the canvas content and refresh the texture inside the animation loop:

let frameCount = 0;

function animate() {
  requestAnimationFrame(animate);

  // 1. Clear and redraw on the 2D canvas context
  ctx.fillStyle = '#1e1e1e';
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  // Draw dynamic content (e.g., a moving circle)
  frameCount++;
  const x = 256 + Math.sin(frameCount * 0.05) * 150;
  const y = 256 + Math.cos(frameCount * 0.05) * 150;

  ctx.beginPath();
  ctx.arc(x, y, 40, 0, Math.PI * 2);
  ctx.fillStyle = '#ff0055';
  ctx.fill();

  // 2. Tell Three.js to update the GPU texture
  texture.needsUpdate = true;

  // Render the Three.js scene
  renderer.render(scene, camera);
}

animate();

By setting texture.needsUpdate = true after modifying the canvas, Three.js automatically re-uploads the modified canvas buffer to the GPU on the next render call, achieving a seamless dynamic texture effect.