🏠 › Overview
⚡ 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
| 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. Saves and replaces player inventory with bottom_items:. |
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. |
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 require Nashorn (Java 8–14) or GraalVM JavaScript. If neither is available, the condition always returns false and a one-time warning is logged.
🏠 › 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. |
RANDOM_PLAYER_COMMAND | Pick a random command as player. |
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"
Variable SubstitutionUse {player} in any command — 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
🏠 › 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
| Command | Description | Permission |
/smartmenus reload | Hot-reload all GUI files and lang.yml | smartmenus.reload |
/smartmenus open <id> [player] | Open a GUI for yourself or another player | smartmenus.open |
/smartmenus 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 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 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
- 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
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."
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" ]