ModsJava
BloomGUI
BloomGUI-Folia No-code, drag-and-drop GUI menus for Paper & Folia. Build in-game, or in your browser. Features • Installation • Commands • Web Editor •…
⬇ Download on SpigotBloomGUI-Folia
No-code, drag-and-drop GUI menus for Paper & Folia. Build in-game, or in your browser.
Features • Installation • Commands • Web Editor • Storage & Merchant • Performance • Configuration
Status: actively developed. Core flows (creating/editing/opening menus, actions, conditions, the web editor, animated and storage-backed menus) have been exercised on a real Paper/Folia server, not just compiled. Some newer or less-common surfaces (the MySQL storage backend in particular) have seen less real-world mileage than the SQLite default. Treat this doc as accurate-to-the-code; where something's still unproven at scale, it says so.Click to expand...
Contents
Getting started
- Features
- Requirements
- Installation
- Quick start
- Commands
- Permissions
- Overview & tabs
- Menus & pages
- Items
- Actions
- Conditions [/td] [td width=33%] Menu types
- Storage vaults
- Merchant menus
- Built-in placeholders
- Snippets & templates
- Item presets
- Folders
- Copy, paste & sharing
- MiniMessage & colors
- Keyboard shortcuts [/td] [td width=33%] Under the hood
- Performance & scaling
- Testing
- Security notes
- Configuration
- Building from source
- Project layout
- Known limitations [/td]
✨ Features
| Two ways to build | An in-game GUI editor (/bloom edit) for quick tweaks, plus a full single-page web editor served by the plugin itself. No external hosting, no database. |
| Multi-page menus | Items shared across every page (borders, nav buttons) plus per-page overrides that win over shared slots, and an optional per-page title override. |
| Authentic layouts | Every fill pattern a border needs (none/border/full/top/bottom/corners/custom) across seven GUI types (chest, workbench, hopper, dispenser, brewing stand, storage, merchant), rendered in the web editor to actually look like the real Minecraft inventory. |
| ️ Personal storage vaults | A STORAGE-type menu is a real, persistent per-player inventory, like an Ender Chest with your own layout, border, and page count. Backed by SQLite (zero setup) or a shared MySQL database. |
| Merchant trading menus | A MERCHANT-type menu is a real villager trade window: configure results, costs, and optional second ingredients, using plain materials or your own item presets. |
| ⚡ 23 actions · 6 conditions | Messaging, commands, navigation, economy, items, effects, teleport, snippets, randomness, text-input prompts, all extensible from a registry. Web editor forms and docs are generated live from what's actually registered, so nothing drifts out of sync. |
| Built-in placeholders | %player_name%, %player_health%, %server_tps%, and 20+ more work out of the box with zero extra plugins; PlaceholderAPI only kicks in for anything beyond that. |
| ️ Conditional lore | Show a price tag, lock notice, or VIP perk line only when a condition passes, independent of the item's own visibility. |
| Cycling & animated items | An item that changes look on click, on a timer, or both: settings toggles, sort buttons, spinning crate previews. |
| Item presets | Capture a real held item (/bloom item save) or build a banner, firework, potion, or written book from scratch, then hand it out exactly as-is. |
| Snippets & templates | Reusable action lists and reusable whole-menu layouts. |
| Version history & live sync | Rollback old versions, conflict detection (never silently overwritten), and live presence: see who else is editing and what they're looking at. |
| ️ Drag & drop everything | Move/swap items (with multi-level undo), multi-slot region copy/paste, whole-page copy/paste, and portable export/import codes for moving menus between servers. |
| Folders | Organize menus in the sidebar once you have more than a handful. |
| Vault & PlaceholderAPI | Soft-depends: economy actions/conditions and %placeholder% expansion light up automatically if installed, no-op otherwise. |
| Hardened by default | Session-protected web editor (no persistent shared secret), path-traversal-safe id handling everywhere a name touches a file, a strict Content-Security-Policy, and request-size limits; see Security notes. |
| Built to scale | Identical content across viewers of the same animated menu is built once and reused, not rebuilt per player per animation frame; see Performance & scaling. |
| Unit-tested | A growing automated test suite (JUnit 5 + MockBukkit) covers the areas most likely to break silently: id sanitization, session lockout, concurrent saves, and more. See Testing. |
Requirements
- Paper or Folia, 1.21+
- Java 21
- Optional: Vault + an economy plugin, for economy actions/conditions
- Optional: PlaceholderAPI, for placeholders beyond the built-in set
- Optional: a MySQL/MariaDB server, only if you want storage vaults shared across multiple server nodes instead of the default per-server SQLite files
Installation
- Drop the built jar into your server's plugins/ folder.
- Start (or restart) the server; a default config.yml is copied into plugins/BloomGUI-Folia/ on first run.
- Grant yourself bloomgui.admin (and bloomgui.web for the web editor); both default to op, so an op needs nothing granted manually.
Quick start
/bloom menu Opens the master dashboard in-game: create, edit, or delete menus from there.
/bloom web Starts the web editor and sends you a clickable link plus a one-time access code in chat. Open the link, paste the code, and you're in.
/bloom stats A one-shot sanity check: dumps live TPS, memory, menu count, cache hit rate, and action counters to chat. Good first command to confirm the plugin's actually running happily.
⌨️ Commands
All subcommands live under /bloom (alias /bgui) and require bloomgui.admin unless noted.
| Command | Does |
| /bloom · /bloom menu (aliases gui, dashboard) | Opens the master dashboard GUI. |
| /bloom create [id] | Creates a new menu and opens the template picker. |
| /bloom edit [id] | Opens a menu in the in-game editor. |
| /bloom open [id] [player] | Opens a menu for yourself or another player. |
| /bloom delete [id] | Deletes a menu. |
| /bloom list | Lists every menu. |
| /bloom reload | Reloads all menus from disk (picks up hand-edited YAML). |
| /bloom item base64 | Prints a copyable, full-fidelity data string for the item in your hand. |
| /bloom item save [name] | Saves the item in your hand directly as a reusable item preset. |
| /bloom web [start|stop|status] | Starts/stops/checks the web editor. Also needs bloomgui.web. |
| /bloom stats | Dumps live performance/usage counters to chat: TPS, memory, cache hit rate, action counts. |
| /bloom perfbar | Toggles a live boss bar of the same stats, updating once a second, for just you. |
Permissions
| Node | Default | Grants |
| bloomgui.admin |
op
|
All /bloom management commands, the in-game editor, /bloom stats, and /bloom perfbar. |
| bloomgui.web |
op
|
Start/stop and log into the web editor (needed in addition to admin). |
Both node names are configurable in config.yml under permissions:. A menu can also require its own permission node to be opened, set per-menu in Menu Settings.
The web editor
/bloom web starts a small, self-hosted HTTP server: no external dependencies, no database, everything is YAML files under the plugin's data folder. There's no persistent shared secret: each /bloom web mints a short-lived, single-use login code sent privately to your chat, exchanged for a session token by the page. Sessions expire after a configurable number of hours; repeated failed logins from one IP get temporarily locked out. HTTPS is supported (see Configuration) and recommended over untrusted networks.
IMPORTANT: The web editor needs its port ( 8123 by default) reachable from wherever you'll browse to it. On a home server or most VPS providers that usually means forwarding/opening that port yourself, through your router if self-hosting, or your provider's firewall/security-group panel otherwise. Many managed Minecraft hosts don't let you open arbitrary ports at all, only the main server port. Check with your host before relying on the web editor; if it's not possible, the in-game editor ( /bloom edit) still covers most of the same ground.Click to expand...
| Tab | Purpose |
| ️ Menus | Create and edit menus, where you'll spend most of your time. Includes the Storage and Merchant type pickers and the trades panel. |
| Snippets | Reusable action lists. |
| Templates | Reusable whole-menu layouts. |
| Items | Reusable, fully-detailed item presets. |
| Docs | Full in-app reference with live, click-through parameter tables generated from the server's actual registered action/condition types. |
TIP: Saving is live: press Save and anyone with that menu open sees it update instantly, no reload needed. If someone else saves the same menu while you're mid-edit, you're asked to keep yours, take theirs, or overwrite; nothing is ever silently lost. A presence bar in the top-right shows who else is signed in.Click to expand...
Core concepts
Menus
A menu is one screen a player can open: a grid of clickable items, or a fixed-shape inventory (workbench, hopper, dispenser, brewing stand), or one of the two special types below. Every menu is a list of one or more pages, plus an optional set of shared items rendered on every page (borders, nav buttons); a page-specific item at the same slot always wins over a shared one there. Each page can also override the menu's own title, handy for a multi-page menu where "Shop, Page 2" reads better than a repeated generic title. Empty slots auto-fill with a border, full-fill, top/bottom row, corners, or a hand-painted custom pattern.
Menu settings: title (MiniMessage), rows (1–6, chest-shaped types only), GUI type, an optional open command (set shop → registers /shop), an optional required permission, and the fill material/pattern.
Items
Each grid slot holds an item with material, display name, amount, cooldown, custom model data, glow, unbreakable, enchantments, hidden tooltip flags, lore, click actions, and visibility/click conditions.
- Lore is a list of lines, each optionally gated by its own condition (independent of the item's own visibility), for price tags, lock notices, VIP-only perks.
- Cycle / dynamic look: attach a list of "frames" (material/name/lore/glow overrides); the item steps through them on a chosen click type, on a timer (ticks), or both. The current frame is remembered per player for as long as the server runs (not persisted across restarts). Auto-animation is floored at 4 ticks (5×/sec) server-side regardless of what you type in, so a fat-fingered value can't accidentally spam every viewer's client with redraws.
️ Storage vaults
Set a menu's GUI type to Storage and it stops being a static layout and becomes a real, per-player inventory, think a personal Ender Chest with your own border, rows, and fill pattern around it. Whatever a player drops in survives their next visit; whatever's in a border/decoration slot stays fixed and isn't part of their storage space.
- Per-player, per-page: if the menu has multiple pages, page 2 is a separate storage space from page 1, not a shared one. A "personal warehouse" with tabs actually has independent tabs.
- Two backends: SQLite by default (one file per player per menu, zero setup) or a shared MySQL/MariaDB database (storage.backend: sql in config.yml) if you're running multiple server nodes that need to see the same vaults. Configure connection details under storage.sql.*.
- Fill patterns work normally: a Storage menu is still chest-shaped under the hood, so border/full/etc. render exactly like on a regular chest menu.
Merchant menus
Set a menu's GUI type to Merchant and the slot grid is replaced entirely by a real villager-style trade window. Configure one or more trades in the web editor's trades panel:
- A result: the item the player receives.
- One or two ingredients: what they pay with.
- Each slot (result or ingredient) can be a plain material with an amount, or one of your own item presets for an exact custom item as the reward or the cost.
⚡ Actions
What happens when a player clicks an item. Each item stores a separate action list per click type (left, right, shift, number key, or "any", which runs in addition to the specific type), executed top to bottom.
Spoiler: 23 action types, grouped
| Category | Actions |
| Messaging & feedback | message · action-bar · title · play-sound |
| ️ Commands | run-command · run-console-command |
| Navigation | open-menu · close-menu · back · refresh-menu · next-page · previous-page |
| Economy & items | economy-charge · economy-give · give-item · take-item · give-exp · take-exp |
| Effects & teleport | potion-effect · teleport |
| Flow & input | run-snippet · random (weighted snippet) · prompt-input (anvil/chat text capture) |
give-item can hand out either a plain vanilla material or an item preset for an exact custom item. open-menu picks its target from a dropdown of your actual menus (rather than typing an id from memory) and, for a multi-page target, lets you pick which page to land on. prompt-input opens an anvil field (or chat) asking the player to type something, then runs a snippet with every %input% swapped for what they typed, the way to build a search box or a teleport-to-warp prompt.
CAUTION: run-console-command runs with console privileges. If you splice a placeholder into the command text (e.g. a nickname-plugin-controlled %player_displayname%), be aware that a crafted nickname could inject extra arguments; the same risk any menu plugin with console-command actions carries. run-command runs as the clicking player, so it's bounded by their own permissions either way.Click to expand...
Conditions
Gate whether an item can be clicked, or even seen. Checks live in groups (match all or match any, each invertible with NOT); an item can have several groups, all of which must pass. A failed group either hides the item entirely or shows it disabled with an optional deny message.
| Check | Tests |
| permission | Player has a given permission node. |
| money | Player's Vault balance is at least an amount. |
| exp-level | Player has at least a given XP level. |
| item | Player has at least N of a material in their inventory. |
| world | Player is in a named world. |
| placeholder | A PlaceholderAPI value compared against a target with an operator. |
The same check types gate individual conditional lore lines.
NOTE: If Vault or PlaceholderAPI isn't installed, money and placeholder conditions pass open rather than permanently locking the item, so a menu doesn't become unusable just because an optional integration is briefly missing. Keep that in mind if you're relying on one of these as a hard gate.Click to expand...
Built-in placeholders
Item names, lore, titles, and messages can use these without installing PlaceholderAPI at all. PAPI only gets invoked for anything outside this list, and is skipped entirely if the text has no %...% left for it to resolve.
Spoiler: Full list
| Placeholder | Value |
| %player% / %player_name% | The viewer's username. |
| %player_displayname% | Their display name (nickname-plugin aware). |
| %player_uuid% | Their UUID. |
| %player_world% | The world they're in. |
| %player_x% / %player_y% / %player_z% | Block-rounded coordinates. |
| %player_health% / %player_max_health% | Current / max health. |
| %player_food% / %player_hunger% / %player_saturation% | Food level and saturation. |
| %player_level% / %player_exp% | XP level and progress. |
| %player_gamemode% | Prettified game mode name. |
| %player_ping% | Connection ping. |
| %player_ip% | Their connection address. |
| %player_flying% / %player_sneaking% / %player_sprinting% / %player_op% | Booleans. |
| %server_online% / %server_max_players% | Online / max player count. |
| %server_name% / %server_version% / %server_motd% | Server metadata. |
| %server_tps% | Current TPS. |
Also used for %player%/ %player_name% as a Player Head's skull texture: set a PLAYER_HEAD item's skull data to %player% and it shows whoever is currently looking at the menu, not one fixed player, for everyone.
Snippets
A named, reusable list of actions: define once, run from as many items as you like via run-snippet. Editing a snippet updates every item that runs it. A self-referential or cyclic snippet (A calling B calling A) is caught by a depth guard and stopped cleanly with a log warning instead of crashing the server.
Templates
A full menu layout, every page, item, action, and condition, saved under a name so a new menu can start from it instead of from scratch. Save any existing menu as a template, or build one directly in the Templates tab. Built-in starters (Blank, Simple Shop, Confirm Dialog, Multi-page Menu) are always available.
Item presets & special builders
A preset stores a real item's complete data (enchantments, potion effects, banner patterns, custom name, everything), not just the handful of fields a menu item's own properties expose.
- Capture a real item: /bloom item save in-game, or /bloom item base64 to copy a data string and import it via the web editor's Items tab.
- Build one from scratch: Items tab → + → Banner, Firework, Potion, or Written Book, each a proper form built server-side with real Minecraft item components. (No shield builder yet; none exists in the underlying API.)
Folders
Purely organizational grouping of menus in the sidebar (drag a menu onto a folder, or right-click → Move to folder). Doesn't affect how a menu behaves in-game; deleting a folder only ungroups its menus.
Copy, paste & sharing
| Scope | How |
| Single item | Right-click a slot → Copy, then Paste on any slot in any menu. |
| Grid region | Select region → click slots → Copy (N); a Paste button appears on any menu's grid. |
| Whole page | Right-click a page tab → Copy page / Paste as new page. |
| Whole menu | Export for a portable code, Import to bring one in, even from another server. |
WARNING: Export codes don't carry your server's economy/permission setup. Double-check those after importing.Click to expand...
MiniMessage & legacy colors
Titles, item names, lore, and messages all support MiniMessage tags (, [URL='https://www.google.com/search?q=gradient:...']gradient:...[/URL], , etc.) as well as legacy &-code formatting; whichever a string looks like is auto-detected. The web editor's Docs tab has a live playground for trying tags.
⌨️ Keyboard shortcuts
| Key | Does |
|
Ctrl /
Cmd +
S
|
Save the menu or snippet currently open. |
|
Esc
|
Close the open modal, or step back out of the item editor. |
|
↑
↓
←
→
|
Jump to the adjacent grid slot while editing an item (plain chest layouts). |
Performance & scaling
The renderer is built around one core idea: identical content shown to different viewers should be built once, not once per viewer.
- Shared item-content cache: for any item whose resolved name/lore has no %placeholder% and no per-viewer lore conditions, the built item is cached per menu/slot/animation-frame and simply cloned for every subsequent viewer instead of re-parsed from scratch. A menu with an animated item and hundreds of concurrent viewers rebuilds that item's handful of distinct frames once each, not once per viewer per tick.
- Automatically invalidated: the cache is dropped for a menu the moment it's edited (so a save is never stale) and cleaned up entirely if the menu is deleted, so a long server uptime with lots of menu churn doesn't leave stale entries behind.
- Placeholder resolution short-circuits: plain text with no % in it never touches the placeholder resolver at all, and PlaceholderAPI is only invoked if something's still unresolved after the built-in pass.
- Concurrency-safe saves: two saves landing on the same menu at the same instant (the web editor and an in-game edit, say) are serialized per menu id, so neither can silently overwrite the other's revision.
- Folia-correct throughout: GUI/command state that's shared across regions is always marshaled onto the appropriate thread, never touched directly from the web server's own worker threads.
Testing
An automated test suite (JUnit 5 + MockBukkit) covers the areas most likely to break silently: id sanitization against path traversal, session login/lockout behavior, the snippet recursion guard, the concurrent-save lock, per-player editor state cleanup on quit, and (found because this suite exists) a cache-invalidation edge case where an edited item could keep showing its pre-edit content. Run it with mvn test from this module's directory.
Security notes
- No persistent web secret: every /bloom web session starts from a short-lived, single-use login code sent privately in chat, never a static password.
- Per-IP lockout on repeated failed login attempts, plus a configurable session lifetime.
- Path-traversal-safe ids: every place a user-supplied name (menu id, template id, snippet name, item preset name) ever becomes part of a file path is validated at the API boundary and sanitized again at the storage layer, so a crafted id can't escape the plugin's data folder.
- Strict transport hardening on the web editor: Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, no-store caching on API responses, and a capped request body size.
- No internal detail leakage: a malformed request gets a clean 400 with a generic message; real server faults are logged in full server-side but never echo internal exception text back to the client.
- Item data (presets, held-item capture) round-trips through Paper's own NBT-based item serialization, not raw Java object deserialization, no gadget-chain deserialization surface there.
⚙️ Configuration
config.yml is created with comments on first run; missing keys are backfilled (without comments) on upgrade so new options get sensible defaults without clobbering your edits.
Spoiler: Full reference
| Key | Default | Meaning |
| message-prefix | [URL='https://www.google.com/search?q=gradient:light_purple:aqua']gradient:light_purple:aqua[/URL][◆ BloomGUI] | Prefix on plugin chat messages. MiniMessage. |
| permissions.admin | bloomgui.admin | Node for management commands and the in-game editor. |
| permissions.web | bloomgui.web | Node for the web editor (needed in addition to admin). |
| appearance.default-border-material | GRAY_STAINED_GLASS_PANE | Fill item for new menus. |
| appearance.default-fill-mode | BORDER | NONE · BORDER · FULL · TOP · BOTTOM · CORNERS · CUSTOM |
| appearance.default-rows | 3 | Height (1–6) of a new chest menu. |
| integrations.use-vault | true | Enable Vault economy actions/condition if Vault is installed. |
| integrations.use-placeholderapi | true | Enable PlaceholderAPI expansion (beyond the built-in set) if it's installed. |
| history.max-versions | 10 | Saved versions kept per menu for History/restore. |
| web-editor.bind-address | 0.0.0.0 | Interface the web server binds to. Use 127.0.0.1 to restrict to localhost. |
| web-editor.port | 8123 | Web editor port. |
| web-editor.security.session-hours | 12 | How long a login session stays valid. |
| web-editor.security.login-code-minutes | 5 | How long an access code from /bloom web stays valid (single-use). |
| web-editor.security.max-login-attempts | 10 | Failed attempts from one IP before a temporary lockout. |
| web-editor.security.lockout-minutes | 10 | Lockout duration after too many failed attempts. |
| web-editor.https.enabled | false | Serve the web editor over HTTPS. Requires a keystore. |
| web-editor.https.keystore-path | keystore.p12 | Path to a JKS/PKCS12 keystore (relative paths resolve inside the plugin's data folder). |
| web-editor.https.keystore-password | i[/i] | Keystore password. |
| storage.backend | sqlite | sqlite (one file per player per menu, zero setup) or sql (shared MySQL/MariaDB, see Storage vaults). |
| storage.sql.host | localhost | MySQL host. Only used when storage.backend: sql. |
| storage.sql.port | 3306 | MySQL port. |
| storage.sql.database | bloomgui | MySQL database name. |
| storage.sql.username | root | MySQL username. |
| storage.sql.password | i[/i] | MySQL password. |
IMPORTANT: Changing the web editor's port at runtime requires a full server restart. It's read once on enable, not re-read on /bloom reload or /bloom web stop/ start.Click to expand...
Building from source
Requires Java 21 and Maven. From this module's directory:
Code (Text):
mvn clean package
Code (Text):
mvn test
️ Project layout
Code (Text):
com.bloomgui ├── model # Plain data: MenuDefinition, ItemDefinition, ActionDefinition, ConditionGroup, … ├── config # YAML persistence: MenuStorage, MenuSerializer, BloomSettings, TemplateRegistry, VaultStorage, … ├── action # Action registry + impl/ (one class per action type) ├── condition # Condition registry + impl/ (one class per condition type) ├── integration # Optional Vault / PlaceholderAPI services (no-op if the plugin isn't present) ├── runtime # MenuRegistry, MenuRenderer, PerfMetrics, PerfBarService: turns a MenuDefinition into a live GUI ├── editor # In-game GUI screens (DashboardGui, MenuEditorGui, ItemEditorGui, …) ├── command # /bloom subcommands ├── util # RichText (MiniMessage/legacy parsing), ItemStackCodec (item preset serialization) └── web # Self-hosted HTTP server, REST API, JSON codec; resources/web/ is the SPA frontend
src/test/java # JUnit 5 + MockBukkit, mirroring the main package layout
src/test/java # JUnit 5 + MockBukkit, mirroring the main package layout
⚠️ Known limitations
- The in-game editor doesn't have UI for everything the web editor does: enchantments/hide flags, cycle/dynamic items, conditional lore, item presets, the special item builders, and Merchant trades are web-editor-only. The web editor is the more complete, actively developed surface.
- No shield builder (banner/firework/potion/book only); the underlying API doesn't provide one yet.
- No raw NBT/component editor; item presets carry full item data, but editing it is limited to capturing/replacing a whole item, not tweaking individual fields in the browser.
- The MySQL storage backend has real, tested migration/schema logic but hasn't seen the same real-world mileage as the SQLite default. If you're relying on it for a multi-node setup, test it on your own data before trusting it in production.
- money/placeholder conditions pass open (don't block) if Vault/PlaceholderAPI isn't installed; see the note under Conditions if you're relying on one as a hard gate.
Quick facts
- Edition: Minecraft Java
- File type: .jar
- Minecraft versions listed: 1.20.6, 1.21, 26.1
- How to install: Install the matching mod loader (Forge, Fabric or NeoForge) for your Minecraft version. → Download the .jar. → Put it in the .minecraft/mods folder and launch that loader profile.
- Where to get it: Opens on Spigot — not every file is mirrored on our own servers.
Install steps are the general flow for this file type — How to install Minecraft Java mods & modpacks walks through it step by step.
BloomGUI is a free Minecraft Java mod. Compatible with Minecraft 1.20.6, 1.21, 26.1, 26.2. Downloaded 25 times (via Spigot). Download it and open it directly in the game.