Решили: смена базового стейта анимации в UnitView идёт кроссфейдом (CrossFadeInFixedTime, поле _poseBlendSeconds, дефолт 0.13 с), а не мгновенным Play, для всех ПОЗНЫХ переходов — Idle / CombatIdle / Stun и переходы в/из локомоции. Раньше блендинг был включён ТОЛЬКО для пары локомоций (RunSprint), всё прочее щёлкало за кадр.

Почему: выход из стана резал глаз сильнее всех, потому что поза стана — самая свёрнутая (меч −40°, щит −28°, плечи назад, корпус сложен), а боевая (Braced) — развёрнутая (меч +58°, щит +88°): жёсткий Play бросал риг через ~100–116° за кадр. Тот же корень бил и по IdleCombatIdle (меч дёргался на ~83° при наведении/потере цели). Альтернатива «чинить только стан» отвергнута Максом: дефект один, класс общий. Секунды, а не нормализованное окно CrossFade — стейты разной длины (Stun 1.2 с против Idle 2.6 с), одна доля дала бы разное реальное время перехода.

Грабли: вход в свинг НА БАЗЕ (Attack/AttackCharge у покадрового бестиария) обязан остаться снапом — DriveSwingScrub тем же кадром зовёт Play в позицию по сим-тику и оборвал бы кроссфейд на полдороге. Гейт — ScrubbedOnBase (проверяет !SwingIsOverlay): у скелетных свинг живёт слоем и на базу с Attack не приходит вовсе, так что проверка бьёт ровно в покадровый случай. Кто добавит кроссфейд «на всё» без этого гейта — сломает удар покадровых юнитов, и в консоли не будет ни строки.

Владелец правды: Presentation/UnitView.cs (блок смены стейта в Update, ScrubbedOnBase), Presentation/UnitAnimation.cs (UnitAnimationSelector.Select — приоритет состояний).