Item JSON reference
Every field, every default, every caveat. Item JSON
This is the fil-rouge tour: build one simple restraint — a pair of wrist cuffs — from an empty Blender file all the way to wearing it in-game. It’s deliberately the minimum path. Each step links to its deep-dive page when you want the full reference.
By the end you’ll have these five files — the item definition (under data/) plus its visuals
(under assets/), all in your one add-on pack:
data/mymod/tiedup_items/wrist_cuffs.json ← the item definitionassets/mymod/models/gltf/binds/wrist_cuffs.glb ← the mesh, texture baked insideassets/mymod/models/item/wrist_cuffs.json ← the inventory icon modelassets/mymod/textures/item/wrist_cuffs.png ← the inventory icon spriteassets/mymod/lang/en_us.json ← the display nameSee Packaging for the full folder layout.
.blend
(EpicFight Animation Rig.blend, bundled at docs/tools/ — a worked example with the cuffs
already modeled lives in docs/object/artist object/). Don’t rebuild the skeleton by hand —
one mistyped bone name and that joint is silently ignored at render time, with no error.wrist_cuffs.blend.Add a simple cuff mesh around each wrist. Keep it tight and low-poly:
.glb).Skin each cuff to the hand it sits on:
| Part | Skin to |
|---|---|
| Left cuff | Hand_L |
| Right cuff | Hand_R |
| A chain between them | blend Hand_R ↔ Hand_L along its length |
Rigid cuffs want a single bone per vertex at weight 1.0 — no blending. The renderer matches
bones by name against the full biped, so a GLB that lists only Hand_R/Hand_L is perfectly
fine — partial bone lists are optimal, not a limitation.
.glbThis is the step everyone gets wrong. Meshes use Blender’s built-in glTF exporter — not the bundled Epic Fight JSON addon (that addon only makes animations).
File → Export → glTF 2.0 (.glb/.gltf).assets/mymod/models/gltf/binds/wrist_cuffs.glb.The mesh lives under models/gltf/<category>/. binds is just the category folder — pick any name
you like.
A textured .glb now renders its baked texture in-game ✅ Available. If you
want player-recolorable zones later, author those zones in grayscale and name their materials
with the tintable_ prefix (tintable_0, tintable_1, …) — see
Tint & colors.
This is the heart of it, and it’s plain JSON — no Java, no tooling. Create
data/mymod/tiedup_items/wrist_cuffs.json:
{ "type": "tiedup:bondage_item", "display_name": "Wrist Cuffs", "translation_key": "item.mymod.wrist_cuffs", "model": "mymod:models/gltf/binds/wrist_cuffs.glb", "icon": "mymod:item/wrist_cuffs", "regions": [ "ARMS" ], "pose_priority": 30, "escape_difficulty": 100, "components": { "lockable": {}, "resistance": { "id": "chain" } }}What each field does, briefly (full schema on Item JSON):
type — must be tiedup:bondage_item; any other value skips the whole definition.display_name — required. Shown verbatim as the item name only when translation_key is
omitted. If you set a translation_key, that key is what renders — and if its lang entry is
missing you’ll see the raw key (item.mymod.wrist_cuffs), not this string. So always ship the
lang entry (Step 7) when you use a translation_key.model — the GLB resource location. The path is conventional; it only needs to be a valid id.icon — the inventory sprite model (Step 6). Treat icon as required — omit it and the item
shows the missing-texture sprite, because the default falls back to a texture that isn’t shipped.regions — the body region(s) the item occupies. ARMS for wrist cuffs. See
Bones & regions.pose_priority — higher wins when two items animate the same joint; 1+ is recommended.escape_difficulty — a difficulty value used when no resistance component is present:
it’s the fallback struggle resistance and it also adds to the furniture-escape difficulty.
Because the example below does ship a resistance component, that component (resistance.id)
wins for the struggle resistance and this field is only the fallback. Keep it set as a sane
default anyway.components — gameplay behaviors. lockable: {} lets a padlock attach; resistance.id
picks a built-in difficulty preset. The registered keys are rope, chain, armbinder, wrap,
straitjacket, latex_sack, ribbon, vine, web, slime, tape, gag, blindfold,
collar. An unrecognized id silently falls back to 100. Full list on
Components.The icon field points at a normal Minecraft item model. Create
assets/mymod/models/item/wrist_cuffs.json:
{ "parent": "minecraft:item/generated", "textures": { "layer0": "mymod:item/wrist_cuffs" }}Then drop the 2D sprite at assets/mymod/textures/item/wrist_cuffs.png (16×16 is standard). This
icon is what shows in the hotbar and inventory — it’s separate from the 3D .glb worn on the body.
Give the translation_key a display string. Create or extend assets/mymod/lang/en_us.json:
{ "item.mymod.wrist_cuffs": "Wrist Cuffs"}config/tiedup/packs/<addon-name>/ — the
data/ half (item JSON) and the assets/ half (GLB, icon model, icon texture, lang) live in the
same folder (see Packaging)./reload to pick up the item JSON, then press F3+T to reload client resources (the
GLB mesh, icon texture and lang only refresh on a resource reload, not on /reload). A freshly
dropped pack is also picked up automatically the next time the world loads.ARMS slot and confirm the cuffs render on the body with the baked texture.Item JSON reference
Every field, every default, every caveat. Item JSON
Components
Locks, resistance, gagging, GPS, shock, ownership, built-in locks. Components
Animations
EF-JSON clips, the constructor block, FULL_BODY vs OVERLAY, per-joint pose nudges.
Animations
Tint & colors
Player-recolorable zones with tintable_* materials. Tint & colors