Решили: смена базового стейта анимации в UnitView идёт кроссфейдом (CrossFadeInFixedTime,
поле _poseBlendSeconds, дефолт 0.13 с), а не мгновенным Play, для всех ПОЗНЫХ переходов —
Idle / CombatIdle / Stun и переходы в/из локомоции. Раньше блендинг был включён ТОЛЬКО для
пары локомоций (Run↔Sprint), всё прочее щёлкало за кадр.
Почему: выход из стана резал глаз сильнее всех, потому что поза стана — самая свёрнутая
(меч −40°, щит −28°, плечи назад, корпус сложен), а боевая (Braced) — развёрнутая (меч +58°, щит
+88°): жёсткий Play бросал риг через ~100–116° за кадр. Тот же корень бил и по Idle↔CombatIdle
(меч дёргался на ~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 — приоритет состояний).