Below are three proven methods for making objects follow each other in Three.js, from simple to advanced. Each builds on the previous concept.
Linear interpolation (lerp) is the most common approach. It smoothly moves the follower a percentage of the remaining distance each frame.
// followSpeed: 0 = no movement, 1 = instant snap
const followSpeed = 0.05;
function animate() {
// Each frame, move 5% of remaining distance toward target
follower.position.lerp(target.position, followSpeed);
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
Key insight: Lower values (0.02-0.05) create a smooth trailing effect. Higher values (0.1-0.3) feel more responsive but less cinematic.
Maintains a fixed distance between follower and target. Perfect for third-person cameras or orbiting objects.
const desiredDistance = 8;
const followSpeed = 0.02;
function animate() {
// Calculate direction FROM target TO follower
const direction = new THREE.Vector3();
direction.subVectors(follower.position, target.position);
direction.normalize();
// Place desired position at fixed distance behind target
const desiredPosition = new THREE.Vector3();
desiredPosition.copy(target.position);
desiredPosition.addScaledVector(direction, desiredDistance);
// Smoothly move toward desired position
follower.position.lerp(desiredPosition, followSpeed);
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
Key insight: The follower orbits at a fixed radius. Change desiredDistance to zoom in/out. This is how most third-person cameras work.
Uses acceleration and damping for physics-like movement. The follower speeds up when far away and decelerates when close — feels natural and responsive.
const maxSpeed = 0.1;
const acceleration = 0.02;
const damping = 0.9;
let velocity = new THREE.Vector3();
function animate() {
const direction = new THREE.Vector3();
direction.subVectors(target.position, follower.position);
if (direction.length() > 0.1) {
// Accelerate toward target
direction.normalize();
velocity.addScaledVector(direction, acceleration);
// Cap at max speed
if (velocity.length() > maxSpeed) {
velocity.normalize().multiplyScalar(maxSpeed);
}
} else {
// Close enough — apply damping to slow down
velocity.multiplyScalar(damping);
}
follower.position.add(velocity);
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
Key insight: This is ideal for enemy AI, homing missiles, or any object that needs momentum. Adjust damping (0.8-0.95) to control how quickly it stops.
Combine any following method with lookAt() to make the follower face the target. Essential for cameras, turrets, and characters.
function animate() {
// Any following method...
follower.position.lerp(target.position, 0.05);
// Make follower face the target
follower.lookAt(target.position);
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
Scene Setup: We create a dark scene with fog, a grid ground plane, and directional lighting with shadows. This gives depth and makes the 3D objects readable.
Target Object (Red Cube): Controlled with WASD keys. This is what the followers chase. In a real game, this would be your player character.
Green Sphere (Lerp): Uses simple position.lerp() — always moves 2% of remaining distance per frame. Creates a smooth, elastic trailing effect.
Blue Cone (Distance): Maintains an 8-unit orbit around the target. Calculates a desired position at fixed distance, then lerps toward it. This is how third-person cameras work.
Yellow Octahedron (Velocity): Accelerates toward the target with a speed cap and damping. Feels like a homing missile — builds momentum and decelerates on approach.
Camera System: The camera itself uses lerp following with an offset vector, creating a smooth cinematic feel as you move the target around.
Performance Tip: Reuse Vector3 objects instead of creating new ones each frame. In the demo we create them inside the loop for clarity, but in production you'd declare them once outside.
Copy this code into an HTML file and open it in your browser. Use WASD to move the red cube — watch the three followers react differently.