Menu Layouts
Layouts dynamically fill a set of slots with items from a collection — the primary tool for building paginated lists, inventories, leaderboards, and any other variable-length content.
How Layouts Work
A
LayoutBlueprintis defined in the menu'slayouts:map.At compute time a
LayoutInstanceis created and bound to a data provider.Items tagged with the layout's
taintare distributed across the layout's slots.Pagination is handled via
next-page,previous-page, andfirst-pageactions.
Blueprint Fields
Field | Type | Description |
|---|---|---|
| String (placeholder) | Resolves to a |
| String | Only |
|
| When any fails the layout renders nothing. |
| object | Optional timer that re-runs the provider and redistributes items (see Auto-refresh). |
| object | Optional. Orders the provider entries before pagination (see Sorting). |
Data Providers
The provider placeholder must resolve to one of:
Type | Description |
|---|---|
| Each element is rendered as one layout slot. The element's placeholder context is active while rendering that slot's item. |
| Each key-value pair is exposed as a placeholder context per slot. |
| Custom Java interface for programmatic item generation. |
Providers are typically passed as parameters when opening the menu:
Slot Assignment
Layout slots are defined by associating items with the layout's taint. The slots those items occupy become the layout's available slots. Items are distributed in slot-index order.
Slots claimed by an input slot are excluded: a slot the player owns can never be rendered into, so it never becomes one of the layout's available slots.
Overlapping layouts
Two layouts may cover the same slot. Ownership is not decided when the layouts are built — it is claimed by whichever one last rendered into the slot, and only that one may clear or refresh it. A layout whose view-requirements stop passing tears itself down without blanking a slot another layout has since drawn into.
This makes "one of these two lists, depending on state" a supported pattern: give both layouts the same slots and keep them apart with mutually exclusive view-requirements. Overlap where the requirements do not keep them apart is not rejected either: nothing is logged and the last render simply wins, so a shared slot that flickers between two layouts points at requirements that both pass.
Entry Placeholders
While a provider entry is being rendered — and while its sort key is being evaluated — the entry is exposed under the parameter namespace, on top of the menu's own placeholders.
Placeholder | Description |
|---|---|
| Index of the entry in the backing provider. Not renumbered by sorting: an entry keeps its original provider index after being reordered. |
| Inventory slot the entry is being rendered into. |
| The entry itself, under its own placeholder namespace (e.g. |
Sorting
A layout can order its provider entries before they are paginated via a sort: block. Useful for lists whose provider returns an arbitrary order (market listings by price, leaderboards by score).
Field | Type | Description |
|---|---|---|
| String (placeholder) | Sort key, resolved inside the comparator — once per entry per comparison, not cached. Required to activate — nothing is sorted when absent. Must resolve to a |
|
| Sort direction, uppercase. Required whenever |
Sorting runs after the view-requirement pass that decides which entries are visible, and before the page count and the page slice are computed — so the ordering is global across all pages, not a per-page shuffle.
by is evaluated in the entry's own context, which is what makes %parameter_<namespace>_…% (and %parameter_index%) usable as a sort key; %parameter_slot% is -1 during that evaluation, so it is meaningless as a key. order is resolved once per compute in the menu context instead, so menu-level placeholders work there but per-entry %parameter_…% do not.
Because the key is re-resolved on every comparison rather than computed once per entry, keep by cheap — a plain provider field, not an $e(...) expression over several placeholders.
Pagination
When the provider has more items than available slots, the layout is automatically paginated. Pages are cut out of the sorted entry list, so navigating pages walks the sorted order.
The current page number is accessible via %layouts_items_page% and the total page count via %layouts_items_maxPages%.
A full menu refresh via the refresh action keeps the viewer on the page they were on: the page is carried across the recompute and clamped to the new page count, so a shrinking provider lands on the last available page rather than resetting to the first.
Auto-refresh
A layout can re-run its provider and redistribute items on a repeating timer via a refresh: block — the layout-level analogue of item auto-refresh. Useful for live lists (online players, leaderboards, market listings) that change without a click.
Field | Type | Description |
|---|---|---|
| double (seconds) | Interval between refreshes, in seconds. Accepts a placeholder / |
|
| Optional. Evaluated every tick; if any fails, that tick is skipped (the timer keeps running). |
|
| Optional. Run every tick that requirements pass, immediately before the layout is re-rendered. |
Each tick re-resolves the provider and redistributes items across the layout's slots — the timer-driven equivalent of a refresh-layout action.
Layout Placeholders
%layouts_<id>% resolves to the live layout instance, and any remaining tokens drill into it.
Placeholder | Description |
|---|---|
| Layout identifier |
| Current page index (0-based) |
| Total number of pages |
|
|
|
|
These keys are commonly combined with view-requirements to hide navigation buttons when no further pages exist, e.g. [compare] %layouts_items_hasNextPage% == true.