In Three.js model animation, two approaches are easy to confuse. You can directly animate a model part with GSAP, or you can play animation clips that are already baked into the model file with AnimationMixer. Both can move things, but they fit different jobs.
Short rule:
- Use GSAP for interaction-driven local movement.
- Use
AnimationMixerfor complete animation clips from the model.
Designer and developer boundary
3D models may arrive in two forms:
- The designer baked animations into the model, such as character actions, camera movement, or a mechanical sequence.
- The model contains separate named parts, and the developer controls movement based on UI state or interaction.
Preserve that boundary. If the model already contains a complete animation clip, do not rebuild the whole thing with hand-written tweens unless there is a clear reason.
Use GSAP for local interactive parts
For a car door, drawer, knob, switch, or product part controlled by a button, GSAP is often direct and readable.
import gsap from "gsap"
let doorLF
let isDoorOpen = false
function toggleDoor() {
if (!doorLF) return
gsap.to(doorLF.rotation, {
y: isDoorOpen ? 0 : Math.PI / 2,
duration: 1,
ease: "power2.out",
})
isDoorOpen = !isDoorOpen
}
The key step is getting the named object:
doorLF = car.getObjectByName("Door_LF")
The name must match the model structure. Ask the 3D designer to keep stable, meaningful object names.
Why GSAP works well here
GSAP is a good fit when animation follows:
- button clicks
- sliders
- scroll progress
- drag state
- UI toggles
- small part transforms
You can map interaction state directly to object rotation, position, or scale.
Use AnimationMixer for baked clips
If the glTF file includes complete animation tracks, use Three.js AnimationMixer:
import * as THREE from "three"
let mixer
loader.load("path/to/model.glb", (gltf) => {
const model = gltf.scene
scene.add(model)
mixer = new THREE.AnimationMixer(model)
const clip = gltf.animations[0]
const action = mixer.clipAction(clip)
action.play()
})
function animate() {
requestAnimationFrame(animate)
const delta = clock.getDelta()
if (mixer) mixer.update(delta)
renderer.render(scene, camera)
}
AnimationMixer keeps the animation data from the DCC tool. It is the right choice for complete authored timelines such as walk cycles, machinery sequences, character actions, and camera moves.
Controlling mixer actions
Actions can be paused, resumed, faded, or time-scaled:
action.paused = true
action.timeScale = 2
action.fadeIn(0.2)
action.fadeOut(0.2)
For scrubbed progress, you can also control action time carefully, but make sure mixer updates and state changes do not fight each other.
Choosing between them
| Scenario | Better fit |
|---|---|
| Click button to open one part | GSAP |
| Scroll maps a product part from closed to open | GSAP or hybrid |
| Play a designer-authored character action | AnimationMixer |
| Pause, resume, or speed up a full model clip | AnimationMixer |
| Combine UI state with a baked clip | hybrid, with a clear ownership rule |
Hybrid approaches are fine, but define ownership. Do not let GSAP and AnimationMixer both write to the same transform at the same time.
Common mistakes
- Losing object names during export.
- Rebuilding authored clips with code tweens.
- Forgetting to call
mixer.update(delta)in the render loop. - Using fixed
0.01update steps instead of frame delta. - Letting two animation systems control the same object.
- Treating animation as separate from loading, state, and interaction design.
Related FreeMac guides
- For React animation, read Motion for React Guide: Animation, Gestures, and Exit Effects.
- For rendering performance, read Reflow and Repaint: Why CSS Animations Get Janky.
- For React overlay boundaries, read React Portal: Render Modals Outside Parent DOM.
Continue reading
Motion for React Guide: Animation, Gestures, and Exit Effects
Learn Motion for React with motion components, variants, gestures, drag, MotionValue, useTransform, AnimatePresence, Next.js client components, and performance boundaries.
7 min readReflow and Repaint: Why CSS Animations Get Janky
Understand browser rendering steps, reflow, repaint, compositing, and why transform and opacity are usually better animation targets than width, height, top, or left.
11 min readDOM and CSSOM: How Browsers Build and Render a Page
Understand DOM, CSSOM, render tree, layout, paint, and performance basics such as batching DOM updates, avoiding forced synchronous layout, and using requestAnimationFrame.
Subscribe to FreeMac
Weekly picks: free Mac software reviews, trusted source updates, alternatives, and low-friction guides.