Browse Source

Merge pull request #528 from djeada/copilot/improve-melee-animation

Fix melee fight animations for more natural strike trajectories
Adam Djellouli 1 day ago
parent
commit
1ce97becba

+ 31 - 12
game/systems/combat_system.cpp

@@ -22,7 +22,15 @@ namespace Game::Systems {
 
 namespace {
 thread_local std::mt19937 gen(std::random_device{}());
+
+auto isUnitInHoldMode(Engine::Core::Entity *entity) -> bool {
+  if (entity == nullptr) {
+    return false;
+  }
+  auto *hold_mode = entity->get_component<Engine::Core::HoldModeComponent>();
+  return (hold_mode != nullptr) && hold_mode->active;
 }
+} // namespace
 
 void CombatSystem::update(Engine::Core::World *world, float delta_time) {
   process_hit_feedback(world, delta_time);
@@ -86,14 +94,17 @@ void CombatSystem::process_attacks(Engine::Core::World *world,
             const float max_melee_separation = 0.9F;
 
             if (dist > max_melee_separation) {
-              float const pull_amount =
-                  (dist - ideal_melee_distance) * 0.3F * delta_time * 5.0F;
+              // Check if attacker is in hold mode - don't pull if so
+              if (!isUnitInHoldMode(attacker)) {
+                float const pull_amount =
+                    (dist - ideal_melee_distance) * 0.3F * delta_time * 5.0F;
 
-              if (dist > 0.001F) {
-                QVector3D const direction(dx / dist, 0.0F, dz / dist);
+                if (dist > 0.001F) {
+                  QVector3D const direction(dx / dist, 0.0F, dz / dist);
 
-                att_t->position.x += direction.x() * pull_amount;
-                att_t->position.z += direction.z() * pull_amount;
+                  att_t->position.x += direction.x() * pull_amount;
+                  att_t->position.z += direction.z() * pull_amount;
+                }
               }
             }
           }
@@ -141,11 +152,14 @@ void CombatSystem::process_attacks(Engine::Core::World *world,
         if (attacker_unit->spawn_type == Game::Units::SpawnType::Archer) {
 
           range *= 1.5F;
-          damage = static_cast<int>(damage * 1.3F);
+          damage = static_cast<int>(damage * 1.5F);
         } else if (attacker_unit->spawn_type ==
                    Game::Units::SpawnType::Spearman) {
 
-          damage = static_cast<int>(damage * 1.4F);
+          damage = static_cast<int>(damage * 2.0F);
+        } else {
+          // All other units in hold mode get a significant attack bonus
+          damage = static_cast<int>(damage * 1.75F);
         }
       }
 
@@ -593,11 +607,16 @@ void CombatSystem::process_attacks(Engine::Core::World *world,
             if (dist > 0.001F) {
               QVector3D const direction(dx / dist, 0.0F, dz / dist);
 
-              att_t->position.x += direction.x() * move_amount;
-              att_t->position.z += direction.z() * move_amount;
+              // Check hold mode - don't move units that are holding
+              if (!isUnitInHoldMode(attacker)) {
+                att_t->position.x += direction.x() * move_amount;
+                att_t->position.z += direction.z() * move_amount;
+              }
 
-              tgt_t->position.x -= direction.x() * move_amount;
-              tgt_t->position.z -= direction.z() * move_amount;
+              if (!isUnitInHoldMode(best_target)) {
+                tgt_t->position.x -= direction.x() * move_amount;
+                tgt_t->position.z -= direction.z() * move_amount;
+              }
             }
           }
         }

+ 34 - 20
render/entity/nations/carthage/spearman_renderer.cpp

@@ -195,29 +195,43 @@ public:
     float const arm_asymmetry = (hash_01(seed ^ 0xDEF0U) - 0.5F) * 0.04F;
 
     if (anim.is_in_hold_mode || anim.is_exiting_hold) {
-      float const t =
+      float const hold_t =
           anim.is_in_hold_mode ? 1.0F : (1.0F - anim.hold_exit_progress);
 
-      controller.kneel(t * k_kneel_depth_multiplier);
+      // Use improved kneel transition when exiting hold
+      if (anim.is_exiting_hold) {
+        controller.kneelTransition(anim.hold_exit_progress, true);
+      } else {
+        controller.kneel(hold_t * k_kneel_depth_multiplier);
+      }
       controller.lean(QVector3D(0.0F, 0.0F, 1.0F),
-                      t * k_lean_amount_multiplier);
-
-      float const lowered_shoulder_y = controller.get_shoulder_y(true);
-      float const pelvis_y = controller.get_pelvis_y();
-
-      QVector3D const hand_r_pos(0.18F * (1.0F - t) + 0.22F * t,
-                                 lowered_shoulder_y * (1.0F - t) +
-                                     (pelvis_y + 0.05F) * t,
-                                 0.15F * (1.0F - t) + 0.20F * t);
-
-      float const offhand_along = lerp(-0.06F, -0.02F, t);
-      float const offhand_drop = 0.10F + 0.02F * t;
-      QVector3D const hand_l_pos =
-          computeOffhandSpearGrip(pose, anim_ctx, hand_r_pos, false,
-                                  offhand_along, offhand_drop, -0.08F);
-
-      controller.placeHandAt(false, hand_r_pos);
-      controller.placeHandAt(true, hand_l_pos);
+                      hold_t * k_lean_amount_multiplier);
+
+      // Check if attacking while in hold position
+      if (anim.is_attacking && anim.is_melee && anim.is_in_hold_mode) {
+        float const attack_phase = std::fmod(
+            anim_ctx.attack_phase * SPEARMAN_INV_ATTACK_CYCLE_TIME, 1.0F);
+        controller.spearThrustFromHold(attack_phase,
+                                       hold_t * k_kneel_depth_multiplier);
+      } else {
+        // Standard hold position hand placement
+        float const lowered_shoulder_y = controller.get_shoulder_y(true);
+        float const pelvis_y = controller.get_pelvis_y();
+
+        QVector3D const hand_r_pos(0.18F * (1.0F - hold_t) + 0.22F * hold_t,
+                                   lowered_shoulder_y * (1.0F - hold_t) +
+                                       (pelvis_y + 0.05F) * hold_t,
+                                   0.15F * (1.0F - hold_t) + 0.20F * hold_t);
+
+        float const offhand_along = lerp(-0.06F, -0.02F, hold_t);
+        float const offhand_drop = 0.10F + 0.02F * hold_t;
+        QVector3D const hand_l_pos =
+            computeOffhandSpearGrip(pose, anim_ctx, hand_r_pos, false,
+                                    offhand_along, offhand_drop, -0.08F);
+
+        controller.placeHandAt(false, hand_r_pos);
+        controller.placeHandAt(true, hand_l_pos);
+      }
 
     } else if (anim.is_attacking && anim.is_melee && !anim.is_in_hold_mode) {
       float const attack_phase = std::fmod(

+ 34 - 20
render/entity/nations/roman/spearman_renderer.cpp

@@ -137,29 +137,43 @@ public:
     float const arm_asymmetry = (hash_01(seed ^ 0xDEF0U) - 0.5F) * 0.04F;
 
     if (anim.is_in_hold_mode || anim.is_exiting_hold) {
-      float const t =
+      float const hold_t =
           anim.is_in_hold_mode ? 1.0F : (1.0F - anim.hold_exit_progress);
 
-      controller.kneel(t * k_kneel_depth_multiplier);
+      // Use improved kneel transition when exiting hold
+      if (anim.is_exiting_hold) {
+        controller.kneelTransition(anim.hold_exit_progress, true);
+      } else {
+        controller.kneel(hold_t * k_kneel_depth_multiplier);
+      }
       controller.lean(QVector3D(0.0F, 0.0F, 1.0F),
-                      t * k_lean_amount_multiplier);
-
-      float const lowered_shoulder_y = controller.get_shoulder_y(true);
-      float const pelvis_y = controller.get_pelvis_y();
-
-      QVector3D const hand_r_pos(0.18F * (1.0F - t) + 0.22F * t,
-                                 lowered_shoulder_y * (1.0F - t) +
-                                     (pelvis_y + 0.05F) * t,
-                                 0.15F * (1.0F - t) + 0.20F * t);
-
-      float const offhand_along = lerp(-0.06F, -0.02F, t);
-      float const offhand_drop = 0.10F + 0.02F * t;
-      QVector3D const hand_l_pos =
-          computeOffhandSpearGrip(pose, anim_ctx, hand_r_pos, false,
-                                  offhand_along, offhand_drop, -0.08F);
-
-      controller.placeHandAt(false, hand_r_pos);
-      controller.placeHandAt(true, hand_l_pos);
+                      hold_t * k_lean_amount_multiplier);
+
+      // Check if attacking while in hold position
+      if (anim.is_attacking && anim.is_melee && anim.is_in_hold_mode) {
+        float const attack_phase = std::fmod(
+            anim_ctx.attack_phase * SPEARMAN_INV_ATTACK_CYCLE_TIME, 1.0F);
+        controller.spearThrustFromHold(attack_phase,
+                                       hold_t * k_kneel_depth_multiplier);
+      } else {
+        // Standard hold position hand placement
+        float const lowered_shoulder_y = controller.get_shoulder_y(true);
+        float const pelvis_y = controller.get_pelvis_y();
+
+        QVector3D const hand_r_pos(0.18F * (1.0F - hold_t) + 0.22F * hold_t,
+                                   lowered_shoulder_y * (1.0F - hold_t) +
+                                       (pelvis_y + 0.05F) * hold_t,
+                                   0.15F * (1.0F - hold_t) + 0.20F * hold_t);
+
+        float const offhand_along = lerp(-0.06F, -0.02F, hold_t);
+        float const offhand_drop = 0.10F + 0.02F * hold_t;
+        QVector3D const hand_l_pos =
+            computeOffhandSpearGrip(pose, anim_ctx, hand_r_pos, false,
+                                    offhand_along, offhand_drop, -0.08F);
+
+        controller.placeHandAt(false, hand_r_pos);
+        controller.placeHandAt(true, hand_l_pos);
+      }
 
     } else if (anim.is_attacking && anim.is_melee && !anim.is_in_hold_mode) {
       float const attack_phase = std::fmod(

+ 190 - 45
render/humanoid/mounted_pose_controller.cpp

@@ -380,38 +380,110 @@ void MountedPoseController::apply_sword_strike(
     bool keep_left_hand) {
   attack_phase = std::clamp(attack_phase, 0.0F, 1.0F);
 
-  QVector3D const rest_pos = seatRelative(mount, 0.0F, 0.15F, 0.05F);
-  QVector3D const raised_pos = seatRelative(mount, 0.0F, 0.20F, 0.50F);
-  QVector3D const strike_pos = seatRelative(mount, 0.40F, 0.25F, -0.15F);
+  // Key positions for mounted cavalry slash (typically to the side/down)
+  QVector3D const rest_pos = seatRelative(mount, 0.08F, 0.20F, 0.12F);
+  QVector3D const chamber_pos = seatRelative(mount, -0.05F, 0.25F, 0.40F);
+  QVector3D const apex_pos = seatRelative(mount, -0.02F, 0.30F, 0.48F);
+  QVector3D const strike_pos = seatRelative(mount, 0.45F, 0.35F, 0.0F);
+  QVector3D const followthrough_pos = seatRelative(mount, 0.55F, 0.25F, -0.10F);
 
   QVector3D hand_r_target;
   QVector3D hand_l_target =
       reinAnchor(mount, true, 0.20F, 0.25F) + mount.seat_up * -0.02F;
 
-  if (attack_phase < 0.30F) {
-    float t = attack_phase / 0.30F;
-    t = t * t;
-    hand_r_target = rest_pos * (1.0F - t) + raised_pos * t;
-    update_head_hierarchy(mount, 0.0F, 0.0F, "sword_raise");
-  } else if (attack_phase < 0.50F) {
-    float t = (attack_phase - 0.30F) / 0.20F;
-    t = t * t * t;
-    hand_r_target = raised_pos * (1.0F - t) + strike_pos * t;
-    hand_r_target += mount.seat_up * (-0.25F - 0.12F * t);
+  // Body dynamics for mounted combat
+  float torso_twist = 0.0F;
+  float side_lean = 0.0F;
+  float forward_lean = 0.0F;
+  float shoulder_dip = 0.0F;
+
+  if (attack_phase < 0.18F) {
+    // Phase 1: Chamber - raise weapon overhead, twist body back
+    float t = attack_phase / 0.18F;
+    float ease_t = t * t;
+    hand_r_target = rest_pos * (1.0F - ease_t) + chamber_pos * ease_t;
+
+    torso_twist = -0.04F * ease_t;
+    shoulder_dip = 0.03F * ease_t;
+
+    update_head_hierarchy(mount, 0.0F, 0.0F, "sword_chamber");
+  } else if (attack_phase < 0.28F) {
+    // Phase 2: Apex - brief pause at highest point
+    float t = (attack_phase - 0.18F) / 0.10F;
+    float ease_t = t * t * (3.0F - 2.0F * t);
+    hand_r_target = chamber_pos * (1.0F - ease_t) + apex_pos * ease_t;
+
+    torso_twist = -0.04F;
+    shoulder_dip = 0.03F + 0.02F * ease_t;
+
+    update_head_hierarchy(mount, 0.0F, 0.0F, "sword_apex");
+  } else if (attack_phase < 0.48F) {
+    // Phase 3: Strike - explosive downward/outward slash
+    float t = (attack_phase - 0.28F) / 0.20F;
+    float power_t = t * t * t;
+    hand_r_target = apex_pos * (1.0F - power_t) + strike_pos * power_t;
+
+    // Uncoil body into the strike
+    torso_twist = -0.04F + 0.12F * power_t;
+    side_lean = 0.08F * power_t;     // Lean into strike direction
+    forward_lean = 0.06F * power_t;
+    shoulder_dip = 0.05F - 0.08F * power_t;
+
+    // Tighten reins during strike for stability
+    hand_l_target += mount.seat_up * (-0.03F * power_t);
+
+    update_head_hierarchy(mount, 0.3F * power_t, 0.2F * power_t, "sword_strike");
+  } else if (attack_phase < 0.65F) {
+    // Phase 4: Follow-through
+    float t = (attack_phase - 0.48F) / 0.17F;
+    float ease_t = t * t * (3.0F - 2.0F * t);
+    hand_r_target = strike_pos * (1.0F - ease_t) + followthrough_pos * ease_t;
+
+    torso_twist = 0.08F - 0.02F * t;
+    side_lean = 0.08F - 0.03F * t;
+    forward_lean = 0.06F - 0.02F * t;
+    shoulder_dip = -0.03F;
+
+    update_head_hierarchy(mount, 0.15F, 0.1F, "sword_followthrough");
+  } else {
+    // Phase 5: Recovery - return to guard
+    float t = (attack_phase - 0.65F) / 0.35F;
+    float ease_t = 1.0F - (1.0F - t) * (1.0F - t);
+    hand_r_target = followthrough_pos * (1.0F - ease_t) + rest_pos * ease_t;
 
-    QVector3D const lean = mount.seat_forward * (0.12F * t);
-    m_pose.shoulder_l += lean;
-    m_pose.shoulder_r += lean;
-    m_pose.neck_base += lean * 0.9F;
+    torso_twist = 0.06F * (1.0F - ease_t);
+    side_lean = 0.05F * (1.0F - ease_t);
+    forward_lean = 0.04F * (1.0F - ease_t);
+    shoulder_dip = -0.03F * (1.0F - ease_t);
 
-    update_head_hierarchy(mount, 0.3F * t, 0.0F, "sword_strike");
-  } else {
-    float t = (attack_phase - 0.50F) / 0.50F;
-    t = 1.0F - (1.0F - t) * (1.0F - t);
-    hand_r_target = strike_pos * (1.0F - t) + rest_pos * t;
     update_head_hierarchy(mount, 0.0F, 0.0F, "sword_recover");
   }
 
+  // Apply body dynamics relative to mount orientation
+  if (std::abs(torso_twist) > 0.001F) {
+    QVector3D const twist_offset = mount.seat_forward * torso_twist;
+    m_pose.shoulder_r += twist_offset;
+    m_pose.shoulder_l -= twist_offset * 0.5F;
+  }
+
+  if (side_lean > 0.001F) {
+    QVector3D const lean_offset = mount.seat_right * side_lean;
+    m_pose.shoulder_l += lean_offset;
+    m_pose.shoulder_r += lean_offset;
+    m_pose.neck_base += lean_offset * 0.8F;
+  }
+
+  if (forward_lean > 0.001F) {
+    QVector3D const lean_offset = mount.seat_forward * forward_lean;
+    m_pose.shoulder_l += lean_offset;
+    m_pose.shoulder_r += lean_offset;
+    m_pose.neck_base += lean_offset * 0.9F;
+  }
+
+  if (std::abs(shoulder_dip) > 0.001F) {
+    m_pose.shoulder_r += mount.seat_up * shoulder_dip;
+  }
+
   get_hand(false) = hand_r_target;
   if (!keep_left_hand) {
     get_hand(true) = hand_l_target;
@@ -432,38 +504,111 @@ void MountedPoseController::apply_spear_thrust(
     const MountedAttachmentFrame &mount, float attack_phase) {
   attack_phase = std::clamp(attack_phase, 0.0F, 1.0F);
 
-  QVector3D const guard_pos = seatRelative(mount, 0.10F, 0.15F, 0.10F);
-  QVector3D const thrust_pos = seatRelative(mount, 0.85F, 0.10F, 0.15F);
+  // Key positions for lance/spear thrust from horseback
+  QVector3D const guard_pos = seatRelative(mount, 0.12F, 0.15F, 0.15F);
+  QVector3D const couch_pos = seatRelative(mount, 0.05F, 0.12F, 0.08F);
+  QVector3D const thrust_pos = seatRelative(mount, 0.95F, 0.08F, 0.18F);
+  QVector3D const extended_pos = seatRelative(mount, 1.05F, 0.05F, 0.15F);
 
   QVector3D hand_r_target;
   QVector3D hand_l_target;
 
-  if (attack_phase < 0.25F) {
-    hand_r_target = guard_pos;
-    hand_l_target = guard_pos - mount.seat_right * 0.25F;
-    update_head_hierarchy(mount, 0.0F, 0.0F, "spear_guard_hold");
-  } else if (attack_phase < 0.45F) {
-    float t = (attack_phase - 0.25F) / 0.20F;
-    t = t * t * t;
-    hand_r_target = guard_pos * (1.0F - t) + thrust_pos * t;
-    hand_l_target = (guard_pos - mount.seat_right * 0.25F) * (1.0F - t) +
-                    (thrust_pos - mount.seat_right * 0.30F) * t;
+  // Body dynamics for couched lance thrust
+  float forward_lean = 0.0F;
+  float torso_twist = 0.0F;
+  float shoulder_drop = 0.0F;
+  float torso_compression = 0.0F;
+
+  if (attack_phase < 0.20F) {
+    // Phase 1: Couch the spear - lower and align for thrust
+    float t = attack_phase / 0.20F;
+    float ease_t = t * t;
+    hand_r_target = guard_pos * (1.0F - ease_t) + couch_pos * ease_t;
+    hand_l_target = guard_pos - mount.seat_right * 0.25F +
+                    (couch_pos - guard_pos) * ease_t * 0.6F;
+
+    // Slight crouch for power
+    torso_compression = 0.03F * ease_t;
+    forward_lean = 0.04F * ease_t;
+
+    update_head_hierarchy(mount, 0.1F * ease_t, 0.0F, "spear_couch");
+  } else if (attack_phase < 0.30F) {
+    // Phase 2: Brief tension before thrust
+    hand_r_target = couch_pos;
+    hand_l_target = couch_pos - mount.seat_right * 0.22F;
+
+    torso_compression = 0.03F;
+    forward_lean = 0.04F;
+
+    update_head_hierarchy(mount, 0.1F, 0.0F, "spear_tension");
+  } else if (attack_phase < 0.50F) {
+    // Phase 3: Explosive thrust - extend fully forward
+    float t = (attack_phase - 0.30F) / 0.20F;
+    float power_t = t * t * t;
+    hand_r_target = couch_pos * (1.0F - power_t) + thrust_pos * power_t;
+    hand_l_target = (couch_pos - mount.seat_right * 0.22F) * (1.0F - power_t) +
+                    (thrust_pos - mount.seat_right * 0.28F) * power_t;
+
+    // Explosive body extension
+    forward_lean = 0.04F + 0.16F * power_t;
+    torso_twist = 0.05F * power_t;
+    shoulder_drop = 0.04F * power_t;
+    torso_compression = 0.03F * (1.0F - power_t * 0.5F);
+
+    update_head_hierarchy(mount, 0.5F * power_t, 0.0F, "spear_thrust");
+  } else if (attack_phase < 0.65F) {
+    // Phase 4: Full extension - hold at maximum reach
+    float t = (attack_phase - 0.50F) / 0.15F;
+    float ease_t = t * t * (3.0F - 2.0F * t);
+    hand_r_target = thrust_pos * (1.0F - ease_t) + extended_pos * ease_t;
+    hand_l_target = (thrust_pos - mount.seat_right * 0.28F) * (1.0F - ease_t) +
+                    (extended_pos - mount.seat_right * 0.32F) * ease_t;
+
+    forward_lean = 0.20F;
+    torso_twist = 0.05F;
+    shoulder_drop = 0.04F;
+
+    update_head_hierarchy(mount, 0.5F, 0.0F, "spear_extend");
+  } else {
+    // Phase 5: Recovery - return to guard
+    float t = (attack_phase - 0.65F) / 0.35F;
+    float ease_t = 1.0F - (1.0F - t) * (1.0F - t);
+    hand_r_target = extended_pos * (1.0F - ease_t) + guard_pos * ease_t;
+    hand_l_target = (extended_pos - mount.seat_right * 0.32F) * (1.0F - ease_t) +
+                    (guard_pos - mount.seat_right * 0.25F) * ease_t;
 
-    QVector3D const lean = mount.seat_forward * (0.18F * t);
-    m_pose.shoulder_l += lean;
-    m_pose.shoulder_r += lean;
-    m_pose.neck_base += lean * 0.9F;
+    forward_lean = 0.20F * (1.0F - ease_t);
+    torso_twist = 0.05F * (1.0F - ease_t);
+    shoulder_drop = 0.04F * (1.0F - ease_t);
 
-    update_head_hierarchy(mount, 0.5F * t, 0.0F, "spear_thrust");
-  } else {
-    float t = (attack_phase - 0.45F) / 0.55F;
-    t = 1.0F - (1.0F - t) * (1.0F - t);
-    hand_r_target = thrust_pos * (1.0F - t) + guard_pos * t;
-    hand_l_target = (thrust_pos - mount.seat_right * 0.30F) * (1.0F - t) +
-                    (guard_pos - mount.seat_right * 0.25F) * t;
     update_head_hierarchy(mount, 0.0F, 0.0F, "spear_recover");
   }
 
+  // Apply body dynamics relative to mount orientation
+  if (forward_lean > 0.001F) {
+    QVector3D const lean_offset = mount.seat_forward * forward_lean;
+    m_pose.shoulder_l += lean_offset;
+    m_pose.shoulder_r += lean_offset;
+    m_pose.neck_base += lean_offset * 0.85F;
+  }
+
+  if (std::abs(torso_twist) > 0.001F) {
+    QVector3D const twist_offset = mount.seat_forward * torso_twist;
+    m_pose.shoulder_r += twist_offset;
+    m_pose.shoulder_l -= twist_offset * 0.3F;
+  }
+
+  if (shoulder_drop > 0.001F) {
+    m_pose.shoulder_r -= mount.seat_up * shoulder_drop;
+    m_pose.shoulder_l -= mount.seat_up * (shoulder_drop * 0.3F);
+  }
+
+  if (torso_compression > 0.001F) {
+    m_pose.shoulder_l -= mount.seat_up * torso_compression;
+    m_pose.shoulder_r -= mount.seat_up * torso_compression;
+    m_pose.neck_base -= mount.seat_up * (torso_compression * 0.6F);
+  }
+
   get_hand(false) = hand_r_target;
   get_hand(true) = hand_l_target;
 

+ 776 - 187
render/humanoid/pose_controller.cpp

@@ -23,29 +23,140 @@ void HumanoidPoseController::kneel(float depth) {
     return;
   }
 
-  float const kneel_offset = depth * 0.40F;
+  // Smooth easing for more natural motion
+  float const eased_depth = depth * depth * (3.0F - 2.0F * depth);
+
+  float const kneel_offset = eased_depth * 0.40F;
   float const pelvis_y = HP::WAIST_Y - kneel_offset;
   m_pose.pelvis_pos.setY(pelvis_y);
 
   float const stance_narrow = 0.11F;
 
-  float const left_knee_y = HP::GROUND_Y + 0.07F * depth;
-  float const left_knee_z = -0.06F * depth;
+  // Left leg (kneeling leg) - knee on ground
+  float const left_knee_y = HP::GROUND_Y + 0.07F * eased_depth;
+  float const left_knee_z = -0.06F * eased_depth;
   m_pose.knee_l = QVector3D(-stance_narrow, left_knee_y, left_knee_z);
   m_pose.foot_l = QVector3D(-stance_narrow - 0.025F, HP::GROUND_Y,
-                            left_knee_z - HP::LOWER_LEG_LEN * 0.93F * depth);
+                            left_knee_z - HP::LOWER_LEG_LEN * 0.93F * eased_depth);
 
+  // Right leg (support leg) - foot planted forward
   float const right_knee_y = pelvis_y - 0.12F;
-  float const right_foot_z = 0.28F * depth;
+  float const right_foot_z = 0.28F * eased_depth;
   m_pose.knee_r = QVector3D(stance_narrow, right_knee_y, right_foot_z - 0.05F);
   m_pose.foot_r = QVector3D(stance_narrow, HP::GROUND_Y + m_pose.foot_y_offset,
                             right_foot_z);
 
+  // Upper body follows down with slight forward lean for stability
   float const upper_body_drop = kneel_offset;
+  float const forward_lean = 0.03F * eased_depth;
+
   m_pose.shoulder_l.setY(m_pose.shoulder_l.y() - upper_body_drop);
   m_pose.shoulder_r.setY(m_pose.shoulder_r.y() - upper_body_drop);
   m_pose.neck_base.setY(m_pose.neck_base.y() - upper_body_drop);
   m_pose.head_pos.setY(m_pose.head_pos.y() - upper_body_drop);
+
+  // Slight forward lean for braced stance
+  m_pose.shoulder_l.setZ(m_pose.shoulder_l.z() + forward_lean);
+  m_pose.shoulder_r.setZ(m_pose.shoulder_r.z() + forward_lean);
+  m_pose.neck_base.setZ(m_pose.neck_base.z() + forward_lean * 0.8F);
+  m_pose.head_pos.setZ(m_pose.head_pos.z() + forward_lean * 0.6F);
+}
+
+void HumanoidPoseController::kneelTransition(float progress, bool standing_up) {
+  using HP = HumanProportions;
+
+  progress = std::clamp(progress, 0.0F, 1.0F);
+
+  // Easing function for natural motion
+  auto ease_in_out = [](float t) { return t * t * (3.0F - 2.0F * t); };
+
+  // When standing up, invert the progress
+  float kneel_amount = standing_up ? (1.0F - progress) : progress;
+  float eased_progress = ease_in_out(progress);
+
+  // Apply base kneel position
+  kneel(kneel_amount);
+
+  if (standing_up) {
+    // Standing up animation enhancements
+    // Early phase: push with front leg, shift weight forward
+    if (progress < 0.35F) {
+      float t = progress / 0.35F;
+      float push_t = ease_in_out(t);
+
+      // Push forward with supporting leg
+      m_pose.foot_r.setZ(m_pose.foot_r.z() - 0.08F * push_t);
+      m_pose.knee_r.setZ(m_pose.knee_r.z() - 0.05F * push_t);
+
+      // Lean forward to build momentum
+      float momentum_lean = 0.06F * push_t;
+      m_pose.shoulder_l.setZ(m_pose.shoulder_l.z() + momentum_lean);
+      m_pose.shoulder_r.setZ(m_pose.shoulder_r.z() + momentum_lean);
+      m_pose.neck_base.setZ(m_pose.neck_base.z() + momentum_lean * 0.9F);
+      m_pose.head_pos.setZ(m_pose.head_pos.z() + momentum_lean * 0.7F);
+
+      // Arms help with momentum
+      m_pose.hand_l.setZ(m_pose.hand_l.z() + 0.04F * push_t);
+      m_pose.hand_r.setZ(m_pose.hand_r.z() + 0.04F * push_t);
+    }
+    // Middle phase: rise up, bring back leg forward
+    else if (progress < 0.70F) {
+      float t = (progress - 0.35F) / 0.35F;
+      float rise_t = ease_in_out(t);
+
+      // Slight upward momentum boost
+      float lift_boost = 0.02F * std::sin(rise_t * std::numbers::pi_v<float>);
+      m_pose.pelvis_pos.setY(m_pose.pelvis_pos.y() + lift_boost);
+      m_pose.shoulder_l.setY(m_pose.shoulder_l.y() + lift_boost);
+      m_pose.shoulder_r.setY(m_pose.shoulder_r.y() + lift_boost);
+
+      // Bring kneeling leg forward
+      m_pose.foot_l.setZ(m_pose.foot_l.z() + 0.15F * rise_t);
+      m_pose.knee_l.setZ(m_pose.knee_l.z() + 0.10F * rise_t);
+      m_pose.knee_l.setY(m_pose.knee_l.y() + 0.20F * rise_t);
+    }
+    // Final phase: settle into standing position
+    else {
+      float t = (progress - 0.70F) / 0.30F;
+      float settle_t = ease_in_out(t);
+
+      // Return forward lean to neutral
+      float correct_lean = -0.04F * settle_t * (1.0F - kneel_amount);
+      m_pose.shoulder_l.setZ(m_pose.shoulder_l.z() + correct_lean);
+      m_pose.shoulder_r.setZ(m_pose.shoulder_r.z() + correct_lean);
+    }
+  } else {
+    // Kneeling down animation enhancements
+    // Early phase: shift weight, prepare to kneel
+    if (progress < 0.30F) {
+      float t = progress / 0.30F;
+      float prep_t = ease_in_out(t);
+
+      // Shift weight back slightly
+      m_pose.pelvis_pos.setZ(m_pose.pelvis_pos.z() - 0.03F * prep_t);
+
+      // Arms move to brace
+      m_pose.hand_l.setY(m_pose.hand_l.y() - 0.02F * prep_t);
+      m_pose.hand_r.setY(m_pose.hand_r.y() - 0.02F * prep_t);
+    }
+    // Middle phase: controlled descent
+    else if (progress < 0.75F) {
+      float t = (progress - 0.30F) / 0.45F;
+
+      // Controlled forward lean during descent
+      float controlled_lean = 0.04F * std::sin(t * std::numbers::pi_v<float>);
+      m_pose.shoulder_l.setZ(m_pose.shoulder_l.z() + controlled_lean);
+      m_pose.shoulder_r.setZ(m_pose.shoulder_r.z() + controlled_lean);
+    }
+    // Final phase: settle into kneel
+    else {
+      float t = (progress - 0.75F) / 0.25F;
+      float settle_t = ease_in_out(t);
+
+      // Small adjustment as knee touches ground
+      m_pose.knee_l.setY(m_pose.knee_l.y() - 0.01F * settle_t);
+    }
+  }
 }
 
 void HumanoidPoseController::lean(const QVector3D &direction, float amount) {
@@ -250,37 +361,98 @@ void HumanoidPoseController::meleeStrike(float strike_phase) {
 
   strike_phase = std::clamp(strike_phase, 0.0F, 1.0F);
 
-  QVector3D const rest_pos(0.25F, HP::SHOULDER_Y, 0.10F);
-  QVector3D const raised_pos(0.30F, HP::HEAD_TOP_Y + 0.2F, -0.05F);
-  QVector3D const strike_pos(0.35F, HP::WAIST_Y, 0.45F);
+  // Define key positions for a natural horizontal slash toward the target
+  QVector3D const rest_pos(0.22F, HP::SHOULDER_Y + 0.02F, 0.18F);
+  QVector3D const chamber_pos(0.30F, HP::SHOULDER_Y + 0.08F, 0.05F);
+  QVector3D const strike_pos(0.28F, HP::SHOULDER_Y - 0.05F, 0.65F);
+  QVector3D const followthrough_pos(0.10F, HP::SHOULDER_Y - 0.12F, 0.55F);
 
   QVector3D hand_r_target;
   QVector3D hand_l_target;
 
-  if (strike_phase < 0.25F) {
+  // Body dynamics
+  float torso_twist = 0.0F;
+  float forward_lean = 0.0F;
+  float shoulder_dip = 0.0F;
+  float step_forward = 0.0F;
+
+  if (strike_phase < 0.20F) {
+    // Phase 1: Chamber - pull weapon back, twist torso away
+    float t = strike_phase / 0.20F;
+    float ease_t = t * t;
+    hand_r_target = rest_pos * (1.0F - ease_t) + chamber_pos * ease_t;
+    hand_l_target = QVector3D(-0.18F, HP::SHOULDER_Y + 0.02F, 0.22F - 0.08F * t);
+
+    // Twist torso back to coil for the strike
+    torso_twist = -0.04F * ease_t;
+    shoulder_dip = -0.02F * ease_t;
+  } else if (strike_phase < 0.28F) {
+    // Phase 2: Brief anticipation hold
+    hand_r_target = chamber_pos;
+    hand_l_target = QVector3D(-0.18F, HP::SHOULDER_Y + 0.02F, 0.14F);
+    torso_twist = -0.04F;
+    shoulder_dip = -0.02F;
+  } else if (strike_phase < 0.48F) {
+    // Phase 3: Explosive strike - uncoil torso, step forward
+    float t = (strike_phase - 0.28F) / 0.20F;
+    float power_t = t * t * (3.0F - 2.0F * t); // smoothstep for power
+    hand_r_target = chamber_pos * (1.0F - power_t) + strike_pos * power_t;
+    hand_l_target = QVector3D(-0.18F + 0.06F * power_t,
+                              HP::SHOULDER_Y + 0.02F - 0.08F * power_t,
+                              0.14F + 0.20F * power_t);
+
+    // Uncoil torso forward and rotate into strike
+    torso_twist = -0.04F + 0.10F * power_t;
+    forward_lean = 0.08F * power_t;
+    shoulder_dip = -0.02F + 0.05F * power_t;
+    step_forward = 0.06F * power_t;
+  } else if (strike_phase < 0.65F) {
+    // Phase 4: Follow-through - weapon continues past target
+    float t = (strike_phase - 0.48F) / 0.17F;
+    float ease_t = t * t;
+    hand_r_target = strike_pos * (1.0F - ease_t) + followthrough_pos * ease_t;
+    hand_l_target = QVector3D(-0.12F, HP::SHOULDER_Y - 0.06F, 0.34F);
+
+    torso_twist = 0.06F - 0.02F * t;
+    forward_lean = 0.08F - 0.03F * t;
+    shoulder_dip = 0.03F;
+    step_forward = 0.06F;
+  } else {
+    // Phase 5: Recovery - return to guard
+    float t = (strike_phase - 0.65F) / 0.35F;
+    float ease_t = 1.0F - (1.0F - t) * (1.0F - t);
+    hand_r_target = followthrough_pos * (1.0F - ease_t) + rest_pos * ease_t;
+    hand_l_target = QVector3D(-0.12F + (-0.18F + 0.12F) * ease_t,
+                              HP::SHOULDER_Y - 0.06F * (1.0F - ease_t) +
+                                  0.02F * ease_t,
+                              0.34F * (1.0F - ease_t) + 0.22F * ease_t);
+
+    torso_twist = 0.04F * (1.0F - ease_t);
+    forward_lean = 0.05F * (1.0F - ease_t);
+    shoulder_dip = 0.03F * (1.0F - ease_t);
+    step_forward = 0.06F * (1.0F - ease_t);
+  }
 
-    float t = strike_phase / 0.25F;
-    t = t * t;
-    hand_r_target = rest_pos * (1.0F - t) + raised_pos * t;
-    hand_l_target = QVector3D(-0.15F, HP::SHOULDER_Y - 0.1F * t, 0.20F);
-  } else if (strike_phase < 0.35F) {
+  // Apply body dynamics
+  if (std::abs(torso_twist) > 0.001F) {
+    m_pose.shoulder_r.setZ(m_pose.shoulder_r.z() + torso_twist);
+    m_pose.shoulder_l.setZ(m_pose.shoulder_l.z() - torso_twist * 0.5F);
+  }
 
-    hand_r_target = raised_pos;
-    hand_l_target = QVector3D(-0.15F, HP::SHOULDER_Y - 0.1F, 0.20F);
-  } else if (strike_phase < 0.55F) {
+  if (forward_lean > 0.001F) {
+    m_pose.shoulder_l.setZ(m_pose.shoulder_l.z() + forward_lean);
+    m_pose.shoulder_r.setZ(m_pose.shoulder_r.z() + forward_lean);
+    m_pose.neck_base.setZ(m_pose.neck_base.z() + forward_lean * 0.8F);
+    m_pose.head_pos.setZ(m_pose.head_pos.z() + forward_lean * 0.6F);
+  }
 
-    float t = (strike_phase - 0.35F) / 0.2F;
-    t = t * t * t;
-    hand_r_target = raised_pos * (1.0F - t) + strike_pos * t;
-    hand_l_target = QVector3D(-0.15F, HP::SHOULDER_Y - 0.1F * (1.0F - t * 0.5F),
-                              0.20F + 0.15F * t);
-  } else {
+  if (std::abs(shoulder_dip) > 0.001F) {
+    m_pose.shoulder_r.setY(m_pose.shoulder_r.y() + shoulder_dip);
+  }
 
-    float t = (strike_phase - 0.55F) / 0.45F;
-    t = 1.0F - (1.0F - t) * (1.0F - t);
-    hand_r_target = strike_pos * (1.0F - t) + rest_pos * t;
-    hand_l_target = QVector3D(-0.15F, HP::SHOULDER_Y - 0.05F * (1.0F - t),
-                              0.35F * (1.0F - t) + 0.20F * t);
+  if (step_forward > 0.001F) {
+    m_pose.foot_r.setZ(m_pose.foot_r.z() + step_forward);
+    m_pose.knee_r.setZ(m_pose.knee_r.z() + step_forward * 0.5F);
   }
 
   placeHandAt(false, hand_r_target);
@@ -307,67 +479,262 @@ void HumanoidPoseController::spearThrust(float attack_phase) {
 
   attack_phase = std::clamp(attack_phase, 0.0F, 1.0F);
 
-  QVector3D const guard_pos(0.28F, HP::SHOULDER_Y + 0.05F, 0.25F);
-  QVector3D const prepare_pos(0.35F, HP::SHOULDER_Y + 0.08F, 0.05F);
-  QVector3D const thrust_pos(0.32F, HP::SHOULDER_Y + 0.10F, 0.90F);
-  QVector3D const recover_pos(0.28F, HP::SHOULDER_Y + 0.06F, 0.40F);
+  // Key positions for a powerful spear thrust
+  QVector3D const guard_pos(0.26F, HP::SHOULDER_Y + 0.08F, 0.28F);
+  QVector3D const chamber_pos(0.32F, HP::SHOULDER_Y + 0.12F, 0.02F);
+  QVector3D const thrust_pos(0.28F, HP::SHOULDER_Y + 0.05F, 0.95F);
+  QVector3D const extended_pos(0.25F, HP::SHOULDER_Y + 0.02F, 1.05F);
+  QVector3D const recover_pos(0.28F, HP::SHOULDER_Y + 0.06F, 0.45F);
 
   QVector3D hand_r_target;
   QVector3D hand_l_target;
 
+  // Body dynamics for spear thrust
+  float forward_lean = 0.0F;
+  float torso_twist = 0.0F;
+  float shoulder_drop = 0.0F;
+  float step_forward = 0.0F;
+  float hip_rotation = 0.0F;
+
   auto easeInOutCubic = [](float t) {
     return t < 0.5F ? 4.0F * t * t * t
                     : 1.0F - std::pow(-2.0F * t + 2.0F, 3.0F) / 2.0F;
   };
 
-  auto smoothstep = [](float edge0, float edge1, float x) {
-    float t = std::clamp((x - edge0) / (edge1 - edge0), 0.0F, 1.0F);
-    return t * t * (3.0F - 2.0F * t);
-  };
+  auto smoothstep = [](float t) { return t * t * (3.0F - 2.0F * t); };
+  auto ease_out = [](float t) { return 1.0F - (1.0F - t) * (1.0F - t); };
 
-  auto lerp = [](float a, float b, float t) { return a * (1.0F - t) + b * t; };
+  if (attack_phase < 0.18F) {
+    // Phase 1: Chamber - pull spear back, coil body
+    float const t = easeInOutCubic(attack_phase / 0.18F);
+    hand_r_target = guard_pos * (1.0F - t) + chamber_pos * t;
+    hand_l_target = QVector3D(-0.08F, HP::SHOULDER_Y - 0.04F,
+                              0.22F * (1.0F - t) + 0.06F * t);
+
+    // Twist body back to load power
+    torso_twist = -0.06F * t;
+    hip_rotation = -0.04F * t;
+    forward_lean = -0.03F * t; // Slight lean back
+  } else if (attack_phase < 0.28F) {
+    // Phase 2: Tension hold - brief pause before explosion
+    float const t = (attack_phase - 0.18F) / 0.10F;
+    hand_r_target = chamber_pos;
+    hand_l_target = QVector3D(-0.08F, HP::SHOULDER_Y - 0.04F, 0.06F);
+
+    torso_twist = -0.06F;
+    hip_rotation = -0.04F;
+    forward_lean = -0.03F - 0.02F * t; // Slight additional coil
+  } else if (attack_phase < 0.48F) {
+    // Phase 3: Explosive thrust - uncoil and drive forward
+    float t = (attack_phase - 0.28F) / 0.20F;
+    float power_t = t * t * t;
+    hand_r_target = chamber_pos * (1.0F - power_t) + thrust_pos * power_t;
+    hand_l_target =
+        QVector3D(-0.08F + 0.06F * power_t, HP::SHOULDER_Y - 0.04F + 0.02F * power_t,
+                  0.06F + 0.50F * power_t);
+
+    // Explosive uncoil
+    torso_twist = -0.06F + 0.14F * power_t;
+    hip_rotation = -0.04F + 0.10F * power_t;
+    forward_lean = -0.05F + 0.18F * power_t;
+    shoulder_drop = 0.05F * power_t;
+    step_forward = 0.10F * power_t;
+  } else if (attack_phase < 0.60F) {
+    // Phase 4: Full extension - maximum reach
+    float const t = smoothstep((attack_phase - 0.48F) / 0.12F);
+    hand_r_target = thrust_pos * (1.0F - t) + extended_pos * t;
+    hand_l_target = QVector3D(-0.02F, HP::SHOULDER_Y - 0.02F, 0.56F + 0.10F * t);
+
+    torso_twist = 0.08F;
+    hip_rotation = 0.06F;
+    forward_lean = 0.13F + 0.05F * t;
+    shoulder_drop = 0.05F + 0.02F * t;
+    step_forward = 0.10F + 0.04F * t;
+  } else if (attack_phase < 0.78F) {
+    // Phase 5: Withdraw - pull back from extension
+    float const t = easeInOutCubic((attack_phase - 0.60F) / 0.18F);
+    hand_r_target = extended_pos * (1.0F - t) + recover_pos * t;
+    hand_l_target = QVector3D(-0.02F * (1.0F - t) - 0.08F * t,
+                              HP::SHOULDER_Y - 0.02F * (1.0F - t) - 0.05F * t,
+                              0.66F * (1.0F - t) + 0.38F * t);
+
+    torso_twist = 0.08F * (1.0F - t);
+    hip_rotation = 0.06F * (1.0F - t);
+    forward_lean = 0.18F * (1.0F - t) + 0.04F * t;
+    shoulder_drop = 0.07F * (1.0F - t);
+    step_forward = 0.14F * (1.0F - t * 0.5F);
+  } else {
+    // Phase 6: Recovery - return to guard
+    float const t = ease_out((attack_phase - 0.78F) / 0.22F);
+    hand_r_target = recover_pos * (1.0F - t) + guard_pos * t;
+    hand_l_target =
+        QVector3D(-0.08F, HP::SHOULDER_Y - 0.05F * (1.0F - t) - 0.02F * t,
+                  0.38F * (1.0F - t) + 0.22F * t);
 
-  if (attack_phase < 0.20F) {
+    forward_lean = 0.04F * (1.0F - t);
+    step_forward = 0.07F * (1.0F - t);
+  }
 
-    float const t = easeInOutCubic(attack_phase / 0.20F);
-    hand_r_target = guard_pos * (1.0F - t) + prepare_pos * t;
-    hand_l_target = QVector3D(-0.10F, HP::SHOULDER_Y - 0.05F,
-                              0.20F * (1.0F - t) + 0.08F * t);
-  } else if (attack_phase < 0.30F) {
+  // Apply body dynamics
+  if (std::abs(torso_twist) > 0.001F) {
+    m_pose.shoulder_r.setZ(m_pose.shoulder_r.z() + torso_twist);
+    m_pose.shoulder_l.setZ(m_pose.shoulder_l.z() - torso_twist * 0.4F);
+  }
 
-    hand_r_target = prepare_pos;
-    hand_l_target = QVector3D(-0.10F, HP::SHOULDER_Y - 0.05F, 0.08F);
-  } else if (attack_phase < 0.50F) {
+  if (std::abs(hip_rotation) > 0.001F) {
+    m_pose.pelvis_pos.setZ(m_pose.pelvis_pos.z() + hip_rotation * 0.5F);
+  }
 
-    float t = (attack_phase - 0.30F) / 0.20F;
-    t = t * t * t;
-    hand_r_target = prepare_pos * (1.0F - t) + thrust_pos * t;
+  if (std::abs(forward_lean) > 0.001F) {
+    m_pose.shoulder_l.setZ(m_pose.shoulder_l.z() + forward_lean);
+    m_pose.shoulder_r.setZ(m_pose.shoulder_r.z() + forward_lean);
+    m_pose.neck_base.setZ(m_pose.neck_base.z() + forward_lean * 0.85F);
+    m_pose.head_pos.setZ(m_pose.head_pos.z() + forward_lean * 0.7F);
+  }
+
+  if (shoulder_drop > 0.001F) {
+    m_pose.shoulder_r.setY(m_pose.shoulder_r.y() - shoulder_drop);
+    m_pose.shoulder_l.setY(m_pose.shoulder_l.y() - shoulder_drop * 0.3F);
+  }
+
+  if (step_forward > 0.001F) {
+    m_pose.foot_r.setZ(m_pose.foot_r.z() + step_forward);
+    m_pose.knee_r.setZ(m_pose.knee_r.z() + step_forward * 0.6F);
+    m_pose.foot_l.setZ(m_pose.foot_l.z() - step_forward * 0.15F);
+  }
+
+  // Compute offhand grip along spear shaft
+  float const thrust_extent =
+      std::clamp((attack_phase - 0.18F) / 0.60F, 0.0F, 1.0F);
+  float const along_offset = -0.08F + 0.04F * thrust_extent;
+  float const y_drop = 0.08F + 0.03F * thrust_extent;
+
+  hand_l_target = computeOffhandSpearGrip(m_pose, m_anim_ctx, hand_r_target,
+                                          false, along_offset, y_drop, -0.06F);
+
+  placeHandAt(false, hand_r_target);
+  placeHandAt(true, hand_l_target);
+}
+
+void HumanoidPoseController::spearThrustFromHold(float attack_phase,
+                                                 float hold_depth) {
+  using HP = HumanProportions;
+
+  attack_phase = std::clamp(attack_phase, 0.0F, 1.0F);
+  hold_depth = std::clamp(hold_depth, 0.0F, 1.0F);
+
+  // Calculate lowered positions based on hold depth
+  float const height_offset = -hold_depth * 0.35F;
+
+  // Key positions adjusted for kneeling - spear angled forward/down
+  QVector3D const guard_pos(0.22F, HP::SHOULDER_Y + height_offset + 0.05F, 0.32F);
+  QVector3D const chamber_pos(0.28F, HP::SHOULDER_Y + height_offset + 0.10F, 0.08F);
+  QVector3D const thrust_pos(0.24F, HP::SHOULDER_Y + height_offset - 0.08F, 0.90F);
+  QVector3D const extended_pos(0.22F, HP::SHOULDER_Y + height_offset - 0.12F, 1.00F);
+  QVector3D const recover_pos(0.24F, HP::SHOULDER_Y + height_offset + 0.02F, 0.48F);
+
+  QVector3D hand_r_target;
+  QVector3D hand_l_target;
+
+  // Body dynamics for kneeling thrust - limited due to position
+  float forward_lean = 0.0F;
+  float torso_twist = 0.0F;
+  float shoulder_extension = 0.0F;
+
+  auto smoothstep = [](float t) { return t * t * (3.0F - 2.0F * t); };
+  auto ease_out = [](float t) { return 1.0F - (1.0F - t) * (1.0F - t); };
+  auto ease_in = [](float t) { return t * t; };
+
+  if (attack_phase < 0.15F) {
+    // Phase 1: Quick chamber from braced position
+    float const t = ease_in(attack_phase / 0.15F);
+    hand_r_target = guard_pos * (1.0F - t) + chamber_pos * t;
+    hand_l_target = QVector3D(-0.06F, HP::SHOULDER_Y + height_offset - 0.03F,
+                              0.28F * (1.0F - t) + 0.10F * t);
+
+    torso_twist = -0.04F * t;
+  } else if (attack_phase < 0.22F) {
+    // Phase 2: Brief tension
+    hand_r_target = chamber_pos;
+    hand_l_target = QVector3D(-0.06F, HP::SHOULDER_Y + height_offset - 0.03F, 0.10F);
+
+    torso_twist = -0.04F;
+  } else if (attack_phase < 0.42F) {
+    // Phase 3: Explosive thrust from kneeling - drive from hip
+    float t = (attack_phase - 0.22F) / 0.20F;
+    float power_t = t * t * t;
+    hand_r_target = chamber_pos * (1.0F - power_t) + thrust_pos * power_t;
     hand_l_target =
-        QVector3D(-0.10F + 0.05F * t, HP::SHOULDER_Y - 0.05F + 0.03F * t,
-                  0.08F + 0.45F * t);
-  } else if (attack_phase < 0.70F) {
-
-    float const t = easeInOutCubic((attack_phase - 0.50F) / 0.20F);
-    hand_r_target = thrust_pos * (1.0F - t) + recover_pos * t;
-    hand_l_target = QVector3D(-0.05F * (1.0F - t) - 0.10F * t,
-                              HP::SHOULDER_Y - 0.02F * (1.0F - t) - 0.06F * t,
-                              lerp(0.53F, 0.35F, t));
+        QVector3D(-0.06F + 0.05F * power_t,
+                  HP::SHOULDER_Y + height_offset - 0.03F + 0.01F * power_t,
+                  0.10F + 0.48F * power_t);
+
+    // Drive forward from braced position
+    torso_twist = -0.04F + 0.10F * power_t;
+    forward_lean = 0.12F * power_t;
+    shoulder_extension = 0.06F * power_t;
+  } else if (attack_phase < 0.55F) {
+    // Phase 4: Full extension - maximum reach from kneel
+    float const t = smoothstep((attack_phase - 0.42F) / 0.13F);
+    hand_r_target = thrust_pos * (1.0F - t) + extended_pos * t;
+    hand_l_target = QVector3D(-0.01F, HP::SHOULDER_Y + height_offset - 0.02F,
+                              0.58F + 0.08F * t);
+
+    torso_twist = 0.06F;
+    forward_lean = 0.12F + 0.04F * t;
+    shoulder_extension = 0.06F + 0.03F * t;
+  } else if (attack_phase < 0.75F) {
+    // Phase 5: Withdraw back to braced position
+    float const t = smoothstep((attack_phase - 0.55F) / 0.20F);
+    hand_r_target = extended_pos * (1.0F - t) + recover_pos * t;
+    hand_l_target = QVector3D(-0.01F * (1.0F - t) - 0.05F * t,
+                              HP::SHOULDER_Y + height_offset - 0.02F * (1.0F - t) -
+                                  0.04F * t,
+                              0.66F * (1.0F - t) + 0.40F * t);
+
+    torso_twist = 0.06F * (1.0F - t);
+    forward_lean = 0.16F * (1.0F - t) + 0.03F * t;
+    shoulder_extension = 0.09F * (1.0F - t);
   } else {
-
-    float const t = smoothstep(0.70F, 1.0F, attack_phase);
+    // Phase 6: Return to guard in hold position
+    float const t = ease_out((attack_phase - 0.75F) / 0.25F);
     hand_r_target = recover_pos * (1.0F - t) + guard_pos * t;
     hand_l_target =
-        QVector3D(-0.10F - 0.02F * (1.0F - t),
-                  HP::SHOULDER_Y - 0.06F + 0.01F * t, lerp(0.35F, 0.25F, t));
+        QVector3D(-0.05F - 0.01F * t, HP::SHOULDER_Y + height_offset - 0.04F * (1.0F - t) -
+                                          0.03F * t,
+                  0.40F * (1.0F - t) + 0.28F * t);
+
+    forward_lean = 0.03F * (1.0F - t);
+  }
+
+  // Apply body dynamics (limited by kneeling position)
+  if (std::abs(torso_twist) > 0.001F) {
+    m_pose.shoulder_r.setZ(m_pose.shoulder_r.z() + torso_twist);
+    m_pose.shoulder_l.setZ(m_pose.shoulder_l.z() - torso_twist * 0.3F);
+  }
+
+  if (forward_lean > 0.001F) {
+    // When kneeling, lean is more from upper body only
+    m_pose.shoulder_l.setZ(m_pose.shoulder_l.z() + forward_lean);
+    m_pose.shoulder_r.setZ(m_pose.shoulder_r.z() + forward_lean);
+    m_pose.neck_base.setZ(m_pose.neck_base.z() + forward_lean * 0.9F);
+    m_pose.head_pos.setZ(m_pose.head_pos.z() + forward_lean * 0.75F);
   }
 
+  if (shoulder_extension > 0.001F) {
+    // Extend right shoulder forward for reach
+    m_pose.shoulder_r.setZ(m_pose.shoulder_r.z() + shoulder_extension);
+    m_pose.shoulder_r.setY(m_pose.shoulder_r.y() - shoulder_extension * 0.3F);
+  }
+
+  // Compute offhand grip
   float const thrust_extent =
-      std::clamp((attack_phase - 0.20F) / 0.60F, 0.0F, 1.0F);
-  float const along_offset = -0.06F + 0.02F * thrust_extent;
-  float const y_drop = 0.10F + 0.02F * thrust_extent;
+      std::clamp((attack_phase - 0.15F) / 0.55F, 0.0F, 1.0F);
+  float const along_offset = -0.06F + 0.03F * thrust_extent;
+  float const y_drop = 0.06F + 0.02F * thrust_extent;
 
   hand_l_target = computeOffhandSpearGrip(m_pose, m_anim_ctx, hand_r_target,
-                                          false, along_offset, y_drop, -0.08F);
+                                          false, along_offset, y_drop, -0.05F);
 
   placeHandAt(false, hand_r_target);
   placeHandAt(true, hand_l_target);
@@ -378,57 +745,109 @@ void HumanoidPoseController::sword_slash(float attack_phase) {
 
   attack_phase = std::clamp(attack_phase, 0.0F, 1.0F);
 
+  // Key positions for a diagonal downward slash
   QVector3D const rest_pos(0.20F, HP::SHOULDER_Y + 0.05F, 0.15F);
-  QVector3D const prepare_pos(0.26F, HP::HEAD_TOP_Y + 0.18F, -0.06F);
-  QVector3D const raised_pos(0.25F, HP::HEAD_TOP_Y + 0.22F, 0.02F);
-  QVector3D const strike_pos(0.30F, HP::WAIST_Y - 0.05F, 0.50F);
+  QVector3D const chamber_pos(0.28F, HP::SHOULDER_Y + 0.20F, 0.02F);
+  QVector3D const apex_pos(0.30F, HP::SHOULDER_Y + 0.25F, 0.08F);
+  QVector3D const strike_pos(0.18F, HP::SHOULDER_Y - 0.15F, 0.62F);
+  QVector3D const followthrough_pos(0.05F, HP::WAIST_Y + 0.10F, 0.50F);
   QVector3D const recover_pos(0.22F, HP::SHOULDER_Y + 0.02F, 0.22F);
 
   QVector3D hand_r_target;
   QVector3D hand_l_target;
 
-  auto easeInOutCubic = [](float t) {
-    return t < 0.5F ? 4.0F * t * t * t
-                    : 1.0F - std::pow(-2.0F * t + 2.0F, 3.0F) / 2.0F;
-  };
-
-  auto smoothstep = [](float edge0, float edge1, float x) {
-    float t = std::clamp((x - edge0) / (edge1 - edge0), 0.0F, 1.0F);
-    return t * t * (3.0F - 2.0F * t);
-  };
-
-  auto lerp = [](float a, float b, float t) { return a * (1.0F - t) + b * t; };
+  // Body dynamics
+  float torso_twist = 0.0F;
+  float forward_lean = 0.0F;
+  float shoulder_rotation = 0.0F;
+  float weight_shift = 0.0F;
+
+  auto smoothstep = [](float t) { return t * t * (3.0F - 2.0F * t); };
+  auto ease_out = [](float t) { return 1.0F - (1.0F - t) * (1.0F - t); };
+  auto ease_in = [](float t) { return t * t; };
+
+  if (attack_phase < 0.15F) {
+    // Phase 1: Prepare - raise weapon to chamber position
+    float t = attack_phase / 0.15F;
+    float ease_t = ease_in(t);
+    hand_r_target = rest_pos * (1.0F - ease_t) + chamber_pos * ease_t;
+    hand_l_target = QVector3D(-0.20F, HP::SHOULDER_Y - 0.02F, 0.15F + 0.02F * t);
+
+    // Rotate shoulders back, coiling for strike
+    torso_twist = -0.05F * ease_t;
+    shoulder_rotation = 0.03F * ease_t;
+  } else if (attack_phase < 0.28F) {
+    // Phase 2: Apex - weapon at highest point, brief tension
+    float t = (attack_phase - 0.15F) / 0.13F;
+    float ease_t = smoothstep(t);
+    hand_r_target = chamber_pos * (1.0F - ease_t) + apex_pos * ease_t;
+    hand_l_target = QVector3D(-0.20F, HP::SHOULDER_Y - 0.04F, 0.17F);
+
+    torso_twist = -0.05F;
+    shoulder_rotation = 0.03F + 0.02F * ease_t;
+    weight_shift = -0.02F * ease_t; // Weight shifts back before strike
+  } else if (attack_phase < 0.48F) {
+    // Phase 3: Strike - explosive diagonal slash downward
+    float t = (attack_phase - 0.28F) / 0.20F;
+    float power_t = t * t * t; // Fast acceleration
+    hand_r_target = apex_pos * (1.0F - power_t) + strike_pos * power_t;
+    hand_l_target =
+        QVector3D(-0.20F + 0.08F * power_t,
+                  HP::SHOULDER_Y - 0.04F - 0.06F * power_t, 0.17F + 0.22F * power_t);
+
+    // Explosive uncoil - torso rotates into strike, body leans forward
+    torso_twist = -0.05F + 0.14F * power_t;
+    forward_lean = 0.10F * power_t;
+    shoulder_rotation = 0.05F - 0.08F * power_t;
+    weight_shift = -0.02F + 0.08F * power_t;
+  } else if (attack_phase < 0.62F) {
+    // Phase 4: Follow-through - weapon continues past target
+    float t = (attack_phase - 0.48F) / 0.14F;
+    float ease_t = smoothstep(t);
+    hand_r_target = strike_pos * (1.0F - ease_t) + followthrough_pos * ease_t;
+    hand_l_target = QVector3D(-0.12F, HP::SHOULDER_Y - 0.10F, 0.39F);
+
+    torso_twist = 0.09F - 0.03F * t;
+    forward_lean = 0.10F - 0.02F * t;
+    weight_shift = 0.06F;
+  } else {
+    // Phase 5: Recovery - return to guard
+    float t = (attack_phase - 0.62F) / 0.38F;
+    float ease_t = ease_out(t);
+    hand_r_target =
+        followthrough_pos * (1.0F - ease_t) + recover_pos * 0.5F * ease_t +
+        rest_pos * 0.5F * ease_t;
+    hand_l_target =
+        QVector3D(-0.12F - 0.08F * ease_t, HP::SHOULDER_Y - 0.10F * (1.0F - ease_t),
+                  0.39F * (1.0F - ease_t) + 0.15F * ease_t);
 
-  if (attack_phase < 0.18F) {
+    torso_twist = 0.06F * (1.0F - ease_t);
+    forward_lean = 0.08F * (1.0F - ease_t);
+    weight_shift = 0.06F * (1.0F - ease_t);
+  }
 
-    float const t = easeInOutCubic(attack_phase / 0.18F);
-    hand_r_target = rest_pos * (1.0F - t) + prepare_pos * t;
-    hand_l_target =
-        QVector3D(-0.21F, HP::SHOULDER_Y - 0.02F - 0.03F * t, 0.15F);
-  } else if (attack_phase < 0.32F) {
+  // Apply body dynamics
+  if (std::abs(torso_twist) > 0.001F) {
+    m_pose.shoulder_r.setZ(m_pose.shoulder_r.z() + torso_twist);
+    m_pose.shoulder_l.setZ(m_pose.shoulder_l.z() - torso_twist * 0.6F);
+  }
 
-    float const t = easeInOutCubic((attack_phase - 0.18F) / 0.14F);
-    hand_r_target = prepare_pos * (1.0F - t) + raised_pos * t;
-    hand_l_target = QVector3D(-0.21F, HP::SHOULDER_Y - 0.05F, 0.17F);
-  } else if (attack_phase < 0.52F) {
+  if (std::abs(shoulder_rotation) > 0.001F) {
+    m_pose.shoulder_r.setY(m_pose.shoulder_r.y() - shoulder_rotation);
+    m_pose.shoulder_l.setY(m_pose.shoulder_l.y() + shoulder_rotation * 0.4F);
+  }
 
-    float t = (attack_phase - 0.32F) / 0.20F;
-    t = t * t * t;
-    hand_r_target = raised_pos * (1.0F - t) + strike_pos * t;
-    hand_l_target = QVector3D(
-        -0.21F, HP::SHOULDER_Y - 0.03F * (1.0F - 0.5F * t), 0.17F + 0.20F * t);
-  } else if (attack_phase < 0.72F) {
-
-    float const t = easeInOutCubic((attack_phase - 0.52F) / 0.20F);
-    hand_r_target = strike_pos * (1.0F - t) + recover_pos * t;
-    hand_l_target = QVector3D(-0.20F, HP::SHOULDER_Y - 0.015F * (1.0F - t),
-                              lerp(0.37F, 0.20F, t));
-  } else {
+  if (forward_lean > 0.001F) {
+    m_pose.shoulder_l.setZ(m_pose.shoulder_l.z() + forward_lean);
+    m_pose.shoulder_r.setZ(m_pose.shoulder_r.z() + forward_lean);
+    m_pose.neck_base.setZ(m_pose.neck_base.z() + forward_lean * 0.7F);
+    m_pose.head_pos.setZ(m_pose.head_pos.z() + forward_lean * 0.5F);
+    m_pose.pelvis_pos.setZ(m_pose.pelvis_pos.z() + forward_lean * 0.3F);
+  }
 
-    float const t = smoothstep(0.72F, 1.0F, attack_phase);
-    hand_r_target = recover_pos * (1.0F - t) + rest_pos * t;
-    hand_l_target = QVector3D(-0.20F - 0.02F * (1.0F - t), HP::SHOULDER_Y,
-                              lerp(0.20F, 0.15F, t));
+  if (std::abs(weight_shift) > 0.001F) {
+    m_pose.foot_r.setZ(m_pose.foot_r.z() + weight_shift);
+    m_pose.knee_r.setZ(m_pose.knee_r.z() + weight_shift * 0.6F);
   }
 
   placeHandAt(false, hand_r_target);
@@ -500,22 +919,34 @@ void HumanoidPoseController::sword_slash_variant(float attack_phase,
 
   attack_phase = std::clamp(attack_phase, 0.0F, 1.0F);
 
+  // Strike direction constants
+  constexpr float kStrikeRightToLeft = 1.0F;
+  constexpr float kStrikeLeftToRight = -1.0F;
+
+  // Base positions - will be modified by variant
   QVector3D rest_pos(0.20F, HP::SHOULDER_Y + 0.05F, 0.15F);
-  QVector3D prepare_pos(0.26F, HP::HEAD_TOP_Y + 0.18F, -0.06F);
-  QVector3D raised_pos(0.25F, HP::HEAD_TOP_Y + 0.22F, 0.02F);
-  QVector3D strike_pos(0.30F, HP::WAIST_Y - 0.05F, 0.50F);
-  QVector3D recover_pos(0.22F, HP::SHOULDER_Y + 0.02F, 0.22F);
+  QVector3D chamber_pos(0.28F, HP::SHOULDER_Y + 0.20F, 0.02F);
+  QVector3D apex_pos(0.30F, HP::SHOULDER_Y + 0.25F, 0.08F);
+  QVector3D strike_pos(0.18F, HP::SHOULDER_Y - 0.15F, 0.62F);
+  QVector3D followthrough_pos(0.05F, HP::WAIST_Y + 0.10F, 0.50F);
 
+  // Variant-specific attack patterns
+  float strike_direction = kStrikeRightToLeft;
   switch (variant % 3) {
   case 1:
-    prepare_pos = QVector3D(-0.10F, HP::HEAD_TOP_Y + 0.15F, 0.0F);
-    raised_pos = QVector3D(-0.08F, HP::HEAD_TOP_Y + 0.18F, 0.05F);
-    strike_pos = QVector3D(0.35F, HP::SHOULDER_Y - 0.10F, 0.48F);
+    // Left-to-right diagonal slash
+    chamber_pos = QVector3D(-0.10F, HP::SHOULDER_Y + 0.22F, 0.04F);
+    apex_pos = QVector3D(-0.08F, HP::SHOULDER_Y + 0.28F, 0.10F);
+    strike_pos = QVector3D(0.32F, HP::SHOULDER_Y - 0.12F, 0.58F);
+    followthrough_pos = QVector3D(0.40F, HP::WAIST_Y + 0.08F, 0.48F);
+    strike_direction = kStrikeLeftToRight;
     break;
   case 2:
-    prepare_pos = QVector3D(0.35F, HP::SHOULDER_Y + 0.08F, -0.10F);
-    raised_pos = QVector3D(0.38F, HP::SHOULDER_Y + 0.05F, 0.0F);
-    strike_pos = QVector3D(0.15F, HP::WAIST_Y + 0.05F, 0.55F);
+    // Horizontal slash from right
+    chamber_pos = QVector3D(0.35F, HP::SHOULDER_Y + 0.10F, 0.0F);
+    apex_pos = QVector3D(0.38F, HP::SHOULDER_Y + 0.08F, 0.06F);
+    strike_pos = QVector3D(0.05F, HP::SHOULDER_Y - 0.05F, 0.65F);
+    followthrough_pos = QVector3D(-0.10F, HP::SHOULDER_Y - 0.10F, 0.55F);
     break;
   default:
     break;
@@ -524,43 +955,87 @@ void HumanoidPoseController::sword_slash_variant(float attack_phase,
   QVector3D hand_r_target;
   QVector3D hand_l_target;
 
-  auto easeInOutCubic = [](float t) {
-    return t < 0.5F ? 4.0F * t * t * t
-                    : 1.0F - std::pow(-2.0F * t + 2.0F, 3.0F) / 2.0F;
-  };
+  // Body dynamics
+  float torso_twist = 0.0F;
+  float forward_lean = 0.0F;
+  float shoulder_rotation = 0.0F;
+  float weight_shift = 0.0F;
+
+  auto smoothstep = [](float t) { return t * t * (3.0F - 2.0F * t); };
+  auto ease_out = [](float t) { return 1.0F - (1.0F - t) * (1.0F - t); };
+
+  if (attack_phase < 0.15F) {
+    float t = attack_phase / 0.15F;
+    float ease_t = t * t;
+    hand_r_target = rest_pos * (1.0F - ease_t) + chamber_pos * ease_t;
+    hand_l_target = QVector3D(-0.20F, HP::SHOULDER_Y - 0.02F, 0.15F);
+
+    torso_twist = strike_direction * (-0.05F * ease_t);
+    shoulder_rotation = 0.03F * ease_t;
+  } else if (attack_phase < 0.28F) {
+    float t = (attack_phase - 0.15F) / 0.13F;
+    float ease_t = smoothstep(t);
+    hand_r_target = chamber_pos * (1.0F - ease_t) + apex_pos * ease_t;
+    hand_l_target = QVector3D(-0.20F, HP::SHOULDER_Y - 0.04F, 0.17F);
+
+    torso_twist = strike_direction * (-0.05F);
+    shoulder_rotation = 0.03F + 0.02F * ease_t;
+    weight_shift = -0.02F * ease_t;
+  } else if (attack_phase < 0.48F) {
+    float t = (attack_phase - 0.28F) / 0.20F;
+    float power_t = t * t * t;
+    hand_r_target = apex_pos * (1.0F - power_t) + strike_pos * power_t;
+    hand_l_target =
+        QVector3D(-0.20F + 0.08F * power_t,
+                  HP::SHOULDER_Y - 0.04F - 0.06F * power_t, 0.17F + 0.22F * power_t);
+
+    torso_twist = strike_direction * (-0.05F + 0.14F * power_t);
+    forward_lean = 0.10F * power_t;
+    shoulder_rotation = 0.05F - 0.08F * power_t;
+    weight_shift = -0.02F + 0.08F * power_t;
+  } else if (attack_phase < 0.62F) {
+    float t = (attack_phase - 0.48F) / 0.14F;
+    float ease_t = smoothstep(t);
+    hand_r_target = strike_pos * (1.0F - ease_t) + followthrough_pos * ease_t;
+    hand_l_target = QVector3D(-0.12F, HP::SHOULDER_Y - 0.10F, 0.39F);
+
+    torso_twist = strike_direction * (0.09F - 0.03F * t);
+    forward_lean = 0.10F - 0.02F * t;
+    weight_shift = 0.06F;
+  } else {
+    float t = (attack_phase - 0.62F) / 0.38F;
+    float ease_t = ease_out(t);
+    hand_r_target = followthrough_pos * (1.0F - ease_t) + rest_pos * ease_t;
+    hand_l_target =
+        QVector3D(-0.12F - 0.08F * ease_t, HP::SHOULDER_Y - 0.10F * (1.0F - ease_t),
+                  0.39F * (1.0F - ease_t) + 0.15F * ease_t);
 
-  auto smoothstep = [](float edge0, float edge1, float x) {
-    float t = std::clamp((x - edge0) / (edge1 - edge0), 0.0F, 1.0F);
-    return t * t * (3.0F - 2.0F * t);
-  };
+    torso_twist = 0.06F * strike_direction * (1.0F - ease_t);
+    forward_lean = 0.08F * (1.0F - ease_t);
+    weight_shift = 0.06F * (1.0F - ease_t);
+  }
 
-  auto lerp = [](float a, float b, float t) { return a * (1.0F - t) + b * t; };
+  // Apply body dynamics
+  if (std::abs(torso_twist) > 0.001F) {
+    m_pose.shoulder_r.setZ(m_pose.shoulder_r.z() + torso_twist);
+    m_pose.shoulder_l.setZ(m_pose.shoulder_l.z() - torso_twist * 0.6F);
+  }
 
-  if (attack_phase < 0.18F) {
-    float const t = easeInOutCubic(attack_phase / 0.18F);
-    hand_r_target = rest_pos * (1.0F - t) + prepare_pos * t;
-    hand_l_target =
-        QVector3D(-0.21F, HP::SHOULDER_Y - 0.02F - 0.03F * t, 0.15F);
-  } else if (attack_phase < 0.32F) {
-    float const t = easeInOutCubic((attack_phase - 0.18F) / 0.14F);
-    hand_r_target = prepare_pos * (1.0F - t) + raised_pos * t;
-    hand_l_target = QVector3D(-0.21F, HP::SHOULDER_Y - 0.05F, 0.17F);
-  } else if (attack_phase < 0.52F) {
-    float t = (attack_phase - 0.32F) / 0.20F;
-    t = t * t * t;
-    hand_r_target = raised_pos * (1.0F - t) + strike_pos * t;
-    hand_l_target = QVector3D(
-        -0.21F, HP::SHOULDER_Y - 0.03F * (1.0F - 0.5F * t), 0.17F + 0.20F * t);
-  } else if (attack_phase < 0.72F) {
-    float const t = easeInOutCubic((attack_phase - 0.52F) / 0.20F);
-    hand_r_target = strike_pos * (1.0F - t) + recover_pos * t;
-    hand_l_target = QVector3D(-0.20F, HP::SHOULDER_Y - 0.015F * (1.0F - t),
-                              lerp(0.37F, 0.20F, t));
-  } else {
-    float const t = smoothstep(0.72F, 1.0F, attack_phase);
-    hand_r_target = recover_pos * (1.0F - t) + rest_pos * t;
-    hand_l_target = QVector3D(-0.20F - 0.02F * (1.0F - t), HP::SHOULDER_Y,
-                              lerp(0.20F, 0.15F, t));
+  if (std::abs(shoulder_rotation) > 0.001F) {
+    m_pose.shoulder_r.setY(m_pose.shoulder_r.y() - shoulder_rotation);
+    m_pose.shoulder_l.setY(m_pose.shoulder_l.y() + shoulder_rotation * 0.4F);
+  }
+
+  if (forward_lean > 0.001F) {
+    m_pose.shoulder_l.setZ(m_pose.shoulder_l.z() + forward_lean);
+    m_pose.shoulder_r.setZ(m_pose.shoulder_r.z() + forward_lean);
+    m_pose.neck_base.setZ(m_pose.neck_base.z() + forward_lean * 0.7F);
+    m_pose.head_pos.setZ(m_pose.head_pos.z() + forward_lean * 0.5F);
+  }
+
+  if (std::abs(weight_shift) > 0.001F) {
+    m_pose.foot_r.setZ(m_pose.foot_r.z() + weight_shift);
+    m_pose.knee_r.setZ(m_pose.knee_r.z() + weight_shift * 0.6F);
   }
 
   placeHandAt(false, hand_r_target);
@@ -573,66 +1048,180 @@ void HumanoidPoseController::spear_thrust_variant(float attack_phase,
 
   attack_phase = std::clamp(attack_phase, 0.0F, 1.0F);
 
-  QVector3D guard_pos(0.28F, HP::SHOULDER_Y + 0.05F, 0.25F);
-  QVector3D prepare_pos(0.35F, HP::SHOULDER_Y + 0.08F, 0.05F);
-  QVector3D thrust_pos(0.32F, HP::SHOULDER_Y + 0.10F, 0.90F);
-  QVector3D recover_pos(0.28F, HP::SHOULDER_Y + 0.06F, 0.40F);
+  // Thrust height constants for variants
+  constexpr float kThrustHigh = 1.0F;
+  constexpr float kThrustMiddle = 0.0F;
+  constexpr float kThrustLow = -1.0F;
+
+  // Base key positions
+  QVector3D guard_pos(0.26F, HP::SHOULDER_Y + 0.08F, 0.28F);
+  QVector3D chamber_pos(0.32F, HP::SHOULDER_Y + 0.12F, 0.02F);
+  QVector3D thrust_pos(0.28F, HP::SHOULDER_Y + 0.05F, 0.95F);
+  QVector3D extended_pos(0.25F, HP::SHOULDER_Y + 0.02F, 1.05F);
+  QVector3D recover_pos(0.28F, HP::SHOULDER_Y + 0.06F, 0.45F);
+
+  // Variant-specific thrust patterns
+  float thrust_height = kThrustMiddle;
+  float crouch_amount = 0.0F;
 
   switch (variant % 3) {
   case 1:
-    prepare_pos = QVector3D(0.30F, HP::SHOULDER_Y + 0.15F, 0.0F);
-    thrust_pos = QVector3D(0.28F, HP::WAIST_Y + 0.20F, 0.95F);
+    // Low thrust - target legs/lower body, with crouch
+    chamber_pos = QVector3D(0.30F, HP::SHOULDER_Y + 0.18F, 0.0F);
+    thrust_pos = QVector3D(0.28F, HP::WAIST_Y + 0.15F, 0.98F);
+    extended_pos = QVector3D(0.25F, HP::WAIST_Y + 0.10F, 1.08F);
+    recover_pos = QVector3D(0.28F, HP::SHOULDER_Y - 0.05F, 0.42F);
+    thrust_height = kThrustLow;
+    crouch_amount = 0.08F;
     break;
   case 2:
-    prepare_pos = QVector3D(0.40F, HP::SHOULDER_Y, 0.10F);
-    thrust_pos = QVector3D(0.35F, HP::SHOULDER_Y + 0.05F, 0.85F);
+    // High thrust - target head/upper body, slight upward angle
+    chamber_pos = QVector3D(0.35F, HP::SHOULDER_Y + 0.05F, 0.08F);
+    thrust_pos = QVector3D(0.30F, HP::SHOULDER_Y + 0.12F, 0.92F);
+    extended_pos = QVector3D(0.28F, HP::SHOULDER_Y + 0.15F, 1.02F);
+    thrust_height = kThrustHigh;
     break;
   default:
+    // Standard middle thrust
     break;
   }
 
   QVector3D hand_r_target;
   QVector3D hand_l_target;
 
+  // Body dynamics for spear thrust variant
+  float forward_lean = 0.0F;
+  float torso_twist = 0.0F;
+  float shoulder_drop = 0.0F;
+  float step_forward = 0.0F;
+  float hip_rotation = 0.0F;
+  float crouch_factor = 0.0F;
+
   auto easeInOutCubic = [](float t) {
     return t < 0.5F ? 4.0F * t * t * t
                     : 1.0F - std::pow(-2.0F * t + 2.0F, 3.0F) / 2.0F;
   };
 
-  auto smoothstep = [](float edge0, float edge1, float x) {
-    float t = std::clamp((x - edge0) / (edge1 - edge0), 0.0F, 1.0F);
-    return t * t * (3.0F - 2.0F * t);
-  };
+  auto smoothstep = [](float t) { return t * t * (3.0F - 2.0F * t); };
+  auto ease_out = [](float t) { return 1.0F - (1.0F - t) * (1.0F - t); };
 
-  auto lerp = [](float a, float b, float t) { return a * (1.0F - t) + b * t; };
-
-  if (attack_phase < 0.20F) {
-    float const t = easeInOutCubic(attack_phase / 0.20F);
-    hand_r_target = guard_pos * (1.0F - t) + prepare_pos * t;
-    hand_l_target = QVector3D(-0.10F, HP::SHOULDER_Y - 0.05F,
-                              0.20F * (1.0F - t) + 0.08F * t);
-  } else if (attack_phase < 0.30F) {
-    hand_r_target = prepare_pos;
-    hand_l_target = QVector3D(-0.10F, HP::SHOULDER_Y - 0.05F, 0.08F);
-  } else if (attack_phase < 0.50F) {
-    float t = (attack_phase - 0.30F) / 0.20F;
-    t = t * t * t;
-    hand_r_target = prepare_pos * (1.0F - t) + thrust_pos * t;
+  if (attack_phase < 0.18F) {
+    // Phase 1: Chamber - pull spear back, coil body
+    float const t = easeInOutCubic(attack_phase / 0.18F);
+    hand_r_target = guard_pos * (1.0F - t) + chamber_pos * t;
+    hand_l_target = QVector3D(-0.08F, HP::SHOULDER_Y - 0.04F,
+                              0.22F * (1.0F - t) + 0.06F * t);
+
+    torso_twist = -0.06F * t;
+    hip_rotation = -0.04F * t;
+    forward_lean = -0.03F * t;
+    crouch_factor = crouch_amount * t;
+  } else if (attack_phase < 0.28F) {
+    // Phase 2: Tension hold
+    hand_r_target = chamber_pos;
+    hand_l_target = QVector3D(-0.08F, HP::SHOULDER_Y - 0.04F, 0.06F);
+
+    torso_twist = -0.06F;
+    hip_rotation = -0.04F;
+    forward_lean = -0.03F;
+    crouch_factor = crouch_amount;
+  } else if (attack_phase < 0.48F) {
+    // Phase 3: Explosive thrust
+    float t = (attack_phase - 0.28F) / 0.20F;
+    float power_t = t * t * t;
+    hand_r_target = chamber_pos * (1.0F - power_t) + thrust_pos * power_t;
     hand_l_target =
-        QVector3D(-0.10F + 0.05F * t, HP::SHOULDER_Y - 0.05F + 0.03F * t,
-                  0.08F + 0.45F * t);
-  } else if (attack_phase < 0.70F) {
-    float const t = easeInOutCubic((attack_phase - 0.50F) / 0.20F);
-    hand_r_target = thrust_pos * (1.0F - t) + recover_pos * t;
-    hand_l_target = QVector3D(-0.05F * (1.0F - t) - 0.10F * t,
-                              HP::SHOULDER_Y - 0.02F * (1.0F - t) - 0.06F * t,
-                              lerp(0.53F, 0.35F, t));
+        QVector3D(-0.08F + 0.06F * power_t, HP::SHOULDER_Y - 0.04F + 0.02F * power_t,
+                  0.06F + 0.50F * power_t);
+
+    torso_twist = -0.06F + 0.14F * power_t;
+    hip_rotation = -0.04F + 0.10F * power_t;
+    forward_lean = -0.05F + 0.20F * power_t;
+    shoulder_drop = 0.05F * power_t;
+    step_forward = 0.12F * power_t;
+    crouch_factor = crouch_amount * (1.0F - power_t * 0.3F);
+
+    // Adjust for thrust height
+    if (thrust_height < 0) {
+      // Low thrust - additional crouch during strike
+      crouch_factor += 0.06F * power_t;
+    } else if (thrust_height > 0) {
+      // High thrust - rise up slightly
+      crouch_factor -= 0.03F * power_t;
+    }
+  } else if (attack_phase < 0.60F) {
+    // Phase 4: Full extension
+    float const t = smoothstep((attack_phase - 0.48F) / 0.12F);
+    hand_r_target = thrust_pos * (1.0F - t) + extended_pos * t;
+    hand_l_target = QVector3D(-0.02F, HP::SHOULDER_Y - 0.02F, 0.56F + 0.10F * t);
+
+    torso_twist = 0.08F;
+    hip_rotation = 0.06F;
+    forward_lean = 0.15F + 0.05F * t;
+    shoulder_drop = 0.05F + 0.02F * t;
+    step_forward = 0.12F + 0.04F * t;
+    crouch_factor = crouch_amount * 0.7F;
+  } else if (attack_phase < 0.78F) {
+    // Phase 5: Withdraw
+    float const t = easeInOutCubic((attack_phase - 0.60F) / 0.18F);
+    hand_r_target = extended_pos * (1.0F - t) + recover_pos * t;
+    hand_l_target = QVector3D(-0.02F * (1.0F - t) - 0.08F * t,
+                              HP::SHOULDER_Y - 0.02F * (1.0F - t) - 0.05F * t,
+                              0.66F * (1.0F - t) + 0.38F * t);
+
+    torso_twist = 0.08F * (1.0F - t);
+    hip_rotation = 0.06F * (1.0F - t);
+    forward_lean = 0.20F * (1.0F - t) + 0.04F * t;
+    shoulder_drop = 0.07F * (1.0F - t);
+    step_forward = 0.16F * (1.0F - t * 0.5F);
+    crouch_factor = crouch_amount * 0.7F * (1.0F - t);
   } else {
-    float const t = smoothstep(0.70F, 1.0F, attack_phase);
+    // Phase 6: Recovery
+    float const t = ease_out((attack_phase - 0.78F) / 0.22F);
     hand_r_target = recover_pos * (1.0F - t) + guard_pos * t;
     hand_l_target =
-        QVector3D(-0.10F - 0.02F * (1.0F - t),
-                  HP::SHOULDER_Y - 0.06F + 0.01F * t, lerp(0.35F, 0.25F, t));
+        QVector3D(-0.08F, HP::SHOULDER_Y - 0.05F * (1.0F - t) - 0.02F * t,
+                  0.38F * (1.0F - t) + 0.22F * t);
+
+    forward_lean = 0.04F * (1.0F - t);
+    step_forward = 0.08F * (1.0F - t);
+  }
+
+  // Apply body dynamics
+  if (std::abs(torso_twist) > 0.001F) {
+    m_pose.shoulder_r.setZ(m_pose.shoulder_r.z() + torso_twist);
+    m_pose.shoulder_l.setZ(m_pose.shoulder_l.z() - torso_twist * 0.4F);
+  }
+
+  if (std::abs(hip_rotation) > 0.001F) {
+    m_pose.pelvis_pos.setZ(m_pose.pelvis_pos.z() + hip_rotation * 0.5F);
+  }
+
+  if (std::abs(forward_lean) > 0.001F) {
+    m_pose.shoulder_l.setZ(m_pose.shoulder_l.z() + forward_lean);
+    m_pose.shoulder_r.setZ(m_pose.shoulder_r.z() + forward_lean);
+    m_pose.neck_base.setZ(m_pose.neck_base.z() + forward_lean * 0.85F);
+    m_pose.head_pos.setZ(m_pose.head_pos.z() + forward_lean * 0.7F);
+  }
+
+  if (shoulder_drop > 0.001F) {
+    m_pose.shoulder_r.setY(m_pose.shoulder_r.y() - shoulder_drop);
+    m_pose.shoulder_l.setY(m_pose.shoulder_l.y() - shoulder_drop * 0.3F);
+  }
+
+  if (step_forward > 0.001F) {
+    m_pose.foot_r.setZ(m_pose.foot_r.z() + step_forward);
+    m_pose.knee_r.setZ(m_pose.knee_r.z() + step_forward * 0.6F);
+    m_pose.foot_l.setZ(m_pose.foot_l.z() - step_forward * 0.15F);
+  }
+
+  // Apply crouch for low thrusts
+  if (crouch_factor > 0.001F) {
+    m_pose.pelvis_pos.setY(m_pose.pelvis_pos.y() - crouch_factor);
+    m_pose.shoulder_l.setY(m_pose.shoulder_l.y() - crouch_factor * 0.6F);
+    m_pose.shoulder_r.setY(m_pose.shoulder_r.y() - crouch_factor * 0.6F);
+    m_pose.neck_base.setY(m_pose.neck_base.y() - crouch_factor * 0.5F);
+    m_pose.head_pos.setY(m_pose.head_pos.y() - crouch_factor * 0.4F);
   }
 
   placeHandAt(false, hand_r_target);

+ 2 - 0
render/humanoid/pose_controller.h

@@ -15,6 +15,7 @@ public:
   void standIdle();
 
   void kneel(float depth);
+  void kneelTransition(float progress, bool standing_up);
 
   void lean(const QVector3D &direction, float amount);
 
@@ -24,6 +25,7 @@ public:
   void meleeStrike(float strike_phase);
   void graspTwoHanded(const QVector3D &grip_center, float hand_separation);
   void spearThrust(float attack_phase);
+  void spearThrustFromHold(float attack_phase, float hold_depth);
   void sword_slash(float attack_phase);
   void sword_slash_variant(float attack_phase, std::uint8_t variant);
   void spear_thrust_variant(float attack_phase, std::uint8_t variant);