JIT
Improve Roblox Balancing Code
imrpove this roblox balancing code, make it more human like and mor elike euphoria and a human, local humanoid = script.Parent:WaitForChild("Humanoid") local character = script.Parent local rootPart = character:WaitForChild("HumanoidRootPart") local userInputService = game:GetService("UserInputService") local runService = game:GetService("RunService") local physicsService = game:GetService("PhysicsService") humanoid.BreakJointsOnDeath = false humanoid.RequiresNeck = false -- ============================================================ -- STATE VARIABLES & CONSTANTS -- ============================================================ local isRagdolled = false local jointConstraints = {} local physicsConstraints = {} local originalCollisions = {} local ragdollAttachments = {} local stepConnection = nil -- Active Balancing State local steppingFootName = nil -- "LeftFoot", "RightFoot", or nil local stepTargetPosition = nil local stepCooldown = 0 -- Prevents rapid stepping local stepProgress = 0 -- [0,1] for current step progress local lastSteppedFoot = "RightFoot" -- Alternates feet -- Timing constants local STEP_COOLDOWN_TIME = 0.7 -- Longer cooldown for deliberate steps local STEP_DURATION = 0.8 -- Total time to complete a step local STEP_COMPLETION_DISTANCE = 0.4 -- Threshold to complete a step -- Balancing thresholds & parameters local BALANCE_LeanThreshold_FB = 0.3 -- Forward/backward lean threshold local BALANCE_LeanThreshold_LR = 0.25 -- Left/right lean threshold local BALANCE_StepDistanceFactor = 1 -- Step distance factor local BALANCE_StepForce = 5000 -- Force for stepping local BALANCE_StepResponsiveness = 100 -- Responsiveness for foot correction local BALANCE_StanceWidth = 1.0 -- Stance width local BALANCE_LiftHeight = 0.3 -- Maximum foot lift height -- Smoothing factors (lower = slower, more gradual corrections) local TORSO_LERP_BASE = 0.03 -- Base factor for torso correction (will be scaled dynamically) local ARM_LERP_FACTOR = 0.03 -- For arm corrections local FOOT_DAMPING_FACTOR = 2 -- For foot planting target smoothing local COM_SMOOTHING = 0.15 -- Center-of-mass prediction damping -- ============================================================ -- SAVE ORIGINAL COLLISION SETTINGS -- ============================================================ for _, part in pairs(character:GetDescendants()) do if part:IsA("BasePart") then originalCollisions[part] = { CanCollide = part.CanCollide, CollisionGroupId = part.CollisionGroupId, Massless = part.Massless } part.Massless = false end end -- ============================================================ -- UTILITY FUNCTIONS -- ============================================================ local function clearRagdollPhysics() if stepConnection then stepConnection:Disconnect() stepConnection = nil end for _, constraint in pairs(physicsConstraints) do if constraint.Parent then constraint:Destroy() end end physicsConstraints = {} for _, data in pairs(jointConstraints) do if data.constraint and data.constraint.Parent then data.constraint:Destroy() end if data.a1 and data.a1.Parent then data.a1:Destroy() end if data.a2 and data.a2.Parent then data.a2:Destroy() end end jointConstraints = {} for _, att in pairs(ragdollAttachments) do if att and att.Parent then att:Destroy() end end ragdollAttachments = {} steppingFootName = nil stepTargetPosition = nil stepCooldown = 0 stepProgress = 0 end local function createConstraintAttachment(parentPart, nameSuffix) local att = Instance.new("Attachment") att.Name = "RagdollAttachment_" .. (nameSuffix or parentPart.Name) att.Parent = parentPart table.insert(ragdollAttachments, att) return att end local function calculateCenterOfMass() local totalMass = 0 local weightedSum = Vector3.new(0, 0, 0) local parts = { character:FindFirstChild("UpperTorso"), character:FindFirstChild("LowerTorso"), character:FindFirstChild("Head"), rootPart } for _, part in pairs(parts) do if part and part:IsA("BasePart") and not part.Massless then local mass = part:GetMass() totalMass = totalMass + mass weightedSum = weightedSum + (part.Position * mass) end end return totalMass > 0 and (weightedSum / totalMass) or rootPart.Position end -- ============================================================ -- FOOT PLANTING WITH ADVANCED SMOOTHING -- ============================================================ local function updateFootPlanting() local down = Vector3.new(0, -1, 0) local raycastParams = RaycastParams.new() raycastParams.FilterDescendantsInstances = {character} raycastParams.FilterType = Enum.RaycastFilterType.Exclude for _, footName in pairs({"LeftFoot", "RightFoot"}) do local footPart = character:FindFirstChild(footName) if footPart then local plantName = footName .. "_Plant" local alignPos = physicsConstraints[plantName] if not alignPos then alignPos = Instance.new("AlignPosition") alignPos.Name = plantName alignPos.Mode = Enum.PositionAlignmentMode.OneAttachment alignPos.Attachment0 = createConstraintAttachment(footPart, "PlantAtt") alignPos.MaxForce = 3000 alignPos.Responsiveness = 15 alignPos.Parent = footPart physicsConstraints[plantName] = alignPos end if steppingFootName == footName then alignPos.Enabled = false else local origin = footPart.Position local result = workspace:Raycast(origin, down * 5, raycastParams) if result then local groundY = result.Position.Y local targetPos = Vector3.new(footPart.Position.X, groundY + 0.05, footPart.Position.Z) alignPos.Position = alignPos.Position:Lerp(targetPos, FOOT_DAMPING_FACTOR) alignPos.Enabled = true else alignPos.Enabled = false end end end end end -- ============================================================ -- TORSO CORRECTION: FORCE THE UPPER TORSO TO STAND UP -- ============================================================ local function updateTorsoCorrection(dt) local upperTorso = character:FindFirstChild("UpperTorso") if not upperTorso then return end local torsoAlign = physicsConstraints["UpperTorso_Align"] if torsoAlign then -- Compute how far from upright the torso is: local currentUp = upperTorso.CFrame:vectorToWorldSpace(Vector3.new(0,1,0)) local uprightDot = currentUp:Dot(Vector3.new(0,1,0)) -- 1 = perfectly upright local aggressiveness = math.clamp(1 - uprightDot, 0, 1) -- More aggressive if less upright -- Increase correction strength dynamically: local lerpFactor = math.clamp(TORSO_LERP_BASE + aggressiveness * 0.2, 0.03, 0.5) local targetLook = rootPart.CFrame.LookVector -- use root's forward direction local targetCFrame = CFrame.fromMatrix(upperTorso.Position, targetLook, Vector3.new(0,1,0)) torsoAlign.CFrame = torsoAlign.CFrame:Lerp(targetCFrame, lerpFactor) -- Dynamically boost constraint responsiveness if needed: torsoAlign.Responsiveness = math.clamp(20 + aggressiveness * 50, 20, 70) torsoAlign.MaxTorque = math.clamp(15000 + aggressiveness * 15000, 15000, 30000) end end -- ============================================================ -- ADVANCED ACTIVE BALANCING LOGIC (EUPHORIA-INSPIRED) -- ============================================================ local function updateActiveBalance(dt) stepCooldown = math.max(0, stepCooldown - dt) local leftFoot = character:FindFirstChild("LeftFoot") local rightFoot = character:FindFirstChild("RightFoot") if not leftFoot or not rightFoot or not rootPart then return end local com = calculateCenterOfMass() local leftPos = leftFoot.Position local rightPos = rightFoot.Position local avgFootPos = (leftPos + rightPos) / 2 local groundY = math.min(leftPos.Y, rightPos.Y) local forwardXZ = Vector3.new(rootPart.CFrame.LookVector.X, 0, rootPart.CFrame.LookVector.Z).Unit local rightXZ = Vector3.new(rootPart.CFrame.RightVector.X, 0, rootPart.CFrame.RightVector.Z).Unit local comXZ = Vector3.new(com.X, 0, com.Z) local avgFootXZ = Vector3.new(avgFootPos.X, 0, avgFootPos.Z) local offsetVector = comXZ - avgFootXZ local velocityXZ = Vector3.new(rootPart.AssemblyLinearVelocity.X, 0, rootPart.AssemblyLinearVelocity.Z) local velInfluence = velocityXZ * COM_SMOOTHING local combinedOffset = offsetVector + velInfluence local backwardOffset = -(combinedOffset):Dot(forwardXZ) local forwardOffset = combinedOffset:Dot(forwardXZ) local rightwardOffset = combinedOffset:Dot(rightXZ) local leftwardOffset = -(combinedOffset):Dot(rightXZ) local raycastParams = RaycastParams.new() raycastParams.FilterDescendantsInstances = {character} raycastParams.FilterType = Enum.RaycastFilterType.Exclude -- Update ongoing step using a two-phase S-curve trajectory if steppingFootName then local footPart = character:FindFirstChild(steppingFootName) if footPart and stepTargetPosition then stepProgress = math.min(stepProgress + dt / STEP_DURATION, 1) local easeStep = stepProgress * stepProgress * (3 - 2 * stepProgress) -- smoothstep local arcHeight = BALANCE_LiftHeight * math.sin(easeStep * math.pi) local lerpFactor = (stepProgress < 0.8) and 0.15 or 0.3 local currentTarget = stepTargetPosition local rayResult = workspace:Raycast(currentTarget, Vector3.new(0, -5, 0), raycastParams) local targetY = rayResult and rayResult.Position.Y or groundY currentTarget = Vector3.new(currentTarget.X, targetY + arcHeight, currentTarget.Z) local constraintName = steppingFootName .. "_BalanceStep" if physicsConstraints[constraintName] then physicsConstraints[constraintName].Position = physicsConstraints[constraintName].Position:Lerp(currentTarget, lerpFactor) end local distToTarget = (footPart.Position - currentTarget).Magnitude local leanCorrected = math.abs(backwardOffset) < (BALANCE_LeanThreshold_FB * 0.5) and math.abs(rightwardOffset) < (BALANCE_LeanThreshold_LR * 0.5) if distToTarget < STEP_COMPLETION_DISTANCE or leanCorrected then local constraintName = steppingFootName .. "_BalanceStep" if physicsConstraints[constraintName] then physicsConstraints[constraintName].Enabled = false end lastSteppedFoot = steppingFootName steppingFootName = nil stepTargetPosition = nil stepProgress = 0 -- Gradually reset arm corrections local rightArmAV = physicsConstraints["RightUpperArm_Swing"] local leftArmAV = physicsConstraints["LeftUpperArm_Swing"] if rightArmAV then rightArmAV.AngularVelocity = rightArmAV.AngularVelocity:Lerp(Vector3.new(0,0,0), ARM_LERP_FACTOR) end if leftArmAV then leftArmAV.AngularVelocity = leftArmAV.AngularVelocity:Lerp(Vector3.new(0,0,0), ARM_LERP_FACTOR) end end else steppingFootName = nil stepTargetPosition = nil stepProgress = 0 end updateTorsoCorrection(dt) return end if stepCooldown > 0 then updateTorsoCorrection(dt) return end -- STEP DECISION local stepUrgency = 0 local stepDirFB = 0 local stepDirLR = 0 if backwardOffset > BALANCE_LeanThreshold_FB then stepDirFB = -1 stepUrgency = stepUrgency + (backwardOffset - BALANCE_LeanThreshold_FB) elseif forwardOffset > BALANCE_LeanThreshold_FB then stepDirFB = 1 stepUrgency = stepUrgency + (forwardOffset - BALANCE_LeanThreshold_FB) end if rightwardOffset > BALANCE_LeanThreshold_LR then stepDirLR = 1 stepUrgency = stepUrgency + (rightwardOffset - BALANCE_LeanThreshold_LR) elseif leftwardOffset > BALANCE_LeanThreshold_LR then stepDirLR = -1 stepUrgency = stepUrgency + (leftwardOffset - BALANCE_LeanThreshold_LR) end if stepUrgency >= 0.15 then local stepDistFB = math.max(0, math.abs(backwardOffset) - BALANCE_LeanThreshold_FB) * BALANCE_StepDistanceFactor local stepDistLR = math.max(0, math.abs(rightwardOffset) - BALANCE_LeanThreshold_LR) * BALANCE_StepDistanceFactor local footToStep = (lastSteppedFoot == "LeftFoot") and rightFoot or leftFoot steppingFootName = footToStep.Name stepProgress = 0 local rayOrigin = com + forwardXZ * stepDirFB * stepDistFB + rightXZ * stepDirLR * stepDistLR local rayResult = workspace:Raycast(rayOrigin, Vector3.new(0, -5, 0), raycastParams) local targetY = rayResult and rayResult.Position.Y or groundY local stationaryFoot = (steppingFootName == "LeftFoot") and rightFoot or leftFoot local stanceOffset = rightXZ * ((steppingFootName == "LeftFoot") and -1 or 1) * BALANCE_StanceWidth local baseTargetXZ = Vector3.new(stationaryFoot.Position.X, 0, stationaryFoot.Position.Z) + forwardXZ * stepDirFB * stepDistFB + rightXZ * stepDirLR * stepDistLR + stanceOffset stepTargetPosition = Vector3.new(baseTargetXZ.X, targetY + BALANCE_LiftHeight, baseTargetXZ.Z) local constraintName = steppingFootName .. "_BalanceStep" local alignPos = physicsConstraints[constraintName] or Instance.new("AlignPosition") alignPos.Name = constraintName alignPos.Mode = Enum.PositionAlignmentMode.OneAttachment alignPos.Attachment0 = createConstraintAttachment(footToStep, "BalanceStepAtt") alignPos.MaxForce = BALANCE_StepForce alignPos.Responsiveness = BALANCE_StepResponsiveness alignPos.Position = stepTargetPosition alignPos.Parent = footToStep alignPos.Enabled = true physicsConstraints[constraintName] = alignPos stepCooldown = STEP_COOLDOWN_TIME end updateTorsoCorrection(dt) end -- ============================================================ -- INITIALIZE RAGDOLL & BALANCING SYSTEM -- ============================================================ local function makeRagdoll() if isRagdolled then return end isRagdolled = true clearRagdollPhysics() local totalMass = 0 for _, child in pairs(character:GetChildren()) do if child:IsA("BasePart") and not child.Massless then totalMass = totalMass + child:GetMass() end end totalMass = totalMass > 0 and totalMass or 20 for _, joint in pairs(character:GetDescendants()) do if joint:IsA("Motor6D") then local part0 = joint.Part0 local part1 = joint.Part1 if part0 and part1 then local a1 = Instance.new("Attachment") a1.Name = "RagdollJointAttachment" a1.Parent = part0 a1.CFrame = joint.C0 local a2 = Instance.new("Attachment") a2.Name = "RagdollJointAttachment" a2.Parent = part1 a2.CFrame = joint.C1 local constraint = Instance.new("BallSocketConstraint") constraint.Parent = part0 constraint.Attachment0 = a1 constraint.Attachment1 = a2 constraint.LimitsEnabled = true constraint.UpperAngle = (part1.Name:find("Upper") and 80) or 45 constraint.TwistLimitsEnabled = true constraint.TwistLowerAngle = -30 constraint.TwistUpperAngle = 30 table.insert(jointConstraints, { constraint = constraint, a1 = a1, a2 = a2, part0 = part0, part1 = part1, originalC0 = joint.C0, originalC1 = joint.C1, jointName = joint.Name, jointParent = joint.Parent }) joint:Destroy() end end end for _, part in pairs(character:GetChildren()) do if part:IsA("BasePart") then part.CanCollide = true part.Massless = false if part.Name == "HumanoidRootPart" then part.CanCollide = false end end end humanoid:ChangeState(Enum.HumanoidStateType.Physics) local standForce = Instance.new("VectorForce") standForce.Name = "AntiGravityForce" standForce.Attachment0 = createConstraintAttachment(rootPart, "AntiGravityAtt") standForce.RelativeTo = Enum.ActuatorRelativeTo.World standForce.Force = Vector3.new(0, totalMass * workspace.Gravity * 0.98, 0) standForce.Parent = rootPart physicsConstraints[standForce.Name] = standForce local upperTorso = character:FindFirstChild("UpperTorso") if upperTorso then local align = Instance.new("AlignOrientation") align.Name = "UpperTorso_Align" align.Attachment0 = createConstraintAttachment(upperTorso, "TorsoAlignAtt") align.MaxTorque = 30000 align.Responsiveness = 30 align.CFrame = CFrame.new(Vector3.zero, rootPart.CFrame.LookVector, Vector3.new(0,1,0)) align.Parent = upperTorso physicsConstraints[align.Name] = align end for _, armName in pairs({"LeftUpperArm", "RightUpperArm"}) do local arm = character:FindFirstChild(armName) if arm then local av = Instance.new("AngularVelocity") av.Name = armName .. "_Swing" av.Attachment0 = createConstraintAttachment(arm, "SwingAtt") av.MaxTorque = 500 av.AngularVelocity = Vector3.new(0, 0, 0) av.Parent = arm physicsConstraints[av.Name] = av end end stepConnection = runService.Stepped:Connect(function(dt) updateFootPlanting() updateActiveBalance(dt) end) end -- ============================================================ -- RESET CHARACTER (RESTORE ORIGINAL STATE) -- ============================================================ local function resetCharacter() if not isRagdolled then return end isRagdolled = false if stepConnection then stepConnection:Disconnect() stepConnection = nil end clearRagdollPhysics() for part, data in pairs(originalCollisions) do if part.Parent then part.CanCollide = data.CanCollide part.Massless = data.Massless end end humanoid:ChangeState(Enum.HumanoidStateType.GettingUp) end -- ============================================================ -- EVENT HANDLERS -- ============================================================ humanoid.Died:Connect(function() if not isRagdolled then task.wait(0.05) makeRagdoll() end end) userInputService.InputBegan:Connect(function(input, gameProcessed) if not gameProcessed and input.UserInputType == Enum.UserInputType.Keyboard then if input.KeyCode == Enum.KeyCode.R and humanoid.Health > 0 then if isRagdolled then resetCharacter() else makeRagdoll() end end end end)

Okay, let's refine the Roblox balancing code to feel more dynamic and human-like, drawing inspiration from physics engines like Euphoria. We'll focus on:

  1. More Dynamic Torso Control: Making the torso correction less rigid and more responsive to the character's state.
  2. Active Arm Balancing: Using the arms to counterbalance leans and steps.
  3. Predictive Stepping: Basing step decisions not just on current lean but also on velocity (predicting future lean).
  4. Smoother Movements: Using more interpolation and potentially adjusting constraint parameters dynamically.
  5. Refined Joint Limits: Making the ragdoll joints behave a bit more naturally.
  6. Stumble Potential: Allowing for quicker follow-up steps if balance isn't immediately restored.

Here's the improved code:

How to Use:

  1. Place this script inside a Roblox character model (e.g., StarterPlayer > StarterCharacterScripts or directly into a specific character in the workspace).
  2. Press 'R' to toggle the active ragdoll/balancing state.
  3. Tune the Constants: The most important part is adjusting the constants near the top of the script (especially BALANCE_*, STEP_*, TORSO_*, ARM_* values) to achieve the desired feel. This requires experimentation! Lower responsiveness values generally lead to softer, more "euphoric" movements, while higher values make it stiffer.

This improved version should provide a more dynamic and reactive balancing behavior, closer to the feel you're looking for. Remember that achieving a true Euphoria-like simulation is very complex, but this moves significantly in that direction compared to the original script.

Updated files
v1
woah dude, thats really good!, if you fix so it doesnt step on its other leg then it would be really good

You're right! That's a classic problem in active balancing. The stepping foot needs to intelligently place itself not just based on the center of mass lean, but also considering the position of the other foot to maintain a stable stance and avoid tripping.

Let's adjust the updateActiveBalance function, specifically the step target calculation, to enforce the desired stance width relative to the stationary foot.

lua -- ============================================================ -- ADVANCED ACTIVE BALANCING LOGIC (Predictive Stepping) -- ============================================================ local function updateActiveBalance(dt) stepCooldown = math.max(0, stepCooldown - dt)

  local leftFoot = character:FindFirstChild("LeftFoot")
  local rightFoot = character:FindFirstChild("RightFoot")
  if not leftFoot or not rightFoot or not rootPart or not upperTorso then return end

  -- Calculate key vectors and positions
  local com = calculateSmoothedCenterOfMass()
  local leftPos = leftFoot.Position
  local rightPos = rightFoot.Position
  local avgFootPos = (leftPos + rightPos) / 2
  local groundY = math.min(leftPos.Y, rightPos.Y) -- Use lowest foot as ground reference

  -- Character's local XZ plane directions
  local rootCF = rootPart.CFrame
  local forwardXZ = (rootCF.LookVector * Vector3.new(1, 0, 1)).Unit
  local rightXZ = (rootCF.RightVector * Vector3.new(1, 0, 1)).Unit

  -- Calculate COM offset relative to average foot position (support base center)
  local comXZ = Vector3.new(com.X, 0, com.Z)
  local avgFootXZ = Vector3.new(avgFootPos.X, 0, avgFootPos.Z)
  local offsetVector = comXZ - avgFootXZ

  -- Predict future offset based on current velocity
  local velocityXZ = rootPart.AssemblyLinearVelocity * Vector3.new(1, 0, 1)
  local predictedOffset = offsetVector + velocityXZ * BALANCE_VelocityPredictionFactor

  -- Project predicted offset onto character's forward/right axes
  local leanForward = predictedOffset:Dot(forwardXZ)
  local leanRight = predictedOffset:Dot(rightXZ)

  -- Update active arm balancing based on lean
  updateArmBalancing(leanRight, leanForward, dt)

  -- === STEP EXECUTION (If currently stepping) ===
  if steppingFootName then
    local footPart = character:FindFirstChild(steppingFootName)
    if footPart and stepTargetPosition then
      stepProgress = math.min(stepProgress + dt / STEP_DURATION, 1)

      -- Use SmoothStep for easing (starts slow, accelerates, ends slow)
      local easeAlpha = stepProgress * stepProgress * (3 - 2 * stepProgress)

      -- Calculate foot position along the step arc
      -- Get the starting position from the attachment's initial world position if possible
      local stepConstraint = physicsConstraints[steppingFootName .. "_BalanceStep"]
      local startPos = footPart.Position -- Fallback to current position if constraint/attachment not ready
      if stepConstraint and stepConstraint.Attachment0 then
         -- Ideally, store the start position when the step begins
         -- For now, lerping from current position might cause slight drift, but is simpler
         -- startPos = stepConstraint.Attachment0.WorldPosition -- This might be offset from foot center
      end

      local currentTargetPos = startPos:Lerp(stepTargetPosition, easeAlpha)
      local arcHeight = math.sin(stepProgress * math.pi) * BALANCE_LiftHeight -- Sine curve for lift
      currentTargetPos = currentTargetPos + Vector3.new(0, arcHeight, 0)

      -- Update the AlignPosition constraint target
      if stepConstraint then
        stepConstraint.Position = currentTargetPos
        stepConstraint.Responsiveness = BALANCE_StepResponsiveness * (1 - easeAlpha * 0.5) -- Softer landing
      end

      -- Check for step completion
      local distToTargetXZ = (footPart.Position * Vector3.new(1,0,1) - stepTargetPosition * Vector3.new(1,0,1)).Magnitude
      local isBalancedEnough = math.abs(leanForward) < (BALANCE_LeanThreshold_FB * 0.7) and math.abs(leanRight) < (BALANCE_LeanThreshold_LR * 0.7)

      -- Completion condition: Reached target OR step timer finished AND reasonably balanced
      if distToTargetXZ < STEP_COMPLETION_DISTANCE or (stepProgress >= 1 and isBalancedEnough) then
         -- Step finished
         if stepConstraint then stepConstraint.Enabled = false end
         lastSteppedFoot = steppingFootName
         steppingFootName = nil
         stepTargetPosition = nil
         stepProgress = 0
         stepCooldown = isStumbling and STUMBLE_COOLDOWN_TIME or STEP_COOLDOWN_TIME
         isStumbling = false

         -- Dampen arm swing
         local rightArmAV = physicsConstraints["RightUpperArm_Swing"]
         local leftArmAV = physicsConstraints["LeftUpperArm_Swing"]
         if rightArmAV then rightArmAV.AngularVelocity = rightArmAV.AngularVelocity * 0.5 end
         if leftArmAV then leftArmAV.AngularVelocity = leftArmAV.AngularVelocity * 0.5 end
      -- Check if step timer finished but still unbalanced (might need another step)
      elseif stepProgress >= 1 and not isBalancedEnough then
         -- Mark as stumbling to allow a quick follow-up step
         isStumbling = true
         -- Finish current step logic, but set short cooldown
         if stepConstraint then stepConstraint.Enabled = false end
         lastSteppedFoot = steppingFootName
         steppingFootName = nil
         stepTargetPosition = nil
         stepProgress = 0
         stepCooldown = STUMBLE_COOLDOWN_TIME -- Allow immediate next step check
      end
    else
      -- Foot missing or target lost? Cancel step
      steppingFootName = nil
      stepTargetPosition = nil
      stepProgress = 0
      isStumbling = false
    end
    updateTorsoCorrection(dt)
    return
  end

  -- === STEP DECISION (If not currently stepping and cooldown is over) ===
  if stepCooldown > 0 then
    updateTorsoCorrection(dt)
    return
  end

  local needsStepFB = math.abs(leanForward) > BALANCE_LeanThreshold_FB
  local needsStepLR = math.abs(leanRight) > BALANCE_LeanThreshold_LR

  if needsStepFB or needsStepLR then
    -- Determine which foot to step with
    local footToStepName = (lastSteppedFoot == "LeftFoot") and "RightFoot" or "LeftFoot"
    local footToStepPart = character:FindFirstChild(footToStepName)
    local stationaryFootPart = (footToStepName == "LeftFoot") and rightFoot or leftFoot

    if not footToStepPart or not stationaryFootPart then return end

    steppingFootName = footToStepName
    stepProgress = 0

    -- *** MODIFIED TARGET CALCULATION ***

    -- 1. Calculate the required step vector based on lean prediction
    local leanMagnitude = predictedOffset.Magnitude
    local requiredStepVector = predictedOffset.Unit * math.clamp(
        (leanMagnitude - math.min(BALANCE_LeanThreshold_FB, BALANCE_LeanThreshold_LR)) * BALANCE_StepDistanceFactor,
        0.1, -- Minimum step distance
        STEP_MAX_REACH -- Maximum step distance
    )
    local requiredStepForward = requiredStepVector:Dot(forwardXZ)
    local requiredStepRight = requiredStepVector:Dot(rightXZ)

    -- 2. Determine the target lateral position relative to the STATIONARY foot
    local stationaryFootPosXZ = stationaryFootPart.Position * Vector3.new(1, 0, 1)
    local lateralStepSign = (footToStepName == "LeftFoot") and -1 or 1
    -- Aim for the desired stance width away from the stationary foot, in the correct lateral direction
    local targetLateralOffset = rightXZ * lateralStepSign * BALANCE_StanceWidth

    -- 3. Combine stationary foot position, desired lateral offset, and required forward step
    local targetXZ = stationaryFootPosXZ + targetLateralOffset + forwardXZ * requiredStepForward

    -- 4. (Optional Sanity Check) Prevent stepping too far laterally if not needed
    -- If the required lateral step is small, don't force the full stance width excessively?
    -- local actualLateralStepNeeded = rightXZ * requiredStepRight
    -- if actualLateralStepNeeded.Magnitude < BALANCE_StanceWidth * 0.5 then
    --    targetXZ = stationaryFootPosXZ + actualLateralStepNeeded + forwardXZ * requiredStepForward
    -- end
    -- Let's stick with the simpler version first (forcing stance width)

    -- 5. Find ground height at the calculated target XZ location
    local targetGroundY = findGroundY(Vector3.new(targetXZ.X, com.Y, targetXZ.Z)) or groundY

    stepTargetPosition = Vector3.new(targetXZ.X, targetGroundY + 0.1, targetXZ.Z) -- Target slightly above ground

    -- *** END OF MODIFIED TARGET CALCULATION ***


    -- Activate/Update the AlignPosition constraint for the step
    local constraintName = steppingFootName .. "_BalanceStep"
    local alignPos = physicsConstraints[constraintName]
    if not alignPos then
      alignPos = Instance.new("AlignPosition")
      alignPos.Name = constraintName
      alignPos.Mode = Enum.PositionAlignmentMode.OneAttachment
      local stepAtt = createConstraintAttachment(footToStepPart, "BalanceStepAtt")
      -- stepAtt.Position = Vector3.new(0, -footToStepPart.Size.Y/2 * 0.8, 0) -- Apply force slightly below center?
      alignPos.Attachment0 = stepAtt
      alignPos.MaxForce = BALANCE_StepForce
      alignPos.ApplyAtCenterOfMass = true -- Apply force more smoothly
      alignPos.Parent = footToStepPart
      physicsConstraints[constraintName] = alignPos
    end

    alignPos.Responsiveness = BALANCE_StepResponsiveness
    alignPos.Position = footToStepPart.Position -- Initialize target for Lerp start
    alignPos.Enabled = true

    -- Set cooldown and stumbling status
    if leanMagnitude > (BALANCE_LeanThreshold_FB + BALANCE_LeanThreshold_LR) * 0.8 then
      isStumbling = true
      stepCooldown = STUMBLE_COOLDOWN_TIME
    else
      isStumbling = false
      stepCooldown = STEP_COOLDOWN_TIME
    end
  end

  -- Always update torso correction
  updateTorsoCorrection(dt)
end

Changes Made:

  1. Target Calculation Logic: Inside the if needsStepFB or needsStepLR then block, the calculation for targetXZ is rewritten.
    • It now explicitly calculates the requiredStepVector based on the predicted lean and step distance factor.
    • It determines the targetLateralOffset based directly on the stationaryFootPart.Position and the desired BALANCE_StanceWidth, ensuring the stepping foot aims to land laterally away from the stationary one.
    • It combines the stationary foot's XZ position, the calculated lateral offset, and the forward component of the required step (forwardXZ * requiredStepForward) to get the final targetXZ.
  2. Step Completion Logic: Slightly refined the step completion check (distToTargetXZ < STEP_COMPLETION_DISTANCE or (stepProgress >= 1 and isBalancedEnough)) to better handle cases where the foot might not reach the exact target but the timer is up and balance is restored. Added a condition to handle stumbling if the timer finishes but balance isn't restored.
  3. AlignPosition ApplyAtCenterOfMass: Changed ApplyAtCenterOfMass to true for the stepping AlignPosition. This often results in smoother, less jerky motion compared to applying the force directly at the attachment point, especially for larger forces.

This change should make the character prioritize maintaining a reasonable stance width relative to the non-stepping foot, significantly reducing the chance of stepping on its own leg. Test it out and see how it feels! You might still need to fine-tune BALANCE_StanceWidth and potentially BALANCE_StepDistanceFactor.