monkbody
The four gardener-monks, carved. Silhouette first, then the pass that makes them made things.
monkbody
The four gardener-monks, carved. Silhouette first, then the pass that makes them made things.
From the tactical camera you should be able to name each of them with the labels off:
| Reads as | Carries | |
|---|---|---|
| Brother Anselm | one long vertical line — stooped, and the billhook doubles his height | a hooked billhook on an ash shaft with a brass ferrule and a leather grip |
| Sister Meridia | a wide low triangle — a broad straw brim that is a disc from directly above | a sling, a seed-apron with pockets sewn on it, a bandolier of vials |
| Brother Cassian | a hunched block with a brass pressure tank standing higher than his own head | a pipe wrench, a hose coiled at his hip, goggles pushed up on a leather cap |
| Sister Vespera | a thin taper under a tall pointed hood | a lit censer swinging out on a chain — the only light a monk carries |
Layered habits with dirt baked into the hems, a gold-thread hem on every cape (the one mark of the order, and the brightest thing on a body at distance), and tools with their own material story: ash, brass, verdigris, steel, leather.
Using it
local MonkBody = require("game.units.monkbody")
local body = MonkBody.build(parentEntity, "vespera", "unit_v1")
body.root.localPosition = Core.cellCenter(4, 2, 0)
body.root.localRotation = MonkBody.quat(0, MonkBody.yawOf("n"), 0)
body.parts.head -- every named part, ready to be driven
| Call | Returns |
|---|---|
MonkBody.ids() | { "anselm", "meridia", "cassian", "vespera" } |
MonkBody.spec(id) | the body spec — { height, hipY, torsoY, scale, idle, parts }, built once and cached |
MonkBody.build(parent, id, name) | { root, parts, spec } — the entity hierarchy, already assembled |
MonkBody.quat(rx, ry, rz) | a { x, y, z, w } quaternion from XYZ Euler radians |
MonkBody.yawOf(facing) | the yaw a facing letter means |
MonkBody.material(name) | the slice's cloth or emissive material, pinned by literal name |
MonkBody.flush() | forget the cached geometry, so the next spec rebuilds it |
The skeleton
Every body is built to the same skeleton, so one animator drives all four:
root ── hips ── skirt the lower habit
└─ torso ── chest the upper habit, cape, belt
├─ head skull + hood — this LAGS the turn
├─ armL shoulder joint; the arm hangs from it
└─ armR ── tool the weapon, on the working arm
Vespera inserts a chain between armR and tool so the censer can swing as a
pendulum without dragging the arm, and hangs an ember off the tool. Cassian
carries a pack; Anselm a kit on the off hip.
Each part is authored in its joint's own local space, with the joint at the
origin, so rotating the entity swings the part the way a shoulder swings an arm.
A part's authored rot is its REST pose — the animator adds to it rather than
replacing it.
Facing
Bodies are authored facing +Z, and yawOf turns them: "n" (up the board,
away from the camera, toward the blight) is yaw 0, "e" is 90°, "s" is 180°,
"w" is 270°. The engine's own capture { viewpoint = "front" } treats −Z as an
entity's front, so a capture labelled front shows a monk's back; ask for
back when you want the face.
The two materials
A whole monk is standard_default (everything, coloured per vertex) plus
emissive_white (Vespera's ember). MonkBody.material(name) resolves both from
literal names — a computed asset.resolve is refused on a component, because it
cannot be statically pinned and would break when the world is imported
elsewhere.
Scoped to this part · feeds back into the world's score.