← Back to list
⚡

threejs-gltf-loading Checked

Load glTF/GLB models in three.js with GLTFLoader and play their skinned animations with Animation…
⚡ Productivity skills By gamedev-skills Version v1.0.0 Added 2026-10-21 Updated 2026-10-21 Source ↗
7.7Overall rating
0Views
0Downloads
2.0kStars

Installation

🤖 Install via AI

Copy the prompt below and send it to your AI assistant (e.g. Claude Code) — it will follow the instructions and install automatically.

Install the "threejs-gltf-loading" skill by following the instructions at https://skill123.me/install/threejs-gltf-loading.
⌨️ Command line install

Run in your terminal — downloads and installs to ~/.claude/skills/.

curl -fsSL https://skill123.me/install/threejs-gltf-loading.sh | bash
📦 Download ZIP

Download the zip and extract it into your skills directory (e.g. ~/.claude/skills/), then restart your session.

⬇ Download v1.0.0 · 6 KB
📊 Static rating
7.7/10
Trigger
8.0
Structure
0.0
Workflow
8.0
Content
0.0
Engineering
0.0
Security
7.0

Six-dimension rubric with reviewer rationale.

View scorecard ↓
🛡 Dynamic test
—

Not live-tested yet — this skill is rated on static analysis only.

About this skill

Load glTF/GLB models in three.js with GLTFLoader and play their skinned animations with AnimationMixer, including DRACO/Meshopt-compressed meshes and KTX2 textures. Use when importing 3D models into three.js — when the user mentions glTF, GLB, GLTFLoader, AnimationMixer, animation clips, DRACOLoader, or "load a 3D model". For scene/camera/renderer setup use threejs-scene-setup; for materials and lights use threejs-materials-lighting.

three.js glTF Loading

Load .gltf/.glb models and play their animations in three.js, including

compressed geometry (DRACO/Meshopt) and textures (KTX2). Patterns target

**r186**; preserve an existing project's pinned release unless migration is requested.

Documentation

Load glTF/GLB models in three.js with GLTFLoader and play their skinned animations with AnimationMixer, including DRACO/Meshopt-compressed meshes and KTX2 textures. Use when importing 3D models into three.js — when the user mentions glTF, GLB, GLTFLoader, AnimationMixer, animation clips, DRACOLoader, or "load a 3D model". For scene/camera/renderer setup use threejs-scene-setup; for materials and lights use threejs-materials-lighting.

three.js glTF Loading

Load .gltf/.glb models and play their animations in three.js, including

compressed geometry (DRACO/Meshopt) and textures (KTX2). Patterns target

**r186**; preserve an existing project's pinned release unless migration is requested.

When to use

  • Use to import a 3D model, add it to the scene, inspect its node hierarchy, and

play baked/skinned animation clips with an AnimationMixer.

  • Use when files are .gltf/.glb, or code imports GLTFLoader /

DRACOLoader / KTX2Loader from three/addons/loaders/....

**When *not* to use:** creating the renderer/camera/loop → threejs-scene-setup.

Tuning surface look, lights, or shadows on the loaded model →

threejs-materials-lighting. Authoring/exporting the model itself (Blender) is out

of scope; prefer glTF over OBJ/FBX for runtime.

Core workflow

1. **Why glTF.** It's a transmission format: binary vertex data, PBR materials, and

animations are ready to render with minimal parsing. Prefer it over OBJ (no scene

graph, no animation) and FBX (heavy) for the web.

2. **Load with GLTFLoader.** loader.load(url, onLoad, onProgress, onError). The

result gltf has gltf.scene (the Object3D root), gltf.animations

(AnimationClip[]), gltf.cameras, and gltf.asset.

3. **Add gltf.scene to your scene** and frame it. Inspect the hierarchy with

traverse / getObjectByName to find the parts you'll control.

4. **Play animations with an AnimationMixer.** One mixer per animated root;

mixer.clipAction(clip).play(); advance with mixer.update(delta) every frame.

5. **Decode compressed assets.** Attach a DRACOLoader (and/or KTX2Loader +

Meshopt) so DRACO meshes and KTX2 textures load; point the decoders at their

files.

6. **Verify what loaded** — log the scene graph and gltf.animations, and confirm

the model is visible (right scale, lit) and the clip actually plays.

Patterns

### 1. Load a model and frame it


import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';

const loader = new GLTFLoader();
loader.load(
  'assets/robot.glb',
  (gltf) => {
    const root = gltf.scene;
    scene.add(root);
    // Inspect: gltf.animations is an array of AnimationClip.
    console.log('clips:', gltf.animations.map((c) => c.name));
  },
  (event) => console.log(`${(event.loaded / event.total) * 100}% loaded`),
  (error) => console.error('glTF load failed:', error)
);

### 2. Play a skinned animation with AnimationMixer

View full documentation

import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';

let mixer;                                  // declare outside so the loop can see it
const timer = new THREE.Timer();            // THREE.Clock is deprecated since r183

new GLTFLoader().load('assets/character.glb', (gltf) => {
  scene.add(gltf.scene);
  mixer = new THREE.AnimationMixer(gltf.scene);          // one mixer per animated root
  const clip = THREE.AnimationClip.findByName(gltf.animations, 'Run')
            ?? gltf.animations[0];
  mixer.clipAction(clip).play();
});

renderer.setAnimationLoop((time) => {
  timer.update(time);
  const dt = timer.getDelta();
  if (mixer) mixer.update(dt);              // advance the animation by real seconds
  renderer.render(scene, camera);
});

### 3. Cross-fade between two clips


const actions = {};
mixer = new THREE.AnimationMixer(gltf.scene);
for (const clip of gltf.animations) {
  actions[clip.name] = mixer.clipAction(clip);
}
actions['Idle'].play();

function transitionTo(name, duration = 0.3) {
  const next = actions[name];
  next.reset().play();
  for (const [n, action] of Object.entries(actions)) {
    if (n !== name) action.crossFadeTo(next, duration, false);
  }
}

### 4. DRACO-compressed geometry


import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';

const draco = new DRACOLoader();
// Point at the decoder files you ship (or a pinned CDN copy of the same version).
draco.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.186.0/examples/jsm/libs/draco/');

const loader = new GLTFLoader();
loader.setDRACOLoader(draco);
loader.load('assets/city-draco.glb', (gltf) => scene.add(gltf.scene));

### 5. Find and animate a named part


new GLTFLoader().load('assets/car.glb', (gltf) => {
  scene.add(gltf.scene);
  const wheels = [];
  gltf.scene.traverse((node) => {
    if (node.name.startsWith('Wheel')) wheels.push(node);
  });
  renderer.setAnimationLoop((time) => {
    timer.update(time);
    const dt = timer.getDelta();
    for (const w of wheels) w.rotation.x += dt * 4;
    renderer.render(scene, camera);
  });
});

Pitfalls

  • **Model loads but is invisible** → it has lit (PBR) materials and the scene has no

light or environment. Add a light or scene.environment (see

threejs-materials-lighting), and check scale — glTF is in metres, so a 0.01-scaled

asset is tiny.

  • **load is async** → gltf only exists inside the callback; declare mixer/refs

outside and assign them in the callback, or use await loader.loadAsync(url).

  • **Animation never moves** → you didn't call mixer.update(delta) each frame, or you

passed milliseconds instead of seconds (use timer.getDelta() after

timer.update(time)), or you forgot

action.play().

  • **DRACO/KTX2 model fails** → the decoder/transcoder path is wrong or version-

mismatched. setDecoderPath/setTranscoderPath must point at files matching your

three.js version.

  • **Multiple mixers fighting** → use **one** AnimationMixer per animated root and

create all actions from it; don't make a new mixer per clip.

  • **Baked-in transforms surprise you** → exporters sometimes bake scale/rotation onto

child nodes. Dump the hierarchy (names + position/rotation/scale) before relying on

a node's local transform; re-export from the source if the rig is unusable.

  • **Origins are off** → re-parent a part under a fresh Object3D to give it a clean

pivot rather than fighting baked offsets.

References

  • For the full decode/transcode setup (DRACO + Meshopt + KTX2 together), loadAsync

+ a LoadingManager progress bar, reusing models with SkeletonUtils.clone, and

exporter guidance (apply transforms, one clean root), read

references/loaders-and-animation.md.

Related skills

  • threejs-scene-setup — the renderer, camera, and loop this model renders into.
  • threejs-materials-lighting — lighting/environment so PBR models look right.
  • fps-shooter — a 3D genre that composes three.js skills.

Score breakdown

Trigger
8.0
Structure
0.0
Workflow
8.0
Content
0.0
Engineering
0.0
Security
7.0