Saltar al contenido principal

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: IntroductionLayout TypesInteractions. Everything on this page builds on those concepts.

The big picture

Three entry types share the work:

EntryRoleAnalogy
quest_categoryDeclares a category: title, icon, parent, visibility criteriaThe folder
quest_assignmentLinks quests into a category, with ordering and per-status overridesThe folder's contents
category_menuThe menu design: a full GUI layoutPool with placeholder slotsThe 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:

PlaceholderReplaced by
CATEGORY_SLOTOne sub-category icon per visible category (title, icon, click → opens it)
QUEST_SLOTOne quest per assignment (icon + per-status lore from quest_lore, click → track/untrack)
SORT_SLOTThe 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:

  1. 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 (or repeatY: 8). direction is required — a marker with count but no direction stays a single slot (this also applies to decorative panes that "don't spread").
  2. Markers scroll. Since 0.3.0, markers are indexed before parsing and live inside the layout tree — put them in a scrollable layout'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 frame composing a decorative layer and a scrollable viewport, repetition fields for borders and the quest grid.
  • Placeholder slots are ordinary items tagged with buttonType — one marker item with count: 7, repeatY: 8 expands 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.

Beyond the content placeholders, you can tag a slot with a navigation buttonTypeCLOSE, 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.

nota

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

  1. A quest_codex_config entry (global sounds, defaults, messages).
  2. At least one quest_category (top level = no parent).
  3. One quest_assignment per category, listing quest entries.
  4. A category_menu whose layout pool contains at least one QUEST_SLOT (and CATEGORY_SLOT if you use sub-categories).
  5. Open it via the commands or a Typewriter trigger.
consejo

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.