1423 lines
46 KiB
JavaScript
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,
|
|
};
|
|
|
|
})();
|