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

# Animation timelines and tracks

Animations provide smooth menu entrances and exits, as well as movement, rotation, scaling and changes to text and other frontend elements.

Configure them in `plugins/ArcMenu/animations.yml` on Paper, Folia, Leaf and similar servers. Spigot does not support animations. Players need no client mod; images used in animations still follow [Images and resource packs](/arcmenu-wiki/feature-configuration/resource-packs.md).

## File structure

| Top-level field  | Purpose                                          |
| ---------------- | ------------------------------------------------ |
| `schema-version` | Use `1` for the configuration format.            |
| `transitions`    | Named effects for the entire menu.               |
| `tracks`         | Named property animations for frontend elements. |
| `menus`          | Selects transitions and tracks by menu ID.       |

The hierarchies are **`transitions` → transition ID → phase → phase properties** and **`tracks` → track ID → track properties**, followed by bindings under **`menus` → menu ID**.

Transition and track IDs use lowercase letters, digits, underscores and hyphens, starting with a letter or digit. They are separate from menu IDs and target element names.

## Configuration example

This example uses the `menu-guide` menu and its `title` text element from [Menu document structure](/arcmenu-wiki/menu-configuration/menus.md). Create and load that menu first, then merge these entries into the corresponding sections of `animations.yml`. Retain animations required by existing menus.

```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}}

  title-message:
    target: title
    property: content
    duration: 40
    easing: linear
    loop: once
    trigger: api
    keyframes:
      - {at: 0, value: '&fMenu guide'}
      - {at: 0.5, value: '&aWelcome!'}
      - {at: 1, value: '&fMenu guide'}

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

Opening the menu plays the entrance transition and title fade. `title-bob` and `title-message` wait for an action or command instead of starting automatically.

## Whole-menu transitions: `transitions`

A transition contains at least one of these phases:

| Phase    | Timing and effect                                                                               |
| -------- | ----------------------------------------------------------------------------------------------- |
| `enter`  | On initially opening a menu, moves from the configured offset and scale to the normal state.    |
| `exit`   | On closing, moves from the normal state to the configured offset and scale.                     |
| `switch` | On switching from another menu, moves from the configured offset and scale to the normal state. |

Omitted phases do not play. The example omits `switch`, so switching to this menu does not substitute its `enter` transition.

### Phase properties

| Field      | Purpose                                                   |
| ---------- | --------------------------------------------------------- |
| `duration` | Required integer duration from `1` to `72000` game ticks. |
| `easing`   | Rate of change; defaults to `linear`.                     |
| `offset`   | `x`, `y` and `z` offsets, each defaulting to `0`.         |
| `scale`    | `x` and `y` scales, each defaulting to `1` when omitted.  |

`offset` is relative to the whole menu's normal placement, using menu coordinate directions. The example's `enter.offset.x: -20` moves in from the left without rewriting element positions.

A scale of `1` is normal size. Scale values must be nonzero with an absolute value at most `1000`; positive values are usual. Whole-menu transitions do not configure rotation, text content or `scale.z`.

Button input is suspended and tooltips are hidden during whole-menu transitions. Normal interaction resumes afterward; the menu closes when its exit transition finishes.

## Element tracks: `tracks`

One track controls one property of one frontend element.

### Track properties

| Field       | Purpose                                                   | Default   |
| ----------- | --------------------------------------------------------- | --------- |
| `target`    | Required frontend element or group name.                  | None.     |
| `property`  | Required property to animate, listed below.               | None.     |
| `duration`  | Required one-way duration from `1` to `72000` game ticks. | None.     |
| `easing`    | Rate of change.                                           | `linear`. |
| `loop`      | Once, repeating or back-and-forth playback.               | `once`.   |
| `trigger`   | Starts on opening or waits for manual playback.           | `open`.   |
| `keyframes` | Required ordered keyframe list.                           | None.     |

`target` must exist in the bound menu's `frontend`. It can be a group or a nested element, but not a backend region. Animating a group's placement, rotation or scale affects its visible children.

### Properties and keyframe values

| `property` | `value` syntax        | Supported targets                                 |
| ---------- | --------------------- | ------------------------------------------------- |
| `offset`   | `{x: 0, y: 20, z: 1}` | Frontend element and group positions.             |
| `rotation` | `{x: 0, y: 90, z: 0}` | Frontend element and group rotations, in degrees. |
| `scale`    | `{x: 1.1, y: 1.1}`    | Frontend element and group scales.                |
| `content`  | `'&aWelcome!'`        | Text elements only.                               |
| `opacity`  | `255`                 | Text elements only, integer `0` to `255`.         |

Track values replace the target's own property rather than adding to it. A title originally at `y: 20` moves from `20` to `28` in `title-bob`, rather than from `40` to `48`.

Omitted position and rotation axes are `0`. Scale frames require both `x` and `y`. Only item and block targets may include `z`; omitting it preserves the original depth scale. Scales must be nonzero with absolute values at most `1000`. Position and rotation axes have absolute values at most `100000`.

### Keyframes: `keyframes`

Each frame contains `at` and `value`:

* Use at least two frames, starting at `at: 0` and ending at `at: 1`.
* `at` is progress through the animation. Values must increase strictly, without duplicates.
* `value` must match the track property's type.

With `duration: 40` and `easing: linear`, `at: 0.5` is reached after `20` game ticks. At normal server speed, `20` ticks are approximately `1` second.

Position, rotation, scale and opacity change gradually between frames. Text content switches when its frame is reached rather than appearing character by character. Other easing curves also change when intermediate frames are reached.

### Easing: `easing`

| Value         | Effect                                        |
| ------------- | --------------------------------------------- |
| `linear`      | Constant rate.                                |
| `ease-in`     | Starts slowly, then accelerates.              |
| `ease-out`    | Starts quickly, then slows.                   |
| `ease-in-out` | Slower at both ends and faster in the middle. |

Transition phases and element tracks use the same names.

### Loops: `loop`

| Value       | Behavior                                               |
| ----------- | ------------------------------------------------------ |
| `once`      | Plays once and holds the last frame's value.           |
| `repeat`    | Starts again from the first frame after each cycle.    |
| `ping-pong` | Moves from first to last frame, then back, repeatedly. |

`duration` is one-way time. The example's `title-bob` takes `20` ticks upward and another `20` downward, for a `40`-tick round trip.

### Triggers: `trigger`

`open` starts when the menu opens. `api` waits for an animation action or management command. Despite the configuration name, manual playback needs no coding.

Different properties of the same element may animate together, such as title position and opacity. A menu cannot bind multiple `open` tracks to the same element and property. Manually starting another track for that property replaces the running one.

Playing the same track again restarts it. A `once` track keeps its property at the last frame until stopped. Stopping restores the menu's original configured value. While a `content` track remains active, that element's periodic text updates are paused.

## Menu bindings: `menus`

Under each menu ID, `transition` selects one whole-menu transition and `tracks` lists available track IDs. Omit `transition` if unnecessary. A menu using only a transition may set `tracks: []`.

A track cannot play in a menu unless included in that menu's `tracks`. Missing menus, missing tracks or incompatible targets cause validation errors. Several menus may select the same track, but each must provide a valid target element.

## Playing and stopping

Menu buttons use these actions:

```yaml
backend:
  animation-area:
    x: 50
    y: 0
    width: 30
    height: 18
    actions:
      left: 'animation: title-bob'
      right: 'animation: title-message'
      shift-left: 'stop-animation: title-bob'
```

Added to `menu-guide`, this region starts title motion on left-click, plays the title message on right-click and stops motion on Shift+left-click. Configure its visible button separately. Actions take track IDs, not transition IDs such as `soft-slide`.

Administrators can also run these commands in a normally opened menu:

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

Commands require `arcmenu.admin`. Playing and stopping require an in-game player with a menu open and the corresponding track bound.

## Display and interaction limits

Element tracks change only `frontend` display. They do not move, rotate or scale `backend` hit regions. Hiding text through opacity does not disable a button.

Use element tracks for moving decoration. When animating a clickable button, consider whether its fixed region still matches the visible position. Use whole-menu transitions for entrances and exits rather than moving every button separately.

Animations do not change saved menu files. Closing and reopening restarts automatically triggered tracks. Preview mode does not test normal playback or button triggers.

## Loading and checking

After editing menus or `animations.yml`, run `/arcmenu validate` and `/arcmenu reload`. Reopen the menu to check automatic playback, manual triggers, loops and restored values after stopping. Animation parameter changes alone do not require rebuilding the pack.

Check sustained loops, whether final text should remain and whether animated buttons' regions are correct. Whole-menu transitions should restore clicks and tooltips afterward. Verify these display and interaction effects in-game.
