Documentation is a work in progress — some pages may be incomplete.
Unify

Menu System

Build paginated, bordered, interactive GUIs with buttons

Unify's menu framework supports multiple menu types, animated buttons, interactive slots, and pagination — all with minimal boilerplate.

The base class for all menus. You define buttons and a title.

class ExampleMenu : Menu("&b&lExample Menu") {

    override fun getButtons(player: Player): MutableMap<Int, Button> {
        val buttons = mutableMapOf<Int, Button>()

        buttons[13] = object : Button() {
            override fun getName(player: Player) =
                CC.translate("&a&lClick Me!")

            override fun getMaterial(player: Player) =
                Material.DIAMOND

            override fun clicked(player: Player, slot: Int, clickType: ClickType, action: InventoryAction) {
                player.sendMessage("§aClicked!")
                player.closeInventory()
            }
        }

        return buttons
    }
}

Open it:

ExampleMenu().openMenu(player)

Menu with a glass-pane border around the edges. You define buttons in the inner content area.

class SettingsMenu : BorderedMenu("&8Settings") {

    override fun getContentButtons(player: Player): MutableMap<Int, Button> {
        val buttons = mutableMapOf<Int, Button>()

        buttons[12] = object : Button() {
            override fun getName(player: Player) = CC.translate("&aToggle")
            override fun getMaterial(player: Player) = Material.LEVER
            override fun clicked(player: Player, slot: Int, clickType: ClickType, action: InventoryAction) {
                player.sendMessage("§aToggled!")
            }
        }

        return buttons
    }
}

The border is filled automatically with GlassButton.

Spread items across multiple pages with automatic navigation arrows.

class ShopMenu : PaginatedMenu() {

    private val items = listOf(Material.DIAMOND, Material.EMERALD, Material.IRON_INGOT)

    override fun getPrePaginatedTitle(player: Player): String =
        CC.translate("&6&lShop")

    override fun getAllPagesButtons(player: Player): MutableMap<Int, Button> {
        val buttons = mutableMapOf<Int, Button>()

        for ((index, mat) in items.withIndex()) {
            buttons[index] = object : Button() {
                override fun getName(player: Player) = CC.translate("&e${mat.name}")
                override fun getMaterial(player: Player) = mat
                override fun clicked(player: Player, slot: Int, clickType: ClickType, action: InventoryAction) {
                    player.sendMessage("§eSelected ${mat.name}")
                }
            }
        }

        return buttons
    }
}

Change navigation button style:

pageButtonType = PageButtonType.HEAD    // Player heads
pageButtonType = PageButtonType.ARROW   // Arrows
pageButtonType = PageButtonType.CARPET  // Carpet blocks

Let players place and take items from specific slots.

class StorageMenu : InteractiveMenu("&8Storage") {

    override fun getInteractiveSlots(): Set<Int> =
        setOf(10, 11, 12, 13, 14, 15, 16)

    override fun onSlotChange(
        player: Player,
        slot: Int,
        oldItem: ItemStack?,
        newItem: ItemStack?
    ) {
        storage.save(player.uniqueId, slot, newItem)
    }

    override fun getButtons(player: Player): MutableMap<Int, Button> {
        val buttons = mutableMapOf<Int, Button>()
        buttons[0] = BackButton(parentMenu)
        buttons[8] = CloseButton()
        return buttons
    }
}
Slot TypeBehavior
getInteractiveSlots()Players can place AND take
getInputOnlySlots()Players can only place (deposit)
getOutputOnlySlots()Players can only take (withdraw)

Built-in yes/no confirmation dialog.

ConfirmMenu(
    title = "&cConfirm Delete",
    confirmText = "&aYes, delete",
    cancelText = "&cCancel",
    onConfirm = { player ->
        deletePlayerData(player)
        player.sendMessage("§aData deleted.")
    },
    onCancel = { player ->
        player.sendMessage("§cCancelled.")
    }
).openMenu(player)

Built-in Buttons

ButtonPurpose
BackButton(menu)Opens a previous menu
GlassButton()Decorative border filler
CloseButton()Closes the inventory
AnimatedButtonButton with frame animation
InteractiveSlotButtonSlot in InteractiveMenu
class MyMenu : Menu("Title") {

    init {
        autoUpdate = true          // Refresh buttons automatically
        autoUpdateInterval = 500L  // Milliseconds between updates
        updateAfterClick = true    // Refresh after any click
        fillBackground = true      // Fill empty slots with glass
        placeholder = true         // Use placeholder items
        nonCancelling = false      // Cancel click events (default: true)
        manualClose = true         // Allow manual closing
    }
}
PhaseMethod
Openmenu.openMenu(player)
Closemenu.onClose(player)
Updatemenu.updateButtons()
Destroymenu.closed = true

Next Steps

  • Combine menus with Scheduling for animated updates
  • Use Items for complex button item stacks
  • Hook menus to Commands for /menu commands

On this page