Animate

gsap example

You can animate things in Three.js the same way you animate anything else — by changing numbers over time. Three.js has its own built-in animation system, but I tend to use the GSAP library instead. Here's why.

GSAP can animate any numeric property on any JavaScript object. Three.js objects are just JavaScript objects with numeric properties — so GSAP can animate them.

import gsap from 'gsap';
import * as THREE from 'three';

// GSAP can tween any object's numeric properties
const obj = { x: 0, y: 0 };
gsap.to(obj, { x: 10, y: 20, duration: 1 });

You apply this to Three.js objects the same way — you create a plain object as a "target," tween its properties, then apply them back to the Three.js object in an onUpdate callback.

animating position

You can't directly tween mesh.position because it's a Vector3 with methods, not plain properties — so you create a plain JS proxy object.

import gsap from 'gsap';

const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

// Create a plain JS object to tween
const target = { x: 0, y: 0, z: 0 };

gsap.to(target, {
    x: 5,
    y: 3,
    z: -2,
    duration: 2,
    ease: 'power2.out',
    onUpdate: () => {
        // this is where the magic happens
        mesh.position.set(target.x, target.y, target.z);
    },
});

animating rotation

rotation is a Euler, also not plain properties — same proxy approach:

const target = { x: 0, y: 0 };

gsap.to(target, {
    x: Math.PI * 2, // full rotation
    y: Math.PI,
    duration: 3,
    ease: 'power1.inOut',
    onUpdate: () => {
        mesh.rotation.x = target.x;
        mesh.rotation.y = target.y;
    },
});

animating ShaderMaterial uniforms

This is even simpler because uniforms are plain objects.

// overlayMaterial.uniforms.uAlpha is { value: 1.0 }
gsap.to(overlayMaterial.uniforms.uAlpha, {
    duration: 3,
    value: 0, // GSAP tweens the `.value` property directly
});

No onUpdate needed — GSAP tweens the uniform's value property directly, and Three.js picks it up on the next render.

animating color

Three.js Color objects work with GSAP's built-in color interpolation:

const material = new THREE.MeshStandardMaterial({ color: 0xff0000 });

gsap.to(material.color, {
    r: 0, // 0-1 range
    g: 0,
    b: 1, // result: blue
    duration: 1,
});

Or with hex strings (GSAP converts them):

gsap.to(material.color, {
    value: '#00ff88',
    duration: 1,
});

timelines — sequencing animations

You can sequence multiple Three.js animations with GSAP timelines:

const startPos = { x: player.position.x, z: player.position.z };

const timeline = gsap.timeline();
timeline.to(startPos, {
    x: 5,
    z: 3,
    duration: 0.3,
    ease: 'back.out',
    onUpdate: () => {
        player.position.x = startPos.x;
        player.position.z = startPos.z;
    },
});
// You can chain more tweens with .to(), .fromTo(), etc.
// timeline.to(...)
// timeline.fromTo(...)

good tips to know

  • Always kill old tweens before creating new ones on the same target — if (cameraTween) cameraTween.kill();
  • Clean up when you navigate awaygsap.killTweensOf('*'); kills all GSAP tweens globally, preventing memory leaks.
  • Use gsap.timeline() for multi-step sequences (move → rotate → fade) instead of nesting callbacks.
  • Eases work the samepower2.out, back.out(1.7), elastic.out(1, 0.3) all apply to any numeric value.