---
title: "Latios, Kinemation & skinned animation"
slug: /workflows/latios-animation/
markdown: /workflows/latios-animation.md
section: dots-ecs
tier: 2
summary: "Skeletons, deform shaders and bone masks under Latios, and why units freeze in bind pose."
sources: ['dots/latios-anim.md']
canonical: https://unityworkflowlibrary.dev/workflows/latios-animation/
read_first: /read-first.md
---

> Read first, on every prompt: [non-destructive rules](/read-first.md).

# Latios, Kinemation & skinned animation

> Skeletons, deform shaders and bone masks under Latios, and why units freeze in bind pose.

Skinned animation under Latios: skeletons, deform shaders, bone masks, and the several ways a unit ends up a bind-pose statue with a completely clean console.

- **Kinemation skin instances: bake a REAL entity prefab via a baker `GetEntity(prefabGameObject)`
  reference — never Prefab-tag a live skeleton and clone it; and under NetCode don't `Parent` a
  skeleton root to a ghost.** Two paired landmines from wiring per-unit Latios skins: (1) manually
  adding `Prefab` to a baked live skeleton (or promoting one at runtime) clones WITHOUT its
  LinkedEntityGroup/bind state — the instance holds `DependentSkinnedMesh` etc. but renders nothing
  and Kinemation jobs throw (`Index -1 out of range`); the only reliable source is a SubScene
  authoring MB whose Baker stores `GetEntity(authoring.skinPrefab, Dynamic)` (LEG + binding baked
  prefab-side, Instantiate just works). (2) A `Unity.Transforms.Parent` added to a skeleton-root
  skin gets stripped the same frame by the NetCode/Latios stack (no PreviousParent left behind) —
  drive the skin with a per-tick follow system copying the root's position/rotation (and destroy
  the skin when its root is gone, or they leak per respawn). (Seen in a survival RTS: unit skins.)

- **Kinemation skin prefab ASSETS stay FBX prefab VARIANTS, and runtime skeleton spawners pin
  ordering against the buffer-init workaround.** Two more skin landmines (same day, same stack):
  (1) building a skin prefab by UNPACKING the FBX instance and deleting unwanted kit-part nodes
  breaks Kinemation's optimized-rig mapping — socket bone indices bake against one hierarchy while
  the runtime `OptimizedBoneTransform` buffer is another length (`UpdateSocketsSystem` IndexOutOfRange
  flood). Keep the prefab a VARIANT of the FBX and trim kit parts with `SetActive(false)` overrides
  (inactive nodes bake `Disabled`, don't render, rig identical). (2) On Latios 0.15.x with a
  PreBounds/buffer-expansion workaround system, ANY system that `Instantiate`s optimized skeletons
  at runtime must declare `[UpdateBefore(<init system>)]` — unpinned, the implicit sort reshuffles
  the day another system is added, fresh skeletons reach TransformSystemGroup with bind-pose-length
  buffers, and every spawn frame throws (classic unpinned read-after-write). Also: a follow job that
  writes `LocalTransform` by iteration while reading it via lookup needs
  `[NativeDisableContainerSafetyRestriction]` on the read lookup when the sets are provably disjoint.

- **Latios deform clothing lives on `_Albedo_Map`, not `_BaseMap`.** Generated `M_Deform_*`
  variants keep the generic deform base on `_BaseMap` and the pack/clothing atlas on
  `_Albedo_Map`. Comparing or swapping only `_BaseMap` (URP Lit habit) silently no-ops
  in-match rematerial — units keep the pack look. Read `_Albedo_Map` first; never assign a
  URP Lit kit material onto a Kinemation skin (T-pose). Mounts (horse/wolf) are a second
  deform mat — skip them or every cavalry rematerial paints the animal.

- **Kinemation's deform path requires TANGENTS — vendor FBX packs that ship without them bake
  clean-looking skins whose subscene bake floods `InvalidOperationException: Mesh data does not
  have Tangent vertex component` from import workers.** The skin-prefab build itself succeeds
  (the exceptions land seconds LATER during entity-scene bake/warmup, easily blamed on the wrong
  step), and Unity's importer default `importTangents: Import` silently yields NONE when the FBX
  carries no tangents (`ImportFBX Warnings: Can't import tangents and binormals` is the only
  breadcrumb). Before wiring a new model pack into a Latios/Entities-Graphics pipeline, audit
  every mesh with `mesh.HasVertexAttribute(VertexAttribute.Tangent)` — read the imported MESH
  back, never trust importer settings (same class as texture `textureCompression` lying) — and
  set `ModelImporterTangents.CalculateMikk` + `SaveAndReimport` on the misses. Packs are
  inconsistent even within one vendor line: in one four-pack drop exactly one race pack (all 22
  FBXs) lacked tangents while 143 sibling models were fine. (Seen in a mobile strategy game: wiring
  the Dwarf unit pack; SW3 water has the same tangent requirement on meshes — see unity.md.)

- **In-place AnimatorController regeneration does NOT rebake dependent Mecanim data — force
  reimport controllers + skin prefabs + subscene, and let the bake FINISH before entering play.**
  Editing a controller asset in place (GUID kept, per ASSET-REGEN-GUID) leaves already-baked
  skin-prefab `MecanimController` blobs and `MecanimParameter` buffers stale/mismatched against
  the new parameter list — name-resolved parameter writes land in wrong slots and NO transition
  ever fires (every skin frozen in its default state while Speed still drives; reads as "walk
  cycle during attacks / no death anim"). After any generator run: `ImportAsset(...ForceUpdate)`
  the controllers, the prefabs referencing them, AND the baked subscene — then WAIT for the
  import/bake to go idle; entering play mid-bake loads the stale artifacts again. (Seen in practice: twice
  same day on SC unit controllers.)

- **MecanimV2: freezing a final pose = a hold state pinned by a TIME parameter — `state.speed ≈ 0` +
  `cycleOffset` does NOT freeze.** MecanimV2 samples non-looping clips through `LoopToClipTime`
  (unconditional fmod), so a finished one-shot state visibly REPLAYS its clip forever, and the tempting
  speed≈0/cycleOffset≈1 "park" state doesn't hold the pose either. The working mechanism (PT AC_Pawn
  DeathHold, re-proven on SC generated controllers): a float parameter defaulting to ~0.99, and a hold
  state with `timeParameterActive = true; timeParameter = "<param>"` playing the SAME clip — normalized
  time is pinned by the parameter, nothing ever advances. Chain: one-shot state → (exit time 0.9-0.95,
  NEVER exactly 1.0 — that transition never fires in MecanimV2) → pinned hold with zero outgoing
  transitions. Works from `AnimatorController` generation code (`UnityEditor.Animations.AnimatorState
  .timeParameterActive/.timeParameter`).

- **Never InstallKinemation / Mecanim on a world that ticks before match start.** Menu `CreateLocalWorld`
  and the Editor dummy are not presentation worlds — installing skins there Burst-JITs BatchSkinning
  in the Editor while the player AOT path stays ~1 GB. Do not `GetAll(Default)` on those worlds either
  (Default = Client+Server). Client world at match launch only. Rule owner:
  `BOOT-LOCAL-IS-NOT-THE-MATCH` in the [Netcode overview](/workflows/networking-overview/) page.

- **SIM-WINDOW-ANIM-FIT — every one-shot anim state tied to a sim window is speed-scaled to that
  window (`speedParameter`, driver sets `clipSeconds / windowSeconds`, clamp ≥1) — for EVERY window
  kind, not just the one that burned first.** The server paces by AUTHORED seconds (attack cooldown,
  cast wind-up root, channel time); the client plays a fixed-length pack clip. Any window shorter
  than the clip leaves the tail animating over resumed behavior — reads as foot-slide the moment
  movement returns (the unit "casts while walking"). The trap is partial application: the attack
  swing gets the fit rule ("one swing fits one cooldown", PT bow lesson) and the NEXT one-shot state
  added (Cast, channel, emote) ships without it because nothing fails loudly — the slide is cosmetic
  and only developer eyes catch it. When adding any one-shot state driven by a sim window: add the speed
  param in the controller generator, set it on the trigger edge from the ghosted window seconds, and
  scale the FALLBACK path too (a caster without a Cast state plays its attack clip — same fit, same
  window). (a mobile strategy game: Blood Rage 0.7s cast root vs the 1.33s `_11_cast` pack clip — orcs
  slid the last ~0.6s of every cast; Attack had the fit for months, Cast never did.)

- **MECANIMV2-OPTIMIZED-SKELETON-ONLY (HARD) - Latios MecanimV2 drives OPTIMIZED skeletons
  exclusively; a skin rig imported with `optimizeGameObjects=false` bakes an EXPOSED skeleton
  whose Mecanim pose is silently never applied - a bind-pose statue with zero errors.** The
  addon's own feature table says "Exposed Skeletons: Not Supported" (V1 supported them - the
  V1 habit is the trap). Parameters tick, blobs bake, transitions fire; nothing ever writes
  the bones, so every asset-side audit (clips pose the rig when sampled, controllers correct,
  registry wired, materials fine) comes back clean because nothing IS broken except the import
  flag. The diagnostic tell is elimination symmetry: Humanoid pack skins (optimized) animate
  while Generic authored-AC skins (exposed) freeze. Fix: `optimizeGameObjects=true` on every
  skin source FBX. Companion trap: vendor COLOR PREFABS (pack _Rd/_Pe colorway variants) are
  often plain UNPACKED copies, not prefab variants - they freeze the pre-optimization
  hierarchy, so a skin built FROM the color prefab stays exposed even after its FBX is
  optimized. Build the skin from the FBX and transfer the colorway's materials by
  renderer-node name. (a mobile strategy game: six air flyers + nine vendor god/hero
  replacements all bind-pose statues in match; an earlier lane had even play-claimed
  "wing-animating".)

## Kinemation deform and masks (a project, both invisible-with-no-error)

- **A skinned mesh needs a DEFORM-AWARE shader — Kinemation ships a Shader Graph NODE, not a shader.**
  The bake classifies deform by scanning the material's shader for `_latiosCurrentDeformBase` /
  `_latiosCurrentVertexSkinningMatrixBase` / `_latiosCurrentVertexSkinningDqsBase`; with none present it
  REFUSES the deform blob and the mesh renders bind-pose. Duplicate the vendor shader and add the
  `Latios Deform` node (SG browser: Input → Mesh Deformation, object space, Vertex block only) — never
  edit the vendor shader in place. Vendor environment/prop shaders carry no skinning nodes and will
  silently T-pose anything skinned that uses them. (Extends LATIOS-DEFORM-ALBEDO-MAP with the *why* and
  the fix.)

- **Layer bone masks need a TRANSFORM AvatarMask.** Build them with `SetTransformPath` /
  `SetTransformActive` from the rig MODEL's `ModelImporter.transformPaths`. A mask authored via
  `SetHumanoidBodyPartActive` has `transformCount == 0` and bakes a mask with ZERO bits — the layer looks
  completely healthy (weight 1, transitions fire, states advance) while writing its pose to no bones. The
  rig being humanoid is a red herring; Latios works at bone-transform level. Never enumerate the
  instantiated prefab hierarchy — an optimized skeleton has no bone Transforms there.

- **Drain skinned-skeleton spawns at a few per frame (~4)**, not `EntityManager.Instantiate(prefab, N, …)`.
  At N ≳ 10 the simultaneous skeleton allocations plus first compute-skin dispatches stall the GPU past
  Windows' ~2 s TDR, which presents as a graphics-driver crash and gets blamed on hardware. Player-spawn
  paths (1–2 per connection) are exempt.

- **MECANIMV2-TRIGGERS-NEVER-RESET — MecanimV2 0.1.6 (source drop) never auto-resets triggers,
  although its docs promise it: transitions loop.** It is a vendored-framework bug, patched in
  `MecanimUpdater.Update`; the patch must survive every addon re-drop, and "clear triggers every
  frame in game code" was the misdiagnosis that preceded it. (a project `docs/pitfalls/pawn-animation-latios-mecanimv2.md:48`.)
