Three.js - Animations
Three.js - Animations
Section titled “Three.js - Animations”Static 3D scenes are interesting, but animation is what truly brings them to life. In Three.js, animation is achieved by creating a render loop that updates the scene and re-renders it on every frame, creating the illusion of motion.
The Render Loop with requestAnimationFrame
Section titled “The Render Loop with requestAnimationFrame”The standard, browser-native way to create an efficient animation loop is with the window.requestAnimationFrame() method. It tells the browser that you wish to perform an animation and requests that the browser calls a specified function to update an animation before the next repaint. This is much more efficient than using setInterval, as it allows the browser to optimize rendering, pause animations in inactive tabs, and sync with the display’s refresh rate.
function tick() { // Code to update objects in the scene goes here
// Render the scene renderer.render(scene, camera);
// Schedule the next frame window.requestAnimationFrame(tick);}
// Start the looptick();Frame Rate Independent Animation
Section titled “Frame Rate Independent Animation”A common mistake is to update an object’s properties by a fixed amount on each frame, like cube.rotation.y += 0.01;. This creates a problem: the animation will run faster on high-refresh-rate monitors (e.g., 144Hz) and slower on standard ones (60Hz).
To solve this, we must use the time elapsed between frames to calculate our updates. Three.js provides a handy THREE.Clock utility for this.
import * as THREE from 'three';
const clock = new THREE.Clock();
function tick() { // Get the time elapsed since the last frame const deltaTime = clock.getDelta();
// Get the total time elapsed since the clock started const elapsedTime = clock.getElapsedTime();
// Update object rotation based on elapsed time for smooth, consistent speed // cube.rotation.y = elapsedTime * Math.PI; // Rotates 180 degrees per second
// Update object position in a circle cube.position.x = Math.cos(elapsedTime) * 5; cube.position.z = Math.sin(elapsedTime) * 5;
renderer.render(scene, camera); window.requestAnimationFrame(tick);}
tick();Advanced Animation with Tweening Libraries
Section titled “Advanced Animation with Tweening Libraries”For more complex, timeline-based animations (e.g., moving an object from point A to B over 2 seconds with a specific easing effect), a dedicated tweening library is invaluable. While the original tutorial used Tween.js, a highly popular and powerful industry standard is GSAP (GreenSock Animation Platform). It’s known for its performance, flexibility, and excellent documentation.
Let’s see how to integrate GSAP into our project.
1. Installation
Section titled “1. Installation”npm install gsap2. Usage
Section titled “2. Usage”GSAP can directly animate the properties of any JavaScript object, including Three.js objects like mesh.position, mesh.rotation, or material.color.
import gsap from 'gsap';
// Animate the cube's Y position over 1 secondgsap.to(cube.position, { duration: 1, delay: 0.5, y: 5 });
// Animate back down with an elastic easing effectgsap.to(cube.position, { duration: 1.5, delay: 1.5, y: 0, ease: 'elastic.out(1, 0.3)' });One of GSAP’s key advantages is that you don’t need to call an update function inside your render loop. It manages its own internal ticker, making for very clean and declarative animation code.
Animation Best Practices
Section titled “Animation Best Practices”- Performance: Avoid creating new objects (
new THREE.Vector3()) or performing heavy calculations inside the render loop. Do as much setup as possible outside the loop. - Debugging: Use
console.log(elapsedTime)to check timing or thestats.jslibrary to monitor your scene’s frame rate (FPS). - Control: Use libraries like GSAP for complex sequences, but leverage the
tickfunction withTHREE.Clockfor continuous, procedural animations like waves, floating, or constant rotation. - User Experience: Always provide a way for users to pause or reduce motion if they are sensitive to it. Consider using the
(prefers-reduced-motion)CSS media query to disable non-essential animations by default.
Mini-Project Idea: An Animated Solar System
Section titled “Mini-Project Idea: An Animated Solar System”A great way to practice these concepts is to build a simple solar system.
- Create a sphere for the sun and several smaller spheres for planets.
- In the
tickfunction, useelapsedTimewithMath.sin()andMath.cos()to make the planets orbit the sun at different speeds and distances. - Make the planets rotate on their own axes using
planet.rotation.y = elapsedTime * speed;. - Challenge: Use GSAP to animate the camera moving from a wide view to focus on a specific planet when the user clicks on it.