Responsive Resizing

Responsive Resizing

A red box on a grid that resizes with the window

A real webpage can change size — the user resizes their browser or rotates their phone. Without handling this, your Three.js scene gets stretched or blurry. This final lesson of the chapter shows the standard resize pattern: listen to the window resize event, update the camera aspect and the renderer size so the scene stays sharp and correctly proportioned.

The Resize Problem

Two things must update together on resize:

  • Camera aspect ratio must match the new width/height, or the scene distorts.
  • Renderer canvas size must match the window, or it is blurry/scaled.

Full Example

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Three.js – Responsive Resizing</title>
  <style>body{margin:0;overflow:hidden;background:#0b0f1a}
    #ui{position:absolute;top:12px;left:12px;color:#fff;font:13px sans-serif;z-index:10;background:rgba(0,0,0,.45);padding:8px 12px;border-radius:6px}</style>
</head>
<body>
  <div id="ui">Resize the window – the scene stays sharp</div>
  <script type="importmap">
    { "imports": {
        "three": "https://unpkg.com/three@0.160.0/build/three.module.js",
        "three/addons/": "https://unpkg.com/three@0.160.0/examples/jsm/"
    } }
  </script>
  <script type="module">
    import * as THREE from 'three';

const scene = new THREE.Scene(); scene.background = new THREE.Color(0x0b0f1a);

const camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 0.1, 1000); camera.position.set(2.5, 2, 4);

const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(innerWidth, innerHeight); document.body.appendChild(renderer.domElement);

scene.add(new THREE.AmbientLight(0x404040)); const dir = new THREE.DirectionalLight(0xffffff, 1); dir.position.set(3, 4, 2); scene.add(dir); scene.add(new THREE.GridHelper(10, 20, 0x3a4763, 0x232c40));

const box = new THREE.Mesh( new THREE.BoxGeometry(1, 1, 1), new THREE.MeshStandardMaterial({ color: 0xe02424 }) ); scene.add(box);

// Keep aspect ratio and canvas size correct on any resize window.addEventListener('resize', () => { camera.aspect = innerWidth / innerHeight; camera.updateProjectionMatrix(); renderer.setSize(innerWidth, innerHeight); });

function animate() { requestAnimationFrame(animate); renderer.render(scene, camera); } animate(); </script> </body> </html>

The Resize Handler

The three lines inside the resize listener are the standard pattern:

window.addEventListener('resize', () => {
  camera.aspect = innerWidth / innerHeight;   // update aspect ratio
  camera.updateProjectionMatrix();            // apply it to the projection
  renderer.setSize(innerWidth, innerHeight);  // resize the canvas
});
  • camera.aspect is the width/height ratio the perspective camera was built from; it must track the window or the image distorts.
  • camera.updateProjectionMatrix() recalculates the camera's internal projection using the new aspect. Forgetting this line is a classic bug — the aspect changes but nothing applies it.
  • renderer.setSize(innerWidth, innerHeight) resizes the actual canvas to fill the window, keeping it sharp rather than scaled.

Try It Yourself

  • Resize your browser window and notice the scene stays proportioned and crisp.
  • Comment out camera.updateProjectionMatrix() and resize — the image distorts sideways until you refresh.
  • Comment out renderer.setSize(...) and resize — the canvas keeps its old physical size.
  • Add renderer.setPixelRatio(Math.min(devicePixelRatio, 2)) after setSize for extra sharpness on high-DPI (Retina) displays.

Summary

A robust Three.js page responds to resize by updating the camera aspect with updateProjectionMatrix() and resizing the renderer. This keeps your 3D scene sharp and correctly proportioned on any screen — a vital bit of polish for real pages.

Next Lesson

You now have every tool: scene, cameras, controls, geometries, materials, lights, animation, interaction, shadows, textures and responsive sizing. The final chapter combines them all into a single ambitious project — an interactive 3D diorama.

Quiz - Quiz - Responsive Resizing

1. On window resize, the camera aspect must be updated and then

2. renderer.setSize(innerWidth, innerHeight) does what on resize?

3. Forgetting to update the projection matrix on resize causes

Textures: Mapping Images onto Materials