The game already tracks "things a player is carrying" in three unrelated places, each with its own shape, its own UI, and its own access code. Blocks, ammo, and now seeds all mean the same thing — a count of an item you hold — yet nothing connects them. This asks what a single inventory plugin could be, so the next stackable thing (rations, tools, keys, a cooked meal) is a line of data, not a fourth system.
Each was added when it was needed, and each is fine alone — but they don't share a model, so "how many do I have" and "show it to me" are re-solved every time.
Same idea, three shapes: a keyed map with a selection, a keyed map, and a bare number. A new stackable — rations, a hoe, a door key — has nowhere to go but a fourth one.
An inventory infrastructure plugin owns one data model — item → count, per player — and blocks, ammo, seeds become entries in it. The existing wheel, weapon bar, and HUD counter keep their looks but read from the one store. Least disruptive; the single source of truth that every other direction sits on.
local inv = engine.require("inventory") -- a stack is just an item + a count on a player inv.add(pid, "dirt", 8) -- pickup gave blocks inv.add(pid, "seeds", 3) if inv.count(pid, "seeds") > 0 then -- plant control inv.take(pid, "seeds", 1) plant(pid) end -- items declare how they stack once, as data inv.define("seeds", { stack = 99, icon = "seed", category = "crop" })
One model, one add/take/count. Every current UI keeps working; a new stackable is a define + add. Fixes /give (route through it) and the campfire stock (12.4) for free.
No new player-facing UI by itself — it's plumbing. The "see everything in one place" want (below) still needs a face.
Medium: migrate blocks/ammo/seeds onto it without changing how they feel. The prerequisite for B–D.
A single panel (a key opens it) shows everything you hold — blocks, seeds, ammo, food — as icon slots with counts, grouped by category. The survival/RPG bag: one place, scannable, room to grow. Built as a new UI-framework template fed by the inventory store.
-- the bag is a template over the inventory store plugin.bag({ open = "KeyB", title = "Backpack", categories = { "blocks", "crop", "food", "ammo" }, }) -- clicking a slot fires its item's "use", if it has one inv.define("ration", { icon = "food", category = "food", use = function(pid) eat(pid, 45) end })
The obvious "what am I carrying" answer, and it scales — dozens of item types with no new UI each. Categories keep it legible.
A modal grid is slower than a wheel for a twitch shooter; opening a bag mid-fight is a pause you didn't ask for. Best as the deep view, not the quick one.
Medium–high: a new grid template + slot interactions, on top of A.
A row of quick slots along the bottom — the few things you actually use in the moment (a weapon, seeds, a ration, a campfire kit). Number keys or the scroll wheel pick the active one; the full bag (B) sits behind it. Keeps hands on the fight.
plugin.hotbar({ slots = 6, keys = "1..6" }) -- an item can ask to sit on the hotbar by default inv.define("campfire", { icon = "fire", hotbar = true, use = function(pid) place_campfire(pid) end }) -- "use active slot" is a control the player rebinds plugin.control("use", { default = "KeyF" }, function(pid) inv.use_active(pid) end)
Fast and always-visible; the fight never stops to open anything. Folds the weapon bar, seed counter, and campfire kit into one familiar strip.
Only a handful of slots — needs the bag (B) behind it for everything else, and a rule for what auto-lands on the bar.
Medium: a hotbar strip + slot assignment + "use active", on top of A. Naturally pairs with B.
The game already picks blocks and cooking actions with a radial. Lean all the way in: an inventory is a set of category wheels — a blocks wheel, a consumables wheel — each on a key, each a UI-framework menu fed by the store. No new widget vocabulary; it just is the framework we built.
-- a wheel is a template menu whose options ARE a category plugin.menu("consumables", { template = "radial", open = "KeyQ", from = { inventory = "food" }, -- auto-filled from the store }, function(pid, item) inv.use(pid, item) end)
Zero new UI concepts — reuses framework D exactly, so it's consistent with the block wheel and cooking menu, and fast to open.
A wheel gets crowded past ~8 items, and it's a picker, not an overview — you can't see everything at once the way a bag shows it.
Low: mostly "let a menu's options come from an inventory category", on top of A + the existing D.
A is not optional — it's the thing the other three stand on, and it's what actually retires the three-implementations problem. The face is then a small choice you can make late, and change.
inventory plugin: define / add / take / count, item categories + icons. Migrate blocks, ammo, and seeds onto it so nothing feels different. This alone fixes /give <anything> and lets the campfire kit become a stocked item you place (Set 12.4).The through-line: an inventory plugin is a data model plus UI-framework declarations — HUD counts (A), template menus/wheels (D), and later a grid template (B). It doesn't invent a new system so much as it collects the three we already have and hands the next stackable a home.