# Porting characters and animation from Unreal

# Porting characters and animation from Unreal

Characters go through `ue/inventory_characters.py` (what exists), `ue/characters.py` (export), `characters.mjs` (clips, assembly, size) and `animbp.mjs` (Animation Blueprints to graphs). The engine part knows no game; which parts make a character and with which values is the game's spec. The overview of the pipeline is in Porting from Unreal Engine 5 (skill `ferret-unreal-porting`).

## The order that works

1. **Inventory** every skeletal mesh, skeleton, Animation Blueprint, sequence, blend space and montage: sizes, bones, morph targets, which skeleton each clip is on. It shows which families share a skeleton (then they share clips) and which have their own.
2. **Read the game's data, not its meshes**: a playable character built by a customizer is a preset (head, body, apparel rows with material options and tints, hair rows, scalars, face morphs) in data tables; an NPC Blueprint often holds one body component and builds the rest in its graph. Dump the presets and tables first.
3. **Export one mesh per editor run**, with its clips (`FERRET_CLIPS=1`) on a scratch level.
4. **Clips** (`characters.mjs clips`): one skeleton with the N clips; keep only what the game plays (`--keep`).
5. **Assemble** a character from parts (`characters.mjs assemble`): one skin, morphs baked by name, four influences, tints.
6. **Size** per tier (`characters.mjs optimize`): triangle budget, textures capped, morph targets dropped.
7. **Animation Blueprints** (`animbp.mjs`): the pose chain, blend spaces, slots, variables to a graph; what it cannot read goes to `unknown`.
8. **Check in the character viewer** (`?characters=<index.json>`): every file loads, every clip moves bones, no part without skin or material.

## Traps found in real ports

- **Clips export only through a playing component.** An animation sequence is not exportable as an asset. `characters.py` puts one actor per sequence on a scratch level and exports that world; the scratch level keeps earlier actors, so **one mesh per editor run** or the file carries every earlier family's clips.
- **The same skeleton under two names.** `CC_Skeleton` (70 bones) and `metahuman_base_skel` (87) share bone names: the clips bind by name, no retarget map, no `restRotation`. Compare bone names before writing a retarget.
- **The template's clips are shared.** Seven families played the six `ThirdPerson*` clips of the UE template; only a few had clips of their own. Do not export the same clips seven times.
- **Morph targets dominate the size.** A head with 104 targets was 65 MB; a body family came to 106 MB with them. Bake the few a preset uses (by name, from `<mesh>.morphs.json`, because the glTF targets have no names) and drop the rest.
- **Hair strands do not survive the bake.** UE draws hair with groom shading, not the card's UV: a bob came out as stripes, a fade and a beard not at all. Make hair and beards one opaque colour (`solid`); eyebrows and lashes keep their alpha.
- **A hair tint is not a colour.** The customizer's `Hair Tint` R and G are melanin and redness weights of UE's hair material, so `(0.35, 0, 0)` is dark brown, not red. `hairColor()` reproduces the engine's melanin function; check it against UE's own bake of the material.
- **Parts on their own skeleton lose bones.** Hair on a hair skeleton has bones the body lacks; `assemble` makes such a bone follow its nearest body ancestor (else the head), so it moves with the head instead of standing in the rest pose.
- **One skin per part costs skeletons.** The glTF loader makes a Babylon skeleton per skin (14-16 per person); `assemble` puts every part on the body's skin (2-3 per person). Parts whose bind pose of the neck or head differs by centimetres stay on their own skin.
- **Facing.** The exported model faces +Z; a 180-degree "fix" made the hero walk backwards. Measure the toes against the walk direction instead of guessing.
- **Budgets are sums.** A family made of many small parts (each under the size that is left alone) lands over the tier's triangle budget; count them.
- **Additive poses export as ordinary clips** (aim offsets, leans): `--no-additive` or `--keep` them out unless a graph layers them.
- **Animation Blueprints with one name in several folders** overwrite each other in a dump keyed by name; key by path.
- **A packaged game for OS Beroun** relies on the system's `/lib/ferret/` (the navigation WASM); a game that loads it from its own folder on the web stays on a black screen on the console when the system lacks it.

## Check afterwards

- The viewer report: no file that fails, no mesh without a skin or material, every clip moves bones (clip bones the body lacks are noted, not counted).
- In the game: the body shows in third person and hides in first, the clips follow the movement speed, and the hero walks forwards.
- Sizes per tier against the budget, clips file included.
