Skip to content

Item JSON reference

A bondage item is a single JSON file at data/<namespace>/tiedup_items/<item>.json. The whole schema is plain text — no Java, no special tooling beyond the .glb mesh it points at. This page documents every field the game actually reads.

The smallest valid definition — required fields only:

{
"type": "tiedup:bondage_item",
"display_name": "Ropes",
"model": "tiedup:models/gltf/binds/ropes.glb",
"regions": ["ARMS"]
}
FieldTypeDefaultNotes
typestringRequired. Must be exactly tiedup:bondage_item. Any other value rejects the whole definition.
display_namestringRequired, non-empty. Used as the fallback name when translation_key is absent.
modelRLRequired. Resource location of the .glb mesh. Convention: tiedup:models/gltf/<category>/<item>.glb.
slim_modelRLnoneOptional Alex-arm mesh variant. Invalid RL → ignored (warning in the log).
regionsstring[]Required. One or more body regions this item occupies (uppercased; case-insensitive).
blocked_regionsstring[]= regionsRegions this item prevents others from using. Omit it and it defaults to the occupied regions — not to “nothing”.
translation_keystringnoneLang key for the name. If set, the name is translatable; otherwise display_name is shown literally.
pose_priorityint0On joints two items both animate, the higher priority wins. Author binds usually use ≥ 1 (shipped binds use 30, collars 5).
creatorstringnoneAuthor name, shown in the tooltip.

Textures & tint ✅ Available

Section titled “Textures & tint ”

The mesh’s baked texture renders. A tinted mesh renders texture × tint.

FieldTypeDefaultNotes
supports_colorboolfalseMarks the item as dye-able / tintable.
tint_channelsobject{}Map of GLB material name → hex colour (#RRGGBB, with or without #). Bad hex → that channel skipped (warning in the log).
  1. Bake the texture into the .glb when you export from Blender.
  2. For tintable parts, author the texture in grayscale so the tint multiply reads correctly.
  3. Name the tintable material(s) tintable_* and list them in tint_channels.

Inventory icon ⚠️ Partial

Section titled “Inventory icon ”
FieldTypeDefaultNotes
iconRLtiedup:item/data_driven_itemInventory-sprite model.

Pose type ⚠️ Partial

Section titled “Pose type ”
"pose_type": "STANDARD"
ValueEffect
STANDARDDefault. Normal upright biped render.
DOGLowers the camera and leash for a floor/dog pose — prefer the explicit modern fields camera_offset + leash_anchor. ⚠️ Partial The camera/leash drop applies, but the third-person dog/quadruped pose is not rendered yet — the figure still stands upright to onlookers.

These replace the special-cased pose_type branches with explicit, composable controls.

FieldTypeDefaultNotes
hides_armsboolfalse⚠️ Partial Drives full NPC immobilization, and is the modern way to author sacks/wraps. The third-person arm-hiding is not active yet (the wearer’s arms still show under a full wrap/latex enclosure to onlookers); the immobilization and first-person mitten behaviour apply, the visual arm removal does not.
camera_offset{x,y,z}0,0,0First-person camera offset. Missing axes default to 0.0. Lower y for floor/dog poses.
leash_anchordouble1.3Leash attach height (Y). Lower it for floor poses (the dogbinder uses 0.35).

Movement style ✅ Available

Section titled “Movement style ”
"movement_style": "CRAWL"

A worn item can change how the player physically moves. Server-authoritative and synced to clients. When several styled items are worn, the highest severity wins.

ValueSeveritySpeed ×Jump
WADDLE10.6allowed
SHUFFLE20.4disabled
HOP30.35disabled (auto-hop)
CRAWL40.2disabled (swim-like hitbox)

Values are case-insensitive; an unknown value is ignored (with a warning in the log).

FieldTypeDefaultNotes
movement_modifier{speed_multiplier, jump_disabled}style defaultsOverrides the style’s defaults. Ignored unless movement_style is also set, and only the winning item’s modifier applies.
"movement_style": "WADDLE",
"movement_modifier": { "speed_multiplier": 0.5, "jump_disabled": true }
FieldTypeDefaultNotes
can_attach_padlockbooltrueThe real per-item padlock gate. Defaults true unconditionally (not “true if lockable”). Organic items set it false.
lockablebooltrue⚠️ Partial For worn items this is not consumed — only furniture reads it. Worn-item locking = can_attach_padlock + the lockable component.
escape_difficultyint0⚠️ Partial Fallback resistance, used only when the item has no resistance component. Most shipped items carry components.resistance (which wins), but a few rely on this field — e.g. leather_mittens (20) and test_cloth (50) have no resistance component, so their top-level escape_difficulty is live.

Usable in both regions and blocked_regions (uppercased, case-insensitive). Unknown values are skipped individually (with a warning in the log); if all are invalid the item is rejected.

HEAD EYES EARS MOUTH NECK TORSO ARMS
HANDS FINGERS WAIST LEGS FEET TAIL WINGS

components{} holds the gameplay behaviours (gag, lock, shock, GPS…). Unknown component keys are ignored (with a warning in the log). The full field-by-field reference lives on its own page:

Components reference

Every component key — lockable, resistance, gagging, shock, gps, choking, adjustable, blinding, plus the two often-forgotten ones: ownership and built_in_lock. Includes which fields are inert.

Components reference

Quick orientation on the two most-missed components:

  • ownership — owner registration, removal alerts, owner/nickname tooltips. Used by the 5 shipped collars.
  • built_in_lock — “permanently locked, no padlock” mechanic; blocks unequip and denies padlocks. Used by the 8 organic items (slime/vine/web/tape).

animations{} binds Epic Fight clips to the item — idle/walk/struggle overlays, equip/unequip one-shots, and equip/unequip sounds. Full reference on its own page:

Animations reference

living_motions (FULL_BODY vs OVERLAY + joints), on_equip / on_unequip one-shots, and the properties unlocks (pose_modifier, speed/time modifiers, events).

Animations reference

The cloth block 🖥️ Client / singleplayer only

Section titled “The cloth block ”

Top-level cloth declares one or more verlet cloth strands (cape, dangling tail, pendant) that physically simulate on top of the item. The value is a single object (one strand) or an array of objects (several). It is client-side cosmetic render only — no gameplay effect, no server sync.

FieldTypeDefaultNotes
meshRLRequired. Cloth-mesh asset id (rig soft-body JSON, not a .glb); must carry a cloth_info block. Unregistered/missing → strand skipped (warning in the log, no crash).
parent_jointstringRequired. Biped joint the strand anchors to (case-sensitive, e.g. Torso). Unknown → skipped (warning in the log).
textureRLRequired, full namespace:path. The cloth render texture. A strand with no valid texture is dropped (no skin fallback).
collider_presetstringBIPEDBIPED or BIPED_SLIM only. Unknown → falls back to BIPED (warning in the log).
gravityfloat⚠️ Partial Parsed but ignored — recorded for forward-compat; no per-strand gravity hook exists yet.

These look authorable but do nothing. Don’t ship them expecting an effect.

KeyStatusWhat actually happens
resistance_id (top-level)❌ PlannedNever read. A copy-trap from stale examples. Use components.resistance.id.
color_variants (top-level)❌ PlannedNever read. Also from stale examples.
animation_bones (top-level)❌ PlannedIgnored (warning in the log) — a PlayerAnimator-era dead key. Drop it.
animation_source❌ PlannedRead and stored but has no effect (GLB-embedded clips aren’t played; animation runs via EF-JSON). Treat as legacy.

A complete, copy-pasteable bind that exercises the common fields. Real shipped values (adapted from armbinder.json and dogbinder.json):

{
"type": "tiedup:bondage_item",
"display_name": "Armbinder",
"translation_key": "item.tiedup.armbinder",
"model": "tiedup:models/gltf/binds/armbinder.glb",
"regions": ["ARMS"],
"pose_type": "STANDARD",
"pose_priority": 30,
"can_attach_padlock": true,
"supports_color": false,
"animations": {
"living_motions": {
"IDLE": {
"animation": "tiedup:armbinder_idle",
"mode": "OVERLAY",
"joints": ["Shoulder_R", "Arm_R", "Elbow_R", "Hand_R",
"Shoulder_L", "Arm_L", "Elbow_L", "Hand_L"]
},
"WALK": {
"animation": "tiedup:armbinder_walk",
"mode": "OVERLAY",
"joints": ["Shoulder_R", "Arm_R", "Elbow_R", "Hand_R",
"Shoulder_L", "Arm_L", "Elbow_L", "Hand_L"]
},
"STRUGGLE": {
"animation": "tiedup:armbinder_struggle",
"mode": "OVERLAY",
"joints": ["Shoulder_R", "Arm_R", "Elbow_R", "Hand_R",
"Shoulder_L", "Arm_L", "Elbow_L", "Hand_L"]
}
},
"on_equip": "tiedup:armbinder_equip_oneshot"
},
"components": {
"lockable": {},
"resistance": { "id": "armbinder" }
}
}

And a floor/dog-pose variant using the modern movement & camera fields:

{
"type": "tiedup:bondage_item",
"display_name": "Dogbinder",
"translation_key": "item.tiedup.dogbinder",
"model": "tiedup:models/gltf/binds/dogbinder.glb",
"regions": ["ARMS"],
"pose_type": "DOG",
"camera_offset": { "y": -0.6 },
"leash_anchor": 0.35,
"movement_style": "CRAWL",
"pose_priority": 30,
"can_attach_padlock": true,
"components": {
"lockable": {},
"resistance": { "id": "armbinder" }
}
}