Skip to main content
Version: Minecraft 26.2

Mob Models

You define a mob's look in code as a box model. If you give no model, the mob is drawn with the player-shaped model wearing a 64×64 skin texture.

mod.content().entity("wisp", EntityDefinition.builder(ResourceId.of("my_mod", "textures/entity/wisp.png"))
.size(0.6f, 0.8f)
.maxHealth(6)
.noGravity()
.spawnEgg(CreativeTab.SPAWN_EGGS)
.model(EntityModelDefinition.builder(32, 32) // texture size
.part("body", part -> part.pivot(0, 16, 0)
.box(0, 0, -3, -3, -3, 6, 6, 6) // u, v, x, y, z, width, height, depth
.animation(PartAnimation.BOB))
.part("ring", part -> part.parent("body")
.pivot(0, 0, 0)
.box(0, 12, -4, 0, -4, 8, 1, 8)
.animation(PartAnimation.SPIN))
.build())
.build());

Coordinates​

  • Coordinates are in the game's model space. The unit is the pixel (1/16 block), y increases downward, and the ground is at y=24.
  • These are the same coordinates as Blockbench's "Modded Entity" format.
  • box(u, v, x, y, z, width, height, depth): the texture position (u, v) and the box's corner and size. mirroredBox flips the texture left to right.
  • pivot(x, y, z) is the center of rotation, rotation(x, y, z) is the base rotation, and parent(name) is the parent part.

Part animations​

PartAnimationBehavior
NONEDoes not move
HEADTurns to follow the gaze
WALK_SWING, WALK_SWING_OPPOSITESwings back and forth while walking (opposite phase)
BOBMoves up and down
SPINRotates

Keyframe animations​

As in Blockbench animations, you give each part values over time (keyframes), and the part moves smoothly between them. The values are added to the part's base pose. The game's keyframe animation engine does the drawing.

.model(EntityModelDefinition.builder(32, 32)
.part("body", part -> part.pivot(0, 16, 0).box(0, 0, -3, -3, -3, 6, 6, 6))
.part("ring", part -> part.parent("body").box(0, 12, -4, 0, -4, 8, 1, 8))
// Always repeats: grows and shrinks smoothly over 2 seconds
.animation("pulse", KeyframeAnimation.builder(2)
.looping()
.trigger(KeyframeAnimation.Trigger.ALWAYS)
.smooth()
.scale("body", 0, 1, 1, 1)
.scale("body", 1, 1.15f, 1.15f, 1.15f)
.scale("body", 2, 1, 1, 1)
.build())
// Only when the server starts it: lifts the ring for 1 second
.animation("wave", KeyframeAnimation.builder(1)
.rotation("ring", 0, 0, 0, 0)
.rotation("ring", 0.5f, 45, 0, 0)
.rotation("ring", 1, 0, 0, 0)
.build())
.build())
When it plays (Trigger)Meaning
ALWAYSAlways, while the mob is visible (breathing, spinning)
WHILE_MOVINGWhile moving, faster the faster the mob moves (walking, wing flaps, tail)
ON_DEMAND (default)When the server starts it with MobView.playAnimation(name). Every client that sees the mob plays it from the start
KeyframeUnit
rotation(part, time, x, y, z)Degrees
position(part, time, x, y, z)Model pixels, y is up (same as Blockbench)
scale(part, time, x, y, z)Scale factor, 1 is the original size
  • time is in seconds and must be within 0..length.
  • Keyframes added after smooth() are joined by a curve (Catmull-Rom). Keyframes added before it are joined by straight lines.
  • An ON_DEMAND animation without looping() stops when it ends. With other triggers, it keeps its last value.

Playing from the server:

MobView wisp = (MobView) world.spawnEntity(WISP, x, y, z);
world.schedule(10, () -> wisp.playAnimation("wave")); // after the client has received the mob
wisp.stopAnimation("wave"); // stop a repeating animation
  • If you move a part the model does not have, or a name does not match [a-z0-9_]+, defining it throws IllegalArgumentException.
  • A model can have up to 64 ON_DEMAND animations.
  • If the entity is not a mod mob, or has no such ON_DEMAND animation, playAnimation throws IllegalArgumentException.
Needs human verification

A person must check whether the drawn result looks right. Automatic verification only confirms that the drawing path runs.

Buy me a coffee