Make Responsive

responsive

If you've ever opened a Three.js scene on your phone and seen a stretched or squished mess, you know the pain. Your scene looks great on your full-screen monitor, but resize the window or pull it up on a phone — and suddenly everything's broken.

The fix is simple: you need to update the camera and renderer whenever the window (or your canvas container) changes size.

the basic resize handler

function resize() {
    const width = canvas.clientWidth;
    const height = canvas.clientHeight;

    // Update the camera's aspect ratio so it doesn't stretch
    camera.aspect = width / height;
    camera.updateProjectionMatrix();

    // Update the renderer size to match
    renderer.setSize(width, height);
}

window.addEventListener('resize', resize);

That's it. Three things:

  1. Update the camera's aspect ratiowidth / height so objects don't look squished
  2. Tell the camera to recalculatecamera.updateProjectionMatrix() applies the change
  3. Resize the rendererrenderer.setSize(width, height) matches the canvas to the container

using ResizeObserver (better for containers)

If your canvas is inside a container that might change size on its own (like a sidebar that expands, or a panel that resizes), window.addEventListener('resize', ...) won't catch it. That's where ResizeObserver comes in:

const observer = new ResizeObserver(resize);
observer.observe(canvas.parentElement);

// Cleanup when your component unmounts
return () => observer.disconnect();

This watches the canvas's parent element and fires your resize function whenever it changes size — no matter why.

cleaning up

If your scene lives inside a Svelte or React component, you need to remove the event listener when the component goes away, otherwise it keeps running invisibly:

// Using addEventListener
window.addEventListener('resize', resize);

// Cleanup
return () => window.removeEventListener('resize', resize);
// Using ResizeObserver
const observer = new ResizeObserver(resize);
observer.observe(canvas.parentElement);

// Cleanup
return () => observer.disconnect();

full example

// Create your scene, camera, renderer…

function resize() {
    const width = window.innerWidth;
    const height = window.innerHeight;
    camera.aspect = width / height;
    camera.updateProjectionMatrix();
    renderer.setSize(width, height);
}

resize(); // run once on load
window.addEventListener('resize', resize);

That's all you need. Your scene now adapts to any screen size.