Skip to main content

threejs-animation

"Implement — Three.js animation - keyframe animation, skeletal animation, morph targets, animation mixing. Use when animating"

Zur Installation springen

Quellinformationen

Repository
thiagofernandes1987-create/APEX
Letzte Quellaktivität
18. April 2026 um 09:35
Erkannte Sprache von SKILL.md
Englisch
Sterne
2
Forks
0

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
threejs-animation
description
"Implement — Three.js animation - keyframe animation, skeletal animation, morph targets, animation mixing. Use when animating"
# Three.js Animation ## When to Use - You need to animate objects, rigs, morph targets, or imported GLTF animations in Three.js. - The task involves mixers, clips, keyframes, procedural motion, or animation blending. - You are building motion behavior in a Three.js scene rather than just static rendering. ## Quick Start ```javascript import * as THREE from "three"; // Simple procedural animation with Timer (recommended in r183) const timer = new THREE.Timer(); renderer.setAnimationLoop(() => { timer.update(); const delta = timer.getDelta(); const elapsed = timer.getElapsed(); mesh.rotation.y += delta; mesh.position.y = Math.sin(elapsed) * 0.5; renderer.render(scene, camera); }); ``` **Note:** `THREE.Timer` is recommended over `THREE.Clock` as of r183. Timer pauses when the page is hidden and has a cleaner API. `THREE.Clock` still works but is considered legacy. ## 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, values, ); const clip = new THREE.AnimationClip("bounce", 2, [track]); ``` ### KeyframeTrack Types ```javascript // 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 ```javascript 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 function ``` ### BezierInterpolant (r183) Three.js r183 adds `THREE.BezierInterpolant` for bezier curve interpolation in keyframe tracks, enabling smoother animation curves with tangent control. ## AnimationMixer Plays animations on an object and its descendants. ```javascript 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 ```javascript 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. ```javascript 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 ```javascript // 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. ```javascript 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 ```javascript // 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 ```javascript 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 ```javascript // 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. ```javascript // 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 ```javascript // 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. ```javascript // 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 ```javascript // 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 ```javascript 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 ```javascript // 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))
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen