# gouraart
Tawpy as a thing on screen: the meshes, the plumage maps, the materials, the
entity tree, and the pose clock that moves it. `game.hero.gouramesh` says what
shape every part is; this module uploads those shapes, paints the slate mantle,
the maroon breast shield, the white-tipped lace crest and the pale wing bar
against their UVs, hangs the parts from `gouramesh.ANCHOR`, and poses the
result.
Everything it spawns is temporary and unsynced. A rig is a picture of a body
entity, rebuilt wherever that body exists, never saved into a scene.
## Exports
- `M.ensure()` — builds every mesh and the ten runtime materials. Idempotent;
the first call costs a few tens of milliseconds and the rest are free.
- `M.make(body, opts?) -> rig` — dresses one body entity and hands back the rig.
`opts.scale` is her height to the crest tips in metres, `opts.seed` fixes the
phase of her breathing. Called again for a body that already carries a rig, it
returns the rig it already has.
- `M.setPose(rig, name)` — ask for one of `idle`, `walk`, `gather`, `flurry`,
`boom`, `startled`, `caught`, `roosted` (`M.POSE_NAMES`). Unknown names hold
whatever she had.
- `M.punch(rig, amount)` — a knock that decays over a beat: the pulse on a boom,
the pop of a launch.
- `M.tick(dt)` — poses every live rig. Safe to call more than once a frame; the
second call in the same frame does nothing.
- `M.owns(rig)` — whether THIS load of the module still holds the rig. A hot
reload empties the rig list, so a rig made under the previous load is an
orphan nothing poses any more; a component asks this before trusting the
handle it holds.
- `M.dispose(rig)`, `M.clear()`, `M.count()`, `M.report()`, `M.meshes()`.
## The poses
Each names a target set — lean, crouch, puff, stretch, roll, neck and head
pitch, head thrust, crest flare, wing spread and pitch, tail pitch and fan, leg
pitch, tremble — which the tick approaches exponentially, so a pose change reads
as a move rather than a cut. On top of the target sit the beats:
- **walk** — the cadence follows her ground speed, and the head-bob is the real
one: the head holds still in the world while the body carries under it, then
darts forward to catch up.
- **gather** — a crouch with a tremble that grows with how long she has held it.
- **flurry** — wings hammering at speed, the whole bird rolling on two beats at
once, legs trailing. She flies badly and it shows.
- **boom** — the chest pulses on the beat of the call, crest at full flare, head
drawn back and down.
- **startled** — frozen tall, crest flattened, a fine shake that decays.
- **caught** — rolled onto her side, the flail settling out over a beat.
- **idle** / **roosted** — a slow breath, and in idle a look about her every few
seconds, being a giddy bird.
## Painting
Each map is written against the part's own UVs, measured from the engine rather
than from the sweep's maths: on a lens or a lathe `u = 0` is the surface facing
her front, `0.25` her left flank, `0.5` her back and `0.75` her right flank, and
`v` runs from the low end of the sweep to the high end. On a ribbon `u` is only
the two edges and `v` runs base to tip, which is what carries the crest's white
tip and the tail's terminal band.
## Notes
- The materials are runtime GPU materials (`renderer.material.create`) rather
than `.material` assets: every colour and every painted map is code in this
file, so the bird is one artefact and there is nothing to keep in step with
it. `renderer.material.create` takes its values under `properties` and
`textures` — a `colors` or `floats` block is accepted and dropped.
- If a map fails to paint, every material renders its own base colour and the
bird is flat rather than absent.