> For the complete documentation index, see [llms.txt](https://docs.myarc.icu/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.myarc.icu/en/feature-configuration/animations.md).

# Animation timelines and tracks

Animations let menus transition smoothly when opening, closing, or switching, and let you move, rotate, scale, fade, or recolor frontend text, images, rectangles, items, or entire groups. Players see all of these animations directly on a vanilla client.

Menu animations are configured in `plugins/ArcMenu/animations.yml` (animations installed from ArcPack expansion packages are placed in `plugins/ArcMenu/animations/` and loaded automatically).

## Configuration file structure

`animations.yml` has four top-level fields. You first define reusable transitions and tracks, then bind them to specific menus:

| Top-level field  | Purpose and valid values                                                           |
| ---------------- | ---------------------------------------------------------------------------------- |
| `schema-version` | Configuration file format version; always set to the integer `1`.                  |
| `transitions`    | Defines whole-menu entry, exit, and switch transitions.                            |
| `tracks`         | Defines keyframe animation tracks for a single frontend element or group property. |
| `menus`          | Binds a `transition` and list of `tracks` to each menu by its `id`.                |

Custom identifiers under `transitions` and `tracks` may only contain lowercase English letters, digits, underscores (`_`), and hyphens (`-`), and must start with a letter or digit.

## Complete configuration example

Suppose we have a menu with ID `menu-guide` containing a text element named `title` and a rectangle element named `button-bg`. We can write its animations in `animations.yml` like this:

```yaml
schema-version: 1

transitions:
  soft-slide:
    enter:
      duration: 8
      easing: ease-out
      offset: {x: -20, y: 0, z: 0}
      scale: {x: 0.95, y: 0.95}
    exit:
      duration: 6
      easing: ease-in
      offset: {x: 0, y: -20, z: 0}
      scale: {x: 0.95, y: 0.95}

tracks:
  title-fade:
    target: title
    property: opacity
    duration: 20
    easing: linear
    loop: once
    trigger: open
    keyframes:
      - {at: 0, value: 80}
      - {at: 1, value: 255}

  title-bob:
    target: title
    property: offset
    duration: 20
    easing: ease-in-out
    loop: ping-pong
    trigger: api
    keyframes:
      - {at: 0, value: {x: 0, y: 20, z: 1}}
      - {at: 1, value: {x: 0, y: 28, z: 1}}

  button-highlight:
    target: button-bg
    property: color
    duration: 4
    easing: ease-out
    loop: once
    trigger: api
    keyframes:
      - {at: 0, value: '#181916'}
      - {at: 1, value: '&#DF432D'}

menus:
  menu-guide:
    transition: soft-slide
    tracks: [title-fade, title-bob, button-highlight]
```

In this example, when a player opens `menu-guide`, the entire menu slides in smoothly from the left (`soft-slide`) while the title opacity fades from `80` to `255` (`title-fade`). Because `title-bob` and `button-highlight` use `trigger: api`, they play on demand when hovering or clicking buttons.

## Whole-menu transitions (`transitions`)

Each transition definition can include any one or more of the three phases `enter`, `exit`, and `switch` (at least one phase must be configured):

| Phase    | Trigger timing and direction                                                                                                                               |
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enter`  | Plays when a player first opens the menu. The menu transitions smoothly from your configured `offset` and `scale` back to its normal position and size.    |
| `exit`   | Plays when a player closes the menu. The menu transitions smoothly from its normal state to your configured `offset` and `scale`, then closes.             |
| `switch` | Plays when switching to this menu from another open menu. The menu transitions smoothly from the configured `offset` and `scale` back to its normal state. |

Each phase supports the following fields:

| Field      | Description and valid values                                                                                                                                                   |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `duration` | Required. Transition duration as an integer from `1` to `72000` (in game ticks, where `20` ticks is roughly 1 second).                                                         |
| `easing`   | Timing curve: `linear`, `ease-in`, `ease-out`, or `ease-in-out`. Defaults to `linear` when omitted.                                                                            |
| `offset`   | Starting (or ending) position offset relative to the menu's normal position, with `x`, `y`, and `z` up to an absolute value of `100000` per axis. Omitted axes default to `0`. |
| `scale`    | Overall starting (or ending) scale multiplier, with `x` and `y` as non-zero numbers up to an absolute value of `1000`. Omitted axes default to `1`.                            |

While a whole-menu transition is playing, button clicks are briefly locked and tooltips are hidden; normal interaction resumes as soon as the transition finishes.

## Element property tracks (`tracks`)

Each track controls a single property on one frontend element (or group). A track configuration includes the following fields:

| Field       | Description and valid values                                                                                               | Default  |
| ----------- | -------------------------------------------------------------------------------------------------------------------------- | -------- |
| `target`    | Required. Name of the target frontend element or group (must exist in the bound menu's frontend).                          | None     |
| `property`  | Required. Property to animate: `offset`, `rotation`, `scale`, `content`, `opacity`, or `color`.                            | None     |
| `duration`  | Required. One-way playback duration as an integer from `1` to `72000` (in game ticks).                                     | None     |
| `easing`    | Timing curve for the track's overall one-way progress: `linear`, `ease-in`, `ease-out`, or `ease-in-out`.                  | `linear` |
| `loop`      | Loop mode: `once` (single play), `repeat` (restart from beginning), or `ping-pong` (back and forth).                       | `once`   |
| `trigger`   | Trigger mode: `open` (plays automatically when the menu opens) or `api` (triggered by actions, hover events, or commands). | `open`   |
| `keyframes` | Required. Time-ordered list of keyframes.                                                                                  | None     |

When `target` points to a `group`, `offset`, `rotation`, and `scale` tracks move, rotate, or scale all child elements inside that group together.

### Animatable properties and keyframe values (`property` and `value`)

Each entry in the `keyframes` list contains `at` (time progress) and `value` (property value).

* `at` takes a number from `0` to `1`, representing the fraction of the total `duration` (for example, with `duration: 40`, `at: 0.5` corresponds to tick `20`).
* A track requires at least **2 keyframes**: the first frame must have `at: 0`, the last frame must have `at: 1`, and any intermediate frames must have strictly increasing, non-duplicate `at` values.

The `value` format and supported element types for each `property` are as follows:

| `property` | Example `value` format      | Valid range and applicable elements                                                                                                                                                        |
| ---------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `offset`   | `{x: 0, y: 20, z: 1}`       | Applies to all frontend elements and groups. Each axis accepts an absolute value up to `100000`; omitted axes default to `0`.                                                              |
| `rotation` | `{x: 0, y: 90, z: 0}`       | Applies to all frontend elements and groups, in degrees. Each axis accepts an absolute value up to `100000`; omitted axes default to `0`.                                                  |
| `scale`    | `{x: 1.1, y: 1.1}`          | Applies to all frontend elements and groups. `x` and `y` are required, and `item` and `block` elements may also specify `z`; values must be non-zero with an absolute value up to `1000`.  |
| `content`  | `'&aWelcome!'`              | Applies only to `text` elements. Switches the displayed text when playback reaches the keyframe.                                                                                           |
| `opacity`  | `255`                       | Applies only to `text` elements. Accepts an integer from `0` to `255` and interpolates smoothly between keyframes.                                                                         |
| `color`    | `'#DF432D'` or `'&#DF432D'` | Applies only to `rectangle`, `line`, and `frame` elements. Accepts a quoted 6-digit hex color, interpolating smoothly across RGB channels while preserving the element's original opacity. |

Note that during playback, a track's `value` **directly replaces** the corresponding property configured on the target element in the menu YAML rather than adding to it. For instance, if a title is originally placed at `y: 20` and you want it to float upward by `8` units, your keyframes should go from `y: 20` to `y: 28`. When the track is stopped (`stop-animation`), the element automatically returns to the initial value configured in the menu YAML.

### Timing curves and loop modes

`easing` applies to the overall normalized progress (`0` to `1`) of a single one-way pass across the entire track. ArcMenu first maps the overall time progress through the easing curve, then locates the active keyframe interval and interpolates linearly within it, rather than resetting the curve between every adjacent pair of keyframes:

* `linear`: Advances at a constant speed from start to finish.
* `ease-in`: Starts slowly and gradually accelerates.
* `ease-out`: Starts quickly and decelerates smoothly toward the end.
* `ease-in-out`: Starts and ends gently with faster movement through the middle.

`loop` controls what happens after the track reaches `at: 1`:

* `once`: Plays a single time and holds the final keyframe's value indefinitely (until the track is manually stopped). While a `content` track is active on a text element, that element's periodic text refresh pauses so it does not overwrite the animated text.
* `repeat`: Jumps back to the first keyframe and replays immediately each time it reaches the end.
* `ping-pong`: Plays forward from the first frame to the last, then reverses back to the first frame continuously. Because `duration` measures a single one-way pass, a full round trip takes `2 × duration`.

## Binding animations to menus (`menus`)

Once your `transitions` and `tracks` are defined, bind them to specific menu IDs under `menus`:

```yaml
menus:
  menu-guide:
    transition: soft-slide
    tracks: [title-fade, title-bob, button-highlight]
```

* If a menu only needs element tracks and no whole-menu transition, omit `transition`.
* If a menu only needs a whole-menu transition, write `tracks: []`.
* **Different properties** on the same element (such as `offset` and `opacity`) can each run their own automatic `trigger: open` track simultaneously, while the **same property** on the same element can bind at most one `trigger: open` track. Manual `trigger: api` tracks have no count limit—starting a new track on the same property automatically takes control of that property.
* Any track triggered by an action inside a menu must be listed in that menu's `tracks` list.

## Triggering and stopping track animations

Tracks configured with `trigger: api` can be controlled through button click actions, hover events, or admin commands.

### Hover highlights and button click triggers

Inside a menu's `backend` regions, use `animate: <track-id>` (or the equivalent `animation: <track-id>`) to start a track, and `stop-animation: <track-id>` to stop it and restore the element's initial value.

For example, combining the `button-highlight` color track from earlier, you can build a button that smoothly changes color when pointed at and reverts when the pointer leaves:

```yaml
frontend:
  button-bg:
    type: rectangle
    width: 80
    height: 30
    color: '#181916'

backend:
  button-area:
    x: 0
    y: 0
    width: 80
    height: 30
    on-hover: 'animate: button-highlight'
    on-leave: 'stop-animation: button-highlight'
    actions:
      left: 'animate: title-bob'
      shift-left: 'stop-animation: title-bob'
```

When a player points at `button-area`, `on-hover` triggers the `button-highlight` color transition once without restarting it on every tick while hovering; when the pointer leaves, `on-leave` stops the track and restores the `#181916` base color. If you also want a smooth fade-out when the pointer leaves, define a second track that transitions from the highlight color back to the base color and trigger it in `on-leave`.

### Debugging animations with admin commands

Administrators with the `arcmenu.admin` permission can inspect or test tracks in-game while viewing a menu that has those tracks bound:

```
/arcmenu animations
/arcmenu animate title-bob
/arcmenu stop-animation title-bob
```

## Client-side interpolation optimization

In `config.yml`, `client-playback.linear-offsets` is enabled (`true`) by default:

```yaml
client-playback:
  linear-offsets: true
```

When enabled, eligible linear position tracks (`property: offset` with `easing: linear`) use Minecraft's native display-entity client interpolation for smooth movement, reducing how often the server sends per-tick position update packets. Keyframe transitions, loop resets, and play/stop controls remain accurately synchronized by the server.

After editing and saving `animations.yml`, run `/arcmenu reload` to apply your changes. If you want to build full-screen cutscenes with synchronized audio, fixed-camera staging, and multi-layer timelines, see [Effect cutscenes](/en/feature-configuration/effect.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.myarc.icu/en/feature-configuration/animations.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
