跳到主要内容

How the GUI system works

The GUI extension turns a Typewriter entry into an interactive inventory menu. You never place items slot-by-slot in code — you describe a tree of layouts, and the engine assembles, clips and renders it for each player.

Think of it like building with boxes:

  • A layout is a box that produces items at positions.
  • Boxes can contain other boxes (a scrollable box wrapping a grid box, a composite box stacking several boxes…).
  • The viewport is the window the player looks through — a double chest shows 9×6 slots, but your content can be much bigger and scroll behind it.

The flow, end to end

  1. A player triggers an open_gui action entry (from a quest, an NPC, a command…).
  2. The entry's layoutPool contains named layout definitions; mainLayoutId picks the root.
  3. The engine builds the layout tree, opens the inventory, and starts a session for that player.
  4. Every scroll, page change or reactive update re-renders the visible viewport.
  5. Clicks are matched to the virtual slot under the cursor and run its commands, triggers or internal actions (gui:scroll, gui:back…).

Vocabulary

TermWhat it really is
open_gui entryThe menu itself: container type, title, size, layout pool, audio
layoutPoolA list of named layout definitions. Layouts reference each other by id
mainLayoutIdThe id of the layout used as the root of the tree
LayoutA node producing items: a grid, a scroll area, pages, frames… (all types)
Virtual sizeThe full size of a layout's content (e.g. 9×20 rows)
ViewportThe visible window (9 columns × inventory rows). Scrolling moves the viewport over the virtual space
Item (GuiItemData)One visual cell: an ItemStack + name/lore + interactions + options
SessionThe per-player runtime state: scroll positions, current pages, history for gui:back

Your first menu, step by step

A 3-row chest with a decorated border and a close button in the middle:

{
"id": "my_first_menu",
"type": "open_gui",
"name": "First Menu",
"guiType": "CHEST",
"size": "ROWS_3",
"title": "<gradient:#4f8cff:#3ecf6f>My First Menu</gradient>",
"mainLayoutId": "main",
"layoutPool": [
{
"case": "composite",
"value": { "id": "main", "children": ["border", "content"] }
},
{
"case": "simple",
"value": {
"id": "border",
"items": [
{ "x": 0, "y": 0, "count": 9, "direction": "right",
"item": { "material": "GRAY_STAINED_GLASS_PANE" }, "displayName": " " },
{ "x": 0, "y": 2, "count": 9, "direction": "right",
"item": { "material": "GRAY_STAINED_GLASS_PANE" }, "displayName": " " }
]
}
},
{
"case": "simple",
"value": {
"id": "content",
"items": [
{ "x": 4, "y": 1,
"item": { "material": "BARRIER" },
"displayName": "<red>Close",
"interactions": [
{ "type": "LEFT", "commands": [], "closeMenu": true }
] }
]
}
}
]
}

What to notice:

  • Two layers stacked by the composite layout — the border renders first, the content on top.
  • Repetition without copy-paste: count: 9, direction: "right" places 9 panes from (0,0).
  • closeMenu: true on the interaction adds the internal gui:close action — no command string needed.
  • The title is MiniMessage: gradients, colors, hover — and custom glyphs if you use a resource pack.
  • Item names and lore render upright by default. Minecraft normally forces custom item text into italics; the GUI engine turns that off so your menus stay clean. If you actually want italics on a name or a lore line, add the <italic> MiniMessage tag explicitly (e.g. <italic><gray>A hint) — it wins over the default.
提示

A web-based WYSIWYG editor (drag & drop, live preview, states) is in development and will write this JSON for you.

Where to go next

  • Layout Types — every layout, when to use it, complete examples
  • Commands & Interactions — click types, internal gui: actions, cooldowns, input dialogs
  • Cookbook — ready-to-paste recipes (shop, pagination, confirmation, storage)