Communitygithub.com

Bailipa/EZTor_FULLBLOOD

Use when playing animations, crossfading between animation states, or loading skeletal animations from GLTF in Three.js. Prevents the common mistake of not calling mixer.update(delta) every frame, wrong crossfade setup, or missing Clock. Covers AnimationMixer, AnimationClip, AnimationAction, KeyframeTrack, crossfade, blending. Keywords: animation, AnimationMixer, AnimationClip, AnimationAction, crossfade, skeletal, GLTF animation, keyframe, blend, Clock, camera animation, smooth camera, fly to, tween, GSAP.

O que é EZTor_FULLBLOOD?

EZTor_FULLBLOOD is a Claude Code agent skill that use when playing animations, crossfading between animation states, or loading skeletal animations from GLTF in Three.js. Prevents the common mistake of not calling mixer.update(delta) every frame, wrong crossfade setup, or missing Clock. Covers AnimationMixer, AnimationClip, AnimationAction, KeyframeTrack, crossfade, blending. Keywords: animation, AnimationMixer, AnimationClip, AnimationAction, crossfade, skeletal, GLTF animation, keyframe, blend, Clock, camera animation, smooth camera, fly to, tween, GSAP.

Funciona com✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Bailipa/EZTor_FULLBLOOD/tree/HEAD/.opencode/skills/threejs/threejs-impl/threejs-impl-animation

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

threejs-impl-animation

Quick Reference

Architecture

AnimationClip        (data: array of KeyframeTrack objects)
  └── AnimationAction  (playback controller: play, pause, fade, crossfade)
        └── AnimationMixer (master scheduler: one per animated root object)
              └── Clock    (provides delta time for mixer.update)

ALWAYS create exactly ONE AnimationMixer per animated root object. ALWAYS call mixer.update(delta) every frame inside the render loop. NEVER instantiate AnimationAction directly -- ALWAYS use mixer.clipAction(clip).

Essential Imports

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

Minimal Animation Setup

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

const clock = new THREE.Clock();
let mixer;

const loader = new GLTFLoader();
loader.load('character.glb', (gltf) => {
  scene.add(gltf.scene);
  mixer = new THREE.AnimationMixer(gltf.scene);

  // Play all animations from the GLTF file
  gltf.animations.forEach((clip) => {
    mixer.clipAction(clip).play();
  });
});

function animate() {
  const delta = clock.getDelta();
  if (mixer) mixer.update(delta);
  renderer.render(scene, camera);
}
renderer.setAnimationLoop(animate);

Critical Warnings

NEVER forget to call mixer.update(delta) in the render loop -- animations will NOT play without it.

NEVER use new Date() or performance.now() to compute delta manually -- ALWAYS use THREE.Clock or renderer.setAnimationLoop which provides stable frame timing.

NEVER call mixer.clipAction(clip) repeatedly in the render loop -- it caches internally, but the lookup is unnecessary overhead. ALWAYS store the returned action in a variable.

NEVER call .play() every frame -- call it ONCE to start playback. Calling .play() again on an already-playing action has no effect, but it signals misunderstanding.

ALWAYS call .reset() before .play() when restarting a stopped or finished action, or the action may resume from its last position.

ALWAYS set action.clampWhenFinished = true when using LoopOnce -- otherwise the action resets to the first frame when finished.


AnimationMixer

The master scheduler that drives all animation actions for a single object hierarchy.

Constructor

const mixer = new THREE.AnimationMixer(rootObject);

rootObject is the root Object3D of the animated model (typically gltf.scene).

Properties

PropertyTypeDefaultDescription
.timenumber0Global mixer time in seconds
.timeScalenumber1Global speed multiplier; 0 pauses ALL actions

Methods

MethodReturnsDescription
.clipAction(clip, root?, blendMode?)AnimationActionReturns or creates an action for the clip
.existingAction(clip, root?)AnimationAction | nullReturns previously created action or null
.update(delta)thisAdvances mixer by delta seconds -- MUST call every frame
.setTime(seconds)thisSets global time, updates all actions
.stopAllAction()thisDeactivates all scheduled actions
.getRoot()Object3DReturns the mixer's root object
.uncacheAction(clip, root?)voidDeallocates cached action
.uncacheClip(clip)voidDeallocates clip data
.uncacheRoot(root)voidDeallocates root object data

Events

Listen via mixer.addEventListener(type, callback):

EventFires When
'finished'Action completes (ONLY with LoopOnce + clampWhenFinished = true)
'loop'Action completes a loop iteration

Event object properties: { action, loopDelta, type }.

Blend Modes

Pass as the third argument to mixer.clipAction(clip, root, blendMode):

ConstantBehavior
THREE.NormalAnimationBlendModeStandard blending (default)
THREE.AdditiveAnimationBlendModeLayered on top of base animation

AnimationAction

Controls playback of a single animation clip. NEVER instantiate directly.

Properties

PropertyTypeDefaultDescription
.blendModenumberNormalAnimationBlendModeBlending strategy
.clampWhenFinishedbooleanfalsePause at last frame when done
.enabledbooleantrueDisable without resetting
.loopnumberLoopRepeatLoop mode
.pausedbooleanfalseFreeze playback
.repetitionsnumberInfinityLoop count
.timenumber0Local time in seconds
.timeScalenumber1Speed: 0 pauses, negative reverses
.weightnumber1Blend influence [0, 1]
.zeroSlopeAtEndbooleantrueSmooth interpolation at loop end
.zeroSlopeAtStartbooleantrueSmooth interpolation at loop start

Loop Modes

ConstantBehavior
THREE.LoopOncePlays once, stops
THREE.LoopRepeatRestarts from beginning each loop
THREE.LoopPingPongAlternates forward/backward

Playback Methods

MethodDescription
.play()Start playback
.stop()Stop and reset to start
.reset()Reset time, weight, speed to initial state
.startAt(mixerTime)Delay start until specified mixer time

Fading and Crossfade Methods

MethodDescription
.fadeIn(duration)Fade weight from 0 to 1
.fadeOut(duration)Fade weight from 1 to 0
.crossFadeFrom(fadeOutAction, duration, warp)Crossfade from another action into this one
.crossFadeTo(fadeInAction, duration, warp)Crossfade from this action to another
.stopFading()Cancel any active fade

Speed and Timing Methods

MethodDescription
.halt(duration)Decelerate timeScale to 0 over duration
.warp(startScale, endScale, duration)Smoothly transition playback speed
.stopWarping()Cancel any active warp
.setDuration(seconds)Adjust timeScale so one loop takes exactly seconds
.setEffectiveTimeScale(scale)Set effective time scale
.setEffectiveWeight(weight)Set effective weight
.setLoop(mode, repetitions)Set loop mode and count
.syncWith(otherAction)Synchronize time with another action

Query Methods

MethodReturnsDescription
.isRunning()booleantrue only if actively playing
.isScheduled()booleantrue if .play() was called
.getClip()AnimationClipThe associated clip
.getMixer()AnimationMixerThe owning mixer
.getRoot()Object3DThe root object
.getEffectiveTimeScale()numberComputed time scale
.getEffectiveWeight()numberComputed weight

AnimationClip

A reusable set of keyframe tracks. Typically loaded from GLTF files.

Constructor

const clip = new THREE.AnimationClip(name, duration, tracks, blendMode);
  • name -- string identifier (GLTF clips use names from the file)
  • duration -- seconds; -1 to auto-calculate from tracks
  • tracks -- array of KeyframeTrack objects
  • blendMode -- optional blend mode constant

Key Static Methods

MethodDescription
AnimationClip.findByName(arrayOrObject, name)Look up clip by name
AnimationClip.CreateFromMorphTargetSequence(name, targets, fps, noLoop)Create clip from morph targets
AnimationClip.parse(json)Deserialize from JSON

KeyframeTrack Types

Track TypeValue TypeUse Case
VectorKeyframeTrackVector3Position, scale
QuaternionKeyframeTrackQuaternionRotation (uses slerp)
NumberKeyframeTracknumberOpacity, intensity
BooleanKeyframeTrackbooleanVisibility toggles
ColorKeyframeTrackColorColor animation
StringKeyframeTrackstringDiscrete string values

Interpolation Modes

ConstantBehavior
THREE.InterpolateDiscreteStep function, no smoothing
THREE.InterpolateLinearLinear interpolation (default)
THREE.InterpolateSmoothCubic spline interpolation

PropertyBinding Path Format

"meshName.position"                    // animate position
"meshName.material.opacity"            // animate material property
"meshName.morphTargetInfluences[0]"    // animate morph target
"boneName.quaternion"                  // animate bone rotation

Clock

Constructor

const clock = new THREE.Clock(autoStart); // autoStart defaults to true

Methods

MethodReturnsDescription
.getDelta()numberSeconds since last getDelta() call
.getElapsedTime()numberTotal elapsed time in seconds
.start()voidStart the clock
.stop()voidStop without resetting

Crossfade Pattern (Character State Machine)

const actions = {};
gltf.animations.forEach((clip) => {
  actions[clip.name] = mixer.clipAction(clip);
});

let currentAction = actions['Idle'];
currentAction.play();

function switchAction(toName, duration = 0.5) {
  const toAction = actions[toName];
  toAction.reset();
  toAction.setEffectiveTimeScale(1);
  toAction.setEffectiveWeight(1);
  toAction.crossFadeFrom(currentAction, duration, true);
  toAction.play();
  currentAction = toAction;
}

ALWAYS call .reset() on the incoming action before crossfading. ALWAYS store the current action reference for the next transition.


Additive Animation Blending

const baseAction = mixer.clipAction(baseClip);
const additiveAction = mixer.clipAction(
  additiveClip, undefined, THREE.AdditiveAnimationBlendMode
);

baseAction.play();
additiveAction.play();
additiveAction.setEffectiveWeight(0.5);

Use additive blending for layered effects: breathing, damage reactions, aim offsets.


Morph Target Animation

// Manual control
mesh.morphTargetInfluences[0] = Math.sin(elapsed) * 0.5 + 0.5;

// Via GLTF animation clip (preferred)
const morphAction = mixer.clipAction(morphClip);
morphAction.play();

Reference Links

Official Sources

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

Bailipa/EZTor_FULLBLOOD

Create video compositions, animations, title cards, overlays, captions, voiceovers, audio-reactive visuals, and scene transitions in HyperFrames HTML. Use when asked to build any HTML-based video content, add captions or subtitles synced to audio, generate text-to-speech narration, create audio-reactive animation (beat sync, glow, pulse driven by music), add animated text highlighting (marker sweeps, hand-drawn circles, burst lines, scribble, sketchout), or add transitions between scenes (crossfades, wipes, reveals, shader transitions). Covers composition authoring, timing, media, and the full video production workflow. For CLI commands (init, lint, preview, render, transcribe, tts) see the hyperframes-cli skill.

Bailipa/EZTor_FULLBLOOD

A single-frame motion-design composition with looping CSS animations — rotating type ring, animated globe, ticking timer, parallax labels. Renders as a hero video poster you can hand straight to HyperFrames or any keyframe-based exporter. Use when the brief asks for "motion design", "animated hero", "loop", "video poster", "title card", or pairs Open Claude Design with HyperFrames for a kinetic export.

Bailipa/EZTor_FULLBLOOD

A pixel / sprite-style animated explainer slide — full-bleed cream stage, bold display year, animated pixel-art mascot (e.g. Hanafuda card, mushroom, or 8-bit console), kinetic Japanese display type, ticking timeline ribbon. Reads like a single frame of an educational motion video — looping CSS keyframes, no JS, ready to be screen-recorded into a vertical video. Use when the brief asks for a "sprite animation", "pixel-art video", "8-bit explainer", "history of X explainer", "kinetic typography history", "Nintendo-style", "精灵图动画", "像素动画", or "复古动画".

Bailipa/EZTor_FULLBLOOD

Short-form video generation skill — 3-10 second clips for product reveals, motion teasers, ambient loops. Defaults to Seedance 2 but works the same with Kling 3 / 4, Veo 3 or Sora 2. Output is one MP4 saved to the project folder. When the workspace also ships an interactive-video / hyperframes skill, prefer composing several short shots into a single timeline rather than one long monolithic clip.

Habilidades Relacionadas