--- date: 2026-06-06 type: session tags: [session, animation, rukhanka, synty, netcode, presentation, dots, slice] --- # Session 2026-06-06 — Animation pipeline (Rukhanka + Synty), Slice 1: the player is alive ## Goal Operator (via `/dots-dev`, ultracode): *"Explore animations for this DOTS project — Rukhanka 2 (netcode-aware), alternatives, how much I can wire via MCP. Build something scalable/stable/sustainable for a solo dev. The game feels dead — the player is a capsule with no movement. Make it feel alive."* ## Process - **Research (adversarial Workflow):** verify exact Rukhanka 2.9 / Entities 6.4 APIs against the installed source + docs + context7 → synthesize a code-ready spec → 2 adversarial critics → finalize. Landscape: **Rukhanka is the only maintained Entities-native option on the 6.4 stack** (Latios/Kinemation explicitly not 6.4-compatible; Unity official = vaporware; DMotion dead). 3 parallel research agents up front (Rukhanka capability+netcode, alternatives, Synty rig/anim-pack compat). - **Clarifying gate (AskUserQuestion):** clip source = **Synty anim pack** (already imported: `AnimationBaseLocomotion`), first slice = **player only**, netcode = **advise-me** → chose **client-derived**, look = **SciFiSpace soldier**. - **Plan → approval → execution.** A permissions misfire (my subagent guardrail text "don't enter Play / use UnityMCP" was read by the auto-approver as the *user's* rule) blocked Play; operator reconnected MCP and cleared it. - **Execution serialized through the one live editor** (research fanned out in parallel; all Unity mutations done by me, validating each). ## Done - **De-risk (task 1):** entered Play → Rukhanka 2.9 initializes clean on Entities 6.4 (zero Rukhanka errors). GO. - **FBX (task 2):** SciFiSpace `Characters.fbx` already Generic + Optimize-GO-OFF + Mikk tangents → verify-only. - **Controller (task 3):** authored `AC_PlayerTopDown.controller` via the AnimatorController API (robust vs the enum/Vector-drop MCP traps) — 4 params, Idle / 2D-Freeform-Directional strafe Locomotion (9 in-place Synty run clips) / Death; 0 missing clips. - **Drive system (task 5, done before assets to compile-validate the Rukhanka API):** `AnimParamMath` (pure, **10 EditMode tests**) + client-only `PlayerAnimationDriveSystem` (Local CC-velocity + Remote position-delta jobs; `[WithAll(GhostOwnerIsLocal)]` / `[WithDisabled]` / `[WithPresent(Dead)]`). Asmdef refs added; **also `Unity.Physics`** (source-gen needs it directly — `KinematicCharacterBody` nests `ColliderKey`; the verified spec missed it). EditMode **204/204**. - **Material + prefab (task 4):** imported Rukhanka samples for `AnimatedLitShader` (multi-target ShaderGraph w/ a UniversalTarget → URP-valid), built `M_SpaceSoldier_Animated` (Synty atlas → `_BaseColorMap`). Assembled `Player.prefab`: flattened the soldier skeleton + body/head SMRs onto the **player root** (so the rig co-locates with gameplay components — required for the drive query), `Animator`+`RigDefinitionAuthoring`(CPU, root-motion off) on the root, capsule visual removed / collider kept. **Recovered a broken first attempt** (used `rootBone`=Spine_03 → destroyed the lower skeleton) via `git checkout` + correct walk-up-to-skeleton-root detection. - **Samples cleanup:** moved the 3 deformation ShaderGraphs to `_Project/Shaders/RukhankaSampleShaders` (GUID-preserving) and **deleted the whole samples tree** — it had dragged in 26 sample subscenes (one NRE'd Rukhanka's unguarded clip baker), sample systems that run in our worlds, and a conflicting TextMesh Pro folder. - **Ground offset:** skeleton `Root` local Y = −0.9 (entity origin = capsule center ~1 m up). Clips key no Root/Hips position → Rukhanka bakes it as a constant → persists. Feet 0.90 → ≈0.00. ## Validation (runtime, focused editor, real Server+Client) - ClientWorld player entity: `PlayerTag` + rig + 4 params + facing/stats/CC/`Dead` + **`GhostOwnerIsLocal` enabled** → drive job matches. **Idle and a forced run pose both deform the mesh** (distinct silhouettes, screenshots); **feet at y≈0**; capsule replaced by the textured soldier. Console clean (no NRE, no skinning warning). - ServerWorld: our drive system correctly **absent**. - **EditMode 204/204** (+10 `AnimParamMath`). ## Decisions [[DR-022_Animation_Pipeline_Rukhanka_Synty]] — Rukhanka client-derived; Generic-rig + Synty clips; CPU engine + deformation material; slim top-down controller; **rig-on-root** for entity co-location; client-only two-path drive (local CC-velocity / remote position-delta). **Runtime finding the adversarial spec got wrong:** `RukhankaAnimationSystemGroup` **is** created in `ServerWorld` (the spec read a `WorldFlags` gate and concluded otherwise). Harmless (drive is client-only; bones unreplicated; animation never feeds the sim) but wastes server CPU — only Play-validation caught it. Logged as a follow-up (server-strip). ## Next-session intent - ~~Server-strip Rukhanka~~ **DONE (same session):** `ServerStripAnimationSystem` (server-only one-shot) disables all `Rukhanka.Runtime` systems on the server (validated: server enabled=0 / 4 disabled, client 8 running, console clean). Also added a **Phase 10 (Commit)** to the `/dots-dev` skill — offer + commit only on explicit operator approval, logical groups, proper messages, no push. - Template the pipeline to **enemies** (Husk/Brute/Swarmer) — same flow, swap mesh + reuse `AC_PlayerTopDown` (or per-enemy clips). - Source a **combat/hit-react/death** anim pack (Base Locomotion is locomotion-only; Death is a crouch placeholder; Fire has no clip yet). - **Aim-IK** upper body toward the cursor (twin-stick), then ragdoll-on-death, bone-socket weapons, GPU engine + VAT for crowds. - Operator live play-through to tune anim-speed scaling / blend thresholds / the −0.9 offset, and a 2-client MPPM check that remote players animate (the position-delta path).