acestep
AI music generation with ACE-Step 1.5 — background music, vocal tracks, covers, stem extraction for video production. Use when generating music, soundtracks,…
Three.js animation - keyframe animation, skeletal animation, morph targets, animation mixing. Use when animating objects, playing GLTF animations, creating procedural motion, or blending animations.
$ npx -y skills add calesthio/OpenMontage --skill threejs-animation --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/threejs-animationContext preview
The summary Claude sees to decide when to auto-load 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.
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.
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();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
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]);// 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"],
);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 functionPlays 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.addEventListener("finished", (e) => {
console.log("Animation finished:", e.action.getClip().name);
});
mixer.addEventListener("loop", (e) => {
console.log("Animation looped:", e.action.getClip().name);
});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 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();
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);
}// 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.finWorld's first open-source, agentic video production system. 12 production pipelines, 100+ tools, 700+ agent skill and production-knowledge files. Turn your AI coding assistant into a full video production studio.
Repo: calesthio/OpenMontage
AI music generation with ACE-Step 1.5 — background music, vocal tracks, covers, stem extraction for video production. Use when generating music, soundtracks,…
Build voice AI agents with ElevenLabs. Use when creating voice assistants, customer service bots, interactive voice characters, or any real-time voice…
Generate AI videos from text prompts using multiple provider gateways. Use when: (1) Generating videos from text descriptions, (2) Creating AI-generated video…
Create AI avatar videos with precise control over avatars, voices, scripts, scenes, and backgrounds using HeyGen's v2 API. Use when: (1) Choosing a specific…
Transcribe audio to text using Azure AI Speech (Fast Transcription REST API). Use when converting audio/video to text, generating subtitles, or processing…
Generate neural narration audio using Azure AI Speech (REST text-to-speech). Use when synthesizing voiceovers or narration in OpenMontage. Optional cloud TTS…