Skip to content

Rigs

A rig tells Townstead how a species or life stage should render. It connects a body model to textures, animation bones, face placement, held items, worn equipment, hitboxes, camera height, sleep orientation, and optional emote remapping.

Species choose the default rig for a root. Life stages can override that rig for temporary forms such as eggs, cocoons, larvae, or other bodies that do not share the adult shape.

For a first custom body, start small:

  1. Add rig.base to the species.
  2. Create one data/<namespace>/rig/<path>.json file.
  3. Define model, texture, and the core bones.
  4. Test the body in game before adding armour, held items, wearables, poses, or emotes.

Custom rigs are easiest to debug when the base body renders correctly before anything else is layered on top.

The species file selects the rig used by roots in that species.

{
"schema": "townstead:species/v2",
"display_name": "Skeletownie",
"rig": {
"base": "townstead_skeleton:skeletownie",
"scale": 0.96
},
"breasts": false
}
FieldTypeRequiredNotes
baseidnoRig id or model-layer style id. Defaults to the MCA villager-style body when omitted.
scalenumbernoGlobal render scale for the species. Defaults to 1.0.

Use scale for species-wide body size. Use life-stage scale when only one stage should render larger or smaller.

Path: data/<namespace>/rig/<path>.json

Schema: townstead:rig/v1

The file id comes from its path. For example:

data/townstead_spider/rig/webster.json

loads as:

townstead_spider:webster

This kind of rig reuses a model layer that already behaves like a humanoid. It can map the expected animation channels directly and use normal armour layers.

{
"schema": "townstead:rig/v1",
"model": {
"type": "entity_layer",
"layer": "minecraft:skeleton#main"
},
"texture": "townstead_skeleton:textures/entity/skeletownie.png",
"bones": {
"head": "head",
"headwear": "hat",
"body": "body",
"right_arm": "right_arm",
"left_arm": "left_arm",
"right_leg": "right_leg",
"left_leg": "left_leg"
},
"armor": {
"type": "layers",
"inner": "minecraft:skeleton#inner_armor",
"outer": "minecraft:skeleton#outer_armor"
},
"face": {
"bone": "head",
"center": [0, -4, -4],
"size": [8, 8],
"forward": -1
}
}

Non-humanoid rigs usually need more placement data. This example shows a spider-like body with a face anchor, held-item grips, wearable anchors, boots, equipment restrictions, hitbox, camera bone, sleep orientation, crouch pose, and emote mapping.

{
"schema": "townstead:rig/v1",
"model": {
"type": "entity_layer",
"layer": "minecraft:spider#main"
},
"texture": "townstead_spider:textures/entity/spider.png",
"bones": {
"head": "head",
"body": "body1"
},
"face": {
"bone": "head",
"center": [0, 0, -8],
"size": [8, 8],
"forward": -1
},
"hold": {
"mainhand": {
"bone": "right_front_leg",
"offset": [0, -1, -2],
"rotation": [-60, 100, -60],
"first_person": {
"offset": [0, -10, 10],
"rotation": [20, -40, -20]
}
}
},
"equipment": {
"disabled": ["chest", "legs"]
},
"hitbox": {
"width": 0.9,
"height": 0.9
},
"camera": {
"bone": "head"
},
"sleep": {
"yaw": 0,
"pitch": 0,
"roll": 0
},
"hair": false
}
FieldTypeRequiredNotes
schemastringyestownstead:rig/v1.
modelobjectyesModel source for the body.
textureid/path stringnoBase texture for the body.
bonesobjectnoMaps Townstead animation channels to model bone names. Missing channels fall back to vanilla-style names.
armorobjectnoArmour rendering mode and armour model layers.
faceobjectnoPlane used by face, eye, and mouth overlays.
wearablesobjectnoHead, back, and boot placement for worn layers.
holdobjectnoMainhand and offhand held-item grips.
hairbooleannoWhether MCA hair rendering is supported. Defaults to false.
posesobjectnoNamed additive pose transforms.
hitboxobjectnoCollision and interaction size in blocks.
equipmentobjectnoEquipment slots this rig refuses.
cameraobjectnoBone used to derive first-person eye height.
sleepobjectnoWhole-body orientation used while a non-humanoid rig sleeps.
emoteobjectnoEmotecraft-style humanoid emote remapping and policy.

model.type controls where the body model comes from.

model.typeRequired FieldsNotes
entity_layerlayerUses a Minecraft entity model layer. A #layer suffix selects the layer name; default layer is main.
geometryfileUses a geometry file path, such as my_pack:geo/egg.geo.json.

Entity-layer example:

"model": {
"type": "entity_layer",
"layer": "minecraft:skeleton#main"
}

Geometry example:

"model": {
"type": "geometry",
"file": "townstead_spider:geo/egg.geo.json"
}

bones maps Townstead’s animation channels to the actual bone names in the model. The channel names stay stable even when the model uses different internal bone names.

ChannelDefault BoneUsed For
headheadHead rotation, face placement, camera, head-driven emotes.
headwearhatHat or headwear-style layers.
bodybodyBody movement and body-worn layers.
right_armright_armRight arm animation and right-side humanoid actions.
left_armleft_armLeft arm animation and left-side humanoid actions.
right_legright_legRight leg animation.
left_legleft_legLeft leg animation.

Non-humanoid rigs can map only the channels they need:

"bones": {
"head": "head",
"body": "body1"
}

If a channel is missing, Townstead falls back to its vanilla-style bone name. That is useful for humanoids, but non-humanoid rigs should map important channels explicitly.

Several rig blocks use the same transform shape:

FieldTypeNotes
offsetnumber array[x, y, z] in model pixels. Defaults to [0, 0, 0].
rotationnumber array[x, y, z] in degrees. Defaults to [0, 0, 0].
scalenumberUsed by boots and similar placements when supported. Defaults to 1.

Most placement work is tuned by eye. Add one anchor at a time, reload, inspect, then adjust.

armor controls whether normal armour renders on this body.

FieldTypeRequiredNotes
typestringnonone, layers, or custom. Defaults to none.
innermodel layer idfor layersInner armour layer, usually used for leggings.
outermodel layer idfor layersOuter armour layer, usually used for helmet, chestplate, and boots.
"armor": {
"type": "layers",
"inner": "minecraft:skeleton#inner_armor",
"outer": "minecraft:skeleton#outer_armor"
}

Use none for bodies that should not render standard armour. Use equipment.disabled as well when the body should refuse the equipment slot entirely.

face places a flat overlay plane on a bone. Appearance genes and generated character UI can use this plane for eyes, mouths, and face assets.

FieldTypeDefaultNotes
bonestringheadBone the face plane follows.
centernumber array[0, -4, -4]Centre of the face plane in the bone’s local model pixels.
sizenumber array[8, 8]Width and height of the face plane.
forwardnumber-1Direction the face points along the bone’s local Z axis. Use -1 for the usual front-facing -Z side, 1 for +Z.

Humanoid-style head:

"face": {
"bone": "head",
"center": [0, -4, -4],
"size": [8, 8],
"forward": -1
}

Spider-style head:

"face": {
"bone": "head",
"center": [0, 0, -8],
"size": [8, 8],
"forward": -1
}

wearables moves worn layers onto the rig’s actual body. This matters most for non-humanoid rigs because vanilla head and back layers otherwise assume a standing humanoid.

FieldTypeNotes
headobjectBase transform for head-worn layers and per-item head deltas.
backobjectBase transform for back-worn layers and per-item back deltas.
bootsarrayOne boot placement per leg or foot bone.

Head and back anchors use a base transform plus optional items entries:

"wearables": {
"head": {
"offset": [0, 2, -4],
"rotation": [0, 0, 0],
"items": {
"townstead:scarf": {
"offset": [0, 6, 10],
"rotation": [0, 0, 0]
}
}
},
"back": {
"offset": [0, 0, 0],
"rotation": [90, 0, 0],
"items": {
"backpack": { "offset": [0, -4, 0] },
"cape": {},
"elytra": {}
}
}
}

items keys can be item ids, such as townstead:scarf, or layer keys used by Townstead for broad worn layers, such as backpack, cape, and elytra.

Boot placements are separate because a non-humanoid body may have more than two feet:

"boots": [
{
"bone": "right_hind_leg",
"boot": "right",
"scale": 1.0,
"offset": [-1, -4, -1],
"rotation": [0, 0, 95]
},
{
"bone": "left_hind_leg",
"boot": "left",
"scale": 1.0,
"offset": [1, -4, -1],
"rotation": [0, 0, -95]
}
]
Boot FieldTypeRequiredNotes
bonestringyesLeg or foot bone to attach to.
bootstringnoleft or right. Defaults to right.
scalenumbernoBoot render scale. Defaults to 1.
offsetnumber arraynoBoot placement in local model pixels.
rotationnumber arraynoBoot rotation in degrees.

hold defines where mainhand and offhand items sit.

"hold": {
"mainhand": {
"bone": "right_front_leg",
"offset": [0, -1, -2],
"rotation": [-60, 100, -60],
"first_person": {
"offset": [0, -10, 10],
"rotation": [20, -40, -20]
}
},
"offhand": {
"bone": "left_front_leg",
"offset": [-2, -2, -3],
"rotation": [-60, 100, -60],
"first_person": {
"offset": [0, -10, 10],
"rotation": [20, -40, -20]
}
}
}
FieldTypeRequiredNotes
bonestringnoBone that grips the item. Empty means no useful grip.
offsetnumber arraynoThird-person item offset.
rotationnumber arraynoThird-person item rotation.
first_personobjectnoSeparate offset and rotation used by first-person rendering.

If hold is omitted, the rig does not define custom hand grips.

hair controls whether MCA hair rendering is supported.

"hair": false

Custom bodies often set this to false because their head shape or texture layout does not match MCA hair. Set it to true only when the rig is compatible with MCA hair placement.

equipment.disabled lists vanilla equipment slots this body refuses.

"equipment": {
"disabled": ["head", "chest", "legs", "feet"]
}

Supported slot names are vanilla equipment slot names such as:

Slot
head
chest
legs
feet
mainhand
offhand

Disabled slots are not just hidden visually. Townstead’s equipment backstop can reject items placed into those slots so the body does not keep gear it cannot use.

hitbox sets the rig’s collision and interaction size in blocks.

"hitbox": {
"width": 1.0,
"height": 1.0
}
FieldTypeRequiredNotes
widthnumbernoSquare footprint width in blocks. Defaults to 0.6 if the block exists but the field is omitted.
heightnumbernoHeight in blocks. Defaults to 2.0 if the block exists but the field is omitted.

Omit hitbox to keep the normal MCA-style size. Use it for bodies that would feel wrong with a tall humanoid collision column, such as an egg or low spider body.

camera.bone tells Townstead which bone should drive first-person eye height.

"camera": {
"bone": "head"
}

This is especially useful for short, low, or non-humanoid bodies. If omitted, Townstead keeps the usual height-proportional camera behaviour.

sleep controls the whole-body orientation a non-humanoid rig uses while sleeping.

"sleep": {
"yaw": 0,
"pitch": 0,
"roll": 0
}

For generic non-humanoid rigs, Townstead replaces Minecraft’s normal humanoid lay-down rotation with an upright bed-aligned rest. The sleep block then adds extra whole-body rotation in degrees.

FieldTypeDefaultNotes
yawnumber0Added to the bed-aligned facing direction.
pitchnumber0Leans the whole rig forward or backward around the X axis.
rollnumber0Leans the whole rig side to side around the Z axis.

Use sleep when the whole body needs to face or lean differently on the bed. Use poses.sleep for per-bone settling, such as lowering the body, folding legs, or tucking appendages.

poses applies additive bone transforms for named states.

"poses": {
"crouch": [
{
"bone": "body1",
"offset": [0, 1.5, 0]
},
{
"bone": "right_front_leg",
"offset": [0, 1.5, 0],
"rotation": [0, 0, 25]
},
{
"bone": "left_front_leg",
"offset": [0, 1.5, 0],
"rotation": [0, 0, -25]
}
]
}
Pose FieldTypeRequiredNotes
bonestringyesBone to modify.
offsetnumber arraynoAdditive offset in model pixels.
rotationnumber arraynoAdditive rotation in degrees.

Currently documented examples use crouch. More pose states can be documented as they become stable.

emote describes how humanoid-authored Emotecraft-style motion maps onto this rig. Humanoid rigs usually do not need an emote block. Non-humanoid rigs can use it to decide which humanoid channels they can express and which emotes should be refused.

"emote": {
"body_motion": {
"scale": 0.5,
"floor": -0.25
},
"channels": {
"head": {
"bone": "head"
},
"right_arm": {
"bone": "right_front_leg",
"mode": "additive",
"axis": ["x", "y", "z"],
"gain": [0.0, 0.3, 0.55],
"clamp": {
"z": [-100, 100]
},
"also": [
{
"bone": "right_middle_front_leg",
"gain": [0.0, 0.15, 0.3]
}
]
},
"left_arm": {
"mirror": true
}
},
"policy": {
"min_coverage": 0.5,
"deny": ["kazotsky"]
}
}

body_motion controls whole-body lift, drop, and rotation from the source emote.

FormMeaning
falseSuppress whole-body motion.
trueUse full humanoid body motion.
objectUse scale and optional floor.

Object fields:

FieldTypeNotes
scalenumberMultiplies whole-body motion. 0 suppresses it, 1 keeps it full.
floornumberLowest allowed downward movement in blocks. Useful for low bodies that should not sink under the floor.

Each channels entry maps a humanoid emote channel to one rig bone.

FieldTypeRequiredNotes
bonestringnoTarget rig bone. Defaults to the channel name.
modestringnoabsolute or additive. Defaults to absolute.
axisstring arraynoAxis remap such as ["z", "x", "-y"]. Defaults to ["x", "y", "z"].
eulernumber arraynoExtra rotation in degrees after remapping.
gainnumber arraynoPer-axis multiplier. Defaults to [1, 1, 1].
translationbooleannoWhether translation is used for this channel. Defaults to false.
clampobjectnoPer-axis degree limits.
alsoarraynoAdditional bones driven by the same channel with their own gain.
bendbooleannoApplies segment bend for limb-like bones. Defaults to false.
bend_gainnumbernoBend multiplier. Defaults to 1.
mirrorbooleannoCopies the opposite side channel and swaps left/right bone names.

Use additive when a humanoid limb is being interpreted by a different kind of bone, such as a spider leg. Use absolute when the target bone behaves like the source channel.

axis entries can be x, y, z, or a negative form such as -x.

Clamp example:

"clamp": {
"z": [-90, 90]
}

Fan-out example:

"also": [
{
"bone": "right_middle_front_leg",
"gain": [0.0, 0.15, 0.3]
}
]

policy controls which emotes the rig is willing to play.

FieldTypeNotes
min_coveragenumberMinimum share of emote motion that must land on expressible channels. Defaults to 0.
fallbackstringEmote id or name to use when a refused emote needs a substitute.
allowstring arrayEmote ids or names that are allowed.
denystring arrayEmote ids or names that are refused.

allow and deny match an emote path or display name case-insensitively.

A life stage can set rig to render with a different body from the species default.

{
"id": "egg",
"label": "Egg",
"presents_as": "baby",
"days": 3,
"rig": "townstead_spider:egg",
"mobile": false,
"needs": false,
"talkable": false
}

The stage rig only changes how that stage renders and behaves. The root still belongs to the same species, ancestry, and lineage.

An egg-style rig can be very small:

{
"schema": "townstead:rig/v1",
"model": {
"type": "geometry",
"file": "townstead_spider:geo/egg.geo.json"
},
"texture": "townstead_spider:textures/entity/egg.png",
"bones": {
"head": "egg",
"body": "egg"
},
"hitbox": {
"width": 1.0,
"height": 1.0
},
"equipment": {
"disabled": ["head", "chest", "legs", "feet"]
},
"hair": false
}