Files
2026-04-30 02:14:25 +00:00

1423 lines
46 KiB
JavaScript

/**
* Avatar Animation System
* Defines all animation sequences for the avatar system across 4 rendering modes.
*/
(function() {
'use strict';
// =============================================================================
// RENDERING MODES
// =============================================================================
var MODES = {
HEAD_ONLY: { width: 64, height: 64, showBody: false, showShoulders: false },
HEAD_AND_SHOULDERS: { width: 64, height: 96, showBody: false, showShoulders: true },
UPPER_BODY: { width: 64, height: 128, showBody: 'upper', showShoulders: true },
FULL_BODY: { width: 64, height: 160, showBody: 'full', showShoulders: true },
};
// =============================================================================
// ACCESSORY ANIMATION RULES
// =============================================================================
var ACCESSORY_ANIMATION = {
headwear: {
followHead: true,
bounceMultiplier: 1.2,
rotationDamping: 0.8,
},
eyewear: {
followHead: true,
bounceMultiplier: 1.0,
rotationDamping: 1.0,
},
effects: {
independent: true,
particleSpeed: 1.0,
},
};
// =============================================================================
// DEFAULT FRAME TRANSFORM
// =============================================================================
function defaultFrame() {
return {
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 0 },
leftArm: { rotation: 0, x: 0, y: 0 },
rightArm: { rotation: 0, x: 0, y: 0 },
leftLeg: { rotation: 0, x: 0, y: 0 },
rightLeg: { rotation: 0, x: 0, y: 0 },
accessories: { bounce: 0, rotation: 0 },
};
}
// =============================================================================
// HEAD_ONLY ANIMATIONS (5 animations)
// =============================================================================
var HEAD_ONLY_ANIMATIONS = [
// 1. bob - Gentle up/down bobbing
{
id: 'bob',
name: 'Bob',
modes: ['HEAD_ONLY'],
loop: true,
frameCount: 3,
frameDuration: 150,
frames: [
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
accessories: { bounce: 0, rotation: 0 },
},
{
head: { x: 0, y: -2, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
accessories: { bounce: -2, rotation: 0 },
},
{
head: { x: 0, y: -1, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
accessories: { bounce: -1, rotation: 0 },
},
],
},
// 2. flap - For Flappy Bird style (ears/hair wiggle)
{
id: 'flap',
name: 'Flap',
modes: ['HEAD_ONLY'],
loop: true,
frameCount: 2,
frameDuration: 80,
frames: [
{
head: { x: 0, y: 0, rotation: -3, scaleX: 1.05, scaleY: 0.95 },
eyes: { scaleY: 1 },
accessories: { bounce: 2, rotation: -5 },
},
{
head: { x: 0, y: -3, rotation: 3, scaleX: 0.95, scaleY: 1.05 },
eyes: { scaleY: 1 },
accessories: { bounce: -3, rotation: 5 },
},
],
},
// 3. blink - Eye blink
{
id: 'blink',
name: 'Blink',
modes: ['HEAD_ONLY'],
loop: false,
frameCount: 3,
frameDuration: 60,
frames: [
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
accessories: { bounce: 0, rotation: 0 },
},
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 0.1 },
accessories: { bounce: 0, rotation: 0 },
},
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
accessories: { bounce: 0, rotation: 0 },
},
],
},
// 4. celebrate - Happy bounce
{
id: 'celebrate',
name: 'Celebrate',
modes: ['HEAD_ONLY'],
loop: false,
frameCount: 4,
frameDuration: 100,
frames: [
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 0.9 },
eyes: { scaleY: 1 },
accessories: { bounce: 0, rotation: 0 },
},
{
head: { x: 0, y: -6, rotation: 5, scaleX: 1, scaleY: 1.1 },
eyes: { scaleY: 1 },
accessories: { bounce: -8, rotation: 5 },
},
{
head: { x: 0, y: -3, rotation: -3, scaleX: 1, scaleY: 1.05 },
eyes: { scaleY: 1 },
accessories: { bounce: -4, rotation: -3 },
},
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
accessories: { bounce: 0, rotation: 0 },
},
],
},
// 5. hurt - Damage reaction
{
id: 'hurt',
name: 'Hurt',
modes: ['HEAD_ONLY'],
loop: false,
frameCount: 2,
frameDuration: 80,
frames: [
{
head: { x: -3, y: 0, rotation: -5, scaleX: 1.1, scaleY: 0.9 },
eyes: { scaleY: 0.5 },
accessories: { bounce: 0, rotation: -8 },
},
{
head: { x: 3, y: 0, rotation: 5, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
accessories: { bounce: 0, rotation: 5 },
},
],
},
];
// =============================================================================
// HEAD_AND_SHOULDERS ANIMATIONS (6 animations)
// =============================================================================
var HEAD_AND_SHOULDERS_ANIMATIONS = [
// 1. idle - Subtle breathing
{
id: 'idle',
name: 'Idle',
modes: ['HEAD_AND_SHOULDERS'],
loop: true,
frameCount: 3,
frameDuration: 400,
frames: [
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 0 },
accessories: { bounce: 0, rotation: 0 },
},
{
head: { x: 0, y: -1, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 1, rotation: 0 },
accessories: { bounce: -1, rotation: 0 },
},
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 0 },
accessories: { bounce: 0, rotation: 0 },
},
],
},
// 2. turn-left - Head turns left
{
id: 'turn-left',
name: 'Turn Left',
modes: ['HEAD_AND_SHOULDERS'],
loop: false,
frameCount: 2,
frameDuration: 100,
frames: [
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 0 },
accessories: { bounce: 0, rotation: 0 },
},
{
head: { x: -2, y: 0, rotation: -15, scaleX: 0.95, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: -3 },
accessories: { bounce: 0, rotation: -12 },
},
],
},
// 3. turn-right - Head turns right
{
id: 'turn-right',
name: 'Turn Right',
modes: ['HEAD_AND_SHOULDERS'],
loop: false,
frameCount: 2,
frameDuration: 100,
frames: [
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 0 },
accessories: { bounce: 0, rotation: 0 },
},
{
head: { x: 2, y: 0, rotation: 15, scaleX: 0.95, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 3 },
accessories: { bounce: 0, rotation: 12 },
},
],
},
// 4. look-up - Head tilts up
{
id: 'look-up',
name: 'Look Up',
modes: ['HEAD_AND_SHOULDERS'],
loop: false,
frameCount: 2,
frameDuration: 100,
frames: [
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 0 },
accessories: { bounce: 0, rotation: 0 },
},
{
head: { x: 0, y: -3, rotation: -10, scaleX: 1, scaleY: 0.95 },
eyes: { scaleY: 1.1 },
body: { x: 0, y: 1, rotation: 0 },
accessories: { bounce: -4, rotation: -8 },
},
],
},
// 5. celebrate - Bounce and smile
{
id: 'celebrate',
name: 'Celebrate',
modes: ['HEAD_AND_SHOULDERS'],
loop: false,
frameCount: 3,
frameDuration: 120,
frames: [
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 0.9 },
eyes: { scaleY: 1 },
body: { x: 0, y: 2, rotation: 0 },
accessories: { bounce: 0, rotation: 0 },
},
{
head: { x: 0, y: -8, rotation: 5, scaleX: 1.05, scaleY: 1.1 },
eyes: { scaleY: 0.8 },
body: { x: 0, y: -2, rotation: 3 },
accessories: { bounce: -10, rotation: 5 },
},
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 0 },
accessories: { bounce: 0, rotation: 0 },
},
],
},
// 6. hurt - Recoil
{
id: 'hurt',
name: 'Hurt',
modes: ['HEAD_AND_SHOULDERS'],
loop: false,
frameCount: 2,
frameDuration: 100,
frames: [
{
head: { x: -4, y: 2, rotation: -10, scaleX: 1.1, scaleY: 0.9 },
eyes: { scaleY: 0.3 },
body: { x: -2, y: 2, rotation: -5 },
accessories: { bounce: 3, rotation: -15 },
},
{
head: { x: 2, y: 0, rotation: 5, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 1, y: 0, rotation: 2 },
accessories: { bounce: 0, rotation: 5 },
},
],
},
];
// =============================================================================
// UPPER_BODY ANIMATIONS (8 animations)
// =============================================================================
var UPPER_BODY_ANIMATIONS = [
// 1. idle - Breathing with arm sway
{
id: 'idle',
name: 'Idle',
modes: ['UPPER_BODY'],
loop: true,
frameCount: 3,
frameDuration: 400,
frames: [
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 0 },
leftArm: { rotation: 0, x: 0, y: 0 },
rightArm: { rotation: 0, x: 0, y: 0 },
accessories: { bounce: 0, rotation: 0 },
},
{
head: { x: 0, y: -1, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 1, rotation: 0 },
leftArm: { rotation: 2, x: 0, y: 0 },
rightArm: { rotation: -2, x: 0, y: 0 },
accessories: { bounce: -1, rotation: 0 },
},
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 0 },
leftArm: { rotation: 0, x: 0, y: 0 },
rightArm: { rotation: 0, x: 0, y: 0 },
accessories: { bounce: 0, rotation: 0 },
},
],
},
// 2. wave - Wave one arm
{
id: 'wave',
name: 'Wave',
modes: ['UPPER_BODY'],
loop: false,
frameCount: 4,
frameDuration: 120,
frames: [
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 0 },
leftArm: { rotation: 0, x: 0, y: 0 },
rightArm: { rotation: -45, x: 0, y: -5 },
accessories: { bounce: 0, rotation: 0 },
},
{
head: { x: 0, y: 0, rotation: 3, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 0.9 },
body: { x: 0, y: 0, rotation: 2 },
leftArm: { rotation: 0, x: 0, y: 0 },
rightArm: { rotation: -120, x: 5, y: -10 },
accessories: { bounce: 0, rotation: 3 },
},
{
head: { x: 0, y: 0, rotation: 5, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 0.85 },
body: { x: 0, y: 0, rotation: 3 },
leftArm: { rotation: 0, x: 0, y: 0 },
rightArm: { rotation: -90, x: 8, y: -12 },
accessories: { bounce: 0, rotation: 5 },
},
{
head: { x: 0, y: 0, rotation: 3, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 0.9 },
body: { x: 0, y: 0, rotation: 2 },
leftArm: { rotation: 0, x: 0, y: 0 },
rightArm: { rotation: -120, x: 5, y: -10 },
accessories: { bounce: 0, rotation: 3 },
},
],
},
// 3. point - Point forward
{
id: 'point',
name: 'Point',
modes: ['UPPER_BODY'],
loop: false,
frameCount: 3,
frameDuration: 100,
frames: [
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 0 },
leftArm: { rotation: 0, x: 0, y: 0 },
rightArm: { rotation: 0, x: 0, y: 0 },
accessories: { bounce: 0, rotation: 0 },
},
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 5 },
leftArm: { rotation: 10, x: 0, y: 0 },
rightArm: { rotation: -90, x: 10, y: 0 },
accessories: { bounce: 0, rotation: 0 },
},
{
head: { x: 1, y: 0, rotation: 3, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1.1 },
body: { x: 1, y: 0, rotation: 8 },
leftArm: { rotation: 15, x: 0, y: 0 },
rightArm: { rotation: -85, x: 15, y: 0 },
accessories: { bounce: 0, rotation: 3 },
},
],
},
// 4. steer-left - Lean left for racing
{
id: 'steer-left',
name: 'Steer Left',
modes: ['UPPER_BODY'],
loop: false,
frameCount: 2,
frameDuration: 80,
frames: [
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 0 },
leftArm: { rotation: -30, x: -5, y: 0 },
rightArm: { rotation: -30, x: -5, y: 0 },
accessories: { bounce: 0, rotation: 0 },
},
{
head: { x: -3, y: 0, rotation: -12, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: -2, y: 0, rotation: -10 },
leftArm: { rotation: -45, x: -8, y: -2 },
rightArm: { rotation: -15, x: -3, y: 2 },
accessories: { bounce: 0, rotation: -10 },
},
],
},
// 5. steer-right - Lean right for racing
{
id: 'steer-right',
name: 'Steer Right',
modes: ['UPPER_BODY'],
loop: false,
frameCount: 2,
frameDuration: 80,
frames: [
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 0 },
leftArm: { rotation: 30, x: 5, y: 0 },
rightArm: { rotation: 30, x: 5, y: 0 },
accessories: { bounce: 0, rotation: 0 },
},
{
head: { x: 3, y: 0, rotation: 12, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 2, y: 0, rotation: 10 },
leftArm: { rotation: 15, x: 3, y: 2 },
rightArm: { rotation: 45, x: 8, y: -2 },
accessories: { bounce: 0, rotation: 10 },
},
],
},
// 6. shoot - Arm extends forward
{
id: 'shoot',
name: 'Shoot',
modes: ['UPPER_BODY'],
loop: false,
frameCount: 3,
frameDuration: 60,
frames: [
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 0 },
leftArm: { rotation: 0, x: 0, y: 0 },
rightArm: { rotation: -45, x: 0, y: 0 },
accessories: { bounce: 0, rotation: 0 },
},
{
head: { x: -1, y: 0, rotation: -2, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1.1 },
body: { x: -1, y: 0, rotation: -3 },
leftArm: { rotation: 5, x: -2, y: 0 },
rightArm: { rotation: -90, x: 15, y: 0 },
accessories: { bounce: 0, rotation: -2 },
},
{
head: { x: -2, y: 1, rotation: -3, scaleX: 1.02, scaleY: 0.98 },
eyes: { scaleY: 1 },
body: { x: -2, y: 1, rotation: -5 },
leftArm: { rotation: 10, x: -3, y: 1 },
rightArm: { rotation: -85, x: 12, y: 2 },
accessories: { bounce: 1, rotation: -3 },
},
],
},
// 7. celebrate - Arms up celebration
{
id: 'celebrate',
name: 'Celebrate',
modes: ['UPPER_BODY'],
loop: false,
frameCount: 4,
frameDuration: 120,
frames: [
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 0.9 },
eyes: { scaleY: 1 },
body: { x: 0, y: 2, rotation: 0 },
leftArm: { rotation: 0, x: 0, y: 0 },
rightArm: { rotation: 0, x: 0, y: 0 },
accessories: { bounce: 0, rotation: 0 },
},
{
head: { x: 0, y: -8, rotation: 0, scaleX: 1, scaleY: 1.1 },
eyes: { scaleY: 0.8 },
body: { x: 0, y: -4, rotation: 0 },
leftArm: { rotation: -120, x: -5, y: -10 },
rightArm: { rotation: 120, x: 5, y: -10 },
accessories: { bounce: -10, rotation: 0 },
},
{
head: { x: 0, y: -6, rotation: 5, scaleX: 1, scaleY: 1.05 },
eyes: { scaleY: 0.85 },
body: { x: 0, y: -2, rotation: 3 },
leftArm: { rotation: -135, x: -8, y: -12 },
rightArm: { rotation: 135, x: 8, y: -12 },
accessories: { bounce: -8, rotation: 5 },
},
{
head: { x: 0, y: -6, rotation: -5, scaleX: 1, scaleY: 1.05 },
eyes: { scaleY: 0.85 },
body: { x: 0, y: -2, rotation: -3 },
leftArm: { rotation: -130, x: -6, y: -11 },
rightArm: { rotation: 130, x: 6, y: -11 },
accessories: { bounce: -8, rotation: -5 },
},
],
},
// 8. hurt - Recoil backwards
{
id: 'hurt',
name: 'Hurt',
modes: ['UPPER_BODY'],
loop: false,
frameCount: 2,
frameDuration: 100,
frames: [
{
head: { x: -5, y: 3, rotation: -15, scaleX: 1.1, scaleY: 0.9 },
eyes: { scaleY: 0.2 },
body: { x: -3, y: 3, rotation: -10 },
leftArm: { rotation: 30, x: -5, y: 5 },
rightArm: { rotation: 45, x: -3, y: 5 },
accessories: { bounce: 5, rotation: -20 },
},
{
head: { x: 2, y: 0, rotation: 5, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 0.8 },
body: { x: 1, y: 0, rotation: 3 },
leftArm: { rotation: 10, x: 0, y: 0 },
rightArm: { rotation: -10, x: 0, y: 0 },
accessories: { bounce: 0, rotation: 5 },
},
],
},
];
// =============================================================================
// FULL_BODY ANIMATIONS (12 animations)
// =============================================================================
var FULL_BODY_ANIMATIONS = [
// 1. idle - Standing breathing
{
id: 'idle',
name: 'Idle',
modes: ['FULL_BODY'],
loop: true,
frameCount: 3,
frameDuration: 400,
frames: [
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 0 },
leftArm: { rotation: 0, x: 0, y: 0 },
rightArm: { rotation: 0, x: 0, y: 0 },
leftLeg: { rotation: 0, x: 0, y: 0 },
rightLeg: { rotation: 0, x: 0, y: 0 },
accessories: { bounce: 0, rotation: 0 },
},
{
head: { x: 0, y: -1, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 1, rotation: 0 },
leftArm: { rotation: 2, x: 0, y: 0 },
rightArm: { rotation: -2, x: 0, y: 0 },
leftLeg: { rotation: 0, x: 0, y: 0 },
rightLeg: { rotation: 0, x: 0, y: 0 },
accessories: { bounce: -1, rotation: 0 },
},
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 0 },
leftArm: { rotation: 0, x: 0, y: 0 },
rightArm: { rotation: 0, x: 0, y: 0 },
leftLeg: { rotation: 0, x: 0, y: 0 },
rightLeg: { rotation: 0, x: 0, y: 0 },
accessories: { bounce: 0, rotation: 0 },
},
],
},
// 2. walk - Walk cycle with leg/arm swing
{
id: 'walk',
name: 'Walk Cycle',
modes: ['FULL_BODY'],
loop: true,
frameCount: 4,
frameDuration: 100,
frames: [
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 0 },
leftArm: { rotation: 15, x: 0, y: 0 },
rightArm: { rotation: -15, x: 0, y: 0 },
leftLeg: { rotation: -20, x: 0, y: 0 },
rightLeg: { rotation: 20, x: 0, y: -2 },
accessories: { bounce: 0, rotation: 0 },
},
{
head: { x: 0, y: -1, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: -1, rotation: 0 },
leftArm: { rotation: 0, x: 0, y: 0 },
rightArm: { rotation: 0, x: 0, y: 0 },
leftLeg: { rotation: 0, x: 0, y: -2 },
rightLeg: { rotation: 0, x: 0, y: 0 },
accessories: { bounce: -1, rotation: 0 },
},
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 0 },
leftArm: { rotation: -15, x: 0, y: 0 },
rightArm: { rotation: 15, x: 0, y: 0 },
leftLeg: { rotation: 20, x: 0, y: -2 },
rightLeg: { rotation: -20, x: 0, y: 0 },
accessories: { bounce: 0, rotation: 0 },
},
{
head: { x: 0, y: -1, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: -1, rotation: 0 },
leftArm: { rotation: 0, x: 0, y: 0 },
rightArm: { rotation: 0, x: 0, y: 0 },
leftLeg: { rotation: 0, x: 0, y: 0 },
rightLeg: { rotation: 0, x: 0, y: -2 },
accessories: { bounce: -1, rotation: 0 },
},
],
},
// 3. run - Faster with more movement
{
id: 'run',
name: 'Run Cycle',
modes: ['FULL_BODY'],
loop: true,
frameCount: 6,
frameDuration: 60,
frames: [
{
head: { x: 0, y: -2, rotation: 2, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: -1, rotation: 8 },
leftArm: { rotation: 45, x: 3, y: -2 },
rightArm: { rotation: -60, x: -5, y: 0 },
leftLeg: { rotation: -40, x: -3, y: -5 },
rightLeg: { rotation: 35, x: 5, y: 0 },
accessories: { bounce: -3, rotation: 2 },
},
{
head: { x: 0, y: -4, rotation: 3, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: -3, rotation: 10 },
leftArm: { rotation: 30, x: 2, y: -3 },
rightArm: { rotation: -45, x: -3, y: -1 },
leftLeg: { rotation: -20, x: -1, y: -8 },
rightLeg: { rotation: 15, x: 2, y: -3 },
accessories: { bounce: -5, rotation: 3 },
},
{
head: { x: 0, y: -2, rotation: 2, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: -1, rotation: 8 },
leftArm: { rotation: 0, x: 0, y: 0 },
rightArm: { rotation: 0, x: 0, y: 0 },
leftLeg: { rotation: 10, x: 1, y: -4 },
rightLeg: { rotation: -15, x: -2, y: -1 },
accessories: { bounce: -3, rotation: 2 },
},
{
head: { x: 0, y: -2, rotation: -2, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: -1, rotation: 8 },
leftArm: { rotation: -60, x: -5, y: 0 },
rightArm: { rotation: 45, x: 3, y: -2 },
leftLeg: { rotation: 35, x: 5, y: 0 },
rightLeg: { rotation: -40, x: -3, y: -5 },
accessories: { bounce: -3, rotation: -2 },
},
{
head: { x: 0, y: -4, rotation: -3, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: -3, rotation: 10 },
leftArm: { rotation: -45, x: -3, y: -1 },
rightArm: { rotation: 30, x: 2, y: -3 },
leftLeg: { rotation: 15, x: 2, y: -3 },
rightLeg: { rotation: -20, x: -1, y: -8 },
accessories: { bounce: -5, rotation: -3 },
},
{
head: { x: 0, y: -2, rotation: -2, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: -1, rotation: 8 },
leftArm: { rotation: 0, x: 0, y: 0 },
rightArm: { rotation: 0, x: 0, y: 0 },
leftLeg: { rotation: -15, x: -2, y: -1 },
rightLeg: { rotation: 10, x: 1, y: -4 },
accessories: { bounce: -3, rotation: -2 },
},
],
},
// 4. jump - Crouch, leap, stretch
{
id: 'jump',
name: 'Jump',
modes: ['FULL_BODY'],
loop: false,
frameCount: 3,
frameDuration: 100,
frames: [
{
head: { x: 0, y: 4, rotation: 0, scaleX: 1, scaleY: 0.9 },
eyes: { scaleY: 1 },
body: { x: 0, y: 6, rotation: 0 },
leftArm: { rotation: 20, x: -2, y: 3 },
rightArm: { rotation: -20, x: 2, y: 3 },
leftLeg: { rotation: 30, x: -3, y: 5 },
rightLeg: { rotation: -30, x: 3, y: 5 },
accessories: { bounce: 5, rotation: 0 },
},
{
head: { x: 0, y: -15, rotation: 0, scaleX: 1, scaleY: 1.1 },
eyes: { scaleY: 1.1 },
body: { x: 0, y: -12, rotation: 0 },
leftArm: { rotation: -120, x: -5, y: -10 },
rightArm: { rotation: 120, x: 5, y: -10 },
leftLeg: { rotation: 15, x: -1, y: -3 },
rightLeg: { rotation: -15, x: 1, y: -3 },
accessories: { bounce: -18, rotation: 0 },
},
{
head: { x: 0, y: -20, rotation: 0, scaleX: 1, scaleY: 1.15 },
eyes: { scaleY: 1 },
body: { x: 0, y: -18, rotation: 0 },
leftArm: { rotation: -90, x: -8, y: -12 },
rightArm: { rotation: 90, x: 8, y: -12 },
leftLeg: { rotation: 5, x: 0, y: -5 },
rightLeg: { rotation: -5, x: 0, y: -5 },
accessories: { bounce: -22, rotation: 0 },
},
],
},
// 5. fall - Arms up, legs down
{
id: 'fall',
name: 'Fall',
modes: ['FULL_BODY'],
loop: true,
frameCount: 2,
frameDuration: 150,
frames: [
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1.2 },
body: { x: 0, y: 0, rotation: 0 },
leftArm: { rotation: -150, x: -5, y: -5 },
rightArm: { rotation: 150, x: 5, y: -5 },
leftLeg: { rotation: 10, x: -2, y: 5 },
rightLeg: { rotation: -10, x: 2, y: 5 },
accessories: { bounce: -5, rotation: 0 },
},
{
head: { x: 0, y: -2, rotation: 3, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1.2 },
body: { x: 0, y: -1, rotation: 2 },
leftArm: { rotation: -140, x: -6, y: -6 },
rightArm: { rotation: 160, x: 4, y: -4 },
leftLeg: { rotation: 15, x: -3, y: 6 },
rightLeg: { rotation: -5, x: 1, y: 4 },
accessories: { bounce: -7, rotation: 3 },
},
],
},
// 6. crouch - Duck down
{
id: 'crouch',
name: 'Crouch',
modes: ['FULL_BODY'],
loop: false,
frameCount: 2,
frameDuration: 80,
frames: [
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 0 },
leftArm: { rotation: 0, x: 0, y: 0 },
rightArm: { rotation: 0, x: 0, y: 0 },
leftLeg: { rotation: 0, x: 0, y: 0 },
rightLeg: { rotation: 0, x: 0, y: 0 },
accessories: { bounce: 0, rotation: 0 },
},
{
head: { x: 0, y: 15, rotation: -5, scaleX: 1, scaleY: 0.9 },
eyes: { scaleY: 0.8 },
body: { x: 0, y: 12, rotation: -8 },
leftArm: { rotation: 30, x: -3, y: 8 },
rightArm: { rotation: -30, x: 3, y: 8 },
leftLeg: { rotation: 60, x: -5, y: 10 },
rightLeg: { rotation: -60, x: 5, y: 10 },
accessories: { bounce: 12, rotation: -5 },
},
],
},
// 7. celebrate - Jump and arm wave
{
id: 'celebrate',
name: 'Celebrate',
modes: ['FULL_BODY'],
loop: false,
frameCount: 6,
frameDuration: 100,
frames: [
{
head: { x: 0, y: 3, rotation: 0, scaleX: 1, scaleY: 0.9 },
eyes: { scaleY: 1 },
body: { x: 0, y: 4, rotation: 0 },
leftArm: { rotation: 10, x: 0, y: 2 },
rightArm: { rotation: -10, x: 0, y: 2 },
leftLeg: { rotation: 15, x: -1, y: 3 },
rightLeg: { rotation: -15, x: 1, y: 3 },
accessories: { bounce: 4, rotation: 0 },
},
{
head: { x: 0, y: -12, rotation: 0, scaleX: 1.05, scaleY: 1.1 },
eyes: { scaleY: 0.8 },
body: { x: 0, y: -10, rotation: 0 },
leftArm: { rotation: -135, x: -8, y: -12 },
rightArm: { rotation: 135, x: 8, y: -12 },
leftLeg: { rotation: 10, x: -2, y: -5 },
rightLeg: { rotation: -10, x: 2, y: -5 },
accessories: { bounce: -15, rotation: 0 },
},
{
head: { x: 0, y: -10, rotation: 8, scaleX: 1.03, scaleY: 1.08 },
eyes: { scaleY: 0.85 },
body: { x: 0, y: -8, rotation: 5 },
leftArm: { rotation: -120, x: -10, y: -10 },
rightArm: { rotation: 150, x: 6, y: -14 },
leftLeg: { rotation: 5, x: -1, y: -4 },
rightLeg: { rotation: -5, x: 1, y: -4 },
accessories: { bounce: -12, rotation: 8 },
},
{
head: { x: 0, y: -10, rotation: -8, scaleX: 1.03, scaleY: 1.08 },
eyes: { scaleY: 0.85 },
body: { x: 0, y: -8, rotation: -5 },
leftArm: { rotation: -150, x: -6, y: -14 },
rightArm: { rotation: 120, x: 10, y: -10 },
leftLeg: { rotation: 5, x: -1, y: -4 },
rightLeg: { rotation: -5, x: 1, y: -4 },
accessories: { bounce: -12, rotation: -8 },
},
{
head: { x: 0, y: -8, rotation: 5, scaleX: 1.02, scaleY: 1.05 },
eyes: { scaleY: 0.9 },
body: { x: 0, y: -6, rotation: 3 },
leftArm: { rotation: -130, x: -8, y: -11 },
rightArm: { rotation: 140, x: 7, y: -12 },
leftLeg: { rotation: 3, x: 0, y: -3 },
rightLeg: { rotation: -3, x: 0, y: -3 },
accessories: { bounce: -10, rotation: 5 },
},
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 0 },
leftArm: { rotation: -60, x: -3, y: -5 },
rightArm: { rotation: 60, x: 3, y: -5 },
leftLeg: { rotation: 0, x: 0, y: 0 },
rightLeg: { rotation: 0, x: 0, y: 0 },
accessories: { bounce: 0, rotation: 0 },
},
],
},
// 8. attack - Punch or swing
{
id: 'attack',
name: 'Attack',
modes: ['FULL_BODY'],
loop: false,
frameCount: 4,
frameDuration: 60,
frames: [
{
head: { x: 0, y: 0, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: -5 },
leftArm: { rotation: 15, x: -2, y: 0 },
rightArm: { rotation: -90, x: -5, y: -5 },
leftLeg: { rotation: 5, x: 0, y: 0 },
rightLeg: { rotation: -10, x: 0, y: 0 },
accessories: { bounce: 0, rotation: -3 },
},
{
head: { x: 2, y: 0, rotation: 5, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1.1 },
body: { x: 1, y: 0, rotation: 10 },
leftArm: { rotation: 20, x: -3, y: 0 },
rightArm: { rotation: -45, x: 15, y: 0 },
leftLeg: { rotation: -10, x: -2, y: 0 },
rightLeg: { rotation: 15, x: 3, y: -2 },
accessories: { bounce: 0, rotation: 5 },
},
{
head: { x: 3, y: -1, rotation: 8, scaleX: 1.02, scaleY: 0.98 },
eyes: { scaleY: 1 },
body: { x: 2, y: 0, rotation: 15 },
leftArm: { rotation: 25, x: -4, y: 0 },
rightArm: { rotation: -30, x: 20, y: 2 },
leftLeg: { rotation: -15, x: -3, y: 0 },
rightLeg: { rotation: 20, x: 5, y: -3 },
accessories: { bounce: -1, rotation: 8 },
},
{
head: { x: 1, y: 0, rotation: 3, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 5 },
leftArm: { rotation: 10, x: -1, y: 0 },
rightArm: { rotation: -60, x: 8, y: -2 },
leftLeg: { rotation: -5, x: -1, y: 0 },
rightLeg: { rotation: 8, x: 2, y: -1 },
accessories: { bounce: 0, rotation: 3 },
},
],
},
// 9. hurt - Stagger back
{
id: 'hurt',
name: 'Hurt',
modes: ['FULL_BODY'],
loop: false,
frameCount: 3,
frameDuration: 80,
frames: [
{
head: { x: -5, y: 3, rotation: -15, scaleX: 1.1, scaleY: 0.9 },
eyes: { scaleY: 0.2 },
body: { x: -4, y: 3, rotation: -12 },
leftArm: { rotation: 40, x: -5, y: 5 },
rightArm: { rotation: 50, x: -3, y: 6 },
leftLeg: { rotation: 20, x: -3, y: 2 },
rightLeg: { rotation: -15, x: 2, y: 0 },
accessories: { bounce: 5, rotation: -20 },
},
{
head: { x: -8, y: 5, rotation: -20, scaleX: 1.05, scaleY: 0.95 },
eyes: { scaleY: 0.1 },
body: { x: -6, y: 5, rotation: -18 },
leftArm: { rotation: 60, x: -8, y: 8 },
rightArm: { rotation: 70, x: -5, y: 10 },
leftLeg: { rotation: 30, x: -5, y: 4 },
rightLeg: { rotation: -25, x: 3, y: 2 },
accessories: { bounce: 8, rotation: -25 },
},
{
head: { x: -2, y: 1, rotation: -5, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 0.7 },
body: { x: -1, y: 1, rotation: -3 },
leftArm: { rotation: 15, x: -2, y: 2 },
rightArm: { rotation: 20, x: -1, y: 2 },
leftLeg: { rotation: 8, x: -1, y: 1 },
rightLeg: { rotation: -5, x: 1, y: 0 },
accessories: { bounce: 2, rotation: -5 },
},
],
},
// 10. climb - Climbing motion
{
id: 'climb',
name: 'Climb',
modes: ['FULL_BODY'],
loop: true,
frameCount: 4,
frameDuration: 120,
frames: [
{
head: { x: 0, y: 0, rotation: -5, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: -3 },
leftArm: { rotation: -150, x: -3, y: -15 },
rightArm: { rotation: 60, x: 5, y: 5 },
leftLeg: { rotation: 40, x: -2, y: 8 },
rightLeg: { rotation: -30, x: 2, y: -5 },
accessories: { bounce: 0, rotation: -5 },
},
{
head: { x: 0, y: -2, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: -2, rotation: 0 },
leftArm: { rotation: -120, x: -4, y: -10 },
rightArm: { rotation: 30, x: 4, y: 0 },
leftLeg: { rotation: 20, x: -1, y: 3 },
rightLeg: { rotation: -10, x: 1, y: -2 },
accessories: { bounce: -2, rotation: 0 },
},
{
head: { x: 0, y: 0, rotation: 5, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 3 },
leftArm: { rotation: 60, x: -5, y: 5 },
rightArm: { rotation: -150, x: 3, y: -15 },
leftLeg: { rotation: -30, x: -2, y: -5 },
rightLeg: { rotation: 40, x: 2, y: 8 },
accessories: { bounce: 0, rotation: 5 },
},
{
head: { x: 0, y: -2, rotation: 0, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: -2, rotation: 0 },
leftArm: { rotation: 30, x: -4, y: 0 },
rightArm: { rotation: -120, x: 4, y: -10 },
leftLeg: { rotation: -10, x: -1, y: -2 },
rightLeg: { rotation: 20, x: 1, y: 3 },
accessories: { bounce: -2, rotation: 0 },
},
],
},
// 11. swim - Swimming strokes
{
id: 'swim',
name: 'Swim',
modes: ['FULL_BODY'],
loop: true,
frameCount: 4,
frameDuration: 150,
frames: [
{
head: { x: 0, y: 0, rotation: 10, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 15 },
leftArm: { rotation: -60, x: 10, y: -5 },
rightArm: { rotation: 30, x: -5, y: 5 },
leftLeg: { rotation: 20, x: 0, y: 5 },
rightLeg: { rotation: -20, x: 0, y: -5 },
accessories: { bounce: 0, rotation: 10 },
},
{
head: { x: 0, y: -2, rotation: 15, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: -1, rotation: 20 },
leftArm: { rotation: -30, x: 5, y: -8 },
rightArm: { rotation: -60, x: 10, y: -5 },
leftLeg: { rotation: -10, x: 0, y: -3 },
rightLeg: { rotation: 10, x: 0, y: 3 },
accessories: { bounce: -2, rotation: 15 },
},
{
head: { x: 0, y: 0, rotation: 10, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: 0, rotation: 15 },
leftArm: { rotation: 30, x: -5, y: 5 },
rightArm: { rotation: -60, x: 10, y: -5 },
leftLeg: { rotation: -20, x: 0, y: -5 },
rightLeg: { rotation: 20, x: 0, y: 5 },
accessories: { bounce: 0, rotation: 10 },
},
{
head: { x: 0, y: -2, rotation: 15, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1 },
body: { x: 0, y: -1, rotation: 20 },
leftArm: { rotation: -60, x: 10, y: -5 },
rightArm: { rotation: -30, x: 5, y: -8 },
leftLeg: { rotation: 10, x: 0, y: 3 },
rightLeg: { rotation: -10, x: 0, y: -3 },
accessories: { bounce: -2, rotation: 15 },
},
],
},
// 12. fly - Superhero flying pose
{
id: 'fly',
name: 'Fly',
modes: ['FULL_BODY'],
loop: true,
frameCount: 4,
frameDuration: 100,
frames: [
{
head: { x: 0, y: 0, rotation: 25, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1.1 },
body: { x: 0, y: 0, rotation: 30 },
leftArm: { rotation: -170, x: 10, y: -15 },
rightArm: { rotation: -160, x: 12, y: -12 },
leftLeg: { rotation: 20, x: 0, y: 10 },
rightLeg: { rotation: 25, x: 2, y: 12 },
accessories: { bounce: -5, rotation: 25 },
},
{
head: { x: 0, y: -2, rotation: 28, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1.1 },
body: { x: 0, y: -1, rotation: 32 },
leftArm: { rotation: -175, x: 12, y: -17 },
rightArm: { rotation: -165, x: 14, y: -14 },
leftLeg: { rotation: 15, x: -1, y: 8 },
rightLeg: { rotation: 20, x: 1, y: 10 },
accessories: { bounce: -7, rotation: 28 },
},
{
head: { x: 0, y: 0, rotation: 25, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1.1 },
body: { x: 0, y: 0, rotation: 30 },
leftArm: { rotation: -165, x: 8, y: -13 },
rightArm: { rotation: -155, x: 10, y: -10 },
leftLeg: { rotation: 25, x: 1, y: 12 },
rightLeg: { rotation: 30, x: 3, y: 14 },
accessories: { bounce: -5, rotation: 25 },
},
{
head: { x: 0, y: -1, rotation: 27, scaleX: 1, scaleY: 1 },
eyes: { scaleY: 1.1 },
body: { x: 0, y: -1, rotation: 31 },
leftArm: { rotation: -172, x: 11, y: -16 },
rightArm: { rotation: -162, x: 13, y: -13 },
leftLeg: { rotation: 18, x: 0, y: 9 },
rightLeg: { rotation: 22, x: 2, y: 11 },
accessories: { bounce: -6, rotation: 27 },
},
],
},
];
// =============================================================================
// ORGANIZE ANIMATIONS BY MODE
// =============================================================================
var ANIMATIONS = {
HEAD_ONLY: HEAD_ONLY_ANIMATIONS,
HEAD_AND_SHOULDERS: HEAD_AND_SHOULDERS_ANIMATIONS,
UPPER_BODY: UPPER_BODY_ANIMATIONS,
FULL_BODY: FULL_BODY_ANIMATIONS,
};
// Create a flat map for quick lookup by animation ID
var ANIMATION_MAP = {};
Object.keys(ANIMATIONS).forEach(function(modeName) {
ANIMATION_MAP[modeName] = {};
ANIMATIONS[modeName].forEach(function(anim) {
ANIMATION_MAP[modeName][anim.id] = anim;
});
});
// =============================================================================
// HELPER FUNCTIONS
// =============================================================================
/**
* Get mode configuration by name
*/
function getMode(modeName) {
return MODES[modeName] || null;
}
/**
* Get a specific animation for a mode
*/
function getAnimation(modeName, animationId) {
if (!ANIMATION_MAP[modeName]) return null;
return ANIMATION_MAP[modeName][animationId] || null;
}
/**
* Get all animations for a mode
*/
function getAnimationsForMode(modeName) {
return ANIMATIONS[modeName] || [];
}
/**
* Get a specific frame from an animation
*/
function getFrame(animation, frameIndex) {
if (!animation || !animation.frames) return defaultFrame();
var index = frameIndex % animation.frames.length;
return animation.frames[index];
}
/**
* Interpolate between two values
*/
function lerp(a, b, t) {
return a + (b - a) * t;
}
/**
* Deep interpolate between two frame objects
*/
function interpolateObjects(frameA, frameB, t) {
var result = {};
Object.keys(frameA).forEach(function(key) {
if (typeof frameA[key] === 'object' && frameA[key] !== null) {
result[key] = {};
Object.keys(frameA[key]).forEach(function(subKey) {
var valA = frameA[key][subKey];
var valB = frameB[key] && frameB[key][subKey] !== undefined ? frameB[key][subKey] : valA;
result[key][subKey] = lerp(valA, valB, t);
});
} else {
var valA = frameA[key];
var valB = frameB[key] !== undefined ? frameB[key] : valA;
result[key] = lerp(valA, valB, t);
}
});
// Include any keys in frameB that aren't in frameA
Object.keys(frameB).forEach(function(key) {
if (!(key in frameA)) {
if (typeof frameB[key] === 'object' && frameB[key] !== null) {
result[key] = {};
Object.keys(frameB[key]).forEach(function(subKey) {
result[key][subKey] = frameB[key][subKey];
});
} else {
result[key] = frameB[key];
}
}
});
return result;
}
/**
* Interpolate frame data based on animation progress (0-1)
* Returns smoothly interpolated transform values between frames
*/
function interpolateFrame(animation, progress) {
if (!animation || !animation.frames || animation.frames.length === 0) {
return defaultFrame();
}
var frameCount = animation.frames.length;
var exactFrame = progress * frameCount;
var frameIndex = Math.floor(exactFrame);
var frameFraction = exactFrame - frameIndex;
// Handle looping
if (animation.loop) {
frameIndex = frameIndex % frameCount;
} else {
frameIndex = Math.min(frameIndex, frameCount - 1);
}
var nextFrameIndex;
if (animation.loop) {
nextFrameIndex = (frameIndex + 1) % frameCount;
} else {
nextFrameIndex = Math.min(frameIndex + 1, frameCount - 1);
}
var frameA = animation.frames[frameIndex];
var frameB = animation.frames[nextFrameIndex];
// If we're at the last frame of a non-looping animation, just return it
if (!animation.loop && frameIndex === frameCount - 1) {
return frameA;
}
return interpolateObjects(frameA, frameB, frameFraction);
}
/**
* Get the duration of each frame in milliseconds
*/
function getFrameDuration(animation) {
return animation && animation.frameDuration ? animation.frameDuration : 100;
}
/**
* Get the total duration of an animation in milliseconds
*/
function getTotalDuration(animation) {
if (!animation || !animation.frames) return 0;
return animation.frames.length * getFrameDuration(animation);
}
/**
* Check if an animation loops
*/
function isLooping(animation) {
return animation && animation.loop === true;
}
// =============================================================================
// PUBLIC API
// =============================================================================
window.AvatarAnimations = {
MODES: MODES,
ANIMATIONS: ANIMATIONS,
ACCESSORY_ANIMATION: ACCESSORY_ANIMATION,
getMode: getMode,
getAnimation: getAnimation,
getAnimationsForMode: getAnimationsForMode,
getFrame: getFrame,
interpolateFrame: interpolateFrame,
getFrameDuration: getFrameDuration,
getTotalDuration: getTotalDuration,
isLooping: isLooping,
defaultFrame: defaultFrame,
};
})();