
Threejs Animation
- 10.4k installs
- 2.8k repo stars
- Updated July 9, 2026
- cloudai-x/threejs-skills
threejs-animation is an agent skill that Three.js animation - keyframe animation, skeletal animation, morph targets, animation mixing. Use when animating objects, playing GLTF animations, creating proc.
About
Three js animation keyframe animation skeletal animation morph targets animation mixing Use when animating objects playing GLTF animations creating procedural motion or blending animations name threejs-animation description Three js animation keyframe animation skeletal animation morph targets animation mixing Use when animating objects playing GLTF animations creating procedural motion or blending animations Three js Animation Quick Start javascript import as THREE from three Simple procedural animation const clock new THREE Clock function animate const delta clock getDelta const elapsed clock getElapsedTime mesh rotation y delta mesh position y Math sin elapsed 0 5 requestAnimationFrame animate renderer render scene camera animate Animation System Overview Three js animation system has three main components 1 AnimationClip Container for keyframe data 2 AnimationMixer Plays animations on a root object 3 AnimationAction Controls playback of a clip AnimationClip Stores keyframe animation data javascript Create animation clip const times 0 1 2 Keyframe times seconds const values 0 1 0 Values at each keyframe const track new THREE NumberKeyframeTrack position y Property path times va.
- **AnimationClip** - Container for keyframe data
- **AnimationMixer** - Plays animations on a root object
- **AnimationAction** - Controls playback of a clip
- **Share clips**: Same AnimationClip can be used on multiple mixers
- **Optimize clips**: Call `clip.optimize()` to remove redundant keyframes
Threejs Animation by the numbers
- 10,360 all-time installs (skills.sh)
- +774 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #61 of 1,881 Marketing & SEO skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
threejs-animation capabilities & compatibility
- Capabilities
- **animationclip** container for keyframe data · **animationmixer** plays animations on a root · **animationaction** controls playback of a cli · **share clips**: same animationclip can be used · **optimize clips**: call `clip.optimize()` to re
- Use cases
- documentation
What threejs-animation says it does
--- name: threejs-animation description: Three.js animation - keyframe animation, skeletal animation, morph targets, animation mixing.
Use when animating objects, playing GLTF animations, creating procedural motion, or blending animations.
**AnimationClip** - Container for keyframe data 2.
**AnimationMixer** - Plays animations on a root object 3.
npx skills add https://github.com/cloudai-x/threejs-skills --skill threejs-animationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 10.4k |
|---|---|
| repo stars | ★ 2.8k |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 9, 2026 |
| Repository | cloudai-x/threejs-skills ↗ |
What problem does threejs-animation solve for developers using this skill?
Three.js animation - keyframe animation, skeletal animation, morph targets, animation mixing. Use when animating objects, playing GLTF animations, creating procedural motion, or blending animations.
Who is it for?
Developers who need threejs-animation patterns described in the cached skill documentation.
Skip if: Skip when docs are empty or the task is outside the skill's documented scope.
When should I use this skill?
Three.js animation - keyframe animation, skeletal animation, morph targets, animation mixing. Use when animating objects, playing GLTF animations, creating procedural motion, or blending animations.
What you get
Actionable workflows and conventions from SKILL.md for threejs-animation.
- Animation loop code
- AnimationMixer setup
- Blended clip playback
By the numbers
- Covers 4 animation types: keyframe, skeletal, morph targets, and mixing
- Includes THREE.Clock and requestAnimationFrame procedural animation example
Files
Three.js Animation
Quick Start
import * as THREE from "three";
// Simple procedural animation
const clock = new THREE.Clock();
function animate() {
const delta = clock.getDelta();
const elapsed = clock.getElapsedTime();
mesh.rotation.y += delta;
mesh.position.y = Math.sin(elapsed) * 0.5;
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();Animation System Overview
Three.js animation system has three main components:
1. AnimationClip - Container for keyframe data 2. AnimationMixer - Plays animations on a root object 3. AnimationAction - Controls playback of a clip
AnimationClip
Stores keyframe animation data.
// Create animation clip
const times = [0, 1, 2]; // Keyframe times (seconds)
const values = [0, 1, 0]; // Values at each keyframe
const track = new THREE.NumberKeyframeTrack(
".position[y]", // Property path
times,
values,
);
const clip = new THREE.AnimationClip("bounce", 2, [track]);KeyframeTrack Types
// Number track (single value)
new THREE.NumberKeyframeTrack(".opacity", times, [1, 0]);
new THREE.NumberKeyframeTrack(".material.opacity", times, [1, 0]);
// Vector track (position, scale)
new THREE.VectorKeyframeTrack(".position", times, [
0,
0,
0, // t=0
1,
2,
0, // t=1
0,
0,
0, // t=2
]);
// Quaternion track (rotation)
const q1 = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0));
const q2 = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, Math.PI, 0));
new THREE.QuaternionKeyframeTrack(
".quaternion",
[0, 1],
[q1.x, q1.y, q1.z, q1.w, q2.x, q2.y, q2.z, q2.w],
);
// Color track
new THREE.ColorKeyframeTrack(".material.color", times, [
1,
0,
0, // red
0,
1,
0, // green
0,
0,
1, // blue
]);
// Boolean track
new THREE.BooleanKeyframeTrack(".visible", [0, 0.5, 1], [true, false, true]);
// String track (for morph targets)
new THREE.StringKeyframeTrack(
".morphTargetInfluences[smile]",
[0, 1],
["0", "1"],
);Interpolation Modes
const track = new THREE.VectorKeyframeTrack(".position", times, values);
// Interpolation
track.setInterpolation(THREE.InterpolateLinear); // Default
track.setInterpolation(THREE.InterpolateSmooth); // Cubic spline
track.setInterpolation(THREE.InterpolateDiscrete); // Step functionAnimationMixer
Plays animations on an object and its descendants.
const mixer = new THREE.AnimationMixer(model);
// Create action from clip
const action = mixer.clipAction(clip);
action.play();
// Update in animation loop
function animate() {
const delta = clock.getDelta();
mixer.update(delta); // Required!
requestAnimationFrame(animate);
renderer.render(scene, camera);
}Mixer Events
mixer.addEventListener("finished", (e) => {
console.log("Animation finished:", e.action.getClip().name);
});
mixer.addEventListener("loop", (e) => {
console.log("Animation looped:", e.action.getClip().name);
});AnimationAction
Controls playback of an animation clip.
const action = mixer.clipAction(clip);
// Playback control
action.play();
action.stop();
action.reset();
action.halt(fadeOutDuration);
// Playback state
action.isRunning();
action.isScheduled();
// Time control
action.time = 0.5; // Current time
action.timeScale = 1; // Playback speed (negative = reverse)
action.paused = false;
// Weight (for blending)
action.weight = 1; // 0-1, contribution to final pose
action.setEffectiveWeight(1);
// Loop modes
action.loop = THREE.LoopRepeat; // Default: loop forever
action.loop = THREE.LoopOnce; // Play once and stop
action.loop = THREE.LoopPingPong; // Alternate forward/backward
action.repetitions = 3; // Number of loops (Infinity default)
// Clamping
action.clampWhenFinished = true; // Hold last frame when done
// Blending
action.blendMode = THREE.NormalAnimationBlendMode;
action.blendMode = THREE.AdditiveAnimationBlendMode;Fade In/Out
// Fade in
action.reset().fadeIn(0.5).play();
// Fade out
action.fadeOut(0.5);
// Crossfade between animations
const action1 = mixer.clipAction(clip1);
const action2 = mixer.clipAction(clip2);
action1.play();
// Later, crossfade to action2
action1.crossFadeTo(action2, 0.5, true);
action2.play();Loading GLTF Animations
Most common source of skeletal animations.
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
const loader = new GLTFLoader();
loader.load("model.glb", (gltf) => {
const model = gltf.scene;
scene.add(model);
// Create mixer
const mixer = new THREE.AnimationMixer(model);
// Get all clips
const clips = gltf.animations;
console.log(
"Available animations:",
clips.map((c) => c.name),
);
// Play first animation
if (clips.length > 0) {
const action = mixer.clipAction(clips[0]);
action.play();
}
// Play specific animation by name
const walkClip = THREE.AnimationClip.findByName(clips, "Walk");
if (walkClip) {
mixer.clipAction(walkClip).play();
}
// Store mixer for update loop
window.mixer = mixer;
});
// Animation loop
function animate() {
const delta = clock.getDelta();
if (window.mixer) window.mixer.update(delta);
requestAnimationFrame(animate);
renderer.render(scene, camera);
}Skeletal Animation
Skeleton and Bones
// Access skeleton from skinned mesh
const skinnedMesh = model.getObjectByProperty("type", "SkinnedMesh");
const skeleton = skinnedMesh.skeleton;
// Access bones
skeleton.bones.forEach((bone) => {
console.log(bone.name, bone.position, bone.rotation);
});
// Find specific bone by name
const headBone = skeleton.bones.find((b) => b.name === "Head");
if (headBone) headBone.rotation.y = Math.PI / 4; // Turn head
// Skeleton helper
const helper = new THREE.SkeletonHelper(model);
scene.add(helper);Programmatic Bone Animation
function animate() {
const time = clock.getElapsedTime();
// Animate bone
const headBone = skeleton.bones.find((b) => b.name === "Head");
if (headBone) {
headBone.rotation.y = Math.sin(time) * 0.3;
}
// Update mixer if also playing clips
mixer.update(clock.getDelta());
}Bone Attachments
// Attach object to bone
const weapon = new THREE.Mesh(weaponGeometry, weaponMaterial);
const handBone = skeleton.bones.find((b) => b.name === "RightHand");
if (handBone) handBone.add(weapon);
// Offset attachment
weapon.position.set(0, 0, 0.5);
weapon.rotation.set(0, Math.PI / 2, 0);Morph Targets
Blend between different mesh shapes.
// Morph targets are stored in geometry
const geometry = mesh.geometry;
console.log("Morph attributes:", Object.keys(geometry.morphAttributes));
// Access morph target influences
mesh.morphTargetInfluences; // Array of weights
mesh.morphTargetDictionary; // Name -> index mapping
// Set morph target by index
mesh.morphTargetInfluences[0] = 0.5;
// Set by name
const smileIndex = mesh.morphTargetDictionary["smile"];
mesh.morphTargetInfluences[smileIndex] = 1;Animating Morph Targets
// Procedural
function animate() {
const t = clock.getElapsedTime();
mesh.morphTargetInfluences[0] = (Math.sin(t) + 1) / 2;
}
// With keyframe animation
const track = new THREE.NumberKeyframeTrack(
".morphTargetInfluences[smile]",
[0, 0.5, 1],
[0, 1, 0],
);
const clip = new THREE.AnimationClip("smile", 1, [track]);
mixer.clipAction(clip).play();Animation Blending
Mix multiple animations together.
// Setup actions
const idleAction = mixer.clipAction(idleClip);
const walkAction = mixer.clipAction(walkClip);
const runAction = mixer.clipAction(runClip);
// Play all with different weights
idleAction.play();
walkAction.play();
runAction.play();
// Set initial weights
idleAction.setEffectiveWeight(1);
walkAction.setEffectiveWeight(0);
runAction.setEffectiveWeight(0);
// Blend based on speed
function updateAnimations(speed) {
if (speed < 0.1) {
idleAction.setEffectiveWeight(1);
walkAction.setEffectiveWeight(0);
runAction.setEffectiveWeight(0);
} else if (speed < 5) {
const t = speed / 5;
idleAction.setEffectiveWeight(1 - t);
walkAction.setEffectiveWeight(t);
runAction.setEffectiveWeight(0);
} else {
const t = Math.min((speed - 5) / 5, 1);
idleAction.setEffectiveWeight(0);
walkAction.setEffectiveWeight(1 - t);
runAction.setEffectiveWeight(t);
}
}Additive Blending
// Base pose
const baseAction = mixer.clipAction(baseClip);
baseAction.play();
// Additive layer (e.g., breathing)
const additiveAction = mixer.clipAction(additiveClip);
additiveAction.blendMode = THREE.AdditiveAnimationBlendMode;
additiveAction.play();
// Convert clip to additive
THREE.AnimationUtils.makeClipAdditive(additiveClip);Animation Utilities
import * as THREE from "three";
// Find clip by name
const clip = THREE.AnimationClip.findByName(clips, "Walk");
// Create subclip
const subclip = THREE.AnimationUtils.subclip(clip, "subclip", 0, 30, 30);
// Convert to additive
THREE.AnimationUtils.makeClipAdditive(clip);
THREE.AnimationUtils.makeClipAdditive(clip, 0, referenceClip);
// Clone clip
const clone = clip.clone();
// Get clip duration
clip.duration;
// Optimize clip (remove redundant keyframes)
clip.optimize();
// Reset clip to first frame
clip.resetDuration();Procedural Animation Patterns
Smooth Damping
// Smooth follow/lerp
const target = new THREE.Vector3();
const current = new THREE.Vector3();
const velocity = new THREE.Vector3();
function smoothDamp(current, target, velocity, smoothTime, deltaTime) {
const omega = 2 / smoothTime;
const x = omega * deltaTime;
const exp = 1 / (1 + x + 0.48 * x * x + 0.235 * x * x * x);
const change = current.clone().sub(target);
const temp = velocity
.clone()
.add(change.clone().multiplyScalar(omega))
.multiplyScalar(deltaTime);
velocity.sub(temp.clone().multiplyScalar(omega)).multiplyScalar(exp);
return target.clone().add(change.add(temp).multiplyScalar(exp));
}
function animate() {
current.copy(smoothDamp(current, target, velocity, 0.3, delta));
mesh.position.copy(current);
}Spring Physics
class Spring {
constructor(stiffness = 100, damping = 10) {
this.stiffness = stiffness;
this.damping = damping;
this.position = 0;
this.velocity = 0;
this.target = 0;
}
update(dt) {
const force = -this.stiffness * (this.position - this.target);
const dampingForce = -this.damping * this.velocity;
this.velocity += (force + dampingForce) * dt;
this.position += this.velocity * dt;
return this.position;
}
}
const spring = new Spring(100, 10);
spring.target = 1;
function animate() {
mesh.position.y = spring.update(delta);
}Oscillation
function animate() {
const t = clock.getElapsedTime();
// Sine wave
mesh.position.y = Math.sin(t * 2) * 0.5;
// Bouncing
mesh.position.y = Math.abs(Math.sin(t * 3)) * 2;
// Circular motion
mesh.position.x = Math.cos(t) * 2;
mesh.position.z = Math.sin(t) * 2;
// Figure 8
mesh.position.x = Math.sin(t) * 2;
mesh.position.z = Math.sin(t * 2) * 1;
}Performance Tips
1. Share clips: Same AnimationClip can be used on multiple mixers 2. Optimize clips: Call clip.optimize() to remove redundant keyframes 3. Disable when off-screen: Stop mixer updates for invisible objects 4. Use LOD for animations: Simpler rigs for distant characters 5. Limit active mixers: Each mixer.update() has a cost
// Pause animation when not visible
mesh.onBeforeRender = () => {
action.paused = false;
};
mesh.onAfterRender = () => {
// Check if will be visible next frame
if (!isInFrustum(mesh)) {
action.paused = true;
}
};
// Cache clips
const clipCache = new Map();
function getClip(name) {
if (!clipCache.has(name)) {
clipCache.set(name, loadClip(name));
}
return clipCache.get(name);
}See Also
threejs-loaders- Loading animated GLTF modelsthreejs-fundamentals- Clock and animation loopthreejs-shaders- Vertex animation in shaders
Related skills
Forks & variants (1)
Threejs Animation has 1 known copy in the catalog totaling 261 installs. They canonicalize to this original listing.
- calesthio - 261 installs
How it compares
Choose threejs-animation for raw Three.js clip control; use higher-level React Three Fiber skills when the stack is R3F-based.
FAQ
What does threejs-animation do?
Three.js animation - keyframe animation, skeletal animation, morph targets, animation mixing. Use when animating objects, playing GLTF animations, creating procedural motion, or blending animations.
When should I use threejs-animation?
Three.js animation - keyframe animation, skeletal animation, morph targets, animation mixing. Use when animating objects, playing GLTF animations, creating procedural motion, or blending animations.
Is threejs-animation safe to install?
Review the Security Audits panel on this page before installing in production.