🏠 › Overview
⚡ SmartMenus v2.4
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
| Minecraft | Java | Status |
| 1.21.x | 21+ | ✅ Supported |
| 1.20.x | 17+ | ✅ Supported |
| 1.19.x | 17+ | ✅ Supported |
| 1.18.x | 17 | ⚠️ Untested |
| ≤ 1.17 | — | ❌ Not supported |
Next Steps
🏠 › Installation
Installation
Smart Menus is a Paper/Spigot plugin. Installation takes under two minutes.
Requirements
| Requirement | Version | Notes |
| Server software | Paper / Spigot | Paper strongly recommended |
| Minecraft | 1.19 – 1.21 | |
| Java | 17+ | Java 21 recommended |
| PlaceholderAPI | Any recent | Optional but strongly recommended |
| Vault | Any | Required for economy conditions |
Steps
- Download SmartMenus.jar from the releases page.
- Place it in your server's
plugins/ folder.
- Start or restart the server. Smart Menus will generate its default config files.
- All default GUIs are extracted to
plugins/SmartMenus/guis/ automatically.
- 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
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%"
🏠 › Configuration › GUI Structure
GUI Structure
Every GUI is a top-level YAML key. Under it, you define metadata and an items: map.
Top-level Properties
| Key | Type | Default | Description |
title | String | required | Inventory title. Supports color codes, {player}, and PlaceholderAPI. |
rows | 1 – 6 | 6 | Number of rows (chest only). Ignored for other inventory_type values. |
commands | List | [] | Commands that open this GUI. First entry is primary; rest are aliases. |
inventory_type | String | CHEST | Container type: CHEST, HOPPER, DISPENSER, FURNACE, etc. |
main_menu | GUI ID | — | Target GUI for MAIN_MENU buttons. |
npc_id | Integer | — | ModeledNPCs NPC ID that opens this GUI on right-click. |
fill: | Item block | — | Item used to fill any empty slot after all other items are rendered. |
items: | Map | required | Named item definitions (see below). |
use_bottom_inventory | Boolean | false | Enable 90-slot full-screen mode — uses the player's inventory area as interactive GUI slots. |
bottom_inventory_mode | String | DEFAULT | DEFAULT — saves and restores the real inventory on open/close. PACKET_EVENT — sends GUI items as packets only; real inventory is never modified (requires PacketEvents). |
bottom_items: | Map | — | Items for the player inventory area (slots 0–35). Only used when use_bottom_inventory: true. |
args: | List | — | Typed command arguments passed when opening the GUI. Each arg becomes %arg_name%. |
patterns: | List | — | Reusable pattern IDs applied to all items before individual item config. |
auto-convert | Boolean | false | When true, Bedrock players automatically see a native Paper Dialog built from the GUI's items instead of the chest inventory. Java players are unaffected. See Auto-Convert. |
bedrock: | Block | — | Explicit Bedrock form definition. Overrides auto-convert when present. Supports SIMPLE_FORM, MODAL_FORM, CUSTOM_FORM, and DIALOGUE types. See Form Types. |
Item Properties
| Key | Description |
slot / slots | Single slot number, list, or range like 0-8. |
type | Button type (default NONE). See Button Types. |
material | Bukkit material name, PLAYER_HEAD, or AUTO. |
name | Display name. Color codes and placeholders supported. |
lore | List of lore lines. |
amount | Stack size (1–64). |
custom_model_data | Custom model data integer. |
glow | true to add enchantment glow. |
item_type | Item source: vanilla (default), itemsadder, nexo, headdatabase |
item_id | Custom item namespace ID — used when item_type is not vanilla (e.g. iasurvival:ruby) |
item_flags | List of flags to hide: HIDE_ENCHANTS, HIDE_ATTRIBUTES, HIDE_POTION_EFFECTS, HIDE_UNBREAKABLE |
enchantments | Map of enchantment name → level (e.g. SHARPNESS: 5) |
update | true to auto-refresh item name/lore with live placeholders every tick interval |
update-interval | Ticks between placeholder refreshes (default: 10). Requires update: true |
give-item | For DYNAMIC_PAGINATION: true to give the source item to the player's inventory on click |
take-item | For DYNAMIC_PAGINATION: true to remove the source item from the player's inventory/enderchest on click |
close | true to close the GUI on click. |
commands | List of console commands run on click. Use {player}. |
actions | Structured action list (see Actions). |
conditions | List of condition blocks. All must pass. |
else_item | Item shown when conditions fail (replaces this item). |
view_requirements | Conditions to show the item at all. |
click_type | Limit 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 › Overview
Button Types
Every item in a GUI has a type: field. The default is NONE — a plain clickable item.
| Type | Description |
NONE | Standard clickable item. Runs commands: / actions:. |
INVENTORY | Opens another GUI and pushes current to history stack. |
BACK | Pops history stack — returns to previous GUI. |
HOME | Jumps to the oldest GUI in the history stack. |
MAIN_MENU | Jumps to the GUI set in main_menu: on the current GUI. |
NEXT | Advance to the next page of a PAGINATION/DYNAMIC_PAGINATION GUI. |
PREVIOUS | Go back one page. |
JUMP | Jump to a specific page number (to-page: 2). |
PAGINATION | Renders a static paginated element list. |
DYNAMIC_PAGINATION | Renders a live data source across slots. |
SWITCH | Multi-state toggle driven by a key or placeholder. |
INPUT | Accepts item placement from the player. |
🏠 › Button Types › Navigation
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"
MAIN_MENU
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"
🏠 › Button Types › Dynamic Pagination
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
| Source | Placeholders 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
🏠 › Button Types › Switch
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.
🏠 › Button Types › Input Slot
Input Slot
Allow players to place items into a GUI slot, triggering commands when an item is detected.
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
| Placeholder | Value |
%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 › Overview
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
| Type | Description |
VAULT_MONEY | Requires a Vault balance. Optionally deducts. |
XP_LEVEL | Requires XP levels. |
XP_POINTS | Requires raw XP points. |
PERMISSION | Requires a Bukkit permission node. |
LUCKPERMS_GROUP | Requires LuckPerms group membership. |
PLACEHOLDER | Compares a PAPI placeholder with operator. |
PLACEHOLDER_EQUALS | String equality check. |
PLACEHOLDER_CONTAINS | String contains check. |
PLACEHOLDER_GREATER_THAN | Numeric greater-than check. |
PLACEHOLDER_LESS_THAN | Numeric less-than check. |
EXPRESSION | Full math/logic expression with placeholders. |
SCRIPT | JavaScript expression returning boolean. |
ITEM | Requires a specific item in inventory. |
WORLDGUARD_REGION | Requires player to be inside a WG region. |
WEATHER | Checks current world weather. |
WORLD | Restricts to specific world(s). |
MODELED_NPC | Require player to be within radius of a ModeledNPC. |
OREO_CURRENCY | OreoEssentials custom currency balance. |
OREO_WARPS | Check if an OreoEssentials warp exists and player has permission. |
OREO_WARPS_LOCATION | Require player to be within N blocks of an OreoEssentials warp. |
ITEM_CUSTOM_MODEL | Require player to have an item with a specific custom model data value. |
🏠 › Conditions › Economy & XP
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
🏠 › Conditions › Permissions
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
🏠 › Conditions › Placeholders
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"
🏠 › Conditions › Expression Engine
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
| Category | Operators |
| 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.
🏠 › Conditions › Script Conditions
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
| Variable | Type | Description |
player | Bukkit Player | The clicking player |
Java VersionScript conditions use Nashorn (Java 8–14) or GraalVM JavaScript when available. On Java 17+ servers without GraalVM, SmartMenus automatically falls back to a built-in expression evaluator that supports ==, !=, >=, <=, >, < — after resolving any PlaceholderAPI tokens. Full JavaScript (loops, functions, Bukkit API calls) still requires GraalVM.
🏠 › Conditions › World & Region
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
🏠 › Conditions › Item Conditions
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 › Overview
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
| Type | Description |
PLAYER_MESSAGE | Send a chat message to the player. |
BROADCAST | Broadcast a message to all players. |
ACTION_BAR | Show a message on the action bar. |
TITLE | Show a title + subtitle. |
SOUND | Play a sound to the player. |
BROADCAST_SOUND | Play a sound to all players. |
CONSOLE_COMMAND | Run a command as console. |
PLAYER_COMMAND | Run a command as the player. |
RANDOM_CONSOLE_COMMAND | Pick a random command from a list (equal chance). |
RANDOM_PLAYER_COMMAND | Pick a random command as player (equal chance). |
CHANCE_REWARD | Roll weighted chance and run the matching reward's commands and/or messages. |
TELEPORT | Teleport the player to coordinates. |
OPEN_INVENTORY | Open another GUI by ID. |
CLOSE_INVENTORY | Close the current GUI. |
BACK | Navigate back in history. |
SERVER_CONNECT | Send player to another BungeeCord server. |
SCRIPT | Execute JavaScript code. |
🏠 › Actions › Messages & UI
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
🏠 › Actions › Commands
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"
CHANCE_REWARD
Rolls a number 0–100 and gives the player the first matching reward tier. Each tier has a chance (percentage), an optional commands list (run as console), and an optional messages list (sent directly to the player with full color support). Chances do not need to add up to 100 — any remainder is a silent miss (no reward).
YAML
- type: CHANCE_REWARD
rewards:
- chance: 5 # 5 % → Legendary
commands:
- "give {player} netherite_ingot 1"
- "broadcast &6{player} &7hit the jackpot!"
messages:
- "<gradient:#FFD700:#FF8C00><bold>✦ LEGENDARY!</bold></gradient> <white>Netherite Ingot!"
- chance: 25 # 25 % → Rare
commands:
- "give {player} diamond 3"
messages:
- "<aqua><bold>✦ RARE!</bold></aqua> <gray>You found 3 Diamonds!"
- chance: 70 # 70 % → Common
commands:
- "give {player} iron_ingot 8"
messages:
- "&fCommon. &7You found 8 Iron Ingots."
# remaining 0 % → silent miss
messages: — Color support
Messages under messages: are sent directly to the player and support all color formats:
| Format | Example |
& codes | &a&lGreen Bold |
| Hex colors | &#FF5500text |
| MiniMessage colors | <red>text</red>, <#FF5500>text |
| MiniMessage gradient | <gradient:#FF0000:#0000FF>text</gradient> |
| MiniMessage rainbow | <rainbow>text</rainbow> |
| MiniMessage formatting | <bold>, <italic>, <underlined> |
Variable SubstitutionUse {player} in any command or message — it is replaced with the clicking player's name. PlaceholderAPI placeholders also work.
🏠 › Actions › Teleport
Teleport Action
YAML
- type: TELEPORT
world: "world"
x: 0.5
y: 64.0
z: 0.5
yaw: 0.0
pitch: 0.0
🏠 › Actions › Inventory Actions
Inventory Actions
OPEN_INVENTORY
YAML
- type: OPEN_INVENTORY
inventory: "my_shop"
CLOSE_INVENTORY
YAML
- type: CLOSE_INVENTORY
BACK
YAML
- type: BACK
Opens the bedrock: form of the target GUI for Bedrock players. Java players get the normal chest inventory.
YAML
- type: OPEN_BEDROCK_FORM
inventory: "my_gui"
OPEN_BEDROCK_DIALOGUE
Opens the target GUI's Bedrock DIALOGUE form (NPC speech bubble). Falls back to SIMPLE_FORM if the Dialogue API is unavailable. Falls back to Java inventory for Java players.
YAML
- type: OPEN_BEDROCK_DIALOGUE
inventory: "my_gui"
Auto-RoutingOPEN_INVENTORY also auto-routes to the Bedrock form when auto-convert: true or a bedrock: block is defined on the target GUI. You only need OPEN_BEDROCK_FORM / OPEN_BEDROCK_DIALOGUE when you want to force a specific Bedrock form even if the caller would normally open a different one.
🏠 › Actions › Script Actions
Script Actions
Execute arbitrary JavaScript with the player and plugin bindings.
YAML
- type: SCRIPT
script: "player.sendMessage('\u00a7aHello ' + player.getName() + '!');"
Available Bindings
| Variable | Type |
player | Bukkit Player |
plugin | Smart MenusPlugin instance |
🏠 › Actions › BungeeCord
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
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
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
Commands & Permissions
Plugin Commands
All commands accept the following aliases: /sm, /smenu, /smenus, /smartmenu, /ogui, /gui, /omenu.
| Command | Description | Permission |
/sm reload | Hot-reload all GUI files and lang.yml | smartmenus.reload |
/sm open <id> [player] | Open a GUI for yourself or another player | smartmenus.open |
/sm captureitem <gui> <slot> [key] | Capture the item in your hand into a GUI config | smartmenus.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]
| Argument | Required | Description |
gui_id | ✔ | ID of the GUI to add the item to |
slot | ✔ | Slot number (0–53) where the item will appear |
item_key | — | YAML key name for the item. Defaults to captured_slot_<slot> |
What gets captured automatically:
| Field | Details |
name | Display name — § color codes converted to & for readability |
lore | Every lore line, preserved exactly |
material | Item type (e.g. ENCHANTED_BOOK) |
enchantments | Regular enchants and stored enchants (enchanted books) |
custom_model_data | Captured automatically if present |
item_flags | HIDE_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
| Permission | Default | Description |
smartmenus.open | true | Open GUIs for other players |
smartmenus.reload | op | Use /smartmenus reload |
smartmenus.captureitem | op | Capture held item into a GUI config |
smartmenus.command.* | true | Open all GUI commands |
smartmenus.command.<id> | true | Open a specific GUI command |
smartmenus.* | op | All permissions |
🏠 › Placeholders
Placeholders
Smart Menus supports PlaceholderAPI in all item names, lore lines, titles, and condition values.
Built-in Placeholders
| Placeholder | Where | Value |
{player} | Commands, actions | Clicking player's name |
%page% | Pagination titles/lore | Current page (1-based) |
%max_page% | Pagination titles/lore | Total pages |
%player_name% | ONLINE_PLAYERS source | Player name |
%world_name% | WORLDS source | World name |
%item_name% | Inventory sources | Item display name |
%input_item_material% | INPUT on-place | Material of placed item |
%input_item_name% | INPUT on-place | Display name of placed item |
%input_item_amount% | INPUT on-place | Amount of placed item |
PlaceholderAPIAny %papi_placeholder% works in names, lore, titles, and condition values when PlaceholderAPI is installed.
🏠 › Integrations
Integrations
All integrations are optional. Smart Menus detects each plugin at startup and gracefully degrades if it's not present.
| Plugin | Features Unlocked |
| PlaceholderAPI | Placeholders in names, lore, titles, conditions |
| Vault | VAULT_MONEY condition |
| LuckPerms | LUCKPERMS_GROUP condition, PERMISSION_GROUPS dynamic source |
| WorldGuard | WORLDGUARD_REGION condition |
| ItemsAdder | ITEMSADDER condition; item_type: itemsadder items |
| Nexo | NEXO condition; item_type: nexo items |
| OreoEssentials | OREO_CURRENCY, OREO_WARPS conditions; custom currency items |
| ModeledNPCs | npc_id: binding to open GUI on NPC right-click; MODELED_NPC condition |
| BungeeCord / Velocity | SERVER_CONNECT action |
🏠 › Developer API
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
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
🏠 › Configuration › Plugin Config
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
| Key | Default | Description |
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
- Start with
regenerate-default-guis: true — study the examples.
- Copy and customise what you need into your own folders.
- Delete the example folders.
- Set
regenerate-default-guis: false — they won't come back.
🏠 › Configuration › Language File
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.
| Format | Example | Result |
| Legacy codes | &c&lBold Red | Bold red text |
| Hex color | &#FFD700Gold | Gold / #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: " �FFFF→ &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}
�FF00&l→ Balance: &f${balance}
economy_unavailable: "⚠ Vault not found!"
xp_level:
insufficient: |
<gradient:#00FFFF:#0099FF>⭐ Not Enough Levels!</gradient>
�FFFF&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
| Placeholder | Available in | Value |
{amount} | All cost/requirement messages | Required amount |
{balance} | vault_money, oreo_currency | Player's current balance |
{current} | xp_level, xp_points, item | Player's current amount |
{currency} | oreo_currency | Currency name |
{permission} | permission | Required permission node |
{region} | worldguard_region | Region name |
{placeholder} | placeholder | PAPI placeholder key |
{operator} | placeholder | Comparison operator |
{value} | placeholder | Comparison value |
{required} | weather | Required weather |
{worlds} | world | List of allowed worlds |
{npc} | modeled_npc | NPC name |
{distance} | modeled_npc | Current distance in blocks |
{radius} | modeled_npc | Required max distance |
{warp} | oreo_warps | Warp name |
{item} | item, itemsadder, nexo | Item name |
{count} | reload messages | Number of GUIs loaded |
{gui} | general, npc messages | GUI ID |
{player} | Various | Player name |
{error} | Error messages | Error 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}
�FF00&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.
🏠 › Button Types › Chat Input
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.
- Player clicks the CHAT_INPUT button
- The GUI closes automatically
- The
chat-prompt message is sent to the player
- The next message the player types is captured
- All
actions: fire with {chat_input} replaced by what they typed
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}"
| Key | Required | Description |
chat-prompt | No | Message sent to the player asking for input. Supports color codes and placeholders. |
actions: | No | Actions fired after the player types. {chat_input} is replaced with what they typed. |
{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
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 Slots)
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, SmartMenus takes over the player's 36 inventory slots (main + hotbar) as interactive GUI slots, giving you 90 total. Two rendering modes are available:
| Mode | How it works | Requirements |
DEFAULT | Real inventory is saved to memory on open, slots are filled with GUI items, and the snapshot is restored on close. Zero item loss under normal conditions. | Nothing extra |
PACKET_EVENT | GUI items are sent as packets only. The real inventory is never touched or modified at any point — crash-safe, no snapshot needed, no flicker. | PacketEvents plugin installed |
RecommendedUse
PACKET_EVENT on production servers. Because the real inventory is never modified, a crash cannot cause item loss. Install
PacketEvents and set
bottom_inventory_mode: PACKET_EVENT.
Auto-detectionSmartMenus prints a banner on startup showing whether PacketEvents is detected. If a GUI requests PACKET_EVENT but PacketEvents is absent, SmartMenus automatically falls back to DEFAULT and logs a warning.
Enabling It
YAML
my_fullscreen_gui:
title: "&5&lFull Screen Hub"
rows: 6
use_bottom_inventory: true
bottom_inventory_mode: PACKET_EVENT # DEFAULT or PACKET_EVENT
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 slots | Player inventory area (screen order) | Player inv slots (internal) |
| 0–8 | Main row 1 (top) | 9–17 |
| 9–17 | Main row 2 | 18–26 |
| 18–26 | Main row 3 | 27–35 |
| 27–35 | Hotbar (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
DEFAULT mode:
- 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
PACKET_EVENT mode:
- Real inventory is never modified — no snapshot required
- On close, the real items are re-sent via packets so the client sees them correctly
- Crash-safe — a server crash cannot corrupt or lose inventory because nothing was written
- Navigating between full-screen GUIs is seamless — no flicker, no intermediate restore step
Do not nest full-screen GUIs (DEFAULT mode only)In DEFAULT mode, avoid opening a second use_bottom_inventory GUI from inside one that is already active — the snapshot of the first GUI would be overwritten. In PACKET_EVENT mode this is handled automatically with no risk of item loss.
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
bottom_inventory_mode: PACKET_EVENT # DEFAULT or PACKET_EVENT (PacketEvents required for PACKET_EVENT)
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 never modified."
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
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
| Key | Fires when |
ANY | Any click (same as using actions:) |
LEFT | Left mouse button |
RIGHT | Right mouse button |
SHIFT_LEFT | Shift + left click |
SHIFT_RIGHT | Shift + right click |
MIDDLE | Middle mouse button (scroll wheel click) |
DOUBLE_CLICK | Double 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
| Feature | actions: | 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
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
| Feature | conditions: | 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 item | Hidden 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."
Priority Chain — N Levels
Each else-item can have its own view-requirements and its own else-item, creating an unlimited priority chain on a single slot. SmartMenus walks the chain at render time and displays the first item whose conditions pass.
YAML
rank-display:
slot: 13
material: NETHER_STAR
name: "&4Admin Item"
view-requirements:
- type: PERMISSION
permission: "group.admin"
else-item:
material: DIAMOND
name: "&bVIP Item"
view-requirements:
- type: PERMISSION
permission: "group.vip"
else-item:
material: STONE
name: "&7Default Item"
# No view-requirements = always shown if the above fail
| Chain step | Behaviour |
| Top item passes | Top item is displayed |
| Top fails → else-item passes | else-item is displayed |
| Both fail → else-item's else-item | Walks deeper, no limit |
| Chain exhausted | Slot is empty |
This is equivalent to DeluxeMenus' priority system, and is what the DeluxeMenus Converter produces automatically.
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" ]
🏠 › In-Game Editor
In-Game GUI Editor
SmartMenus ships a fully featured in-game visual editor that lets you create and modify GUIs without ever touching a YAML file. Open it with a command, click items, type values in chat, and every change is saved to disk instantly.
Opening the Editor
Command
/smartmenus editor # opens the GUI list
/ogui editor # alias
Requires the permission smartmenus.editor (default: op).
Screen Flow
The editor is a multi-screen state machine. Every action you take inside it moves you between screens:
| Screen | What you see | Purpose |
| GUI List | All loaded GUIs | Select a GUI to edit, or create a new one |
| Layout Editor | 54-slot replica of the GUI | Click any slot to edit that slot's item |
| Slot Editor | Property picker for one slot | Change material, name, lore, button type, actions, conditions, etc. |
| Action List | All actions on a slot | View, add, reorder, or remove actions |
| Action Editor | A single action's properties | Set action type and parameters |
| Condition List | All conditions on a slot | View, add, or remove conditions |
| Condition Editor | A single condition's properties | Set condition type and parameters |
| Switch States | All states of a SWITCH button | Add/remove individual switch states |
| Pagination Elements | All elements of a PAGINATION button | Add/remove static element definitions |
Universal Controls
| Action | Effect |
| Left-click a slot in Layout Editor | Open Slot Editor for that slot |
| Right-click a slot in Layout Editor | Clear / delete that slot entirely |
| Shift-click an action or condition | Remove it from the list |
| Click slot 53 (Back button) | Return to the previous screen |
| Type a value when prompted | Send it in chat — the editor captures it automatically |
Type cancel in chat | Abort any ongoing chat-input prompt |
Auto-SaveEvery change in the editor is immediately written to the GUI's YAML file on disk. There is no separate "save" step.
Creating a New GUI
- Run
/smartmenus editor.
- Click the lime green "New GUI" item (bottom of the list).
- Type the GUI ID in chat (e.g.
my_gui) and press Enter.
- A new file is created at
guis/<id>/<id>.yml and the Layout Editor opens immediately.
Permissions
| Permission | Default | Description |
smartmenus.editor | op | Access to /smartmenus editor |
ogui.editor | op | Alias permission for /ogui editor |
🏠 › In-Game Editor › Screens
Editor Screens Reference
Every screen in the in-game editor is documented here — what each slot does, what chat prompts appear, and what gets saved.
GUI List Screen
Opened by /smartmenus editor. Displays all currently loaded GUIs as clickable items.
- Left-click any GUI item → open its Layout Editor.
- Slot 53 holds a New GUI button (lime glass). Clicking it prompts you to type a new GUI ID in chat.
Layout Editor Screen
A 54-slot replica of the selected GUI. Each slot mirrors the corresponding button in the actual GUI config.
- Left-click any slot → open the Slot Editor for that slot.
- Right-click any slot → delete that button from the config entirely.
- Slot 53 = Back (returns to GUI List).
Slot Editor Screen
Shown after clicking a slot. A fixed 3-row inventory displaying all editable properties of a single button:
| Slot | Property | Input type |
| 0 | Material | Chat: type an exact Bukkit material name (e.g. DIAMOND) |
| 1 | Display Name | Chat: any text with & color codes |
| 2 | Lore | Chat: lines separated by | |
| 3 | Button Type | Cycles through types: NONE → BACK → NEXT → PREVIOUS → JUMP → HOME → MAIN_MENU → INVENTORY → PAGINATION → SWITCH → INPUT → CHAT_INPUT → (back to NONE) |
| 4 | Glow (enchant effect) | Toggle: left-click to enable/disable |
| 5 | Close on click | Toggle: left-click to enable/disable |
| 6 | Actions | Click to open the Action List screen |
| 7 | Conditions | Click to open the Condition List screen |
| 8 | Update (tick refresh) | Toggle: left-click to enable/disable |
| 13 | Type-specific param 1 | Context-sensitive — see table below |
| 14 | Type-specific param 2 | Context-sensitive — see table below |
| 15 | Type-specific param 3 | Context-sensitive — see table below |
| 16 | Type-specific param 4 | Context-sensitive — see table below |
| 53 | Back | Return to Layout Editor |
Type-Specific Parameters (slots 13–16)
| Button Type | Slot 13 | Slot 14 | Slot 15 | Slot 16 |
| JUMP | to-page (chat: page number) | — | — | — |
| SWITCH | Switch key (chat: string) | Edit States → Switch States screen | — | — |
| PAGINATION | Slots string (chat: e.g. 10-16,19-25) | Edit Elements → Pagination Elements screen | — | — |
| INPUT | — | — | On-place actions count → Action List | Remove-on-place toggle |
Action List Screen
Lists all actions attached to the current button. Each action appears as an item showing its type and parameters.
- Shift-click any action → remove it.
- Slot 45 = Add Action button → prompts for action type in chat, then walks through each required parameter.
- Slot 53 = Back.
Supported action types you can add: PLAYER_COMMAND, CONSOLE_COMMAND, PLAYER_MESSAGE, BROADCAST, SOUND, OPEN_GUI, TITLE, ACTION_BAR, SERVER_CONNECT, TELEPORT, GIVE_ITEM, TAKE_ITEM, GIVE_MONEY, TAKE_MONEY, GIVE_XP, TAKE_XP, SCRIPT.
Condition List Screen
Lists all conditions attached to the current button.
- Shift-click any condition → remove it.
- Slot 45 = Add Condition → prompts for condition type, then walks through each parameter (e.g. amount, permission node, expression string). For parameters that can be skipped, type
skip.
- Slot 53 = Back.
All 23 condition types are available. The PLACEHOLDER_* family (EQUALS, CONTAINS, STARTS_WITH, ENDS_WITH) also accepts an ignore_case parameter — type true, false, or skip.
Switch States Screen
Accessed from the Slot Editor when the button type is SWITCH, via the "Edit States" button (slot 14).
- Each state is displayed as an item showing the state key, material, display name, and command count.
- Shift-click a state → remove it.
- Slot 45 = Add State → multi-step chat prompt: key → material → display name → commands (pipe-separated).
- Slot 53 = Back.
TipState keys become the YAML path under buttons.<state-key> in the SWITCH button config.
Accessed from the Slot Editor when the button type is PAGINATION, via the "Edit Elements" button (slot 14).
- Each element shows its title and description.
- Shift-click an element → remove it.
- Slot 45 = Add Element → two-step chat prompt: title → description.
- Slot 53 = Back.
Chat Input Reference
Whenever the editor needs text input it closes the inventory and shows a prompt in chat. The input is captured from your next chat message. At any point you can type cancel to abort.
| Prompt | Expected input | Example |
| Material | Bukkit enum name (case-insensitive) | diamond_sword |
| Display Name | Text with & codes | &b&lMy Item |
| Lore | Lines separated by | | &7Line one|&7Line two |
| Action type | Action enum name | PLAYER_COMMAND |
| Action parameter | Value for that parameter | give {player} diamond 1 |
| Condition type | Condition enum name | VAULT_MONEY |
| Condition parameter | Value or skip | 100 |
| GUI ID (new GUI) | Alphanumeric + underscore | my_cool_gui |
| JUMP to-page | Integer page number | 2 |
| SWITCH key | String identifier | on |
| PAGINATION slots | Range/list string | 10-16,19-25 |
| State key | Identifier string | enabled |
| State material | Bukkit enum name | GREEN_WOOL |
| State name | Text with color codes | &a Enabled |
| State commands | Pipe-separated commands | say on|give {player} cookie 1 |
| Element title | Text with color codes | &6Quest One |
| Element description | Text with color codes | &7Complete the tutorial |
🏠 › Converters
GUI Converters
SmartMenus can automatically convert GUI configuration files from other popular menu plugins into its own format. Three converters are built in: CommandPanel, DeluxeMenus, and ZMenus.
Workflow
- Place the source GUI file(s) into the appropriate input folder inside the plugin data directory.
- Run the convert command.
- Find the converted
.yml file in plugins/SmartMenus/guis/converted/.
- Run
/smartmenus reload to load it, then test.
Folder Structure
Shell
plugins/SmartMenus/
├── converter/
│ ├── commandpanel/ ← place CommandPanel .yml files here
│ ├── deluxemenus/ ← place DeluxeMenus .yml files here
│ └── zmenus/ ← place ZMenus inventory .yml files here
└── guis/
└── converted/ ← all converted output goes here
All four directories are created automatically on first plugin start — you do not need to create them manually.
Command
Command
/smartmenus convert <type> <file>
/ogui convert <type> <file>
| Argument | Values | Description |
<type> | cp / commandpanel
dm / deluxemenus
zm / zmenus | Which converter to use |
<file> | Filename without .yml | File inside the converter's input folder |
Tab-complete works for both the type and the filename.
Examples
Command
/smartmenus convert cp my_shop
/smartmenus convert dm main_menu
/smartmenus convert zm rtp
Permissions
| Permission | Default |
smartmenus.convert | op |
ogui.convert | op |
What Gets Converted
All three converters map the following concepts:
🏷️
Title & Rows
GUI title (with color codes) and inventory row count.
📦
Items
Material, display name, lore, glow effect, custom model data, item flags.
⚡
Actions
Player commands, console commands, messages, sounds, open GUI, server connect.
🧱
Fill Items
Glass pane border/fill items are auto-detected and mapped to fill.material.
📍
Slot Ranges
Range notation like 0-8 is expanded to individual slot numbers.
🎨
Color Codes
All §/&/hex formats are normalised to SmartMenus & codes.
After ConvertingAlways review the output file and test the GUI in-game. Complex features (conditions, per-click actions, placeholders in lore) may require manual adjustments that fall outside the scope of automatic conversion.
🏠 › Converters › CommandPanel
CommandPanel Converter
Converts GUI YAML files from the CommandPanel plugin into SmartMenus format.
Shell
plugins/SmartMenus/converter/commandpanel/
Usage
Command
/smartmenus convert cp <filename>
Where <filename> is the name of the file without .yml, placed in the input folder above.
CommandPanel GUIs use a layout: section to map slot numbers to item keys, and a separate items: section for item definitions.
CommandPanel YAML
title: "&6My Shop"
rows: 3
command: "myshop"
aliases: [ "shop" ]
items:
diamond-btn:
material: diamond
name: "&bDiamond"
lore:
- "&7Click to purchase."
enchanted: [ true ]
actions:
commands:
- "[player] /buy diamond"
- "[console] eco take {player} 100"
layout:
13: [ diamond-btn ]
fill: [ border-item ]
Conversion Mapping
| CommandPanel field | SmartMenus output |
title | <id>.title |
rows | <id>.rows |
command / commands / aliases | <id>.commands list |
layout.fill | <id>.fill.material |
layout.<N> | <id>.items.<N> |
material (lowercase) | material (uppercase) |
name | name |
lore | lore |
enchanted: [true] | glow: true |
item-model: "1234" | custom_model_data: 1234 |
itemType: [noAttributes] | item_flags: [HIDE_ATTRIBUTES] |
Action Prefix Mapping
| CommandPanel prefix | SmartMenus action type |
[chat] /cmd or [player] /cmd | PLAYER_COMMAND |
[console] cmd | CONSOLE_COMMAND |
[msg] text | PLAYER_MESSAGE |
[broadcast] text | BROADCAST |
[title] t;s | TITLE (title + subtitle split on ;) |
[sound] SOUND | SOUND |
[open] gui_id | OPEN_GUI |
[close] | close: true on the item |
[refresh] | update: true on the item |
[delay] N | Skipped — no equivalent |
Requirement Prefix Mapping
| CommandPanel requirement | SmartMenus condition type |
[permission] node | PERMISSION |
[money] N / [vault] N | VAULT_MONEY |
[exp] N / [xp] N | XP_LEVEL |
[item] material=X amount=N | ITEM |
[item] material=X custom=N | ITEM_CUSTOM_MODEL |
[luckperms] group / [group] group | LUCKPERMS_GROUP |
🏠 › Bedrock / Geyser › Overview
Bedrock / Geyser Support
SmartMenus 2.1 adds full native Bedrock support using Paper's Dialog API. Geyser automatically translates Paper Dialog packets into Bedrock-native forms — no Geyser-specific code, no Cumulus, no extra setup beyond installing Geyser.
How It Works
When a Bedrock player opens a GUI, SmartMenus detects them and opens a Paper Dialog instead of a chest inventory:
- Paper sends a Dialog packet to the client
- Geyser intercepts it and converts it to a Bedrock-native form packet automatically
- The Bedrock player sees a native mobile-friendly form — no chest inventory
- Java players see the normal chest inventory — nothing changes for them
Zero extra codeYou do not need to write Bedrock-specific logic. Add auto-convert: true to a GUI and Bedrock players automatically get a native dialog. Java players are completely unaffected.
Requirements
| Requirement | Version | Notes |
| Paper | 1.21.5+ | Dialog API is Paper-only |
| Geyser-Spigot | Any recent | Handles Java→Bedrock packet translation |
| Floodgate | 2.2+ | Optional but recommended — improves Bedrock detection reliability |
Runs without Bedrock supportSmartMenus works on any Paper/Spigot 1.16+ server. If Geyser and Floodgate are absent, all Bedrock features are simply skipped — nothing breaks.
Bedrock Player Detection
SmartMenus detects Bedrock players in two ways, in priority order:
- Floodgate API —
FloodgateApi.getInstance().isFloodgatePlayer(uuid) when Floodgate is installed (most reliable)
- UUID prefix fallback — UUIDs starting with
00000000-0000-0000- are Bedrock players even without Floodgate
Two Modes
⚡
Auto-Convert
Add auto-convert: true to any existing GUI. SmartMenus builds a Bedrock dialog automatically from your items. Zero extra YAML.
🎛️
Explicit Bedrock Block
Add a bedrock: section for full control — custom buttons with images, inputs, dropdowns, sliders, NPC dialogues.
Java Compatibility
Both modes are fully transparent to Java players. The auto-convert flag and the bedrock: block are only used when the opening player is detected as a Bedrock player. Java players always see the normal chest inventory.
Next Steps
- Auto-Convert — the fastest way to add Bedrock support to existing GUIs
- Form Types — SIMPLE_FORM, MODAL_FORM, CUSTOM_FORM, DIALOGUE reference
🏠 › Bedrock / Geyser › Auto-Convert
Auto-Convert
Add one line to any GUI and Bedrock players automatically get a native dialog built from your items. No additional YAML required.
Enabling It
YAML
my_shop:
title: "&6&l💰 Shop"
rows: 3
commands: [ "shop" ]
auto-convert: true # ← that's all
items:
sword:
slot: 10
material: DIAMOND_SWORD
name: "&b&lDiamond Sword"
lore:
- "&7A sharp blade."
- ""
- "&ePrice: &a$500"
- "&7Click to purchase!"
conditions:
- type: VAULT_MONEY
amount: 500
commands:
- "give {player} diamond_sword 1"
close: true
pickaxe:
slot: 12
material: DIAMOND_PICKAXE
name: "&b&lDiamond Pickaxe"
lore:
- "&7Mine faster."
- ""
- "&ePrice: &a$750"
conditions:
- type: VAULT_MONEY
amount: 750
commands:
- "give {player} diamond_pickaxe 1"
close: true
close-btn:
slot: 22
material: BARRIER
name: "&c&lClose"
close: true
Java players see the normal chest inventory. Bedrock players see a SIMPLE_FORM dialog with buttons automatically generated from the items above.
What Gets Converted
Auto-convert scans all items sorted by slot number and builds a button list:
| Item property | Becomes |
name | Button label (first line) |
First 3 lore lines | Additional label lines below the name |
conditions: | Checked before the button's actions fire |
actions: / commands: | Run when the button is tapped |
close: true | Closes the form after actions fire |
view-requirements: | Button is hidden entirely if conditions fail |
What Gets Skipped
Items with no actions and no commands (decorative fillers, glass pane borders) are automatically excluded — they would produce useless buttons with nothing to do.
Dialog Title
The dialog uses the GUI's title: value. Color codes are converted automatically.
Fallback
If auto-convert: true is set but the player is not on Bedrock (or Geyser/Floodgate are absent), the normal Java inventory opens — no change in behavior.
Overriding with an Explicit Bedrock Block
If you want more control (images on buttons, a content message, custom button order), add a bedrock: block. When both auto-convert: true and bedrock: are present, the explicit bedrock: block takes priority.
YAML
my_shop:
title: "&6Shop"
rows: 3
auto-convert: true # used as fallback if bedrock: is removed
bedrock: # ← this takes priority
type: SIMPLE_FORM
title: "&6&l💰 Shop"
content: "&7Choose an item:"
buttons:
- text: "&b&lDiamond Sword\n&7Price: $500"
image-type: path
image-data: textures/items/diamond_sword
conditions:
- type: VAULT_MONEY
amount: 500
actions:
- type: CONSOLE_COMMAND
command: "give {player} diamond_sword 1"
- type: CLOSE_INVENTORY
items:
# ... your normal Java inventory items ...
All Default GUIs
Every GUI that ships with SmartMenus (34 total) has auto-convert: true set out of the box. Bedrock players can use every default GUI on a fresh install with zero configuration.
🏠 › Bedrock / Geyser › Form Types
Bedrock Form Types
When you add an explicit bedrock: block to a GUI, you choose one of four form types. Each maps to a different Bedrock UI.
Form Type Overview
| Type | Bedrock UI | Best For |
SIMPLE_FORM | Scrollable button list with optional images | Shops, menus, navigation |
MODAL_FORM | Two-button confirmation dialog | Confirm/cancel prompts |
CUSTOM_FORM | Input form with text fields, dropdowns, sliders, toggles | Settings, preferences, name entry |
DIALOGUE | NPC speech bubble with button list | NPC conversations, quest dialogs |
SIMPLE_FORM
A scrollable list of buttons. Each button can have an image (path or URL) and its own conditions and actions.
YAML
bedrock:
type: SIMPLE_FORM
title: "&6&l💰 Money Shop"
content: "&7Choose an item to purchase:"
buttons:
- text: "&b&lDiamond Sword\n&7Price: &a$500"
image-type: path
image-data: textures/items/diamond_sword
conditions:
- type: VAULT_MONEY
amount: 500
actions:
- type: CONSOLE_COMMAND
command: "give {player} diamond_sword 1"
- type: CLOSE_INVENTORY
- text: "&b&lDiamond Pickaxe\n&7Price: &a$750"
image-type: path
image-data: textures/items/diamond_pickaxe
conditions:
- type: VAULT_MONEY
amount: 750
actions:
- type: CONSOLE_COMMAND
command: "give {player} diamond_pickaxe 1"
- type: CLOSE_INVENTORY
- text: "&c&lClose"
actions:
- type: CLOSE_INVENTORY
SIMPLE_FORM Properties
| Key | Description |
title | Form title. Supports & color codes. |
content | Text displayed above the button list. |
buttons | List of button definitions (see below). |
| Key | Description |
text | Button label. Use \n for line breaks within the label. |
image-type | path (resource pack path) or url (image URL). |
image-data | The path or URL value. Example: textures/items/diamond_sword |
conditions | Standard SmartMenus condition list. All must pass for actions to fire. |
actions | Standard SmartMenus action list. Run when the button is tapped and conditions pass. |
MODAL_FORM
A two-button dialog: one confirm button and one deny button. Ideal for purchase confirmations and yes/no prompts.
YAML
bedrock:
type: MODAL_FORM
title: "&c&lConfirm Purchase"
content: "&7Are you sure you want to buy a Diamond Sword for &a$500&7?"
confirm-button: "&a✔ Yes, buy it"
deny-button: "&c✘ No, cancel"
confirm-actions:
- type: CONSOLE_COMMAND
command: "give {player} diamond_sword 1"
- type: PLAYER_MESSAGE
message: "&aPurchase complete! You got a Diamond Sword."
- type: CLOSE_INVENTORY
deny-actions:
- type: PLAYER_MESSAGE
message: "&7Purchase cancelled."
- type: CLOSE_INVENTORY
MODAL_FORM Properties
| Key | Description |
title | Dialog title. |
content | Main message body. |
confirm-button | Label for the confirm/yes button. |
deny-button | Label for the deny/no button. |
confirm-actions | Actions fired when the player taps the confirm button. |
deny-actions | Actions fired when the player taps the deny button. |
CUSTOM_FORM
A form with free-form inputs: text fields, dropdowns, sliders, step sliders, toggles, and labels. Values are captured as variables accessible in submit actions.
YAML
bedrock:
type: CUSTOM_FORM
title: "⚙ Player Preferences"
inputs:
- key: display_name
type: INPUT
label: "Display Name"
placeholder: "Enter a name..."
max-length: 24
- key: gamemode
type: DROPDOWN
label: "Preferred Gamemode"
options: [ "Survival", "Creative", "Adventure" ]
default: 0
- key: walk_speed
type: SLIDER
label: "Walk Speed"
min: 1
max: 10
step: 1
default: 5
- key: pvp_enabled
type: TOGGLE
label: "Enable PvP"
default: false
- key: notice
type: LABEL
label: "&7Changes apply immediately."
submit-actions:
- type: CONSOLE_COMMAND
command: "nick {player} %bedrock_input_display_name%"
- type: PLAYER_MESSAGE
message: "&aPreferences saved! Name: &f%bedrock_input_display_name%"
Input VariablesEach input's value is stored as %bedrock_input_<key>% and available in all submit actions. For example, an input with key: display_name becomes %bedrock_input_display_name%.
CUSTOM_FORM Properties
| Key | Description |
title | Form title. |
inputs | List of input definitions (see below). |
submit-actions | Actions fired when the player submits the form. |
| Type | Description | Specific fields |
INPUT | Single-line text field | placeholder, default (text), max-length |
DROPDOWN | Drop-down option list | options (list of strings), default (index, 0-based) |
SLIDER | Numeric slider | min, max, step, default (float) |
STEP_SLIDER | Slider that snaps to labelled steps | options (list of step labels), default (index) |
TOGGLE | On/off toggle switch | default (true/false) |
LABEL | Non-interactive text label | none — uses label as display text |
| Key | Description |
key | Identifier used in %bedrock_input_<key>%. Defaults to the lowercased label if omitted. |
type | Input type (see table above). |
label | Text shown next to the input field. |
DIALOGUE
An NPC speech bubble with a button list. The npc-name appears as the speaker's name above the dialog.
YAML
bedrock:
type: DIALOGUE
title: "&6Old Merchant"
content: "&7Ahh, a traveler! What brings you to my humble shop today?"
npc-name: "Old Merchant"
buttons:
- text: "Browse Wares"
actions:
- type: OPEN_INVENTORY
inventory: shop_main
- text: "I need repairs"
actions:
- type: OPEN_INVENTORY
inventory: repair_shop
- text: "Never mind"
actions:
- type: CLOSE_INVENTORY
DIALOGUE Properties
| Key | Description |
title | Dialog title (shown at the top). |
content | The NPC's spoken text. |
npc-name | Speaker name shown above the dialog. Usually the NPC's name. |
buttons | List of response buttons. Same format as SIMPLE_FORM buttons. |
NPC BindingYou can bind any GUI to a ModeledNPC using npc_id: at the GUI level. When the NPC is right-clicked, the DIALOGUE form opens automatically for Bedrock players.
Placeholder Support
All text fields in Bedrock forms support:
& color codes — converted automatically
{player} — replaced with the player's name
%placeholder% — any PlaceholderAPI placeholder
%bedrock_input_<key>% — CUSTOM_FORM input values (in submit actions)
🏠 › Changelog
Changelog
Release history for SmartMenus.
v2.4
Bug Fixes
-
Fixed:
OPEN_GUI action not working after DM conversion
Clicking navigation buttons converted from DeluxeMenus [openguimenu] commands did nothing. The OPEN_GUI action type was missing from the internal action parser and was silently discarded. Now correctly opens the target GUI.
-
Fixed: GUI ID hyphen/underscore mismatch
GUIs are registered with underscores derived from their filename (e.g. jobs-farmer.yml → jobs_farmer), but DM configs reference them with hyphens ([openguimenu] jobs-farmer). SmartMenus now normalizes the target ID at lookup time so both forms resolve correctly.
-
Fixed: SmartMenus overriding other plugins' commands
When a converted GUI registered a command alias already owned by another plugin (e.g. /jobs owned by JobsReborn), SmartMenus forcibly stole it — causing the original plugin's command to stop working entirely. Player command actions like jobs join miner would then re-open the GUI instead of running the intended command. SmartMenus now skips conflicting aliases and logs a warning instead of overriding.
-
Fixed: Script conditions always returning
false on Java 17+ servers
Nashorn (the built-in JavaScript engine) was removed in Java 15. Script conditions such as %jobsr_user_joinedjobcount% == %jobsr_maxjobs% always evaluated to false on modern servers without GraalVM. SmartMenus now includes a built-in fallback expression evaluator (after PAPI resolution) supporting ==, !=, >=, <=, >, < for both numeric and string values. Full JavaScript still requires GraalVM.
-
Fixed: GUI not refreshing visually after a click fires a command
When a button with update: true fired a player command (e.g. /jobs join miner), the GUI re-rendered immediately in the same tick — before the server had processed the command — so PlaceholderAPI values hadn't changed yet and the button appeared to do nothing. The GUI now waits 5 ticks (250 ms) after the click before re-rendering.
v2.3 and earlier
See the plugin's Spigot resource page for older release notes.