Syntax and parameter breakdown
At its simplest, /playanimation only needs a target selector and the full identifier of an animation that already exists in a loaded resource pack. Every parameter after the animation name is optional, though because the syntax is positional, you have to fill in the earlier optional slots if you want to reach one near the end. The command runs purely on the client side once the server dispatches the packet, which means the server does not validate whether the bones referenced in the animation actually exist on the target's geometry.
Understanding how the last three parameters interact is the difference between an animation that snaps uglily and one that blends smoothly into vanilla movement. The stop expression is evaluated as Molang on the client every frame while the animation is active; the moment it returns a non-zero value (true), the animation begins blending out over the duration specified by blend_out_time. The controller parameter names a runtime slot on the entity: playing a new animation on the same named controller replaces whatever was running in that slot previously, while leaving it blank or using distinct names lets multiple animations layer on top of one another.
| Parameter | Type | What it does | Notes |
|---|---|---|---|
| entity | Target selector | Selects which entities will play the animation. | Accepts @p, @a, @r, @e, @s, or a player name. The target must have a client entity definition with geometry matching the animation's bone names. |
| animation | String | The full resource pack identifier of the animation. | Must match the key inside an animations/*.json file, such as animation.creeper.swelling or animation.custom.wave. |
| next_state | String (optional) | A state or animation to transition into after the primary animation finishes. | Rarely used in standalone recipes; normally left as default so you can reach later arguments. |
| blend_out_time | Float (optional) | Time in seconds to interpolate bones back to their underlying pose when the animation ends. | Defaults to 0.0 (instant snap). Values between 0.2 and 0.5 usually look natural for humanoid mobs. |
| stop_expression | Molang string (optional) | A Molang expression evaluated each frame; stops the animation when it evaluates to true. | Must be wrapped in quotes if it contains spaces or operators. Pass "0" to let the animation run to its natural length or loop forever. |
| controller | String (optional) | An arbitrary slot name used to group, replace, or cancel animations. | Does not need to exist in any animation_controllers file. It is an ad-hoc track identifier created on the fly. |
How resource pack bone targeting works
A major advantage of /playanimation is that you do not have to edit RP/entity/<mob>.entity.json to register a shortname for the animation before calling it. As long as an animation file inside RP/animations/ defines the full identifier—such as animation.humanoid.celebrate—the command can look it up globally by that string. When the client receives the command, it matches the bone names inside the animation against the bone names in the target entity's current geometry.
Because most vanilla bipedal mobs (players, zombies, skeletons, piglins, villagers to a partial extent) share standardized bone names like head, body, rightArm, leftArm, rightLeg, and leftLeg, a single custom animation file in your resource pack can be played on almost any humanoid mob through /playanimation. Bones mentioned in the animation that do not exist on the target's geometry are silently ignored, and bones on the target that are not mentioned in the animation keep running their normal vanilla walk or idle controllers.
{
"format_version": "1.8.0",
"animations": {
"animation.custom.salute": {
"loop": false,
"animation_length": 1.5,
"bones": {
"rightArm": {
"rotation": {
"0.0": [0.0, 0.0, 0.0],
"0.25": [-135.0, -25.0, 10.0],
"1.25": [-135.0, -25.0, 10.0],
"1.5": [0.0, 0.0, 0.0]
}
},
"head": {
"rotation": {
"0.0": [0.0, 0.0, 0.0],
"0.2": [-5.0, 0.0, 0.0],
"1.3": [-5.0, 0.0, 0.0],
"1.5": [0.0, 0.0, 0.0]
}
}
}
},
"animation.custom.cower_loop": {
"loop": true,
"bones": {
"head": {
"rotation": [35.0, 0.0, 0.0]
},
"rightArm": {
"rotation": [-110.0, -35.0, 0.0]
},
"leftArm": {
"rotation": [-110.0, 35.0, 0.0]
}
}
}
}
}One-shot, looping, and Molang-stopped recipes
When you put these commands inside a behavior pack .mcfunction file, you generally fall into one of three patterns: playing a one-shot gesture that finishes on its own, starting an indefinite pose that waits for a gameplay condition to change, or cancelling an active loop on demand. For a one-shot animation where loop is false in the JSON (or where it is a vanilla non-looping animation), you only need the first two arguments, or up to the fourth if you want a smooth blend out at the end.
For looping animations—including many vanilla pose animations that have no fixed length—the animation will stay stuck on the entity forever unless you give it a way out. You can either pass a Molang query in the stop_expression slot so the client automatically releases the pose when the entity moves, takes damage, or sneaks, or you can assign a custom controller track name in the sixth slot. To cancel a named track later from a command or function, call /playanimation again on the same entity and the same controller name, pass a valid animation identifier, and set the stop_expression to "1" so it terminates immediately.
# 1. Simple one-shot using our custom RP animation, blending out over 0.3 seconds
playanimation @e[type=minecraft:zombie,c=1] animation.custom.salute default 0.3
# 2. Hold a cowering loop until the entity starts moving or takes damage
playanimation @e[type=minecraft:villager,r=10] animation.custom.cower_loop default 0.4 "query.modified_move_speed > 0.1 || query.hurt_time > 0" custom_pose_track
# 3. Lock an armor stand or mob into a sleeping/lying pose indefinitely (stop_expression = 0)
playanimation @e[type=minecraft:armor_stand,tag=statue] animation.player.sleeping default 0.0 "0" statue_track
# 4. Force-cancel whatever is currently running on 'custom_pose_track' with a 0.25s blend out
playanimation @e[type=minecraft:villager,r=10] animation.custom.cower_loop default 0.25 "1" custom_pose_trackKit of reusable vanilla animations
Even in a behavior-pack-only project with no custom resource pack attached, /playanimation can tap into hundreds of animations shipped in the vanilla resource pack. Because the command matches bones by name rather than checking entity types, you can borrow animations from one mob and run them on another so long as they share bone names like body, head, or root.
This technique is widely used for visual tricks: scaling an entity up or down with the creeper swelling or ghast scale animations, spinning mobs upside down or sideways using swimming and sleeping animations, or applying a first-person camera shake to players by targeting their root or camera bones. Keep in mind that some vanilla animations rely on entity-specific Molang variables initialized in that mob's client entity file; if an animation looks frozen or snaps to weird angles on a foreign mob, it usually means a variable like variable.attack_time or a mob-specific timer is missing on the target.
| Vanilla Animation ID | Bones Affected | Visual Effect / Recipe Use |
|---|---|---|
| animation.creeper.swelling | body, head, leg0-leg3 | Pulse-scales the torso and head briefly; relies on swell timers on creepers, so on other mobs its behavior depends on default variable states. |
| animation.player.sleeping | root | Rotates the entire entity flat on its back. Works on almost any entity whose geometry is parented under a root bone. |
| animation.humanoid.bow_and_arrow | rightArm, leftArm | Raises both arms forward aiming at the head's pitch and yaw. Good for making zombies, skeletons, or NPCs aim held items. |
| animation.warden.roar | body, head, arms | Plays the Warden's multi-second roar motion on entities that share its bone hierarchy. |
| animation.minecart.move | bottom, root | Subtle jitter/tilt when applied to entities with matching root structures. |
Driving animations from the Script API
If your add-on uses @minecraft/server scripts rather than .mcfunction files, you do not need to build command strings and pass them to runCommand. The Entity class exposes a native playAnimation(animationName, options) method that sends the exact same network packet with cleaner syntax and type-safe options.
All four optional parameters from the slash command map directly onto the PlayAnimationOptions object: nextState, blendOutTime, stopExpression, and controller. In addition, the Script API adds a players property—an array of Player objects—allowing you to play an animation on an entity so that only specific players in the world see it, which is impossible with the slash command alone.
import { world, system } from "@minecraft/server";
/**
* Plays a looping cower animation on nearby villagers that stops if they move,
* and cancels it manually after 5 seconds (100 ticks).
*/
export function frightenNearbyVillagers(originPlayer) {
const villagers = originPlayer.dimension.getEntities({
type: "minecraft:villager_v2",
location: originPlayer.location,
maxDistance: 12
});
for (const villager of villagers) {
villager.playAnimation("animation.custom.cower_loop", {
blendOutTime: 0.35,
stopExpression: "query.modified_move_speed > 0.15",
controller: "fear_track"
});
}
system.runTimeout(() => {
for (const villager of villagers) {
if (!villager.isValid()) continue;
villager.playAnimation("animation.custom.cower_loop", {
blendOutTime: 0.5,
stopExpression: "1",
controller: "fear_track"
});
}
}, 100);
}Which versions this applies to
The /playanimation command has been available in stable Bedrock releases since 1.16.100 and requires no experimental toggles. In @minecraft/server, Entity.playAnimation is stable in 1.3.0 and later module versions.
When it does not work
| What you see | Why | The fix |
|---|---|---|
| The command outputs "Playanimation request sent to clients for processing" in chat, but the entity does not move at all. | Because the server does not load resource packs, /playanimation always reports success on the server side as long as the target selector matched an entity. If nothing happens visually, either the animation identifier is misspelled, the resource pack is not active on the client, or the bone names inside the animation JSON do not match the bone names in the target entity's geometry. | Open the target entity's geometry file in RP/models/entity/ to verify the exact capitalization of the bone names (for example, rightArm vs right_arm), and double-check that the string in RP/animations/ matches your command character for character. |
| Syntax error: Unexpected "...": at "..." when passing a Molang stop expression. | Any stop_expression containing spaces, comparison operators (>, <, ==), or logical operators (&&, ||) will be split into multiple command arguments by the command parser unless the entire expression is enclosed in double quotes. | Wrap the entire fifth argument in double quotes, such as "query.is_sneaking || query.is_moving", and make sure you also supplied values for next_state and blend_out_time before it. |
| An entity stays permanently frozen in a pose even after the command block or function stops running. | The animation you triggered has "loop": true in its resource pack definition (or is a continuous vanilla pose animation), and you either omitted stop_expression or set it to "0". Once the client receives the instruction, it keeps looping the animation locally until told otherwise or until the entity is unloaded. | Always assign a controller name (the sixth argument) when starting a looping animation. To unfreeze the entity, run /playanimation again targeting the same entity and controller name with the stop_expression set to "1". |
| Content Log shows [Molang][error] when the animation starts playing on a mob. | You played a vanilla animation built for one specific mob (such as a Warden or Iron Golem) onto a different mob or player. The animation curves reference a variable.* that is only initialized inside the original mob's client entity file (pre_animation script). | Instead of calling the vanilla animation directly on foreign mobs, copy the animation into your own resource pack under a new identifier and replace the missing variable.* references with self-contained math using query.anim_time or query.life_time. |
Reference, straight from the game files
Read out of the game itself, so the ids match the version you are building for.
