ellipog

Parts and regions

unreleased

Minecraft 26.3Fabric + NeoForge

A rigRigA named set of part groups and the model paths each group covers, loaded from a datapack. The built-in stature:humanoid rig is the fallback.See also Part factor, Hurt region gives anatomy names to model paths. A part factorPart factorA per-axis multiplier on one model part, or on every part a rig group covers. It changes the silhouette, not the entity's box, unless a frame sets hitbox_from_parts.See also Rig, Scale frame scales one model part, or every part a group covers, so a head can be wider without changing the entity's box. A hurt regionHurt regionA part of a frame's body that takes a different damage multiplier. A region names a rig group, uses that group's fractional box and carries a tag for other mods.See also Rig, Scale frame uses the same rig boxes to make one part take more or less damage. Both are datapack data: a pack declares them, and Stature ships only the default humanoid rig.

Rig files#

data/<namespace>/stature/rigs/<name>.json

The file name is the rig id, so data/mypack/stature/rigs/quadruped.json is mypack:quadruped.

{
  "parent": "stature:humanoid",
  "groups": {
    "head": {
      "paths": ["head", "hat"],
      "box": [0.0, 0.72, 0.0, 1.0, 1.0, 1.0]
    },
    "tail": {
      "paths": ["tail"],
      "box": [0.35, 0.2, 0.0, 0.65, 0.5, 0.4]
    }
  }
}
FieldWhat it does
parentOptional rig id. The parent's groups are merged first, then this file's groups override by name
groupsRequired. An object of group name to either a path list or an object with paths and box
pathsModel paths the group covers, as dot-separated names
boxSix fractions [x0, y0, z0, x1, y1, z1] of the entity's box, used by hurt regions. Omitted means the whole box

A path is a dot-separated walk from the model root, such as body.left_arm. The empty string is the root itself, which is how the humanoid rig's all group covers everything. A path segment may not be empty, so arm..left is invalid.

The built-in stature:humanoid rig cannot be replaced. Extend it with parent instead.

The default humanoid rig#

GroupModel pathsBox
headhead, hat0.0, 0.72, 0.0 to 1.0, 1.0, 1.0
torsobody0.2, 0.35, 0.2 to 0.8, 0.72, 0.8
arm.leftleft_arm0.8, 0.35, 0.3 to 1.0, 0.7, 0.7
arm.rightright_arm0.0, 0.35, 0.3 to 0.2, 0.7, 0.7
leg.leftleft_leg0.55, 0.0, 0.3 to 0.8, 0.35, 0.7
leg.rightright_leg0.2, 0.0, 0.3 to 0.45, 0.35, 0.7
allthe model rootthe whole box

Part factors#

A part factor is a set of three multipliers. It is set by command:

/stature part @s arm.right 1 2 1
/stature part @s head 1.15 1.0 1.15 20

or by a frame:

"parts": {
  "head": [1.15, 1.0, 1.15],
  "arm.right": [1.0, 1.5, 1.0]
}

A group resolves through the entity's rig at set time. The resulting model paths are what is stored, saved and synced, so changing the rig later does not reinterpret a factor that is already set. A raw dot path passes the command if its syntax is valid; only the client's model knows whether the path exists, and a missing path is logged once and does nothing.

Factors are multipliers in context: head: [2, 2, 2] doubles the head inside whatever frame or scale the entity already has. The render side applies them where a part's pose is written, after vanilla's own part scale, so baby offsets and pack-defined model scales keep working underneath.

When a frame has hitbox_from_parts: true, the parts also choose the entity's presence box: the largest factor on each axis, with a floor of 1.0. That is a box, not per-part collision. Without the flag, parts change only the picture.

What follows a part#

Layers that traverse the same posed nodes, including armour, elytra and held items, inherit the part's pose. That is why the seam is on the part's pose rather than in any one renderer.

First-person arms are vanilla's separate rig. They follow the arm part factors unless the frame sets first_person_arms: true, which keeps the hands vanilla. Sleeves travel with the arms.

The held item also has its own stature:held_item channelChannelOne named number a scale can drive, such as reach or motion. Unset, it follows the base scale raised to an exponent; an override replaces it.See also Scale frame, off by default, for the case where the item should scale independently of the hand. The name tag's height and the shadow follow the uniform scale through vanilla, not the parts; the stature:shadow channel bends the shadow further.

Part factors are saved with the entity and sent to players tracking it. Easing progress is not saved: a load lands on the target factors.

Hurt regions#

Hurt regions are declared on a frame, not on a rig:

"regions": [
  { "part": "head", "multiplier": 3.0, "tag": "headshot" },
  { "part": "torso", "multiplier": 0.5, "tag": "gut" }
]
FieldWhat it does
partA group name from the frame's rig. A group the rig does not define is skipped at hit time
multiplierA finite, non-negative damage multiplier. 0 means the region takes no damage
tagA non-empty tag that travels with the hit for other mods to read

The region's box is the rig group's fractional box taken over the entity's current box, then breathed out around its own centre by the group's part factor. A doubled head has a doubled head region. The first matching region in file order wins, so a pack can decide which overlap matters rather than relying on an engine rule.

A hit inside a region multiplies the damage before armour and effects are applied. The matching tag is recorded as the entity's last hit for integrations. Regions do not change collision and do not exist for /stature part factors set without a frame.

Where the hit location comes from#

Projectiles use the impact point of the hit. Melee is re-derived on the server: a view ray must land on the same victim within the player's entity interaction range plus one block of budget, and blocks clip the ray, so a wall between the swing and the target degrades to a normal hit rather than a rewarded one. If two projectiles hit the same victim in the same tick, the last hit wins.

A rig for a quadruped#

{
  "parent": "stature:humanoid",
  "groups": {
    "head": { "paths": ["head"], "box": [0.1, 0.65, 0.0, 0.9, 1.0, 0.5] },
    "torso": { "paths": ["body"], "box": [0.1, 0.3, 0.1, 0.9, 0.75, 0.8] },
    "leg.front.left": { "paths": ["front_left_leg"], "box": [0.6, 0.0, 0.6, 0.9, 0.3, 0.9] },
    "leg.front.right": { "paths": ["front_right_leg"], "box": [0.1, 0.0, 0.6, 0.4, 0.3, 0.9] },
    "leg.back.left": { "paths": ["back_left_leg"], "box": [0.6, 0.0, 0.1, 0.9, 0.3, 0.4] },
    "leg.back.right": { "paths": ["back_right_leg"], "box": [0.1, 0.0, 0.1, 0.4, 0.3, 0.4] },
    "tail": { "paths": ["tail"], "box": [0.35, 0.3, 0.0, 0.65, 0.6, 0.2] }
  }
}

The group names are the pack's choice. head and torso replace the inherited groups; the legs and the tail are new. A frame can now set "rig": "mypack:quadruped" and use those names in parts and regions.

Errors in the log#

A rig file that is not valid JSON, has no groups object, names a group without paths, holds a path that is not a path, or gives a box that is not six numbers or whose minimums exceed its maximums is reported and skipped. A rig whose parent is unknown is skipped too. The rest of the pack still loads.

A part path that the client's model does not have is warned about once per model and path. A region whose group is unknown is skipped when a hit lands. Neither failure takes the frame down.

Support the workko-fi.com/ellipog