Wiki 9Minecraft Wiki 9Minecraft

Running Entity Commands from Animation Controllers

How to execute slash commands, entity events, and Molang expressions using behavior pack animation controllers.

6Sections
3Code examples
4Known errors

Behavior pack animation controllers act as server-side state machines hooked directly to an entity. Instead of posing bones like their resource pack counterparts, they execute slash commands, trigger entity events, and evaluate Molang expressions when entering or leaving a state. You reach for them whenever an entity needs to affect the world, run a function, or swap component groups in direct response to a Molang query.

Behavior Pack vs. Resource Pack Controllers

Minecraft Bedrock uses the same state machine syntax for animation controllers in both resource packs and behavior packs, which frequently trips up new creators. Resource pack controllers live in RP/animation_controllers/ and only handle client-side visuals, sounds, and particle effects. They cannot modify world state or run slash commands.

To run commands on an entity, the controller file must sit inside BP/animation_controllers/. Because behavior packs run on the server (or the local host's internal server), states inside these files have full authority to execute slash commands, dispatch entity events, and write to server-side Molang variables. The format_version for behavior pack animation controllers is 1.10.0, even inside packs targeting the latest game releases.

The Three String Prefixes

Inside a behavior pack animation controller state, the arrays on_entry and on_exit accept strings. The engine determines what to do with each string by looking at its first character. A forward slash runs a standard game command, an at-symbol fires an event on the entity, and anything else is parsed as raw Molang.

Commands execute with the entity itself as both the executor and the execution position. This means the selector @s always targets the entity running the controller, and relative coordinates like ~ ~1 ~ resolve relative to the entity's feet. Commands executed this way bypass normal player permission levels and do not spam the chat log unless command block output is explicitly enabled in the world settings.

PrefixWhat it doesExample
/Executes a slash command as the entity at its current position."/say Hello world"
@s Triggers an entity event defined in the entity's behavior JSON."@s wiki:become_angry"
v. or t.Evaluates a Molang statement, usually to set a variable."v.attack_timer = 0;"

Writing the Animation Controller

A controller contains one or more states, always starting at the state named default unless you specify a different initial_state. Each state can define on_entry, on_exit, and transitions. When the Molang condition inside a transition evaluates to true (non-zero), the controller leaves the current state, runs any strings in on_exit, moves to the target state, and immediately runs the strings in the new state's on_entry array.

The example below watches the entity's target state using query.has_target. The moment the entity acquires a target, it transitions from default to roaring. Entering roaring plays a roar sound, gives the entity a speed boost, Summons particles via a command, and triggers an entity event to add an angry component group. When the target is lost or dies, it transitions back to default, clearing the speed effect on the way out.

BP/animation_controllers/roar_attack.ac.json
{
  "format_version": "1.10.0",
  "animation_controllers": {
    "controller.animation.wiki.roar_attack": {
      "initial_state": "default",
      "states": {
        "default": {
          "transitions": [
            {
              "roaring": "query.has_target"
            }
          ]
        },
        "roaring": {
          "on_entry": [
            "/playsound mob.ravager.roar @a ~ ~ ~ 1.0 1.0",
            "/effect @s speed 10 1 true",
            "/particle minecraft:villager_angry ~ ~2 ~",
            "@s wiki:start_enrage"
          ],
          "on_exit": [
            "/effect @s speed 0"
          ],
          "transitions": [
            {
              "default": "!query.has_target"
            }
          ]
        }
      }
    }
  }
}

Hooking the Controller to an Entity

An animation controller file does nothing on its own; it must be registered and ticked inside your entity's behavior file under description. First, assign a short name to the controller identifier inside the animations object. Despite the key being named animations, it holds both timeline animations and animation controllers.

Next, add that short name to the scripts.animate array. Every entry in scripts.animate is evaluated every tick the entity is loaded. You can either pass the short name as a plain string so it always runs, or pass an object mapping the short name to a Molang condition so the controller only ticks when that condition is true.

BP/entities/custom_guard.json
{
  "format_version": "1.20.0",
  "minecraft:entity": {
    "description": {
      "identifier": "wiki:custom_guard",
      "is_spawnable": true,
      "is_summonable": true,
      "animations": {
        "roar_ctrl": "controller.animation.wiki.roar_attack"
      },
      "scripts": {
        "animate": [
          "roar_ctrl"
        ]
      }
    },
    "component_groups": {
      "wiki:enraged": {
        "minecraft:scale": {
          "value": 1.25
        }
      }
    },
    "components": {
      "minecraft:health": {
        "value": 40,
        "max": 40
      },
      "minecraft:NearestAttackableTargetGoal": {
        "must_see": true,
        "entity_types": [
          {
            "filters": {
              "test": "is_family",
              "subject": "other",
              "value": "monster"
            }
          }
        ]
      }
    },
    "events": {
      "wiki:start_enrage": {
        "add": {
          "component_groups": [
            "wiki:enraged"
          ]
        }
      }
    }
  }
}

Repeating Commands Every Tick

Strings inside on_entry and on_exit only fire once per state change. If you need a command to fire repeatedly while a condition holds—such as running a /damage or /particle command every single tick—you use a two-state loop. Create a second state that has no conditions on its transition back to the first state, or bounces between two active states using the unconditional Molang value (1.0).

Because the controller processes one transition per tick, bouncing between state_a and state_b with "1.0" as the transition condition causes the controller to enter one of those states every other tick (10 times a second). If you put the same on_entry commands in both states, those commands will execute on all 20 ticks per second for as long as the entity stays in the loop. For longer intervals without using commands every tick, pair the controller with a behavior pack timeline animation instead.

BP/animation_controllers/flame_trail.ac.json
{
  "format_version": "1.10.0",
  "animation_controllers": {
    "controller.animation.wiki.flame_trail": {
      "initial_state": "idle",
      "states": {
        "idle": {
          "transitions": [
            {
              "tick_a": "query.is_moving"
            }
          ]
        },
        "tick_a": {
          "on_entry": [
            "/particle minecraft:basic_flame_particle ~ ~0.2 ~"
          ],
          "transitions": [
            {
              "idle": "!query.is_moving"
            },
            {
              "tick_b": "1.0"
            }
          ]
        },
        "tick_b": {
          "on_entry": [
            "/particle minecraft:basic_flame_particle ~ ~0.2 ~"
          ],
          "transitions": [
            {
              "idle": "!query.is_moving"
            },
            {
              "tick_a": "1.0"
            }
          ]
        }
      }
    }
  }
}

Running Function Files

When an entity needs to run more than three or four commands on a state change, listing them all inside on_entry makes the JSON harder to read and maintain. Instead, place your commands inside a standard .mcfunction file in BP/functions/ and call it from the controller using "/function your_file_name".

The function inherits the execution context of the animation controller, meaning @s inside the .mcfunction file still points to the entity that triggered the transition, and ~ ~ ~ still uses that entity's coordinates.

Which versions this applies to

Stable in all current Bedrock versions (introduced in 1.10.0). No experimental toggles are required. The animation controller file itself must keep format_version 1.10.0, while the entity file can use 1.16.0 through 1.21.x.

When it does not work

What you seeWhyThe fix
Content Log error: "Failed to parse expression" mentioning your slash command text.You either forgot the leading forward slash "/" on the command string, or you placed the animation controller inside the Resource Pack instead of the Behavior Pack. Resource pack controllers treat strings without a valid prefix as broken Molang.Ensure the file is in BP/animation_controllers/ and every slash command begins with "/".
The entity spawns and behaves normally, but none of the commands or events in the controller ever fire, with no errors in the Content Log.The controller was defined in description.animations inside the entity JSON, but its short name was omitted from description.scripts.animate.Add the short name to the scripts.animate array in your BP/entities/ file so the game actually ticks the controller.
Commands inside a controller work once when the entity spawns, then never trigger again when the condition is met a second time.The state machine moved from default to your action state, but the action state has no transitions array leading back to default.Add a transition on the action state that returns to default when the condition becomes false (for example, "!query.is_sheared"), allowing the cycle to reset.
Content Log error: "Animation controller ... not found" when loading into a world.You raised the format_version inside the BP animation controller file to match your entity (such as 1.20.0), or made a typo in the controller.animation.* identifier.Set the animation controller's format_version strictly to "1.10.0" and check that the identifier matches the string in your entity file character for character.

Reference, straight from the game files

Read out of the game itself, so the ids match the version you are building for.