Animations can do more than move bones. At any moment in an animation you can spawn particles, play a sound, change a variable, or even run a command. In this guide our Ruby golem gets red sparkles and a heavy thud on every step, and gets angry when it is badly hurt.
This guide builds on Entity animations and Animation controllers.
The files
RP/
animations/
ruby_golem.animation.json
entity/
ruby_golem.entity.json
models/
entity/
ruby_golem.geo.json
BP/
animations/
ruby_golem.animation.json
animation_controllers/
ruby_golem.animation_controllers.json
entities/
ruby_golem.jsonYes, a behavior pack can have animations too. Part 3 explains why.
Which pack can do what
| Event | Resource pack | Behavior pack |
|---|---|---|
Particles (particle_effects) | Yes | No |
Sounds (sound_effects) | Yes | No |
Molang, like variable.x = 1; | Yes | Yes |
Commands, like /say hi | No | Yes |
Entity events, like @s wiki:enrage | No | Yes |
The rule of thumb: the resource pack is about looks and sounds on each player's screen. The behavior pack is about real game changes that everyone shares.
Part 1: particles
Give the particle a short name
The client entity lists the particles the mob can use, each with a short name:
"particle_effects": {
"sparkle": "wiki:ruby_sparkle",
"dust": "minecraft:villager_happy"
}The right side is the identifier of a particle effect. It can be a vanilla one or one you made yourself (see Particles).
Spawn it from an animation
Add particle_effects to the animation. Keys are times in seconds, like keyframes:
"animation.ruby_golem.walk": {
"loop": true,
"animation_length": 1.0,
"bones": { },
"particle_effects": {
"0.0": { "effect": "sparkle", "locator": "left_foot" },
"0.5": { "effect": "sparkle", "locator": "right_foot" }
}
}Every time the walk loops, a sparkle appears under the left foot, then under the right one.
| Field | What it does |
|---|---|
effect | The short name from the client entity. Required. |
locator | Where on the model the particle starts. Leave it out to use the mob's position. |
bind_to_actor | false leaves the particle in the world instead of moving with the mob |
pre_effect_script | Molang that runs just before the particle starts, to set variables the particle reads |
To spawn several particles at the same time, use a list: "0.0": [ { ... }, { ... } ].
Locators
A locator is a named point inside a bone of your model. Add them in the geometry file:
{
"name": "left_leg",
"parent": "body",
"pivot": [3, 12, 0],
"locators": {
"left_foot": [3, 0, 0]
},
"cubes": [ ]
}Because the locator sits in a bone, it moves when the bone moves. A particle at left_foot follows the swinging leg.
Part 2: sounds
Sounds work the same way. First, short names in the client entity:
"sound_effects": {
"thud": "mob.wiki.ruby_golem.step"
}The right side is a sound event name from RP/sounds/sound_definitions.json. Then add sound_effects to the animation:
"sound_effects": {
"0.0": { "effect": "thud" },
"0.5": { "effect": "thud" }
}Each sound entry has effect and an optional locator, just like particles.
Footsteps in time
Put the sound keys at the moments a foot touches the ground in your animation. If the walk uses anim_time_update with query.modified_distance_moved, the steps speed up and slow down with the golem automatically.
From a controller state
Controller states can also have particle_effects and sound_effects. They have no times, because a state has no timeline. Instead they start when the mob enters the state:
"alert": {
"animations": ["fists_up"],
"particle_effects": [{ "effect": "sparkle", "locator": "head" }],
"sound_effects": [{ "effect": "roar" }],
"transitions": [{ "idle": "!query.has_target" }]
}The timeline
Besides particles and sounds, an animation can have a timeline: a list of things to run at set times. In a resource pack, the timeline runs Molang:
"animation.ruby_golem.blink": {
"animation_length": 4.0,
"loop": true,
"timeline": {
"0.0": "variable.eyes_closed = 0;",
"3.8": "variable.eyes_closed = 1;"
}
}Every four seconds the golem closes its eyes for a moment. A render controller can read variable.eyes_closed to show a different texture or hide the eye bones (see Render controllers).
A key can hold one string or a list of strings: "1.0": ["variable.a = 1;", "variable.b = 2;"].
Part 3: behavior pack animations
Here is the clever part. The server can run animations and controllers too. It cannot move bones (the server has no model to move), but it can run timelines and controller states. That makes them a tiny scripting tool inside your mob, with no JavaScript needed.
In a behavior pack, events can be three things:
| Event string | What it does |
|---|---|
"/say Hello" | Runs a command, as if the mob typed it. @s is the mob itself. |
"@s wiki:enrage" | Runs an event from the mob's own events list |
"variable.rage = 1;" | Runs Molang |
Entity events can only target the mob itself, so it is always @s followed by the event name.
Step 1: a controller that watches health
Let's make the golem enrage when its health drops below 20, and calm down again when it heals:
{
"format_version": "1.10.0",
"animation_controllers": {
"controller.animation.ruby_golem.rage": {
"initial_state": "calm",
"states": {
"calm": {
"transitions": [
{ "enraged": "query.health < 20" }
]
},
"enraged": {
"on_entry": [
"/say The ruby golem is cracking!",
"/particle minecraft:lava_particle ~ ~1 ~",
"@s wiki:enrage"
],
"on_exit": [
"@s wiki:calm_down"
],
"transitions": [
{ "calm": "query.health >= 20" }
]
}
}
}
}
}The on_entry list runs once when the golem enters enraged. Commands run from the golem, so ~ ~1 ~ means one block above it.
Step 2: a repeating timer animation
A looping behavior pack animation is a handy timer. This one gives the golem a short heal at the start of every 10 second loop:
{
"format_version": "1.10.0",
"animations": {
"animation.ruby_golem.regen": {
"loop": true,
"animation_length": 10.0,
"timeline": {
"0.0": "/effect @s regeneration 3 0 true"
}
}
}
}Step 3: turn them on in the entity
In the behavior pack entity file, list them under description and play them with scripts.animate, the same way the client entity does:
{
"format_version": "1.21.0",
"minecraft:entity": {
"description": {
"identifier": "wiki:ruby_golem",
"is_spawnable": true,
"is_summonable": true,
"animations": {
"rage": "controller.animation.ruby_golem.rage",
"regen": "animation.ruby_golem.regen"
},
"scripts": {
"animate": ["rage", "regen"]
}
},
"component_groups": {
"wiki:enraged": {
"minecraft:movement": { "value": 0.35 },
"minecraft:attack": { "damage": 12 }
}
},
"components": { },
"events": {
"wiki:enrage": {
"add": { "component_groups": ["wiki:enraged"] }
},
"wiki:calm_down": {
"remove": { "component_groups": ["wiki:enraged"] }
}
}
}
}Now a hurt golem moves faster and hits harder, and goes back to normal once its regeneration brings it above 20 health.
Commands run a lot
A command in on_entry runs every time the state is entered, for every golem in the world. Twenty golems flipping states means twenty /say messages. Keep chat commands for testing and use quiet ones in the finished add-on.
When something goes wrong
| What you see | Most likely cause |
|---|---|
| No particles | The short name is not in the client entity's particle_effects, or the particle identifier is wrong |
| Particles appear at the mob's feet, not the locator | The locator name has a typo or is in a different bone |
| No sound | The sound event name does not exist in sound_definitions.json |
| A command in a resource pack does nothing | Commands only work in behavior pack animations |
| A behavior pack controller never runs | It is in description.animations but not in description.scripts.animate |
@s wiki:enrage does nothing | The event is missing from the entity's events, or its name has a typo |
More help is in Troubleshooting.
What next
- Learn the commands you can run from a timeline in Commands.
- Make your own effects in Particles.
- Read health, targets and more with Molang queries.