---
title: Animating Bones In-Code
hide_meta: true
---

# How to modify bones in-code to do animations

<Callout variant="info">
    This page covers the basics. For a full guide with more examples (head tracking, smoothing, hiding and resizing bones), see [Procedural Animation](./procedural_animation).
</Callout>

- Open your AzAnimator class created for the targeted source you wish to do in-code animations for.

- Override the method `setCustomAnimations` and get your bones after the `super` call:

```java
    @Override
    public void setCustomAnimations(Creeper animatable, float partialTicks) {
        super.setCustomAnimations(animatable, partialTicks);
        AzBoneCache boneCache = this.context().boneCache();
        AzBone leftArm = boneCache.getBakedModel().getBoneOrNull("your_bones_name");
    }
```

- Check that the bone isn't `null` (the name must match Blockbench exactly), and you can start changing its rotation, position and scale in code. Rotations are in radians.

## Setting Values Without Drift

`setCustomAnimations` runs after all of your controllers have been applied and layered, so a value you set here replaces the animated value for that frame.

**To fully control a bone**, set it from the bone's default pose:

```java
bone.setRotX(bone.getInitialAzSnapshot().getRotX() + angle);
```

**To add movement on top of the animation**, only add to the bone's current value if an animation actually moved the bone this frame, and fall back to the default pose otherwise:

```java
float base = boneCache.wasRotationAnimatedThisFrame(bone)
    ? bone.getRotX()
    : bone.getInitialAzSnapshot().getRotX();

bone.setRotX(base + angle);
```

<Callout variant="warning">
    Don't write `bone.setRotX(bone.getRotX() + angle)` on its own. If no animation moved the bone this frame, it still holds the value your code set last frame, so the angle is added again every frame and the bone spins away. `wasPositionAnimatedThisFrame` and `wasScaleAnimatedThisFrame` do the same check for position and scale.
</Callout>

To mix whole animations together, layer controllers instead; see the Layering Controllers section of the [Animation Controller Builder](./animation_controller_builder) page.

## Example

<Callout variant="info">
    This example swings the arms and legs like a player's while walking. It sets each limb from its default pose, so it works whether or not your animations also move the limbs.
</Callout>

```java
    @Override
    public void setCustomAnimations(Creeper animatable, float partialTicks) {
        super.setCustomAnimations(animatable, partialTicks);
        AzBakedModel model = this.context().boneCache().getBakedModel();

        float walkPosition = animatable.walkAnimation.position(partialTicks) * 0.6662F;
        float walkSpeed = animatable.walkAnimation.speed(partialTicks);

        float armSwing = Mth.cos(walkPosition) * walkSpeed;
        float legSwing = Mth.cos(walkPosition) * 1.4F * walkSpeed;

        // Opposite arms and legs swing together, like the player model.
        swing(model.getBoneOrNull("right_Arm"), -armSwing);
        swing(model.getBoneOrNull("left_Arm"), armSwing);
        swing(model.getBoneOrNull("right_Leg"), legSwing);
        swing(model.getBoneOrNull("left_Leg"), -legSwing);
    }

    private static void swing(AzBone bone, float angle) {
        if (bone != null) {
            bone.setRotX(bone.getInitialAzSnapshot().getRotX() + angle);
        }
    }
```
