> For the complete documentation index, see [llms.txt](https://docs.marioded.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.marioded.com/api-how-to-guides/ui-extensions.md).

# UI extension concepts

Choose the right extension point for catalog buttons and in-playback controls.

Reverse has two different UI systems. Before registering an action, choose the one your player will interact with.

## Catalog menus

The catalog and details screens are inventory menus. A configured item invokes a `MenuAction` registered in the runtime's `MenuActionRegistry`.

```java
registry.register("example:show_id", (context, parameters) -> {
    if (context.isActive() && context.hasReplay()) {
        context.player().sendMessage(context.requireReplay().getUniqueId().toString());
    }
});
```

Use this for a details button, an information action, or navigation. Obtain the actual registry from the lobby or standalone player, not a new registry instance that the real menu never uses.

{% content-ref url="/pages/b0n6d9EvXvcCokld68DF" %}
[Custom menu actions](/api-how-to-guides/menu-actions.md)
{% endcontent-ref %}

## Playback hotbar

The hotbar is the control inventory shown while a viewer watches a replay. A `LayoutItem` defines its slot and rendering; its click bindings reference `LayoutAction` IDs registered through `LayoutService`.

```java
layout.registerAction("example:rewind_round", (context, parameters) -> {
    context.playbackService().seekTo(context.session(), 0);
});
```

Use this for seeking, speed selection, or a game-specific replay control. You can bind an action from YAML or install a rendered item programmatically.

{% content-ref url="/pages/1vbkO8abqRJE0jhzMLPi" %}
[Custom hotbar controls](/api-how-to-guides/hotbar-controls.md)
{% endcontent-ref %}

## The differences that matter

| Question           | Menu                                       | Hotbar                                 |
| ------------------ | ------------------------------------------ | -------------------------------------- |
| Main API           | `MenuActionRegistry`, `MenuAction.Context` | `LayoutService`, `LayoutItem.Context`  |
| Where it appears   | Catalog/details inventory                  | During playback                        |
| Configuration      | `gui` in the role's `config.yml`           | `playing` in player `layout.yml`       |
| Slot numbering     | Zero-based inventory slots                 | Hotbar slots 1–9                       |
| Optional selection | A replay may be absent                     | Context has an active playback session |
| Runtime            | Lobby or standalone player                 | Player                                 |

Both surfaces use namespaced IDs. Registering an existing ID replaces the existing callback. Namespacing avoids accidental collisions; it does not create automatic plugin ownership or cleanup.

## Keep contexts local to the callback

Contexts describe the interaction currently being handled. Do not retain them as long-lived state or blindly use them from asynchronous completions. Schedule Bukkit work to the main thread and recheck active state, connection, request identity, and access where appropriate.

Shared playback state belongs to the session. A per-viewer hotbar value can remember a chosen interval, but seeking still changes the shared cursor.

For complete registration and cleanup code, see the [UI example](/api-how-to-guides/examples/ui-extensions.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.marioded.com/api-how-to-guides/ui-extensions.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.
