Item Configuration
Declare items — blocks, tools, weapons, armor, ammo, and more — in your mod's item catalog.
Every item in the game — blocks, tools, weapons, armor, ammo, and more — is declared as an entry in your mod’s item catalog. This is the file that gives an item its name, its stacking behavior, and its type, which determines what it actually does when used.
When several entries share the same field clusters (the identical wielded-item-data block across a weapon tier, say), you can factor the shared shape into a preset and give each entry a preset: key instead of repeating it — see Config Presets.
File Location
Register the file in your mod’s manifest (mods/<YourMod>/<YourMod>.yaml):
item-config: item-config.yaml
Then create the file it points to, relative to your mod’s folder:
mods/<YourMod>/item-config.yaml
The file is a single list of item entries:
items:
- name: my_item
type: item
- name: my_sword
type: weapon
weapon-info:
type: melee
class-name: Short Sword
damage: 10.0
Item names are automatically prefixed with your mod name unless you write one already containing a colon, so my_item becomes YourMod:my_item — this is the full name used anywhere an item is referenced (crafting recipes, loot tables, mob drops, Lua scripts).
Minimal Example
items:
- name: wooden_stick
type: item
type: Item (or type: Empty) declares a plain item with no special behavior — just something that exists and can be held, stacked, and crafted with.
Blocks and interactables don’t need an entry here. Declaring a block in
block-config.yaml(or an interactable ininteractable-config.yaml) automatically registers a matchingtype: block/type: interactableitem. Add an entry here only to give it more than the defaults — adisplay-name,tooltip,material-types, orlight— and your entry replaces the generated one.
Common Fields
Every item entry supports these, regardless of type:
| Field | Default | Description |
|---|---|---|
name | (required) | The item’s identifier — what every recipe, drop table and Lua reference points at. Shown to players only in title-cased form, and only when you omit display-name. |
type | (required) | One of the type keywords below. Determines the *-info block the item needs. |
stackable | true | Set to false to force max-stack-size to 1, regardless of any max-stack-size given — for items like armor that shouldn’t stack at all. |
max-stack-size | 1 for Tool, 1000 for everything else | How many can sit in one inventory slot. Ignored if stackable: false. |
material-types | NONE | Free-form tags (e.g. PLANKS, LOG), case-insensitive — stored and matched in uppercase. Accepts a single value or a list, so one item can be several things at once ([planks, wood] matches a recipe wanting either). Crafting recipes accept “any item carrying this tag” as an ingredient instead of one specific item. |
tags | (none) | General membership tags this item carries — a single value or a list. The item-side counterpart to a block’s tags: a reference field that accepts a #tag (a drop-table entry’s item: "#tag") then matches every item carrying it. Global and case-insensitive. Distinct from material-types / tool-types / ammo-types, which are typed channels; tags is the open, meaning-free registry. |
fuel-value | 0 | How much of a recipe’s fuel: cost this item covers when consumed as fuel. 0 means the item is not fuel. See Fuel. |
fuel-types | (none) | The fuel grade tags this item provides — a single value or a list, case-insensitive (stored uppercase), matched against a recipe’s fuel.type. Only meaningful with fuel-value > 0. |
sells-for | (none) | The coin value a vendor pays for one of this item, when the item is on that vendor’s buy accept-list. Omit it and the item cannot be sold. This is only the sell-back price — a vendor’s buy prices are set per stock entry on the vendor itself, never from this field. |
salvage | (none) | What this item breaks down into at a salvage station — a list of { item, amount } byproducts. Omit it and the item cannot be salvaged. See Salvage. |
interact-range | 10 | How many blocks away this item can be used from. In blocks, as a float — 10.5 is as valid as 10, the same as an interactable’s and a mob’s field of the same name. |
tool-types | (none) | Tool categories this item counts as — a single value or a list. See Tool Types. |
itemstack-slot-types | Any | Which equipment slot(s) this item can go in. A single string or a list — see Slot Types. |
display-name | (derived from the identifier) | Client-only. The name players see, on the tooltip. Omit it and the UI title-cases name with the mod prefix stripped (cherry_log → Cherry Log) — see Display Name. |
tooltip | (none) | Text shown for this item in the UI, below the name. |
itemdrop-draw-priority | 0 | Client-only. Draw order for the dropped item entity. |
light | (none) | Makes dropped copies of this item emit light — see Light. |
wielded-item-data | (none) | Positioning and swing animation for when a player holds this item — see Wielded Item Data. |
scripts | (none) | A map of Lua hooks. Items support server-on-primary-use, called on primary use (left-click) — see Primary Use Function. |
Unknown keys at the top level of an entry (and inside tool-info) are rejected: a misspelled or misplaced field is a load-time error naming the bad key, not a silently-ignored one — so a typo can’t quietly leave your item without its tooltip. Note in particular that power-level and mining-speed belong inside tool-info; writing them at the top level is an error. The nested light and wielded-item-data blocks are validated too — an unrecognized key inside them is a load-time error, not a silently-ignored one (a bad key in wielded-item-data, like a wrong-typed block, makes it fall back to all-defaults). See Unknown Fields.
Salvage
A salvage block lists what an item breaks down into at a salvage station — the byproducts the
player gets back when the item is consumed there:
salvage:
- { item: iron_bar, amount: 2 } # amount defaults to 1
- { item: leather_scrap }
Item names are mod-prefixed like every other reference (iron_bar → YourMod:iron_bar; a
Mod:name stays as written). An amount of 0 is dropped. Omit the block entirely and the item is
not salvageable (the station refuses it).
Any socketed infusions on the specific item are returned intact on top of this list — do not list them here. There is no engine salvage rate: keep the byproducts deliberately below the item’s crafting cost so a salvage→recraft loop can’t be used to multiply materials. Salvage is all-or-nothing — if the whole return set doesn’t fit the player’s inventory, nothing is consumed.
Fuel value & fuel types
An item becomes fuel by giving it a fuel-value above 0 and one or more fuel-types grade tags:
- name: coal
type: item
fuel-value: 8
fuel-types: coal # a single tag, or a list: [coal, solid_fuel]
A recipe’s fuel: block names a grade (type) and a total cost (amount); at craft time the server consumes the minimum whole fuel items carrying that grade whose summed fuel-value covers the cost (highest-value first, excess lost). fuel-value and fuel-types are deliberately separate from material-types — an item’s crafting-ingredient identity and its fuel grade never conflate, so coal can be a normal ingredient elsewhere without every fuel recipe matching it.
Item Types
type selects the item’s behavior. Each (aside from item/empty, block, and interactable) requires a matching *-info block with its own fields.
The value is case-insensitive, and the two-word types accept either separator — projectile-launcher and projectile_launcher are the same value, so the type can be written the same way as the *-info key beside it.
type | *-info block | Behavior |
|---|---|---|
item / empty | none | Plain item — held, stacked, crafted with, nothing else. |
block | none | Places the block of the same name when used. |
interactable | none | Places the interactable of the same name when used. |
tool | tool-info | Mines blocks; power/speed determine what it can break and how fast. |
weapon | weapon-info | Deals damage to entities it hits. |
armor | armor-info | Worn in an equipment slot, reduces incoming damage. |
projectile-launcher | projectile-launcher-info | Fires ammo items (bows, etc.). |
ammo | ammo-info | Consumed by a projectile launcher; defines what gets fired. |
thrown | thrown-info | The held item is its own ammo — each use throws one from the stack (knives, javelins). |
summon | summon-info | Spawns a mob when used. |
summon-mount | summon-mount-info | Spawns a rideable mount when used. |
fishing-rod | none | Casts at water and drives the fishing loop — see Fishing rods. |
recall | recall-info | Channels, then teleports the user to the home world’s spawn (a reusable magic mirror). |
casting | casting-info | A divine focus: casts a projectile or a player-owned AoE zone, paid for with the player’s Channel resource instead of ammo. |
tool-info
tool-info:
power-level: 2 # optional, default 1. Must meet or exceed a block/object's required power to break it.
mining-speed: 1.0 # optional, default 1.0. Multiplies how fast blocks/objects take damage.
weapon-info
weapon-info:
type: melee # required. `melee` is the generic swing-a-hitbox weapon (`short_sword` is an accepted alias for it).
class-name: War Hammer # optional, default "Melee". The weapon class shown on the item's tooltip.
damage: 10.0 # required
hit-cooldown-ms: 250 # optional, default 300. Minimum time between this weapon's hits landing on the same target.
knockback: 20.0 # optional, default 0 (none). Shoves the target away from the wielder on a landed hit.
damage-type: physical # optional, default physical. Mitigation channel: physical, fire, blast, decay, or radiant (see player-config.md#damage-types).
sockets: 2 # optional, default 0 (not infusable). How many infusions a socket station can add; max 2.
melee is one generic weapon that covers every melee class — a dagger, a short sword, a greatsword, a spear and a war hammer are the same swing-a-hitbox behavior with different numbers. What separates them is data: damage, knockback, hit-cooldown-ms and damage-type here, plus the reach (wielded-item-data.hitbox) and swing speed (the primary-use-animation’s time-ms) on the item itself. Give each class its own class-name and it reads as that class everywhere the player sees it.
class-name is the player-facing label on the tooltip’s “Weapon Type” line. It is free text, so name the class whatever your content calls it. When omitted it defaults to Melee — except for a weapon declared with the older type: short_sword spelling, which defaults to Short Sword as it always has.
damage-type picks the mitigation channel every hit runs on, the same set armor resists (see armor-info’s resistances below). Melee is physical unless stated otherwise; an unknown name is a load error rather than a silent fall back.
hit-cooldown-ms sets the per-target invulnerability window this weapon grants on a landed hit — a fast dagger can use a low value, a heavy hammer a high one. Keep it below the weapon’s swing animation time, or alternate swings will silently deal no damage (each swing already hits a given target at most once regardless of this setting).
knockback shoves the target away from the wielder (in the direction the wielder is facing) and lifts it a little on a hit that actually lands — a blocked, invulnerable-deflected, or invincibility-framed hit imparts no force. It is a velocity magnitude in blocks/second that briefly overrides the target’s own movement and decays over a fraction of a second, so it reads as a distinct knock: a light dagger might use a small value, a heavy hammer a large one. A struck mob is knocked clear of whatever it was doing (it stops pathing toward you and gets flung in a short arc), then resumes. 0 (the default) leaves the target where it stands.
reforge — the per-instance re-tuning envelope
A weapon may declare a reforge envelope: how far a single copy of it can be re-tuned by a player, within bounds it can never exceed. Reforge is lateral — a slider trades one stat against another rather than adding raw power — and the envelope is the hard ceiling on that trade. Omit the block entirely and the weapon cannot be reforged.
weapon-info:
type: melee
damage: 6.0
hit-cooldown-ms: 250
knockback: 2.0
reforge:
steps: 4 # required, positive. Slider granularity: a chosen offset runs -steps..=steps.
speed-damage: # optional axis: per-hit damage traded against the per-target hit cooldown.
damage: 2.0 # ± added to `damage` at the damage extreme (offset == +steps).
cooldown-ms: 60.0 # ± added to `hit-cooldown-ms` at that same extreme — SAME sign, so more damage costs a longer cooldown (slower).
knockback: # optional axis: knockback.
knockback: 2.0 # ± added to `knockback` at offset == +steps.
Each axis names two ends of one slider. A stored offset is clamped to -steps..=steps and then scaled: at +steps the full + extreme applies, at -steps the full - extreme, and values between scale linearly. So with the block above, pushing speed-damage all the way to damage gives damage 8.0 / hit-cooldown 310ms (harder but slower), and all the way to speed gives damage 4.0 / hit-cooldown 190ms (weaker but faster) — the envelope is fixed, and the clamp guarantees a reforged weapon never beats its ceiling. The speed-damage cooldown side only moves when the weapon declares a base hit-cooldown-ms; without one, that axis re-tunes damage alone.
Reforge is resolved server-side, per wielded instance — the stored item keeps its base numbers plus the chosen offsets, and the effective stats are recomputed each time the weapon is wielded. (Setting the offsets is an upcoming reforge-station action; the envelope schema is what a weapon author declares here.) The reach ↔ precision axis named in the design is not yet available.
sockets — how many infusions a weapon can hold
sockets is the number of infusion slots a weapon has: 0 (the default) means it cannot be infused, and the ceiling is 2. It only declares the capacity — the infusions themselves are added to an individual copy at a socket station, drawn from the tag-gated infusion pool the weapon’s tags allow (see infusion-config.md). A socketed infusion re-types the weapon’s damage; the socketed count shows on the item’s tooltip. A value above 2 is a load error.
armor-info
armor-info:
armor-type: helmet # required: Helmet, Chestplate, Leggings, or Boots (case-insensitive)
flat-armor: 1.0 # optional, default 0.0. Flat damage subtracted after the percentage step.
armor-rating: 8.0 # optional, default 0.0. General-armor rating (see below).
resistances: # optional. Per-damage-type resistance ratings (see below).
fire: 10.0
blast: 5.0
grants-capabilities: # optional. Capability ids granted while this piece is worn (see below).
- double_jump
set-id: iron_set # optional. Groups this piece with others of the same set (see below).
set-bonuses: # optional. Extra stats unlocked by wearing N pieces of the set.
- pieces: 2 # required per tier: 1–4
armor-rating: 6.0 # optional stat bonuses (same fields as above)
- pieces: 4
resistances:
fire: 15.0
grants-capabilities: # optional. Capabilities granted while this tier is satisfied.
- glide
armor-type is what decides the equipment slot — do not also set itemstack-slot-types on an armor item. Declaring both is a load-time error, because the two could disagree. Previously armor-type was cosmetic (it only fed the tooltip) and itemstack-slot-types did the real work, so every armor item had to write the same value twice: forgetting the second one produced a helmet equippable into every armor slot, and setting them differently produced a piece that equipped into one slot while its tooltip named another. There is now a single source of truth.
How armor mitigates a hit. The worn pieces’ armor-rating values are summed, and the total is turned into a damage-reduction fraction by a diminishing-returns curve — reduction = rating / (rating + 100). So a total rating of 100 gives 50% reduction, 300 gives 75%, and the reduction approaches but never reaches 100%: stacking armor always helps, but no set can make a wearer immune. Because the curve is non-linear, individual armor-rating values do not add up to a percentage — a piece with armor-rating: 8 is not “8% reduction”. After the percentage step, flat-armor is summed and subtracted as a small, roughly constant amount that soaks the trickle from many weak hits. (The 100 constant is a provisional tuning value.)
Per-type resistances (resistances). Optional. A map of damage type (physical / fire / blast; an unknown name is a load-time error) to a resistance rating. Like armor-rating, resistances of the same type are summed across worn pieces and run through the same diminishing-returns curve — they are ratings, not percentages, and can never reach 100%. A resistance applies on top of general armor for a hit of its type: a fire hit is first reduced by general armor-rating, then additionally by summed fire resistance (so full fire gear is much sturdier against fire specifically, without touching physical or blast). A type you don’t list gets no dedicated resistance — general armor + flat still apply. Physical hits normally rely on general armor, but a physical resistance is allowed if you want a piece that specializes against ordinary attacks. Regardless of how much armor and resistance a wearer stacks, every landed hit still deals at least a small minimum amount — mitigation can chip a hit down but never fully negate it.
Set bonuses (set-id + set-bonuses). Optional. Give matching pieces the same set-id, and the wearer gets extra stats for wearing enough of them at once. Each entry under set-bonuses is a tier: pieces is how many of the set must be worn to unlock it (1–4), and the remaining fields (flat-armor, armor-rating, resistances) are the bonus stats it grants — the same stats a piece itself can carry, added on top of the base totals and run through the same curves. Tiers stack cumulatively: a full 4-piece set that defines a 2-piece and a 4-piece tier gets both. Declare the same set-bonuses list on every piece of the set (the engine counts each tier once, no matter how many worn pieces list it) — set-bonuses without a set-id is a load-time error, as is a pieces value outside 1–4. A tier may also carry grants-capabilities (see below).
Capability grants (grants-capabilities). Optional. A list of capability ids — the strings the progression/Metroidvania gating system checks (movement verbs like double_jump, and required-capability barrier blocks — see block-config.md). While the piece is worn, each listed id counts toward the wearer’s capabilities; take the piece off and the grant is withdrawn. The same field on a set-bonus tier grants its capabilities only while that tier’s pieces threshold is met, so a full set can unlock a verb that no single piece does. Gear grants are kept separate from permanent, save-persisted grants (a boss reward, a consumed key): unequipping gear never removes a capability something else granted for good, and a capability held from either source satisfies a gate. Equipping a piece that grants a new capability immediately clears any capability-gated barrier around you, exactly as a scripted grant does.
Most capability ids are free-form — they mean whatever your barriers and scripts decide. Three are recognized by the engine itself as verbs, so granting them from a piece of armor actually changes what the wearer can do:
| Capability | Effect while held |
|---|---|
double_jump | The wearer can jump again in mid-air. |
air_dash | The wearer can dash horizontally while airborne, on the AIR_DASH control. |
dodge | The wearer can roll horizontally while grounded, on the DODGE control, with brief invulnerability. |
All three are tuned in player-config.md — the armor decides who gets the verb, the player config decides how far it goes. A grant takes effect the instant the piece goes on and is withdrawn the instant it comes off. (dodge is in the shipped baseline, so every player already has it; granting it from gear is only meaningful in a mod that removes it from the baseline first.)
projectile-launcher-info
projectile-launcher-info:
ammo-types: # a string or a list; at least one of ammo-types/ammo-names is required
- Arrow
fire-cooldown-ms: 1000 # optional, default 100
launch-velocity: 100.0 # optional, default 50.0
shot-count: 3 # optional, default 1. Projectiles fired per shot (a multishot bow).
spread-degrees: 24.0 # optional, default 0. Total angular fan the volley spreads across.
charge: # optional — makes this a hold-to-charge weapon (a bow)
full-charge-ms: 1200 # optional, default 1000. Hold time to reach full charge.
min-charge-fraction: 0.25 # optional, default 0.0. Release below this looses nothing.
min-velocity-scale: 0.4 # optional, default 0.25. Velocity multiplier at min charge (full = 1.0).
damage-scale: 2.0 # optional, default 1.0. Damage multiplier at full charge (1.0 = off).
interruptible: false # optional, default false. If true, taking a hit mid-draw cancels the charge.
ammo-typesmatches against an ammo item’s ownammo-types(see below) — use this for “anything tagged Arrow.” Both sides use the same plural key and both take a single tag or a list, so acceptance is an intersection: the launcher fires the ammo when they share any one tag. Same shape as a crafting ingredient’smaterial-typesagainst an item’smaterial-types. See Schema Conventions → Tag pairs.ammo-namesmatches specific item names instead, if you want a launcher restricted to exact ammo items. A bare name is namespaced to the launcher’s own mod (ammo-names: arrowin modCreationmatchesCreation:arrow); write the fully-qualifiedmod:nameto accept ammo from another mod.chargeturns the launcher into a draw-and-hold weapon: primary-use begins a draw on press and looses on release, with velocity and damage scaled by how long it was held. Without achargeblock the launcher fires instantly on click (the classic behaviour). The charge time is measured server-side, and the draw is shown on the wielder for other players so an incoming full-draw shot is readable.interruptiblereuses the shared channel-interrupt: a landed hit while drawing cancels the shot (leave itfalsefor a normal bow).shot-countabove1makes a multishot launcher (a hunting bow) that looses that many projectiles in one use, fanned symmetrically acrossspread-degrees(total, centered on the aim line — so24spreads ±12°). Each shot is an ordinary projectile spawned down the existing fire path, so it composes with everything else — including per-projectilepierce. A volley costs one ammo, not one per projectile; multishot is the weapon’s value, not extra cost.spread-degreesis ignored for a single shot, and0spread fires every projectile straight down the aim line. Keep the count modest so it doesn’t trivialize crowds.
ammo-info
ammo-info:
ammo-types: arrow # required. A string or a list; matched against a launcher's ammo-types.
projectile: wooden_arrow # required. The projectile-config.yaml projectile fired when this ammo is used.
damage: 5.0 # optional. Overrides the projectile's own configured damage for this ammo.
gravity-multiplier: 1.0 # optional. Overrides the projectile's own configured gravity-multiplier.
spawn-aoe-on-impact: fire_burst # optional. Overrides the projectile's spawn-aoe-on-impact zone (see projectile-config.md), so one projectile can back several ammo that each burst into a different zone.
Fishing rods
type: fishing-rod marks an item as a rod. It takes no info block, because there is nothing a rod could differ by: one functional rod is a design decision, and rod variation is meant to be cosmetic only. Every timing the activity uses — how long the bite takes, how long the hook window stays open, how many pulls a fighting catch takes — is an engine constant shared by every rod, so a modder’s rod can never be a better rod.
The one field that matters is the ordinary interact-range: how far out a cast can land.
- name: fishing_rod
type: fishing_rod
stackable: false
interact-range: 22
display-name: Fishing Rod
Using a rod does not go through the normal primary-use path. One press means cast, reel in, hook, or pull depending on how far along the cast is, and the server decides which — so a rod defines no primary-use behavior, and Lua on-primary-use hooks on a rod item never fire. What a cast can catch is defined separately, in Fish Configuration; a rod cast into water whose biome declares no fishing-water-type simply produces no bobber.
thrown-info
A thrown item is its own ammo: there is no separate launcher and no ammo slot to manage — each primary-use spends one from the equipped stack and throws the item’s own projectile at the cursor. Use it for knives, javelins, and the like.
thrown-info:
projectile: throwing_knife_projectile # required. The projectile-config.yaml projectile thrown.
damage: 6.0 # optional. Overrides the projectile's own configured damage.
gravity-multiplier: 0.5 # optional. Overrides the projectile's gravity-multiplier (lower = flatter throw).
spawn-aoe-on-impact: fire_burst # optional. Overrides the projectile's spawn-aoe-on-impact zone.
launch-velocity: 120.0 # optional, default 50.0. Throw speed.
fire-cooldown-ms: 300 # optional, default 100. Minimum time between throws.
retrieval: # optional. Omit for a throw that leaves nothing behind.
item: throwing_knife # optional. The item that drops as a pickup; defaults to the thrown item itself.
chance: 0.5 # optional, default 1.0. Probability (0.0–1.0) a spent throw leaves the pickup.
- The projectile stats (
damage,gravity-multiplier,spawn-aoe-on-impact) resolve and override exactly likeammo-info’s — the throw is the projectile, so it carries its own ballistics rather than getting launch speed from a launcher. launch-velocityandfire-cooldown-msbehave like the same keys onprojectile-launcher-info.retrievalmakes a spent throw recoverable: when the projectile despawns — whether it stuck an enemy, hit a wall, or fell short — it rollschanceto dropitem(the thrown weapon itself by default) as a ground pickup. Leave the whole block out for single-use throwables.
summon-info
summon-info:
mob-to-summon: glorbo # required. The mob-config.yaml entry to spawn.
mob-to-summon accepts a bare mob name (shown above) — the common case. It also accepts a block form when you want to override the summoned mob’s presentation:
summon-info:
mob-to-summon:
name: glorbo # required. The mob-config.yaml entry to spawn.
display-name: Glorbo # optional. Overrides the mob's display name.
hitbox: {width: 1.0, height: 1.0} # optional. Overrides the mob's hitbox.
damage-hitbox: {width: 1.0, height: 1.0} # optional. Overrides the mob's damage hitbox.
summon-mount-info
summon-mount-info:
mount-to-summon: my_mount # required. The mount to spawn.
recall-info
recall-info:
channel-ms: 3000 # optional, default 3000. Cast time before the recall fires.
interruptible: true # optional, default true. If true, taking a hit mid-channel cancels the recall.
A recall item is a reusable, magic-mirror-style teleport home. Using it starts a channel of channel-ms; when the channel completes the user is sent to the home world’s spawn — the save’s default-world, its WorldSpawn. The item is not consumed, so one mirror recalls any number of times.
casting-info
A casting item is a divine focus — the Channeler’s weapon. Primary-use casts rather than swings or fires ammo: it spawns a projectile or a player-owned AoE zone at the cursor, paid for by the player’s Channel resource (see player-config.md) instead of a consumed item. If the caster hasn’t enough Channel, nothing happens.
casting-info:
cast: projectile # required: `projectile` or `zone`.
projectile: divine_bolt # required when cast: projectile — a projectile-config.yaml projectile.
zone: holy_fire # required when cast: zone — an aoe-zone-config.yaml zone.
cost: 15.0 # required. Channel spent per cast.
launch-velocity: 70.0 # optional, default 60.0. Projectile speed (ignored for a zone cast).
fire-cooldown-ms: 400 # optional, default 100. Minimum time between casts.
channel-ms: 1200 # optional. If set, the cast is a channel: a cast-time before it fires.
interruptible: true # optional, default true. Only meaningful with channel-ms.
class-name: Divine Focus # optional, default "Divine Focus". The tooltip's weapon-type label.
cast: projectilespawns the named projectile toward the cursor, owned by the caster (it never hits its own caster). The projectile carries its owndamage-typefrom projectile-config.md — use amagic/fire-typed projectile for a divine bolt.projectile:resolves the same way ammo’s does: a bare name is scoped to this mod, and an unknown name is a load error.cast: zonecalls the named AoE zone onto the cursor, owned by the caster (its own damage exempts the caster), reusing the same aoe-zone-config.md system a thrown flask uses — the focus casts one at range without a consumable.channel-msmakes the focus a channelled (cast-time) cast: clicking begins a cast of that many milliseconds, shown as a draw tell on the wielder, and the cast fires when it completes. Withinterruptible: true(the default) a landed hit cancels it — and switching hotbar slot or item mid-cast always cancels it — with nothing cast and no Channel spent (the cost is only paid on a completed cast). This is the “committed cast” for big spells; omitchannel-msfor an instant cast. Uses the same channel machinery as arecallitem.- The cast is server-authoritative and gated on Channel, not ammo, so a focus is never consumed. Channel regenerates over time and is shown on the HUD meter once a focus has been held.
The channel is server-authoritative and reuses the same draw-tell + interrupt machinery as a charged bow: the cast is shown on the wielder for every player, and — with interruptible: true (the default) — a landed hit cancels it, so a recall can’t be used to escape a boss telegraph. Switching hotbar slot or item mid-channel also drops it. Leave interruptible: false only for a recall you explicitly want to be uninterruptible.
Home is a fixed target (the save’s default-world); a recall does not pick a destination or an arrival point. For discovered fast-travel targets, that is a separate (planned) waypoint system.
Display Name
name is an identifier. It’s the key that crafting recipes, loot tables, block drop tables, structure spawns and Lua all use to find the item, so changing it breaks every one of those references. display-name is what players actually read:
items:
- name: wooden_stick # the identifier — referenced everywhere, never changes
type: item
display-name: Sturdy Branch # what the player sees
tooltip: Snapped from a young oak. Good for handles.
Hovering that item shows Sturdy Branch as the tooltip’s title, (YourMod) beneath it, then the tooltip text.
Omit display-name and the UI derives a presentable name from the identifier: the mod prefix is dropped and each _-separated word is title-cased, so Creation:wooden_stick shows as Wooden Stick. Any item whose identifier is already plain snake_case therefore reads correctly with no display-name at all — you only need the field when the derived name is wrong.
Reach for display-name when:
- The name needs punctuation, casing or words the identifier can’t carry —
Miner's Pickaxe,TNT,Ore Vein (Rich). - The identifier is an abbreviation or an internal name —
cu_ingotwould derive asCu Ingot, notCopper Ingot. - The identifier carries a suffix players shouldn’t see —
torch_v2derives asTorch V2.
A few consequences worth knowing:
- Renaming for presentation is now free. Change
display-nameas often as you like; recipes referencingwooden_stickkeep working. Never renamenamefor cosmetic reasons. - It is client-only. The server never reads it, so it doesn’t need to match between client and server, and it isn’t sent over the network.
- It doesn’t have to be unique. Two items may share a display name (a “Torch” from two mods, say) — they stay distinct because their identifiers differ.
- Long names wrap to the tooltip width rather than overflowing, so a descriptive name is fine.
Blocks don’t have their own display-name. A placeable block is registered as an item under the same Mod:name, and a block only ever shows its name while it’s in your inventory as that item — so setting display-name on the item covers the block too.
Tool Types
tool-types is the categories an item counts as, independent of its type. A pickaxe with type: Tool still needs tool-types: pickaxe to actually be recognized as a pickaxe by blocks that require one. Accepts a single value or a list, the same shape a block’s tool-break-types uses.
Tool categories are an open registry — invent your own. Any tag is a valid category, the same way a crafting station’s type or an item’s material-types works. tool-types: hammer on your item plus tool-break-types: hammer on your block is all a new tool category takes; no engine change, no fixed list. Matching is case-insensitive.
The categories the base game ships with, which you’d reuse rather than reinvent:
| Value |
|---|
shovel |
pickaxe |
axe |
shears |
A typo fails closed, not open. Because the registry is open,
tool-break-types: pickaxeeis not a load error — it’s a category, just one no item declares, so the block becomes breakable by nothing. That is the safe direction (it used to resolve to “no tool requirement”, leaving a pickaxe-only block breakable by hand), and the server warns at load naming the object and the unmatched category, so you find it at startup rather than in game.
tool-types: pickaxe # single category
# or
tool-types: [shears, axe] # several
Tags
tags are free-form membership labels an item carries, so another config can refer to a group of items at once instead of listing each by name — the item-side mirror of a block’s tags. Declared plural, as a single value or a list:
- name: iron_ore_chunk
tags: ore # one tag
- name: coal_lump
tags: [ore, fuel] # several
Wherever a field accepts a #tag reference, writing #ore matches every item carrying the ore tag. The one field that accepts it today is a drop-table entry’s item: item: "#ore" drops one random item tagged ore. The # sigil distinguishes a tag from an item name — #ore is the tag, a bare ore is the single item literally named ore. (Quote it in YAML; a bare leading # starts a comment.)
Like a block’s, an item tag is global (never mod-prefixed — two mods tagging their ores ore join one group) and case-insensitive (ore/Ore/ORE normalize to one upper-case tag). It is an open registry, so an unknown #tag is an empty group reported where it’s used, not a load error.
Distinct from the typed tag channels. material-types, tool-types and ammo-types each carry a specific meaning (a crafting ingredient, a tool category, an ammo grade) and pair with a matching “requires” key — see Schema Conventions → Tag pairs. tags is the open, meaning-free registry with no paired requirement; reach for it when you want a group reference that isn’t one of those channels.
Slot Types
itemstack-slot-types restricts which equipment slot(s) an item can be placed in. Accepts a single string or a list, and the values are a closed set — an unrecognized one fails the entry at load rather than being ignored, since a dropped value would silently leave the item unable to enter any restricted slot.
itemstack-slot-types: helmet
# or
itemstack-slot-types: [helmet, chestplate]
| Value |
|---|
any (default) |
helmet |
chestplate |
leggings |
boots |
Not for armor. An
Armor-type item takes its slot fromarmor-info.armor-typeand must not declareitemstack-slot-types— doing so is a load-time error. This field is for non-armor items you want restricted to an equipment slot.
Light
Makes dropped copies of this item — the ones lying on the ground, not the item in an inventory or in a player’s hand — emit light:
light:
magnitude: 8.0
intensity: 1.0
color: { r: 1.0, g: 0.945, b: 0.4627, a: 0.5 }
drop-off-distance: 3.0
is-static: false
This is the shared light: block, identical here to the one on blocks, interactables and particles — see Shared Blocks → light for every field, its default, and how magnitude, intensity and drop-off-distance combine into the falloff curve.
One item-specific note: leave is-static at its false default. A dropped item can be kicked around, and a static light is baked at the position it was created, so a moving item with is-static: true leaves its light behind.
Wielded Item Data
Controls how the item is positioned and animated in a player’s hand:
wielded-item-data:
x-offset: 2.0
y-offset: 1.0
hitbox: # optional — the swing's hit area (default 1x1)
width: 2.0
height: 1.0
primary-use-animation:
- towards-cursor: true # this frame lunges the item toward the cursor
position-offset: 3.0
time-ms: 400
hitbox ({ width, height } in blocks) is the area the item sweeps for melee hit detection — an entity is hit when this box, positioned at the item during its swing, overlaps the target’s damage hitbox. Omitting it defaults to a 1×1 box. Larger or wider weapons (and big boss claws) want a larger hitbox.
Each entry in primary-use-animation is one animation frame, played in sequence, with time-ms as its duration. Two kinds of frame are supported:
towards-cursor: true— moves the item toward wherever the player is aiming, byposition-offsetblocks. A negativeposition-offsetmoves it away from the aim instead, which is how a pull-back pose is written.- Expression-based (used when
towards-cursoris absent orfalse) —x-expression/y-expressionare math expressions (can referenceanimation_time_s, the time in seconds since the whole use began) evaluated each frame to compute the offset, with an optionalalign-rotation-to-user: trueto rotate the item to face the player’s aim.
primary-use-animation:
- x-expression: -1.5 * cos(6.0 * animation_time_s + 1.570796)
y-expression: 2.0 * sin(6.0 * animation_time_s + 1.570796)
align-rotation-to-user: true
time-ms: 500
Each frame starts where the previous one ended, so a sequence reads as one continuous motion.
Two more fields apply to either kind of frame:
| Field | Type | Default | Description |
|---|---|---|---|
damaging | boolean | true | Whether the swing’s hit area can land a hit during this frame |
sound | string | — | Sound played once, when this frame starts |
Wind-ups — giving an attack a tell
A swing with every frame damaging connects the instant it starts, which gives an opponent nothing to react to. Setting damaging: false on the leading frames turns them into a pre-swing wind-up: a pose the attacker visibly strikes while landing nothing, so the blow that follows can be read, dodged, and answered.
primary-use-animation:
- towards-cursor: true
position-offset: -3.0 # pull back, away from the target
time-ms: 450
damaging: false # <- the tell: nothing lands during these 450 ms
sound: YourMod:claw_wind_up
- towards-cursor: true
position-offset: 5.0 # the swing itself, from the pulled-back pose
time-ms: 600
Other players see the wind-up too — the whole animation is replayed on every nearby client — so this is what makes an attack readable in PvP and co-op, not just to whoever is being hit.
Notes:
- Only leading non-damaging frames are a telegraph. A
damaging: falseframe after the swing is a recovery/follow-through, which reads well but isn’t a tell. - Total wind-up length is held to the instance’s telegraph floor (250 ms by default): a shorter declared wind-up is stretched up to it at load time, its frames scaled in proportion. A swing that declares no wind-up at all is left exactly as authored. See combat-config.md.
- A wind-up lengthens the whole use, and a new primary use can’t start while one is in progress — so a wind-up is a real cost in attack rate, not just a visual.
entity-animation — animate the wielder’s body instead of a held item
| Field | Type | Default | Description |
|---|---|---|---|
entity-animation | string | — | Name of a sprite animation on the wielder’s own body to play on primary-use, instead of drawing this item swinging |
Most useful for a mob’s unarmed-attack: an empty-handed mob has no item to swing, so its attack would otherwise be invisible. Set entity-animation to the name of one of the mob’s own animation strips (declared in mob-texture-config.md) and the client plays that on the mob’s body when it attacks — the mob visibly lunges/slashes with its own art.
unarmed-attack:
damage: 5.0
wielded-item-data:
entity-animation: slash # play the mob's own `slash` strip on attack
primary-use-animation:
- towards-cursor: true
position-offset: 3.0
time-ms: 1035 # match the swing length to the `slash` strip's duration
The primary-use-animation above still runs — it is what drives the (now invisible) hit detection, so hitbox, position-offset, damaging wind-ups, and time-ms all keep working exactly as described. Only the item’s visual is suppressed. Two things to keep aligned:
- Match the durations. The body animation runs on its own clock (its strip’s frame timings), while the swing’s length is the sum of the
primary-use-animationtime-ms. If the swing is much shorter than the body strip and the mob re-attacks in range every tick, the body animation restarts before it finishes and you never see the strike — size the swing to the strip (or vice-versa). - Damage timing follows the swing, not the body art. A
damaging: falselead frame still telegraphs off the swing frames; author the body strip so its visible strike lands during the swing’s damaging frames.
The animation-strip name is case-sensitive and must match the sprites[].name in the mob’s texture config exactly (shipped strips are lowercase, e.g. slash, bite).
Primary Use Function
Runs a Lua handler when a player primary-uses (left-clicks with) this item. Declare it under the item’s scripts: map, keyed by server-on-primary-use, with the bare path to a .lua file:
scripts:
server-on-primary-use: /items/sword_use.lua
The path is relative to your mod’s folder, and the file must return its handler function:
-- /items/sword_use.lua
return function(entity, x, y)
entity:animate("SWING", false)
end
Complete Example
items:
- name: wooden_pickaxe
type: tool
tool-types:
- Pickaxe
tool-info:
power-level: 2
interact-range: 10
wielded-item-data:
x-offset: 2.0
y-offset: 1.0
- name: wooden_short_sword
type: weapon
weapon-info:
type: melee
class-name: Short Sword
damage: 0.5
wielded-item-data:
x-offset: 2.0
y-offset: 1.0
primary-use-animation:
- towards-cursor: true
position-offset: 3.0
time-ms: 400
scripts:
server-on-primary-use: /items/sword_use.lua
- name: wooden_helmet
type: armor
stackable: false
armor-info:
armor-type: helmet
flat-armor: 1.0
armor-rating: 8.0
- name: wooden_bow
type: projectile_launcher
projectile-launcher-info:
ammo-types:
- Arrow
fire-cooldown-ms: 1000
launch-velocity: 100.0
- name: wooden_arrow
type: ammo
ammo-info:
ammo-types: arrow
projectile: wooden_arrow
- name: glow_rock
type: block
light:
magnitude: 8.0
color: { r: 1.0, g: 0.945, b: 0.4627, a: 0.5 }
drop-off-distance: 3.0
Last updated