Item definitions
| Field | Default | Contract |
|---|---|---|
id |
required | Unique lowercase identifier: letters, digits, _ and -; 1–64 characters, starts with a letter. Reserved prototype names are rejected. |
name |
ID | Display name, 1–120 characters. |
width, height |
1 | Integers 1–32; rectangles may be rotated 90°. |
maxStack |
1 | Integer 1–1,000,000. Every stack occupies the item's full rectangle. |
weight |
0 | Nonnegative per-unit weight, up to 1,000,000; choose your own unit. |
Catalogs support 1–256 definitions. Extra visual metadata is ignored; keep rarity, icons, meshes and descriptions in your own content data. Every item of the same ID is fungible. Unique durability, rolls or equipment stats are outside this version; use distinct catalog IDs where practical.
Inventory and actions
Construct with {catalog, columns=6, rows=4, maxWeight=1e9}. Grid dimensions are 1–32, and maximum weight is finite from 0–1e9. Getters items, catalog, columns, rows, maxWeight, weight and revision expose state. Arrays are copies, so mutating them does not modify the inventory. An item stack has {id,itemId,quantity,x,y,rotated}. Stack IDs are scoped to one inventory.
| Method | Behavior |
|---|---|
add(itemId, quantity=1) |
Fill compatible stacks, then search row by row for new stacks. Try unrotated, then rotated layouts. All units must fit. |
take(itemId, quantity=1) |
Consume units across stacks in insertion order. All units must exist. |
remove(stackId, quantity=wholeStack) |
Remove units from one stack. |
move(stackId,x,y,rotated=current) |
Set the top-left grid cell and optional orientation. Reject overlap and bounds violations. |
rotate(stackId) |
Rotate in place. Does not search for a different position. |
split(stackId,quantity) |
Move part of a stack into a new automatically placed stack. Leave at least one unit behind. |
merge(sourceId,targetId) |
Move as many compatible units as the target can accept. Return the transferred quantity. |
transfer(stackId,target,quantity=wholeStack) |
Add to the target and remove from the source atomically. Destination catalog definitions govern its dimensions and weight. |
canCraft(recipe,times=1) |
Plan a craft without changing state. |
craft(recipe,times=1) |
Consume every ingredient and place every output, or change nothing. |
count(itemId) |
Count units across all stacks. |
dimensions(stack) |
Return width/height in the stack's current orientation. |
subscribe(callback) |
Notify after commits with a detached snapshot; returns an unsubscribe function. |
Normal game-rule failures return {ok:false,reason}: no-space, weight-limit, blocked, missing-items, not-found, invalid-split, same-stack, different-items, stack-full, same-inventory, id-limit. Successful actions return {ok:true} with a quantity or new stack id when relevant. Invalid argument types, unknown catalog IDs and resource limits throw. Quantities are positive integers ≤1,000,000. Recipes have 1–64 ingredients and outputs, and batch size is 1–1,000; each multiplied quantity must stay within the quantity limit. Stack IDs stop at s999999999999999; an exhausted inventory can still merge into existing stacks, but allocating a new stack fails atomically with id-limit.
Boundaries
This is bounded grid packing, not an optimal packing solver. Failure means the deterministic search could not fit the requested placement; manual rearrangement may create room. No physics, equipment slots, currency ledger, multiplayer authority, undo stack or persistent storage is included. Use server-owned state and your own transaction boundaries for online economies.