by Feiyue Zhang (2025)
Just like cartoon, we create a series of slightly different frames to give the illusion of motion in interactive 3D content.
A metric you might have heard is FPS (frame per second). It's an indicator of how many frames are shown in a second. Higher FPS means more fluid visuals (and higher responsiveness if user control is involved).
Source: TKSST
Source: GameLudere
Animation loop in Three.js (aka render loop) is essentially a while loop that runs non-stop, and each iteration in render loop produces a frame/rendering.
The picture on the left illustrates how an animation loop works.
Footnote:
Even though the diagram is actually a game loop, game loop and animation loop are actually very similar as they both run continuously to update and refresh the screen. The main difference is that game loops update not just 3D objects but also more complex game logic.
The easiest way to animate your scene is to change the positions of objects over time.
animate() is a function that gets called every frame to update the scene and render it again. By slightly changing object properties (like position) each frame, you create the illusion of continuous motion:
function animate() {
// Update position
cube.position.x += 0.01;
// Render the scene
renderer.render( scene, camera );
}
Here the x component of the cube's position is increased a little bit every frame, making the cube slide smoothly to the right.
Here are some useful events that W3C defines:
MouseEvent
KeyboardEvent
TouchEvent
By listening to these input events, you can make your application respond to user actions. Input events are triggered whenever a user presses a key, moves the mouse, or interacts with the screen.
The simplest thing you can do with a keyboard event is implement WASD key movement to control an object, like a camera:
document.addEventListener( 'keydown', ( event ) => {
if ( event.code == 'KeyW' ) camera.translateZ( -STEP );
if ( event.code == 'KeyS' ) camera.translateZ( STEP );
if ( event.code == 'KeyA' ) ) camera.translateX( STEP );
if ( event.code == 'KeyD' ) camera.translateX( STEP );
} );
If the pressed key matches W, A, S, or D, the camera is moved accordingly
STEP controls how far the camera moves with each key press
Now every time you press a button, your object moves at a fixed distance. This does the job, but it just doesn't feel natural because movement only happens once per key press, not continuously as you hold the key.
Here's a trick to achieve continuous updates that make the object move smoothly while a key is pressed down. The idea is to store key state data in memory and respond to the current key state rather than reacting to individual key events.
Listen for keyboard events to track which keys are currently pressed using a hash map:
document.addEventListener( 'keydown', ( event ) => {
keyMap.set( event.code, true );
} );
document.addEventListener( 'keyup', ( event ) => {
keyMap.set( event.code, false );
} );
Instead of moving the object immediately on key press, you check the hash map during every frame update:
function update() {
if ( keyMap.get( 'KeyW' ) ) camera.translateZ( -STEP );
if ( keyMap.get( 'KeyS' ) ) camera.translateZ( STEP );
if ( keyMap.get( 'KeyA' ) ) camera.translateX( STEP );
if ( keyMap.get( 'KeyD' ) ) camera.translateX( STEP );
}
GSAP is a JavaScript library that allows you to create dynamic and high-performance animations in both 2D and 3D. Instead of manually calculating and updating in render loop in order to achieve smooth animation, you can let GSAP handle the work.
You may need it for:
Move an object from one position to another
Make an object move along a curve
Animate the rotation of an object
Check out their website for more information.
Source: GSAP