Three.js BoxHelper for Dynamically Scaling Objects

This article explains how to accurately visualize the bounding box of a Three.js object as its scale changes dynamically in real-time. You will learn how to initialize BoxHelper and keep it perfectly synchronized with a morphing or scaling 3D mesh within your render loop.

The Problem with Dynamic Scaling

When you instantiate a BoxHelper in Three.js, it computes the bounding box based on the target object’s current state. However, if the target object scales, rotates, or translates during runtime, the bounding box helper will not automatically adapt to these changes. It remains static, resulting in an inaccurate representation of the object’s spatial boundaries.

The Solution: Using boxHelper.update()

To keep the bounding box aligned with a dynamically scaling object, you must call the .update() method on your BoxHelper instance inside the animation render loop. This forces Three.js to recalculate the object’s world-space bounds on every frame.

Step-by-Step Implementation

  1. Create the Target Object: Define the mesh that will scale dynamically.
  2. Create the BoxHelper: Instantiate the helper, passing the mesh as the target.
  3. Add Both to the Scene: Ensure both the mesh and the helper are added to your scene.
  4. Update in the Loop: Scale your mesh and call the helper’s .update() method in your requestAnimationFrame loop.

Code Example

import * as THREE from 'three';

// 1. Setup scene, camera, and renderer
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 2. Create the target mesh
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const myMesh = new THREE.Mesh(geometry, material);
scene.add(myMesh);

// 3. Create the BoxHelper
const boxHelper = new THREE.BoxHelper(myMesh, 0xffff00);
scene.add(boxHelper);

camera.position.z = 5;

// 4. The Animation Loop
function animate() {
    requestAnimationFrame(animate);

    // Dynamically scale the mesh over time
    const time = Date.now() * 0.001;
    const scaleFactor = Math.sin(time) + 1.5; // Cycles between 0.5 and 2.5
    myMesh.scale.set(scaleFactor, scaleFactor, scaleFactor);

    // CRITICAL: Update the BoxHelper to match the new scale
    boxHelper.update();

    renderer.render(scene, camera);
}

animate();

How It Works

The BoxHelper internally references the target object’s geometry and world matrix. When boxHelper.update() is called: