Building Codex Menus
The Quest Codex draws zero hardcoded menus. Every screen a player sees — the category browser, the quest list, the sort button — is a regular GUI Extension layout pool that you design. The codex only injects content into the slots you mark for it.
If you haven't read the GUI guides yet, start there: Introduction → Layout Types → Interactions. Everything on this page builds on those concepts.
The big picture
Three entry types share the work:
| Entry | Role | Analogy |
|---|---|---|
quest_category | Declares a category: title, icon, parent, visibility criteria | The folder |
quest_assignment | Links quests into a category, with ordering and per-status overrides | The folder's contents |
category_menu | The menu design: a full GUI layoutPool with placeholder slots | The folder's appearance |
Slot placeholders — the one codex-specific concept
Inside a category_menu layout pool you place placeholder slots. At render time the codex replaces them with live content:
| Placeholder | Replaced by |
|---|---|
CATEGORY_SLOT | One sub-category icon per visible category (title, icon, click → opens it) |
QUEST_SLOT | One quest per assignment (icon + per-status lore from quest_lore, click → track/untrack) |
SORT_SLOT | The sort-mode button (cycles All → Not Started → Active → Completed) |
Everything else in the pool — borders, titles, decoration, extra buttons — is plain GUI content and behaves exactly as documented in the GUI guides.
Two rules to remember:
- One marker = one slot. Markers expand only through their own repetition fields (
count/direction/gap/repeatY); the codex does not auto-fill an area. A 7-wide, 8-row grid needs a marker item per row (orrepeatY: 8).directionis required — a marker withcountbut nodirectionstays a single slot (this also applies to decorative panes that "don't spread"). - Markers scroll. Since 0.3.0, markers are indexed before parsing and live inside the layout tree — put them in a
scrollablelayout's content and the quest list scrolls with the viewport, keeping a stable quest order.
A complete category menu (scrollable)
A 6-row browser: decorative border with the fixed controls, a 7×8 virtual quest grid shown through a 7×4 scroll window:
{
"type": "category_menu",
"name": "default_codex_menu",
"category": "main_quests",
"rows": 6,
"guiType": "CUSTOM",
"mainLayoutId": "root",
"layoutPool": [
{ "case": "simple", "value": { "id": "deco", "items": [
{ "x": 0, "y": 0, "count": 9, "direction": "right",
"item": { "case": "custom_item", "value": { "components": [
{ "case": "material", "value": { "material": "BLACK_STAINED_GLASS_PANE" } } ] } },
"displayName": " " },
{ "x": 0, "y": 5, "count": 9, "direction": "right",
"item": { "case": "custom_item", "value": { "components": [
{ "case": "material", "value": { "material": "BLACK_STAINED_GLASS_PANE" } } ] } },
"displayName": " " },
{ "x": 0, "y": 5, "displayName": "<red>← Back",
"item": { "case": "custom_item", "value": { "components": [
{ "case": "material", "value": { "material": "ARROW" } } ] } },
"interactionList": [ { "type": "LEFT_CLICK", "commands": ["gui:back"] } ] },
{ "x": 4, "y": 5, "buttonType": "SORT_SLOT", "buttonPrefix": "codex_button:",
"item": { "case": "custom_item", "value": { "components": [
{ "case": "material", "value": { "material": "HOPPER" } } ] } } },
{ "x": 8, "y": 5, "displayName": "<red>Close",
"item": { "case": "custom_item", "value": { "components": [
{ "case": "material", "value": { "material": "BARRIER" } } ] } },
"interactionList": [ { "type": "LEFT_CLICK", "commands": [], "closeMenu": true } ] }
] } },
{ "case": "simple", "value": { "id": "quest_grid", "items": [
{ "x": 0, "y": 0, "count": 7, "direction": "right", "gap": 1, "repeatY": 8,
"buttonType": "QUEST_SLOT", "buttonPrefix": "codex_button:",
"item": { "case": "custom_item", "value": { "components": [
{ "case": "material", "value": { "material": "STONE" } } ] } } }
] } },
{ "case": "scrollable", "value": {
"id": "quests", "innerId": "quest_grid",
"virtualWidth": 7, "virtualHeight": 8, "showDefaultButtons": false,
"buttons": [
{ "direction": "UP", "step": 1, "item": { "x": 1, "y": 4, "displayName": "<white>▲",
"item": { "case": "custom_item", "value": { "components": [
{ "case": "material", "value": { "material": "ARROW" } } ] } } } },
{ "direction": "DOWN", "step": 1, "item": { "x": 5, "y": 4, "displayName": "<white>▼",
"item": { "case": "custom_item", "value": { "components": [
{ "case": "material", "value": { "material": "ARROW" } } ] } } } }
] } },
{ "case": "frame", "value": { "id": "root", "frames": [
{ "id": "f_deco", "x": 0, "y": 0, "width": 9, "height": 6, "layoutId": "deco" },
{ "id": "f_scroll", "x": 1, "y": 1, "width": 7, "height": 4, "layoutId": "quests" }
] } }
]
}
What to notice:
- The structure is 100 % GUI Extension: a
framecomposing a decorative layer and ascrollableviewport, repetition fields for borders and the quest grid. - Placeholder slots are ordinary items tagged with
buttonType— one marker item withcount: 7, repeatY: 8expands to a 7×8 grid (56 quest slots), indexed in reading order. - The quest grid lives inside the scrollable content, so quests scroll with the viewport; the ▲/▼ arrows are positioned relative to the scroll frame and only appear when scrolling is possible.
- Scrolling, clicks and sounds are handled by the GUI engine; the codex only decides what goes in each slot.
The sort button
SORT_SLOT renders the current sort mode and cycles on click. Each mode can have its own label, lore and item via the menu's sortDisplay configuration — see category_menu. Modes: All → Not Started → Active → Completed. If you don't configure sortDisplay, a built-in default label/lore is used — set sortDisplay to control the wording and language.
Navigation buttons (Close, Back, Scroll…)
Beyond the content placeholders, you can tag a slot with a navigation buttonType — CLOSE, BACK, PAGE_NEXT / PAGE_PREV, SCROLL_UP / SCROLL_DOWN / SCROLL_LEFT / SCROLL_RIGHT — to wire its click action automatically. Your configured icon, name and lore are kept; the built-in default (e.g. a barrier labelled Close) only fills in when you leave the slot's item empty. Full reference: category_menu → Navigation Buttons.
As shown in the example above, you can also skip the tags entirely and use plain items with interactionList commands (gui:back, gui:close, gui:scroll <dx> <dy> <layoutId>) when you want the visual fully under your control in any menu.
Item names and lore render upright by default — the GUI engine turns off Minecraft's forced italics so menus stay clean. Add the <italic> MiniMessage tag on a name or lore line when you actually want italics.
Per-status quest appearance
A quest slot adapts to the player's progress. quest_lore defines the lore blocks per status (not started / active / completed), and quest_assignment can override icon or visibility per status. Clicking an active quest tracks/untracks it through QuestExtension's native tracker.
Checklist for a working codex
- A
quest_codex_configentry (global sounds, defaults, messages). - At least one
quest_category(top level = no parent). - One
quest_assignmentper category, listing quest entries. - A
category_menuwhose layout pool contains at least oneQUEST_SLOT(andCATEGORY_SLOTif you use sub-categories). - Open it via the commands or a Typewriter trigger.
Design tip: build and test your layout as a plain open_gui menu first (fast iteration with the GUI cookbook recipes), then transplant the pool into your category_menu and swap the content slots for placeholders.