GitHub Discord
⚡ SmartMenus · Latest

Welcome to Smart Menus

Smart Menus is an advanced, fully configuration-driven inventory GUI plugin for Minecraft (Paper/Spigot). Build complex shop menus, navigation hubs, interactive GUIs, and live data displays — all from YAML files, zero coding required.

What is Smart Menus?

Smart Menus lets server administrators define custom inventory GUIs entirely through YAML configuration files. Each GUI lives in its own subfolder under plugins/SmartMenus/guis/, making it easy to organise, share, and reload individual menus without restarting the server.

Whether you need a simple item shop, a multi-page quest board, a dynamic player list, or a complex condition-gated upgrade menu — Smart Menus handles it.

Key Features

🎛️

15+ Button Types

NONE, INVENTORY, BACK, NEXT, PREVIOUS, JUMP, HOME, MAIN_MENU, PAGINATION, DYNAMIC_PAGINATION, SWITCH, INPUT and more.

Full Action System

Messages, titles, action bars, sounds, commands, teleport, BungeeCord server connect, and JavaScript script actions.

Advanced Conditions

Economy, XP, permissions, placeholders, math expressions, script conditions, world/region checks, and item requirements.

🔄

Live Dynamic Data

Paginate over online players, loaded worlds, your inventory, ender chest, or LuckPerms permission groups — live, every tick.

🔣

Expression Engine

Write math conditions like %vault_eco_balance% >= 1000 or %player_level% * 2 > 30 directly in YAML.

🧩

Patterns

Define reusable item templates in patterns/ and apply them across multiple GUIs with variable substitution.

📦

Any Inventory Type

Not just chests — open GUIs as HOPPER, DISPENSER, DROPPER, FURNACE, BLAST_FURNACE, SMOKER and more.

🔌

Rich Integrations

Vault, PlaceholderAPI, LuckPerms, WorldGuard, ItemsAdder, Nexo, OreoEssentials, ModeledNPCs.

How It Works

Each GUI is a .yml file inside a subfolder under plugins/SmartMenus/guis/. Smart Menus scans this folder recursively on startup and reload. A minimal GUI looks like this:

YAML
my_shop: title: "&6My Shop" rows: 3 commands: [ "myshop", "shop" ] items: diamond-item: slot: 13 material: DIAMOND name: "&b&lDiamond" lore: - "&7Click to buy for &a$100" conditions: - type: VAULT_MONEY amount: 100 take: true commands: - "give {player} diamond 1"

Supported Versions

MinecraftJavaStatus
1.21.x21+✅ Supported
1.20.x17+✅ Supported
1.19.x17+✅ Supported
1.18.x17⚠️ Untested
≤ 1.17❌ Not supported

Next Steps

Installation

Smart Menus is a Paper/Spigot plugin. Installation takes under two minutes.

Requirements

RequirementVersionNotes
Server softwarePaper / SpigotPaper strongly recommended
Minecraft1.19 – 1.21
Java17+Java 21 recommended
PlaceholderAPIAny recentOptional but strongly recommended
VaultAnyRequired for economy conditions

Steps

  1. Download SmartMenus.jar from the releases page.
  2. Place it in your server's plugins/ folder.
  3. Start or restart the server. Smart Menus will generate its default config files.
  4. All default GUIs are extracted to plugins/SmartMenus/guis/ automatically.
  5. Use /smartmenus reload after editing any GUI file.
TipYou do not need to restart the server when editing GUIs. Run /smartmenus reload to hot-reload all files.

Folder Structure

Shell
plugins/SmartMenus/ ├── config.yml # Plugin settings ├── lang.yml # All user-facing messages └── guis/ ├── my_shop/ │ └── my_shop.yml ├── rank_upgrade/ │ └── rank_upgrade.yml └── feature_showcase/ ├── showcase_hub.yml └── showcase_pagination.yml
NoteMultiple GUIs can share a single .yml file — just use different top-level keys. Smart Menus loads all .yml files in guis/ recursively.

Quick Start

Create a working GUI in under 5 minutes.

Step 1 — Create the file

Create a new folder and file: plugins/SmartMenus/guis/welcome/welcome.yml

Step 2 — Write the GUI

welcome.yml
welcome_menu: title: "&8&l✦ Welcome &7| &f{player}" rows: 3 commands: [ "welcome", "hub" ] items: # Background filler border: slots: [ 0-8, 18-26 ] material: BLACK_STAINED_GLASS_PANE name: "&8" # Clickable button that runs a command play-btn: slot: 13 material: EMERALD name: "&a&lPlay Now" lore: - "&7Teleport to spawn." - "" - "&eClick!" commands: - "spawn" close-btn: slot: 22 material: BARRIER name: "&c&lClose" close: true

Step 3 — Reload & test

In-game
/smartmenus reload /welcome
That's it!The GUI opens with /welcome. Every player with the smartmenus.command.welcome_menu permission can use it.

Add conditions

Gate the button behind a Vault balance check:

YAML
buy-btn: slot: 13 material: DIAMOND name: "&b&lBuy Diamond — &a$50" conditions: - type: VAULT_MONEY amount: 50 take: true # deducts the money on click commands: - "give {player} diamond 1" else_item: material: COAL name: "&8Not enough money" lore: - "&7Need &a$50&7. You have &c%vault_eco_balance%"

GUI Structure

Every GUI is a top-level YAML key. Under it, you define metadata and an items: map.

Top-level Properties

KeyTypeDefaultDescription
titleStringrequiredInventory title. Supports color codes, {player}, and PlaceholderAPI.
rows1 – 66Number of rows (chest only). Ignored for other inventory_type values.
commandsList[]Commands that open this GUI. First entry is primary; rest are aliases.
inventory_typeStringCHESTContainer type: CHEST, HOPPER, DISPENSER, FURNACE, etc.
main_menuGUI IDTarget GUI for MAIN_MENU buttons.
npc_idIntegerModeledNPCs NPC ID that opens this GUI on right-click.
fill:Item blockItem used to fill any empty slot after all other items are rendered.
items:MaprequiredNamed item definitions (see below).
use_bottom_inventoryBooleanfalseEnable 90-slot full-screen mode. Saves and replaces player inventory with bottom_items:.
bottom_items:MapItems for the player inventory area (slots 0–35). Only used when use_bottom_inventory: true.
args:ListTyped command arguments passed when opening the GUI. Each arg becomes %arg_name%.
patterns:ListReusable pattern IDs applied to all items before individual item config.

Item Properties

KeyDescription
slot / slotsSingle slot number, list, or range like 0-8.
typeButton type (default NONE). See Button Types.
materialBukkit material name, PLAYER_HEAD, or AUTO.
nameDisplay name. Color codes and placeholders supported.
loreList of lore lines.
amountStack size (1–64).
custom_model_dataCustom model data integer.
glowtrue to add enchantment glow.
item_typeItem source: vanilla (default), itemsadder, nexo, headdatabase
item_idCustom item namespace ID — used when item_type is not vanilla (e.g. iasurvival:ruby)
item_flagsList of flags to hide: HIDE_ENCHANTS, HIDE_ATTRIBUTES, HIDE_POTION_EFFECTS, HIDE_UNBREAKABLE
enchantmentsMap of enchantment name → level (e.g. SHARPNESS: 5)
updatetrue to auto-refresh item name/lore with live placeholders every tick interval
update-intervalTicks between placeholder refreshes (default: 10). Requires update: true
give-itemFor DYNAMIC_PAGINATION: true to give the source item to the player's inventory on click
take-itemFor DYNAMIC_PAGINATION: true to remove the source item from the player's inventory/enderchest on click
closetrue to close the GUI on click.
commandsList of console commands run on click. Use {player}.
actionsStructured action list (see Actions).
conditionsList of condition blocks. All must pass.
else_itemItem shown when conditions fail (replaces this item).
view_requirementsConditions to show the item at all.
click_typeLimit to a specific click: LEFT, RIGHT, SHIFT_LEFT, MIDDLE, etc.

Slot Notation

YAML
slot: 13 # single slot slots: [ 0, 1, 2 ] # explicit list slots: [ 0-8 ] # range (inclusive) slots: [ 0-8, 18-26 ] # multiple ranges

Color Codes

YAML
name: "&a&lGreen Bold" name: "&#ff6600Orange Hex" name: "&lBold {player}"

Button Types

Every item in a GUI has a type: field. The default is NONE — a plain clickable item.

TypeDescription
NONEStandard clickable item. Runs commands: / actions:.
INVENTORYOpens another GUI and pushes current to history stack.
BACKPops history stack — returns to previous GUI.
HOMEJumps to the oldest GUI in the history stack.
MAIN_MENUJumps to the GUI set in main_menu: on the current GUI.
NEXTAdvance to the next page of a PAGINATION/DYNAMIC_PAGINATION GUI.
PREVIOUSGo back one page.
JUMPJump to a specific page number (to-page: 2).
PAGINATIONRenders a static paginated element list.
DYNAMIC_PAGINATIONRenders a live data source across slots.
SWITCHMulti-state toggle driven by a key or placeholder.
INPUTAccepts item placement from the player.

Navigation Buttons

Smart Menus maintains a per-player navigation history stack. These buttons let players move through it.

INVENTORY

Opens another GUI and pushes the current one onto the history stack.

YAML
open-shop: type: INVENTORY slot: 10 inventory: my_shop # ID of the target GUI material: CHEST name: "&e&lOpen Shop"

BACK

Pops the history stack and returns to the previous GUI. Hidden if there is no history.

YAML
back-btn: type: BACK slot: 45 material: RED_STAINED_GLASS_PANE name: "&c⬅ Back"

HOME

Jumps directly to the first (oldest) GUI in the navigation stack.

YAML
home-btn: type: HOME slot: 49 material: NETHER_STAR name: "&e⌂ Home"

Opens the GUI specified by main_menu: at the top level of the current GUI definition.

YAML
# At the GUI level: my_sub_gui: main_menu: main_hub ... items: menu-btn: type: MAIN_MENU slot: 50 material: COMPASS name: "&6Main Menu"

JUMP

Jumps to a specific page index (0-based) in a pagination GUI.

YAML
jump-page2: type: JUMP slot: 51 to-page: 1 # 0-indexed material: PAPER name: "&fPage 2"

Pagination

Display a fixed list of elements split across multiple pages.

Setup

YAML
my_menu: title: "&eItems — Page %page%/%max_page%" rows: 6 items: content: type: PAGINATION slots: [ 10-16, 19-25, 28-34 ] # content area material: PAPER name: "&f%title%" lore: - "&7%description%" - "&8Item %index% of %total%" elements: - title: "First Item" description: "This is the first element." total: "10" - title: "Second Item" description: "Another one." total: "10" # ... up to as many as you need next: type: NEXT slot: 53 is-permanent: false # hides on last page material: ARROW name: "&aNext →" prev: type: PREVIOUS slot: 45 is-permanent: false material: ARROW name: "&c← Prev"

Available Placeholders

PlaceholderValue
%page%Current page number (1-based)
%max_page%Total number of pages
%index%Element index (1-based, global)
%total%Total element count
Any element keyValue from the element map (e.g. %title%)

Dynamic Pagination

Render live server data — players, worlds, inventories, and more — across paginated slots.

Setup

YAML
online_players: title: "&bPlayers — %page%/%max_page%" rows: 6 items: players: type: DYNAMIC_PAGINATION source: ONLINE_PLAYERS slots: [ 9-44 ] material: PLAYER_HEAD name: "&e%player_name%" lore: - "&7World: &f%player_world%" - "&7Ping: &f%player_ping%ms" commands: - "tp {player} %player_name%"

Available Sources

SourcePlaceholders Available
ONLINE_PLAYERS%player_name%, %player_world%, %player_gamemode%, %player_health%, %player_level%, %player_ping%
WORLDS%world_name%, %world_type%, %world_players%, %world_time%, %world_difficulty%
PLAYER_INVENTORY%item_name%, %item_amount%, %item_slot%
PLAYER_ENDERCHEST%item_name%, %item_amount%, %item_slot%
PERMISSION_GROUPS%group_name%, %group_weight% (requires LuckPerms)

Taking Items

For inventory/ender chest sources, set take-item: true to remove the item from the player's inventory or ender chest when clicked.

YAML
source: PLAYER_INVENTORY take-item: true

Giving Items

Set give-item: true to add a copy of the source item to the player's main inventory on click. If the inventory is full, the item drops at the player's feet.

YAML
source: PLAYER_ENDERCHEST give-item: true # gives item to main inventory take-item: true # removes item from ender chest (combine both to move)

Inventory Viewer Example

Move items from ender chest to main inventory with a single click:

YAML
enderchest_viewer: title: "&5&l📦 Your Ender Chest" rows: 6 commands: [ "ecview", "enderchestview" ] items: border: slots: [ 0-8, 45-53 ] material: PURPLE_STAINED_GLASS_PANE name: "&8" ec-items: type: DYNAMIC_PAGINATION source: PLAYER_ENDERCHEST slots: [ 9-44 ] material: STONE name: "&f%item_name%" lore: - "&7Amount: &e%item_amount%" - "" - "&aClick &7to move to inventory" give-item: true # adds to main inventory take-item: true # removes from ender chest prev: type: PREVIOUS slot: 46 material: ARROW name: "&c← Previous" is-permanent: false next: type: NEXT slot: 52 material: ARROW name: "&aNext →" is-permanent: false close: slot: 49 material: BARRIER name: "&c&lClose" close: true

Switch Button

A multi-state toggle that evaluates a key or placeholder every tick and displays the matching state.

Setup

YAML
difficulty-switch: type: SWITCH slot: 13 key: "%server_difficulty%" # placeholder or static value material: YELLOW_WOOL name: "&7Unknown" buttons: "easy": material: LIME_WOOL name: "&a&lEASY" commands: [ "difficulty normal" ] "normal": material: YELLOW_WOOL name: "&e&lNORMAL" commands: [ "difficulty hard" ] "hard": material: RED_WOOL name: "&c&lHARD" commands: [ "difficulty easy" ]
NoteThe key: is resolved via PlaceholderAPI every 10 ticks. The matching buttons: entry is displayed. If no key matches, the fallback material/name is shown.

Input Slot

Allow players to place items into a GUI slot, triggering commands when an item is detected.

Setup

YAML
sacrifice-slot: type: INPUT slot: 13 material: MAGMA_BLOCK name: "&c[ Sacrifice Slot ]" lore: - "&7Drop an item here to sacrifice it." on-place: - "broadcast &6{player} &7sacrificed &e%input_item_name%!" - "give {player} diamond 1" remove-on-place: true # false = item stays in slot

Placeholders in on-place

PlaceholderValue
%input_item_material%Material name of the placed item
%input_item_name%Display name (or material if none)
%input_item_amount%Stack size of the placed item

Conditions

Conditions gate whether a button is clickable. All conditions in a list must pass. A failing condition can show an else_item instead.

Structure

YAML
my-item: slot: 13 material: DIAMOND name: "&bDiamond" conditions: - type: VAULT_MONEY amount: 100 take: true - type: PERMISSION permission: "shop.use" else_item: material: BARRIER name: "&cYou can't afford this"

All Condition Types

TypeDescription
VAULT_MONEYRequires a Vault balance. Optionally deducts.
XP_LEVELRequires XP levels.
XP_POINTSRequires raw XP points.
PERMISSIONRequires a Bukkit permission node.
LUCKPERMS_GROUPRequires LuckPerms group membership.
PLACEHOLDERCompares a PAPI placeholder with operator.
PLACEHOLDER_EQUALSString equality check.
PLACEHOLDER_CONTAINSString contains check.
PLACEHOLDER_GREATER_THANNumeric greater-than check.
PLACEHOLDER_LESS_THANNumeric less-than check.
EXPRESSIONFull math/logic expression with placeholders.
SCRIPTJavaScript expression returning boolean.
ITEMRequires a specific item in inventory.
WORLDGUARD_REGIONRequires player to be inside a WG region.
WEATHERChecks current world weather.
WORLDRestricts to specific world(s).
MODELED_NPCRequire player to be within radius of a ModeledNPC.
OREO_CURRENCYOreoEssentials custom currency balance.
OREO_WARPSCheck if an OreoEssentials warp exists and player has permission.
OREO_WARPS_LOCATIONRequire player to be within N blocks of an OreoEssentials warp.
ITEM_CUSTOM_MODELRequire player to have an item with a specific custom model data value.

Economy & XP Conditions

VAULT_MONEY

YAML
- type: VAULT_MONEY amount: 500 take: true # deduct on success (default false)

XP_LEVEL

YAML
- type: XP_LEVEL amount: 10 take: true

XP_POINTS

YAML
- type: XP_POINTS amount: 500 take: true

OREO_CURRENCY

YAML
- type: OREO_CURRENCY currency: "gems" amount: 100 take: true

Permission Conditions

PERMISSION

YAML
- type: PERMISSION permission: "vip.access" negate: false # true = must NOT have the permission

LUCKPERMS_GROUP

YAML
- type: LUCKPERMS_GROUP group: "vip" include_inherited: true # include parent groups negate: false

Placeholder Conditions

PLACEHOLDER

Compare a PAPI placeholder with an operator.

YAML
- type: PLACEHOLDER placeholder: "%player_level%" operator: ">=" value: "10"

Supported operators: == != > >= < <=

PLACEHOLDER_EQUALS

YAML
- type: PLACEHOLDER_EQUALS placeholder: "%player_world%" value: "world" ignore_case: true

PLACEHOLDER_CONTAINS

YAML
- type: PLACEHOLDER_CONTAINS placeholder: "%player_name%" value: "admin" ignore_case: true

PLACEHOLDER_GREATER_THAN

YAML
- type: PLACEHOLDER_GREATER_THAN placeholder: "%vault_eco_balance%" value: "1000"

PLACEHOLDER_LESS_THAN

YAML
- type: PLACEHOLDER_LESS_THAN placeholder: "%player_health%" value: "10"

Expression Engine

Write math and logic expressions directly in YAML. Placeholders are resolved before evaluation — no external library required.

Usage

YAML
- type: EXPRESSION expression: "%vault_eco_balance% >= 1000" - type: EXPRESSION expression: "%player_level% * 2 > 30" - type: EXPRESSION expression: "(%player_health% + %player_food_level%) >= 30"

Supported Operators

CategoryOperators
Arithmetic+ - * /
Grouping( )
Comparison>= <= > < == !=
WarningIf a placeholder resolves to a non-numeric string, the expression returns false. Make sure your placeholders return numbers for arithmetic expressions.

Script Conditions

Evaluate JavaScript expressions as conditions. The player binding gives direct access to the Bukkit Player object.

YAML
- type: SCRIPT script: "player.getLevel() >= 10 && player.getHealth() > 5.0"

Available Bindings

VariableTypeDescription
playerBukkit PlayerThe clicking player
Java VersionScript conditions require Nashorn (Java 8–14) or GraalVM JavaScript. If neither is available, the condition always returns false and a one-time warning is logged.

World & Region Conditions

WORLD

YAML
- type: WORLD worlds: [ "world", "world_nether" ] blacklist: false # true = must NOT be in these worlds

WEATHER

YAML
- type: WEATHER weather: "rain" # clear, rain, thunder

WORLDGUARD_REGION

YAML
- type: WORLDGUARD_REGION region: "spawn" require_member: false # true = must be a WG member

OREO_WARPS

Requires an OreoEssentials warp to exist and the player to have permission to use it. Requires OreoEssentials.

YAML
- type: OREO_WARPS warp: "vip_arena"

OREO_WARPS_LOCATION

Requires the player to be within a certain radius (in blocks) of an OreoEssentials warp location. Requires OreoEssentials.

YAML
- type: OREO_WARPS_LOCATION warp: "spawn" radius: 15.0 # max distance in blocks

MODELED_NPC

Requires the player to be within a certain radius of a ModeledNPCs NPC. Requires ModeledNPCs.

YAML
- type: MODELED_NPC npc: 42 # NPC ID radius: 5.0 # max distance in blocks

Item Conditions

ITEM

YAML
- type: ITEM material: DIAMOND amount: 3 take: true # removes items from inventory on success

ITEM with Custom Model Data

YAML
- type: ITEM material: PAPER custom_model_data: 1001 amount: 1 take: true

ITEMSADDER

YAML
- type: ITEMSADDER item_id: "iasurvival:ruby" amount: 5 take: true

NEXO

YAML
- type: NEXO item_id: "my_custom_item" amount: 1 take: true

ITEM_CUSTOM_MODEL

Requires the player to have an item with a specific custom_model_data value in their inventory.

YAML
- type: ITEM_CUSTOM_MODEL material: PAPER # material must also match custom_model_data: 1001 amount: 1 take: true

Actions

Actions are structured operations that fire when a button is clicked. They replace or supplement the simple commands: list.

Structure

YAML
my-button: slot: 13 material: EMERALD name: "&aBuy" actions: - type: SOUND sound: "ENTITY_PLAYER_LEVELUP" volume: 1.0 pitch: 1.2 - type: TITLE title: "&a&lPurchase Complete!" subtitle: "&7You bought a diamond." fade-in: 10 stay: 40 fade-out: 10 - type: CONSOLE_COMMAND command: "give {player} diamond 1"

All Action Types

TypeDescription
PLAYER_MESSAGESend a chat message to the player.
BROADCASTBroadcast a message to all players.
ACTION_BARShow a message on the action bar.
TITLEShow a title + subtitle.
SOUNDPlay a sound to the player.
BROADCAST_SOUNDPlay a sound to all players.
CONSOLE_COMMANDRun a command as console.
PLAYER_COMMANDRun a command as the player.
RANDOM_CONSOLE_COMMANDPick a random command from a list.
RANDOM_PLAYER_COMMANDPick a random command as player.
TELEPORTTeleport the player to coordinates.
OPEN_INVENTORYOpen another GUI by ID.
CLOSE_INVENTORYClose the current GUI.
BACKNavigate back in history.
SERVER_CONNECTSend player to another BungeeCord server.
SCRIPTExecute JavaScript code.

Message & UI Actions

PLAYER_MESSAGE

YAML
- type: PLAYER_MESSAGE message: "&aYou clicked the button, {player}!"

BROADCAST

YAML
- type: BROADCAST message: "&6{player} &7just bought a rank!"

ACTION_BAR

YAML
- type: ACTION_BAR message: "&e+100 Coins"

TITLE

YAML
- type: TITLE title: "&a&lSuccess!" subtitle: "&7Transaction complete." fade-in: 10 stay: 60 fade-out: 20

SOUND

YAML
- type: SOUND sound: "ENTITY_PLAYER_LEVELUP" volume: 1.0 pitch: 1.0

BROADCAST_SOUND

Plays a sound for all online players — useful for server-wide announcements.

YAML
- type: BROADCAST_SOUND sound: "ENTITY_ENDER_DRAGON_DEATH" volume: 1.0 pitch: 1.0

Command Actions

CONSOLE_COMMAND

YAML
- type: CONSOLE_COMMAND command: "give {player} diamond 1"

PLAYER_COMMAND

YAML
- type: PLAYER_COMMAND command: "spawn"

RANDOM_CONSOLE_COMMAND

YAML
- type: RANDOM_CONSOLE_COMMAND commands: - "give {player} diamond 1" - "give {player} emerald 1" - "give {player} gold_ingot 3"

RANDOM_PLAYER_COMMAND

Picks one command at random from the list and runs it as the player.

YAML
- type: RANDOM_PLAYER_COMMAND commands: - "spawn" - "warp hub" - "home"
Variable SubstitutionUse {player} in any command — it is replaced with the clicking player's name. PlaceholderAPI placeholders also work.

Teleport Action

YAML
- type: TELEPORT world: "world" x: 0.5 y: 64.0 z: 0.5 yaw: 0.0 pitch: 0.0

Inventory Actions

OPEN_INVENTORY

YAML
- type: OPEN_INVENTORY inventory: "my_shop"

CLOSE_INVENTORY

YAML
- type: CLOSE_INVENTORY

BACK

YAML
- type: BACK

Script Actions

Execute arbitrary JavaScript with the player and plugin bindings.

YAML
- type: SCRIPT script: "player.sendMessage('\u00a7aHello ' + player.getName() + '!');"

Available Bindings

VariableType
playerBukkit Player
pluginSmart MenusPlugin instance

BungeeCord Action

YAML
- type: SERVER_CONNECT server: "lobby"
RequirementYour server must be running behind BungeeCord or Velocity (with BungeeCord forwarding). The plugin automatically registers the BungeeCord plugin messaging channel on startup.

Dynamic Sources

Dynamic Sources power DYNAMIC_PAGINATION buttons with live server data.

ONLINE_PLAYERS

One entry per online player. Material PLAYER_HEAD automatically uses that player's skin.

YAML
type: DYNAMIC_PAGINATION source: ONLINE_PLAYERS material: PLAYER_HEAD name: "&e%player_name%"

WORLDS

One entry per loaded world. Material AUTO picks an icon by environment (GRASS_BLOCK for normal, NETHERRACK for nether, END_STONE for the end).

YAML
source: WORLDS material: AUTO name: "&a%world_name%"

PLAYER_INVENTORY / PLAYER_ENDERCHEST

Renders the player's actual inventory or ender chest items. Non-air slots only.

YAML
source: PLAYER_INVENTORY take-item: true # removes item on click

PERMISSION_GROUPS

All LuckPerms groups, sorted by weight.

YAML
source: PERMISSION_GROUPS name: "&6%group_name%" lore: - "&7Weight: %group_weight%"

Patterns

Patterns are reusable item templates. Define once in plugins/SmartMenus/patterns/, apply across any number of GUIs with variable substitution.

Creating a Pattern

plugins/SmartMenus/patterns/shop_button.yml
shop_button: material: "{material}" name: "&e&l{item_name}" lore: - "&7Price: &a{price}" - "" - "&eClick to buy" conditions: - type: VAULT_MONEY amount: "{price}" take: true commands: - "give {player} {material} 1"

Applying a Pattern

YAML
my_shop: items: diamond-btn: slot: 10 patterns: [ "shop_button" ] vars: material: "DIAMOND" item_name: "Diamond" price: "100" emerald-btn: slot: 11 patterns: [ "shop_button" ] vars: material: "EMERALD" item_name: "Emerald" price: "50"

Commands & Permissions

Plugin Commands

CommandDescriptionPermission
/smartmenus reloadHot-reload all GUI files and lang.ymlsmartmenus.reload
/smartmenus open <id> [player]Open a GUI for yourself or another playersmartmenus.open
/smartmenus captureitem <gui> <slot> [key]Capture the item in your hand into a GUI configsmartmenus.captureitem

captureitem — In-Game Item Capture

Hold any item in your main hand, run the command, and SmartMenus writes it directly into the GUI's YAML file. No manual YAML editing — the file is saved and the GUI reloads instantly.

Usage
/smartmenus captureitem <gui_id> <slot> [item_key]
ArgumentRequiredDescription
gui_idID of the GUI to add the item to
slotSlot number (0–53) where the item will appear
item_keyYAML key name for the item. Defaults to captured_slot_<slot>

What gets captured automatically:

FieldDetails
nameDisplay name — § color codes converted to & for readability
loreEvery lore line, preserved exactly
materialItem type (e.g. ENCHANTED_BOOK)
enchantmentsRegular enchants and stored enchants (enchanted books)
custom_model_dataCaptured automatically if present
item_flagsHIDE_ENCHANTS, HIDE_ATTRIBUTES, etc.
Example
# Hold a Sharpness V custom enchant book, then run: /smartmenus captureitem my_shop 13 # With a custom key name: /smartmenus captureitem my_shop 13 sharpness_book

This produces the following in my_shop.yml automatically:

Generated YAML
my_shop: items: sharpness_book: slot: 13 material: ENCHANTED_BOOK name: "&6&lSharpness V" lore: - "&7Applies Sharpness V to any sword." - "&ePrice: &f500 tokens" enchantments: sharpness: 5 item_flags: - HIDE_ENCHANTS
TipAfter capturing, open the GUI with /smartmenus open <id> to verify it looks right. You can always hand-edit the generated YAML to add conditions:, actions:, or a price.

GUI Command Permissions

Every GUI command auto-generates a permission: smartmenus.command.<gui_id>

Example
# GUI with id "my_shop" and commands: [ "shop" ] # Auto-generated permission: smartmenus.command.my_shop

All Permissions

PermissionDefaultDescription
smartmenus.opentrueOpen GUIs for other players
smartmenus.reloadopUse /smartmenus reload
smartmenus.captureitemopCapture held item into a GUI config
smartmenus.command.*trueOpen all GUI commands
smartmenus.command.<id>trueOpen a specific GUI command
smartmenus.*opAll permissions

Placeholders

Smart Menus supports PlaceholderAPI in all item names, lore lines, titles, and condition values.

Built-in Placeholders

PlaceholderWhereValue
{player}Commands, actionsClicking player's name
%page%Pagination titles/loreCurrent page (1-based)
%max_page%Pagination titles/loreTotal pages
%player_name%ONLINE_PLAYERS sourcePlayer name
%world_name%WORLDS sourceWorld name
%item_name%Inventory sourcesItem display name
%input_item_material%INPUT on-placeMaterial of placed item
%input_item_name%INPUT on-placeDisplay name of placed item
%input_item_amount%INPUT on-placeAmount of placed item
PlaceholderAPIAny %papi_placeholder% works in names, lore, titles, and condition values when PlaceholderAPI is installed.

Integrations

All integrations are optional. Smart Menus detects each plugin at startup and gracefully degrades if it's not present.

PluginFeatures Unlocked
PlaceholderAPIPlaceholders in names, lore, titles, conditions
VaultVAULT_MONEY condition
LuckPermsLUCKPERMS_GROUP condition, PERMISSION_GROUPS dynamic source
WorldGuardWORLDGUARD_REGION condition
ItemsAdderITEMSADDER condition; item_type: itemsadder items
NexoNEXO condition; item_type: nexo items
OreoEssentialsOREO_CURRENCY, OREO_WARPS conditions; custom currency items
ModeledNPCsnpc_id: binding to open GUI on NPC right-click; MODELED_NPC condition
BungeeCord / VelocitySERVER_CONNECT action

Developer API

SmartMenus ships a clean, versioned public API at com.ogui.api.SmartMenusAPI. Other plugins can open GUIs, register custom action/condition types, and evaluate scripts — all without touching internal classes.

Setup

Add SmartMenus as a dependency in your plugin.yml:

plugin.yml
name: MyPlugin depend: [SmartMenus]

Then get the API instance anywhere in your plugin:

Java
SmartMenusAPI api = SmartMenusAPI.get(); if (api != null) { // SmartMenus is loaded and ready }

Or throw if SmartMenus is not present (useful if it's a hard dependency):

Java
SmartMenusAPI api = SmartMenusAPI.require(); // throws IllegalStateException if not loaded

Opening a GUI

Java
// Open by GUI ID boolean opened = api.openGui(player, "my_shop"); // Open with custom args (%arg_name% placeholders in the GUI) Map<String, String> args = new HashMap<>(); args.put("category", "weapons"); api.openGui(player, "my_shop", args);

Querying GUIs

Java
// Check if a GUI exists boolean exists = api.isGuiLoaded("my_shop"); // Get the definition GuiDefinition def = api.getGui("my_shop"); // List all loaded GUI IDs Set<String> ids = api.getGuiIds();

Reloading

Java
api.reloadGuis(); // reloads all GUI config files from disk

Registering Custom Action Types

Add a new action type that server owners can use in any GUI's actions: list:

Java
api.registerAction("CUSTOM_FIREWORK", map -> { String color = (String) map.getOrDefault("color", "RED"); return (plugin, player, vars) -> { // your logic here — launch a firework, etc. launchFirework(player, color); }; });

Server owners can then use it in YAML:

YAML
actions: - type: CUSTOM_FIREWORK color: "BLUE"

To remove it when your plugin disables:

Java
api.unregisterAction("CUSTOM_FIREWORK");

Registering Custom Condition Types

Add a new condition type that works in conditions: and view-requirements::

Java
api.registerCondition("PLAYTIME", (smartMenusPlugin, section) -> { int hours = section.getInt("hours", 0); return new Condition() { public boolean check(Player player) { return getPlaytimeHours(player) >= hours; } public boolean take(Player player) { return false; } // consume-on-click? public String getErrorMessage(Player player) { return "&cYou need " + hours + " hours of playtime."; } public ConditionType getType() { return null; } }; });

In YAML:

YAML
conditions: - type: PLAYTIME hours: 10

Script Engine

Java
// Evaluate a JavaScript condition (returns boolean) boolean result = api.evalConditionScript("player.getLevel() >= 10 && player.getHealth() > 5.0", player); // Execute a JavaScript action api.evalActionScript("player.sendMessage('\\u00a7aHello from API!');", player);
JavaScript bindingsScripts have access to player (the Bukkit Player object) and plugin (the SmartMenus plugin instance). Requires Nashorn (Java 11–14) or GraalVM JS.

Full Integration Example

MyPlugin.java
public class MyPlugin extends JavaPlugin { @Override public void onEnable() { SmartMenusAPI api = SmartMenusAPI.get(); if (api == null) { getLogger().warning("SmartMenus not found — GUI integration disabled."); return; } // Register a custom "REWARD_CRATE" action api.registerAction("REWARD_CRATE", map -> { String crateType = (String) map.getOrDefault("crate", "common"); return (plugin, player, vars) -> MyCratePlugin.openCrate(player, crateType); }); // Register a custom "FACTION_RANK" condition api.registerCondition("FACTION_RANK", (smPlugin, section) -> { String rank = section.getString("rank", "member"); return new Condition() { public boolean check(Player p) { return MyFactionPlugin.hasRank(p, rank); } public boolean take(Player p) { return false; } public String getErrorMessage(Player p) { return "&cYou need faction rank: &f" + rank; } public ConditionType getType() { return null; } }; }); getLogger().info("SmartMenus integration loaded."); } @Override public void onDisable() { SmartMenusAPI api = SmartMenusAPI.get(); if (api != null) { api.unregisterAction("REWARD_CRATE"); api.unregisterCondition("FACTION_RANK"); } } }

Examples

Copy-paste ready examples covering the most common server setups. Each one is complete and works out of the box.

GeneratorWant to build GUIs visually instead of writing YAML by hand? Use the ⚙ GUI Config Generator — it produces valid YAML automatically.

1. Item Shop (Vault Economy)

A 3-row shop with a border, two buyable items, and a close button. Items show a grey "can't afford" version when the player has insufficient funds.

plugins/SmartMenus/guis/my_shop/my_shop.yml
my_shop: title: "&8&l🛒 Item Shop" rows: 3 commands: [ "shop", "itemshop" ] items: # ── Background ────────────────────────────────────────── border: slots: [ 0-8, 18-26 ] material: BLACK_STAINED_GLASS_PANE name: "&8" # ── Buy Diamond — $100 ───────────────────────────────── buy-diamond: slot: 11 material: DIAMOND name: "&b&lDiamond &8— &a$100" lore: - "&7A shiny diamond." - "" - "&7Your balance: &a$%vault_eco_balance%" - "&eClick to buy" glow: true conditions: - type: VAULT_MONEY amount: 100 take: true # deducts $100 on successful click actions: - type: SOUND sound: "ENTITY_EXPERIENCE_ORB_PICKUP" pitch: 1.5 - type: PLAYER_MESSAGE message: "&a✔ You bought a &bDiamond &afor &2$100&a!" - type: CONSOLE_COMMAND command: "give {player} diamond 1" else_item: material: GRAY_DYE name: "&7Diamond &8— &cNeed $100" lore: - "&cYou don't have enough money." - "&7Balance: &c$%vault_eco_balance%" # ── Buy Emerald — $50 ────────────────────────────────── buy-emerald: slot: 15 material: EMERALD name: "&a&lEmerald &8— &a$50" lore: - "&7A bright green emerald." - "" - "&7Your balance: &a$%vault_eco_balance%" - "&eClick to buy" conditions: - type: VAULT_MONEY amount: 50 take: true actions: - type: SOUND sound: "ENTITY_EXPERIENCE_ORB_PICKUP" - type: PLAYER_MESSAGE message: "&a✔ You bought an &aEmerald &afor &2$50&a!" - type: CONSOLE_COMMAND command: "give {player} emerald 1" else_item: material: GRAY_DYE name: "&7Emerald &8— &cNeed $50" lore: - "&cYou don't have enough money." # ── Close ────────────────────────────────────────────── close: slot: 22 material: BARRIER name: "&c&lClose" close: true

2. Rank Upgrade Menu

Players can upgrade their rank by paying and clicking. Uses multiple conditions: money, existing rank, and "must NOT already have VIP". Shows the button greyed out if already VIP.

plugins/SmartMenus/guis/rank_upgrade/rank_upgrade.yml
rank_upgrade: title: "&6&l⭐ Rank Upgrades" rows: 4 commands: [ "rankup", "upgrade" ] items: border: slots: [ 0-8, 27-35 ] material: YELLOW_STAINED_GLASS_PANE name: "&8" # ── VIP Upgrade button ───────────────────────────────── vip-upgrade: slot: 13 material: GOLD_INGOT name: "&6&lUpgrade to &e&lVIP" lore: - "&8&m────────────────────" - " &7Cost: &a$5,000" - " &7Requires: &fDefault rank" - "&8&m────────────────────" - "" - "&eClick to upgrade" glow: true conditions: - type: VAULT_MONEY amount: 5000 take: true - type: PERMISSION permission: "group.default" # must have Default rank - type: PERMISSION permission: "group.vip" negate: true # must NOT already be VIP actions: - type: CONSOLE_COMMAND command: "lp user {player} parent set vip" - type: TITLE title: "&6&l⭐ VIP Unlocked!" subtitle: "&7Welcome to VIP, &e{player}&7!" stay: 60 - type: SOUND sound: "UI_TOAST_CHALLENGE_COMPLETE" volume: 1.0 - type: BROADCAST message: "&6⭐ &e{player} &7has upgraded to &6&lVIP&7!" - type: CLOSE_INVENTORY else_item: material: IRON_INGOT name: "&7Already VIP &8or &cInsufficient Funds" lore: - "&7You either already have VIP," - "&7or you need &a$5,000 &7(have: &c$%vault_eco_balance%&7)." close: slot: 31 material: BARRIER name: "&c&lClose" close: true

3. Navigation Hub (Multi-level menus)

A main hub that opens sub-menus. BACK/HOME buttons let players navigate the history stack.

plugins/SmartMenus/guis/hub/hub.yml
# ── Main Hub ────────────────────────────────────────────────── main_hub: title: "&8&l⚙ Server Hub" rows: 3 commands: [ "hub", "menu" ] main_menu: main_hub # MAIN_MENU buttons return here items: border: slots: [ 0-8, 18-26 ] material: BLACK_STAINED_GLASS_PANE name: "&8" btn-shop: type: INVENTORY # opens shop_menu and pushes hub to history slot: 11 inventory: shop_menu material: CHEST name: "&e&lShop" lore: - "&7Buy items and upgrades." - "&eClick →" btn-quests: type: INVENTORY slot: 13 inventory: quest_menu material: BOOK name: "&d&lQuests" lore: - "&7View available quests." - "&eClick →" btn-stats: type: INVENTORY slot: 15 inventory: stats_menu material: EXPERIENCE_BOTTLE name: "&a&lStats" lore: - "&7View your statistics." - "&eClick →" close: slot: 22 material: BARRIER name: "&c&lClose" close: true # ── Shop Sub-menu ────────────────────────────────────────────── shop_menu: title: "&e&lShop" rows: 3 main_menu: main_hub items: border: slots: [ 0-8, 18-26 ] material: YELLOW_STAINED_GLASS_PANE name: "&8" buy-xp: slot: 13 material: EXPERIENCE_BOTTLE name: "&a&lBuy 10 XP Levels — &2$200" conditions: - type: VAULT_MONEY amount: 200 take: true commands: - "xp {player} 10l" else_item: material: GRAY_DYE name: "&7Need &a$200" # BACK returns to main_hub back: type: BACK slot: 20 material: RED_STAINED_GLASS_PANE name: "&c⬅ Back" # HOME also returns to main_hub (they're the same here) home: type: HOME slot: 22 material: NETHER_STAR name: "&e⌂ Home" close: slot: 26 material: BARRIER name: "&c&lClose" close: true

4. Paginated Crate Rewards Preview

A scrollable list of rewards using PAGINATION. Each element is defined in the YAML — no limit on how many.

plugins/SmartMenus/guis/crate/crate_preview.yml
crate_preview: title: "&5&l✦ Crate Rewards &8| &7%page%&8/&7%max_page%" rows: 6 commands: [ "cratepreview" ] items: border-top: slots: [ 0-8 ] material: PURPLE_STAINED_GLASS_PANE name: "&8" border-bot: slots: [ 45-53 ] material: PURPLE_STAINED_GLASS_PANE name: "&8" # Content area: rows 2-5 (slots 9-44), edges filler filler-left: slots: [ 9, 18, 27, 36 ] material: GRAY_STAINED_GLASS_PANE name: "&8" filler-right: slots: [ 17, 26, 35, 44 ] material: GRAY_STAINED_GLASS_PANE name: "&8" rewards: type: PAGINATION slots: [ 10-16, 19-25, 28-34, 37-43 ] material: PAPER name: "&f&l%reward_name%" lore: - "&7Chance: &e%chance%%" - "&7Amount: &f%amount%" - "" - "&8Item %index% of %total%" elements: - reward_name: "Diamond Sword" chance: "5" amount: "1" total: "12" - reward_name: "64x Gold Ingots" chance: "15" amount: "64" total: "12" - reward_name: "$1,000 Cash" chance: "20" amount: "$1,000" total: "12" - reward_name: "Speed Potion" chance: "25" amount: "3" total: "12" - reward_name: "XP Bottle x10" chance: "20" amount: "10" total: "12" - reward_name: "Enchanted Book" chance: "10" amount: "1" total: "12" - reward_name: "Netherite Ingot" chance: "3" amount: "1" total: "12" - reward_name: "VIP 7 Days" chance: "2" amount: "7 days" total: "12" # Add more items here — Smart Menus handles pagination automatically prev: type: PREVIOUS slot: 46 is-permanent: false material: ARROW name: "&c← Previous" page-info: slot: 49 material: PAPER name: "&7Page &f%page% &8/ &f%max_page%" next: type: NEXT slot: 52 is-permanent: false material: ARROW name: "&aNext →" close: slot: 53 material: BARRIER name: "&c&lClose" close: true

5. Online Players List (Dynamic)

Live list of all online players with auto-skinned heads. Clicking teleports you to that player. Updates every tick.

plugins/SmartMenus/guis/players/players.yml
online_players: title: "&b&l👥 Online Players &8(&7%page%&8/&7%max_page%&8)" rows: 6 commands: [ "players", "online" ] items: border: slots: [ 0-8, 45-53 ] material: CYAN_STAINED_GLASS_PANE name: "&8" player-list: type: DYNAMIC_PAGINATION source: ONLINE_PLAYERS slots: [ 9-44 ] material: PLAYER_HEAD # auto-applies that player's skin name: "&e&l%player_name%" lore: - "&8&m──────────────────" - " &7World: &f%player_world%" - " &7Mode: &f%player_gamemode%" - " &7Health: &a%player_health%&7/&a%player_max_health%" - " &7Level: &e%player_level%" - " &7Ping: &f%player_ping%ms" - "&8&m──────────────────" - " &eClick &7to teleport" commands: - "tp {player} %player_name%" prev: type: PREVIOUS slot: 46 is-permanent: false material: ARROW name: "&c← Previous" page-info: slot: 49 material: PAPER name: "&7Page &f%page% &8/ &f%max_page%" next: type: NEXT slot: 52 is-permanent: false material: ARROW name: "&aNext →" close: slot: 53 material: BARRIER name: "&c&lClose" close: true

6. Warp Menu (Expression Conditions)

Warp buttons that use expression conditions — e.g. the nether warp requires level 10+, the end warp requires level 30+.

plugins/SmartMenus/guis/warps/warps.yml
warp_menu: title: "&8&l🗺 Warps" rows: 3 commands: [ "warps", "warp" ] items: border: slots: [ 0-8, 18-26 ] material: GRAY_STAINED_GLASS_PANE name: "&8" # Spawn — always accessible warp-spawn: slot: 10 material: GRASS_BLOCK name: "&a&lSpawn" lore: - "&7Teleport to spawn." - "&eClick!" actions: - type: CLOSE_INVENTORY - type: TELEPORT world: "world" x: 0.5 y: 64.0 z: 0.5 # Nether — requires level 10 warp-nether: slot: 13 material: NETHERRACK name: "&c&lNether &8— &7Lv10+" lore: - "&7Teleport to the nether." - "&7Requires: &eLv10" - "&7Your level: &e%player_level%" conditions: - type: EXPRESSION expression: "%player_level% >= 10" actions: - type: CLOSE_INVENTORY - type: TELEPORT world: "world_nether" x: 0.5 y: 64.0 z: 0.5 else_item: material: SOUL_SAND name: "&7Nether &8— &cLocked" lore: - "&cRequires Level &e10&c." - "&7Your level: &e%player_level%" # End — requires level 30 warp-end: slot: 16 material: END_STONE name: "&5&lThe End &8— &7Lv30+" lore: - "&7Teleport to the end." - "&7Requires: &eLv30" - "&7Your level: &e%player_level%" conditions: - type: EXPRESSION expression: "%player_level% >= 30" actions: - type: CLOSE_INVENTORY - type: TELEPORT world: "world_the_end" x: 0.5 y: 64.0 z: 0.5 else_item: material: END_STONE_BRICKS name: "&7The End &8— &cLocked" lore: - "&cRequires Level &e30&c." - "&7Your level: &e%player_level%" close: slot: 22 material: BARRIER name: "&c&lClose" close: true

7. NPC Shop (ModeledNPCs)

Opens automatically when a player right-clicks NPC #42. Also accessible via /npcshop.

plugins/SmartMenus/guis/npc_shop/npc_shop.yml
npc_shop: title: "&6&l🧙 Wizard's Shop" rows: 4 npc_id: 42 # right-click ModeledNPC ID 42 to open commands: [ "npcshop" ] items: border: slots: [ 0-8, 27-35 ] material: ORANGE_STAINED_GLASS_PANE name: "&8" buy-spell: slot: 13 material: BLAZE_POWDER name: "&6&lFire Spell Book" lore: - "&7Cast fire magic." - "&7Cost: &a10 XP levels" - "" - "&7Your levels: &e%player_level%" - "&eClick to buy" conditions: - type: XP_LEVEL amount: 10 take: true commands: - "give {player} blaze_powder 1" else_item: material: GUNPOWDER name: "&7Fire Spell Book &8— &cNeed 10 Levels" close: slot: 31 material: BARRIER name: "&c&lClose" close: true

Plugin Config

Located at plugins/SmartMenus/config.yml. Auto-generated on first start. Edit then run /smartmenus reload — no restart needed.

Full config.yml

plugins/SmartMenus/config.yml
# ───────────────────────────────────────────── # Smart Menus — Main Configuration # ───────────────────────────────────────────── # Controls whether the default example GUI folders are regenerated on startup. # # true → Missing default files are recreated every server start. # Great while learning — the examples always come back. # # false → Default GUIs are never written after first generation. # Delete example folders and they will stay gone. # Use this once you have your own GUIs set up. regenerate-default-guis: true

Option Reference

KeyDefaultDescription
regenerate-default-guis true When true, every missing default GUI file (all the examples that ship with Smart Menus) is re-extracted from the jar on every server start.

Set to false once you've cleaned up the example GUIs and only want your own configs on disk.
Recommended workflow
  1. Start with regenerate-default-guis: true — study the examples.
  2. Copy and customise what you need into your own folders.
  3. Delete the example folders.
  4. Set regenerate-default-guis: false — they won't come back.

Language File

Located at plugins/SmartMenus/lang.yml. Every message players and the console see comes from here. Supports legacy codes, hex colors, gradients, and rainbow effects.

Color Format Support

FormatExampleResult
Legacy codes&c&lBold RedBold red text
Hex color&#FFD700GoldGold / #FFD700
Gradient<gradient:#FF0000:#FFD700>Fire</gradient>Red→gold gradient
Rainbow<rainbow>Colorful</rainbow>Cycling rainbow
PlaceholderAPI%vault_eco_balance%Live placeholder value

Sections

general

Core plugin messages shown to players.

lang.yml
general: prefix: "<gradient:#FFD700:#FF8C00>&l[SmartMenus]</gradient> &r" no_permission: "<gradient:#FF0000:#FF6B6B>✖ Access Denied</gradient> &7→ &fNo permission." player_only: "&#FF4444&l⚠ &cOnly players can use this command." gui_not_found: "<gradient:#FF0000:#FF6B6B>✖ GUI Not Found</gradient> &7→ &f{gui}" player_not_found: "&#FF6B6B✖ Player not found: &f{player}" gui_opened: "<gradient:#00FF00:#00FFFF>✔ Opened</gradient> &7GUI &f{gui} &7for &f{player}" reload: success: "<gradient:#00FF00:#32CD32>✔ Reloaded!</gradient> &7Smart Menus reloaded." gui_count: " &#00FFFF→ &7Loaded &f{count} &7GUI(s)"

commands

Messages for the /smartmenus command output.

lang.yml
commands: usage: main: "<gradient:#FFD700:#FFA500>&l⚡ Smart Menus</gradient>" line1: "&7Usage: &f/smartmenus &7<&bopen&7|&breload&7> &8[&fid&8] &8[&fplayer&8]" open: usage: "&#FF6B6B&l⚠ Usage: &c/smartmenus open &f<id> &8[player]" available: "<gradient:#00FFFF:#0099FF>Available GUIs:</gradient> &f{guis}" reload: no_permission: "<gradient:#FF0000:#FF6B6B>✖ Permission Denied</gradient>"

conditions

Error messages shown when a condition fails. Each condition type has its own sub-key.

lang.yml
conditions: vault_money: insufficient: | <gradient:#FF0000:#FFD700>💰 Insufficient Funds!</gradient> &#FFD700&l→ Required: &f${amount} &#00FF00&l→ Balance: &f${balance} economy_unavailable: "⚠ Vault not found!" xp_level: insufficient: | <gradient:#00FFFF:#0099FF>⭐ Not Enough Levels!</gradient> &#00FFFF&l→ Required: &f{amount} &7levels &#FFD700&l→ Current: &f{current} &7levels permission: missing: | <gradient:#FF0000:#FFA500>🔒 ACCESS DENIED</gradient> &#FF6B6B&l→ Required: &#FFD700{permission} worldguard_region: not_in_region: | <gradient:#FF6B6B:#FFA500>📍 Wrong Location!</gradient> &#FFA500&l→ Required region: &#FFD700{region}

Condition Message Placeholders

PlaceholderAvailable inValue
{amount}All cost/requirement messagesRequired amount
{balance}vault_money, oreo_currencyPlayer's current balance
{current}xp_level, xp_points, itemPlayer's current amount
{currency}oreo_currencyCurrency name
{permission}permissionRequired permission node
{region}worldguard_regionRegion name
{placeholder}placeholderPAPI placeholder key
{operator}placeholderComparison operator
{value}placeholderComparison value
{required}weatherRequired weather
{worlds}worldList of allowed worlds
{npc}modeled_npcNPC name
{distance}modeled_npcCurrent distance in blocks
{radius}modeled_npcRequired max distance
{warp}oreo_warpsWarp name
{item}item, itemsadder, nexoItem name
{count}reload messagesNumber of GUIs loaded
{gui}general, npc messagesGUI ID
{player}VariousPlayer name
{error}Error messagesError details

Ready-to-use Gradient Examples

Copy & paste these into any message
# 🔥 Fire <gradient:#FF0000:#FF6600:#FFFF00>🔥 Fire text 🔥</gradient> # 🌊 Ocean <gradient:#0000FF:#00FFFF:#1E90FF>🌊 Ocean waves 🌊</gradient> # ✨ Gold Shine <gradient:#FFD700:#FFED4E:#FFD700>✨ Shiny gold ✨</gradient> # ⚡ Neon <gradient:#FF00FF:#00FFFF>⚡ Neon effect ⚡</gradient> # 🌅 Sunset <gradient:#FF6B6B:#FFD93D:#6BCB77>🌅 Sunset glow 🌅</gradient> # Multi-line condition message with gradient header: insufficient: | <gradient:#FF0000:#FFD700>💰 Not Enough Money!</gradient> &#FFD700&l→ Need: &f${amount} &#00FF00&l→ Balance: &f${balance}
TipRun /smartmenus reload after editing lang.yml — changes apply instantly without a server restart.
Multi-line valuesUse the YAML block scalar | for multi-line messages (as shown above). Each new line becomes a new chat line.

CHAT_INPUT Button

Prompts the player to close the inventory and type a response in chat. The typed text is captured as {chat_input} and passed to all actions.

How It Works

  1. Player clicks the CHAT_INPUT button
  2. The GUI closes automatically
  3. The chat-prompt message is sent to the player
  4. The next message the player types is captured
  5. All actions: fire with {chat_input} replaced by what they typed

Setup

YAML
ask-nickname: type: CHAT_INPUT slot: 13 material: NAME_TAG name: "&eSet Your Nickname" lore: - "&7Click and type a new nickname." - "" - "&eClick →" chat-prompt: "&eType your new nickname in chat:" actions: - type: CONSOLE_COMMAND command: "nick {player} {chat_input}" - type: PLAYER_MESSAGE message: "&aYour nickname is now: &f{chat_input}"

Properties

KeyRequiredDescription
chat-promptNoMessage sent to the player asking for input. Supports color codes and placeholders.
actions:NoActions fired after the player types. {chat_input} is replaced with what they typed.

Notes

  • {chat_input} works in all action fields: commands, messages, titles, etc.
  • Conditions are checked on the initial click — before the chat prompt is sent
  • If the player quits before typing, no action fires
  • The player's typed message is not broadcast to other players

Real-World Example: Warp Search

YAML
warp-search-btn: type: CHAT_INPUT slot: 4 material: COMPASS name: "&bSearch Warps" lore: - "&7Type a warp name to teleport." - "&eClick →" chat-prompt: "&bType a warp name:" actions: - type: PLAYER_COMMAND command: "warp {chat_input}" - type: PLAYER_MESSAGE message: "&7Warping to: &b{chat_input}"

Full-Screen GUI — 90 Interactive Slots

SmartMenus is the only GUI plugin that can use the player's own inventory as part of the GUI — giving you up to 90 interactive slots in a single menu.

Overview

When use_bottom_inventory: true is set at the GUI level:

  • The player's 36 inventory slots (main inventory + hotbar) are saved
  • Those slots are replaced with GUI items from the bottom_items: section
  • All 90 slots (54 chest + 36 bottom) support actions, conditions, every button type
  • On close, quit, or server reload — the real inventory is fully restored. Zero item loss.
Unique FeatureNo other free GUI plugin offers full-screen 90-slot GUIs. This is exclusive to SmartMenus.

Enabling It

YAML
my_fullscreen_gui: title: "&5&lFull Screen Hub" rows: 6 use_bottom_inventory: true # ← enables 90-slot mode items: # Slots 0–53 (the top chest section) center: slot: 22 material: NETHER_STAR name: "&dMain Hub" bottom_items: # Slots 0–35 (the player's inventory area shown below) info: slot: 4 material: PAPER name: "&fServer Hub"

Slot Mapping

The bottom_items slot numbers (0–35) map to the player's inventory as displayed on screen:

bottom_items slotsPlayer inventory area (screen order)Player inv slots (internal)
0–8Main row 1 (top)9–17
9–17Main row 218–26
18–26Main row 327–35
27–35Hotbar (bottom row)0–8

So slot: 4 in bottom_items = center of the first visible row of the player's inventory area. slot: 31 = center of the hotbar row.

Safety Guarantees

  • Real inventory saved on open — stored per player UUID in memory
  • Restored on GUI close — 1-tick delayed to let SmartInvs finish cleanup
  • Restored on player quit — fires before the server saves player data to disk
  • Restored on server reload / plugin disable — loops all online players
  • Restored on kick — handled by the quit event
Do not nest full-screen GUIsAvoid opening a second use_bottom_inventory GUI from inside one that already has it active. The first GUI's saved inventory state will be overwritten. Close the first GUI before opening another full-screen GUI.

Both Sections Support Everything

Items in bottom_items: support the full feature set — the same as items::

  • All button types: NONE, SWITCH, INPUT, DYNAMIC_PAGINATION, PAGINATION, etc.
  • All 23 condition types and view-requirements
  • All 16 action types and per-click-type click_actions:
  • close: true, glow: true, enchantments, item_flags
  • Auto-refresh with update: true + update-interval:

Full Example

plugins/SmartMenus/guis/dynamic_examples/full_screen_demo.yml
server_hub: title: "&5&l✦ Server Hub" rows: 6 commands: [ "hub", "fullscreen" ] use_bottom_inventory: true items: border-top: slots: [ 0-8 ] material: PURPLE_STAINED_GLASS_PANE name: "&8" border-bot: slots: [ 45-53 ] material: PURPLE_STAINED_GLASS_PANE name: "&8" side-left: slots: [ 9, 18, 27, 36 ] material: PURPLE_STAINED_GLASS_PANE name: "&8" side-right: slots: [ 17, 26, 35, 44 ] material: PURPLE_STAINED_GLASS_PANE name: "&8" center-info: slot: 22 material: NETHER_STAR name: "&d&lFull-Screen GUI" lore: - "&7The 6 rows above &fand&7 your inventory" - "&7below are all part of this GUI." - "&7Your real items are safely saved." glow: true btn-hello: slot: 25 material: LIME_DYE name: "&a&lSay Hello" actions: - type: PLAYER_MESSAGE message: "&d&lFull-Screen GUI &7says: &fHello, &e{player}&f!" - type: SOUND sound: UI_BUTTON_CLICK close: slot: 49 material: BARRIER name: "&c&lClose" close: true bottom_items: bottom-border-left: slots: [ 0, 9, 18, 27 ] material: GRAY_STAINED_GLASS_PANE name: "&8" bottom-border-right: slots: [ 8, 17, 26, 35 ] material: GRAY_STAINED_GLASS_PANE name: "&8" bottom-btn-one: slot: 4 material: DIAMOND name: "&b&lBottom Button 1" lore: - "&7This button lives in your inventory area." - "&eClick →" actions: - type: PLAYER_MESSAGE message: "&bYou clicked bottom button 1!" - type: SOUND sound: ENTITY_EXPERIENCE_ORB_PICKUP hotbar-center: slot: 31 material: NETHER_STAR name: "&d&lHotbar Center" lore: - "&7This is in the hotbar row." - "&eClick →" actions: - type: TITLE title: "&d✦" subtitle: "&7You clicked the hotbar slot!" stay: 40

Per-Click-Type Actions

Assign completely different actions to different mouse buttons. Left-click can buy, right-click can preview, shift-click can bulk-buy — all on the same item.

Overview

Instead of a single actions: list (which fires for any click), use click_actions: with click-type keys. Each key holds its own independent action list.

Supported Click Types

KeyFires when
ANYAny click (same as using actions:)
LEFTLeft mouse button
RIGHTRight mouse button
SHIFT_LEFTShift + left click
SHIFT_RIGHTShift + right click
MIDDLEMiddle mouse button (scroll wheel click)
DOUBLE_CLICKDouble left-click

Structure

YAML
my-button: slot: 13 material: DIAMOND name: "&bDiamond" lore: - "&eLeft-click &7to buy ×1" - "&eRight-click &7to preview" - "&eShift+left &7to buy ×64" click_actions: LEFT: - type: CONSOLE_COMMAND command: "give {player} diamond 1" - type: SOUND sound: ENTITY_EXPERIENCE_ORB_PICKUP RIGHT: - type: PLAYER_MESSAGE message: "&7Diamond: used for tools, armor, and enchanting tables." SHIFT_LEFT: - type: CONSOLE_COMMAND command: "give {player} diamond 64" - type: SOUND sound: ENTITY_PLAYER_LEVELUP - type: TITLE title: "&b✦ Bulk Buy" subtitle: "&7×64 diamonds added!" stay: 30 MIDDLE: - type: ACTION_BAR message: "&7Middle clicked!"

click_actions vs actions

Featureactions:click_actions:
Single list for all clicks
Different behavior per click type
Works with conditions
Works on DYNAMIC_PAGINATION
Works in bottom_items
Mixing bothYou can use both actions: and click_actions:. The actions: list fires for ANY click. click_actions: fires for the matching type. If LEFT is defined in both, both fire on left-click.

Real-World Example: Admin Player Browser

YAML
player-list: type: DYNAMIC_PAGINATION source: ONLINE_PLAYERS slots: [ 9-44 ] material: PLAYER_HEAD name: "&e%player_name%" lore: - "&7Left: &fTeleport" - "&7Right: &fKick" - "&7Shift+L: &fBan" - "&7Middle: &fMessage" click_actions: LEFT: - type: CONSOLE_COMMAND command: "tp {player} %player_name%" - type: CLOSE_INVENTORY RIGHT: - type: CONSOLE_COMMAND command: "kick %player_name% Kicked by admin" SHIFT_LEFT: - type: CONSOLE_COMMAND command: "ban %player_name% Banned by admin" MIDDLE: - type: CHAT_INPUT chat-prompt: "&7Enter message to send to &e%player_name%&7:" - type: CONSOLE_COMMAND command: "msg %player_name% {chat_input}"

View Requirements

Hide items entirely when conditions fail — the slot appears completely empty. This is different from conditions:, which keeps the item visible but blocks the click.

View Requirements vs Conditions

Featureconditions:view-requirements:
Item visible when condition fails✔ (shows else_item)✘ (slot is empty)
Can show else_item
Checked on click
Checked on every render tick
Use case"Can't afford this" feedback itemHidden VIP/admin-only buttons

Structure

YAML
vip-only-item: slot: 13 material: DIAMOND_SWORD name: "&d&lVIP Sword" lore: - "&7VIP members only." view-requirements: - type: PERMISSION permission: "group.vip" # This slot is completely empty for non-VIP players

With else_item

Show a different item (e.g. a locked indicator) instead of leaving the slot empty:

YAML
secret-feature: slot: 22 material: EMERALD name: "&aSecret Feature" lore: - "&7Exclusive admin tool." view-requirements: - type: PERMISSION permission: "smartmenus.admin" else_item: material: GRAY_STAINED_GLASS_PANE name: "&8???" lore: - "&7Unlock with Admin rank."

Dynamic Behavior

View requirements are re-evaluated every render tick (every ~10 ticks). This means items can appear and disappear in real time as the player's state changes — no need to reopen the GUI.

Example: a button that appears only while the player is in a specific region, or only when they have enough balance:

YAML
spawn-only-btn: slot: 15 material: BEACON name: "&eSpawn Exclusive" lore: - "&7Only available at spawn." view-requirements: - type: WORLDGUARD_REGION region: "spawn"

All Condition Types Work

All 23 condition types work inside view-requirements: just like they do in conditions:. You can stack multiple — all must pass for the item to be visible.

YAML
elite-button: slot: 13 material: NETHERITE_INGOT name: "&4&lElite Reward" view-requirements: - type: PERMISSION permission: "rank.elite" - type: EXPRESSION expression: "%player_level% >= 50" - type: WORLD worlds: [ "survival" ]