Skip to main content
Animation definitions control entity animations in both behavior packs (logic/timelines) and resource packs (visual keyframes).

AnimationBehaviorDefinition

AnimationBehaviorDefinition manages behavior pack animation files (BP/animations/*.json), which define animation timelines and scripted events.

Class Signature

class AnimationBehaviorDefinition implements IDefinition {
  // Properties
  id?: string;
  readonly shortId?: string;
  readonly isLoaded: boolean;
  readonly file?: IFile;
  data?: IAnimationBehaviorWrapper;
  
  // Timeline methods
  getAllTimeline(): IAnimationBehaviorTimelineWrapper[];
  
  // Loading and persistence
  static async ensureOnFile(file: IFile, handler?): Promise<AnimationBehaviorDefinition>;
  async load(): Promise<void>;
  persist(): boolean;
  
  // Utilities
  getFormatVersion(): number[] | undefined;
  async getFormatVersionIsCurrent(): Promise<boolean>;
  setBehaviorPackFormatVersion(version: string): void;
}

Loading Animation Behaviors

import { AnimationBehaviorDefinition } from 'minecraft-creator-tools';

// Load from file
const animBehavior = await AnimationBehaviorDefinition.ensureOnFile(file);

console.log('Animation ID:', animBehavior.id);
console.log('Format version:', animBehavior.getFormatVersion());

Working with Timelines

Behavior animations contain timeline events that execute commands or scripts at specific timestamps:
// Get all timelines
const timelines = animBehavior.getAllTimeline();

for (const timeline of timelines) {
  console.log('Animation:', timeline.animationId);
  console.log('Timestamp:', timeline.timestamp);
  console.log('Commands:', timeline.timeline);
}

Animation Behavior JSON Structure

{
  "format_version": "1.12.0",
  "animations": {
    "animation.custom.attack": {
      "animation_length": 1.0,
      "loop": false,
      "timeline": {
        "0.0": [
          "/playsound mob.zombie.attack @a ~ ~ ~ 1.0 1.0"
        ],
        "0.5": [
          "/particle minecraft:critical_hit_emitter ~ ~1 ~",
          "@s custom:deal_damage"
        ],
        "1.0": [
          "@s custom:reset_attack"
        ]
      }
    },
    "animation.custom.spawn": {
      "animation_length": 2.0,
      "loop": false,
      "timeline": {
        "0.0": [
          "/particle minecraft:huge_explosion_emitter ~ ~ ~"
        ],
        "2.0": [
          "@s custom:spawn_complete"
        ]
      }
    }
  }
}

Creating Behavior Animations

// Ensure data initialized
animBehavior._ensureDataInitialized();

if (animBehavior.data?.animations) {
  // Add animation
  animBehavior.data.animations['animation.custom.special_move'] = {
    animation_length: 3.0,
    loop: false,
    timeline: {
      '0.0': [
        '/playsound custom.special_charge @a ~ ~ ~ 1.0 1.0'
      ],
      '1.5': [
        '/particle minecraft:explosion_emitter ~ ~1 ~',
        '@s custom:execute_special'
      ],
      '3.0': [
        '@s custom:special_complete'
      ]
    }
  };
}

// Save
animBehavior.persist();

AnimationResourceDefinition

AnimationResourceDefinition manages resource pack animation files (RP/animations/*.json), which define visual bone transformations and keyframes.

Class Signature

class AnimationResourceDefinition implements IDefinition {
  // Properties
  id?: string;
  readonly shortId?: string;
  readonly isLoaded: boolean;
  readonly file?: IFile;
  readonly data?: IResourceAnimationWrapper;
  readonly animations?: { [name: string]: IAnimationResource };
  readonly idList?: Set<string>;
  
  // Animation management
  ensureAnimation(name: string): IAnimationResource;
  
  // Loading and persistence
  static async ensureOnFile(file: IFile, handler?): Promise<AnimationResourceDefinition>;
  async load(): Promise<void>;
  persist(): boolean;
  
  // Utilities
  getFormatVersion(): number[] | undefined;
  async getFormatVersionIsCurrent(): Promise<boolean>;
  setResourcePackFormatVersion(version: string): void;
  ensureDefault(): IResourceAnimationWrapper;
}

Loading Animation Resources

import { AnimationResourceDefinition } from 'minecraft-creator-tools';

// Load from file
const animResource = await AnimationResourceDefinition.ensureOnFile(file);

console.log('Animation ID:', animResource.id);

// Get all animation IDs
const animIds = animResource.idList;
if (animIds) {
  for (const id of animIds) {
    console.log('Animation:', id);
  }
}

// Get animations object
const animations = animResource.animations;
if (animations) {
  for (const name in animations) {
    const anim = animations[name];
    console.log('Animation:', name);
    console.log('Loop:', anim.loop);
    console.log('Animation length:', anim.animation_length);
  }
}

Creating Animations

// Ensure animation exists
const walkAnim = animResource.ensureAnimation('animation.custom.walk');

// Configure animation
walkAnim.loop = true;
walkAnim.animation_length = 1.0;
walkAnim.bones = {
  'leftleg': {
    rotation: {
      '0.0': [0, 0, 0],
      '0.5': [45, 0, 0],
      '1.0': [0, 0, 0]
    }
  },
  'rightleg': {
    rotation: {
      '0.0': [0, 0, 0],
      '0.5': [-45, 0, 0],
      '1.0': [0, 0, 0]
    }
  }
};

// Save
animResource.persist();

Animation Resource JSON Structure

{
  "format_version": "1.12.0",
  "animations": {
    "animation.custom.walk": {
      "loop": true,
      "animation_length": 1.0,
      "bones": {
        "leftleg": {
          "rotation": {
            "0.0": [0, 0, 0],
            "0.5": [45, 0, 0],
            "1.0": [0, 0, 0]
          }
        },
        "rightleg": {
          "rotation": {
            "0.0": [0, 0, 0],
            "0.5": [-45, 0, 0],
            "1.0": [0, 0, 0]
          }
        },
        "body": {
          "position": {
            "0.0": [0, 0, 0],
            "0.25": [0, 0.5, 0],
            "0.5": [0, 0, 0],
            "0.75": [0, 0.5, 0],
            "1.0": [0, 0, 0]
          },
          "rotation": {
            "0.0": [0, 0, 0],
            "0.5": [0, 5, 0],
            "1.0": [0, 0, 0]
          }
        },
        "head": {
          "rotation": {
            "0.0": [0, 0, 0],
            "0.5": [0, -5, 0],
            "1.0": [0, 0, 0]
          }
        }
      }
    },
    "animation.custom.attack": {
      "loop": false,
      "animation_length": 0.5,
      "bones": {
        "rightarm": {
          "rotation": {
            "0.0": [0, 0, 0],
            "0.25": [-90, 0, 0],
            "0.5": [0, 0, 0]
          }
        }
      }
    }
  }
}

Working with Bone Transformations

// Create complex animation
const attackAnim = animResource.ensureAnimation('animation.custom.powerful_attack');

attackAnim.loop = false;
attackAnim.animation_length = 1.5;
attackAnim.bones = {
  'rightarm': {
    rotation: {
      '0.0': [0, 0, 0],
      '0.5': [-120, 0, 45],    // Wind up
      '0.7': [-120, 0, 45],    // Hold
      '0.8': [45, 0, -45],     // Swing
      '1.5': [0, 0, 0]         // Return
    },
    position: {
      '0.5': [0, 2, 0],
      '0.8': [0, -1, 2],
      '1.5': [0, 0, 0]
    }
  },
  'body': {
    rotation: {
      '0.0': [0, 0, 0],
      '0.5': [0, -30, 0],
      '0.8': [0, 30, 0],
      '1.5': [0, 0, 0]
    }
  },
  'head': {
    rotation: {
      '0.0': [0, 0, 0],
      '0.5': [-10, 30, 0],
      '0.8': [10, -30, 0],
      '1.5': [0, 0, 0]
    }
  }
};

animResource.persist();

Complete Example: Creating Full Animation

import { 
  AnimationBehaviorDefinition, 
  AnimationResourceDefinition 
} from 'minecraft-creator-tools';

// Create behavior animation (timeline/events)
const animBehavior = await AnimationBehaviorDefinition.ensureOnFile(behaviorFile);
animBehavior.setBehaviorPackFormatVersion('1.20.0');
animBehavior._ensureDataInitialized();

if (animBehavior.data?.animations) {
  animBehavior.data.animations['animation.dragon.fire_breath'] = {
    animation_length: 3.0,
    loop: false,
    timeline: {
      '0.0': [
        '/playsound mob.enderdragon.growl @a ~ ~ ~ 2.0 0.8'
      ],
      '1.0': [
        '/particle minecraft:dragon_breath_fire ~ ~2 ~3 1 1 1 0.1 100'
      ],
      '1.5': [
        '@s custom:deal_fire_damage'
      ],
      '3.0': [
        '@s custom:breath_complete'
      ]
    }
  };
}

animBehavior.persist();

// Create resource animation (visual keyframes)
const animResource = await AnimationResourceDefinition.ensureOnFile(resourceFile);
animResource.setResourcePackFormatVersion('1.20.0');

const breathAnim = animResource.ensureAnimation('animation.dragon.fire_breath');
breathAnim.loop = false;
breathAnim.animation_length = 3.0;
breathAnim.bones = {
  'head': {
    rotation: {
      '0.0': [0, 0, 0],
      '0.5': [-20, 0, 0],      // Head tilts back
      '1.0': [-10, 0, 0],      // Head forward
      '2.0': [-10, 0, 0],      // Hold
      '3.0': [0, 0, 0]         // Return
    }
  },
  'jaw': {
    rotation: {
      '0.5': [0, 0, 0],
      '1.0': [30, 0, 0],       // Mouth opens
      '2.0': [30, 0, 0],       // Hold open
      '2.5': [0, 0, 0]         // Close
    }
  },
  'neck': {
    rotation: {
      '0.0': [0, 0, 0],
      '0.5': [-15, 0, 0],
      '1.0': [10, 0, 0],
      '3.0': [0, 0, 0]
    }
  },
  'body': {
    position: {
      '1.0': [0, 0, 0],
      '1.5': [0, 0, -0.5],     // Recoil from breath
      '2.0': [0, 0, 0]
    }
  }
};

animResource.persist();

console.log('Fire breath animation created!');

Animation Properties

Common Animation Properties

interface IAnimationResource {
  loop?: boolean;                    // Loop animation
  animation_length?: number;         // Duration in seconds
  override_previous_animation?: boolean;
  blend_weight?: number;
  anim_time_update?: string;        // Molang expression
  bones?: { [boneName: string]: IBoneAnimation };
  particle_effects?: any;           // Particle timeline
  sound_effects?: any;              // Sound timeline
  timeline?: any;                   // Generic timeline
}

interface IBoneAnimation {
  rotation?: { [timestamp: string]: number[] | string };
  position?: { [timestamp: string]: number[] | string };
  scale?: { [timestamp: string]: number[] | string };
  relative_to?: {
    rotation?: string;
  };
}

Keyframe Formats

// Numeric array
rotation: {
  '0.0': [0, 0, 0],
  '1.0': [90, 0, 0]
}

// Molang expression
rotation: {
  '0.0': 'math.sin(query.anim_time * 180)',
  '1.0': '0'
}

// Lerp keyframes
rotation: {
  '0.0': {
    pre: [0, 0, 0],
    post: [0, 0, 0],
    lerp_mode: 'linear'
  }
}

Build docs developers (and LLMs) love