movement handler:

local StaminaManager = require(script.Parent:WaitForChild("StaminaModule"))

local defaultSpeed = 16
local sprintSpeed = 22
local normalFov = 70
local sprintFov = 80
local crouchFov = 65
local crouchSpeed = 8
local staminaDrainRate = 17

local Settings = {
	Lifetime = 0.15,
	DashVelocity = 55,
	Cooldown = 3,
	DashStaminaCost = 20,
	JumpCooldown = 1.1
}

local Services = setmetatable({}, {
	__index = function(Self, Index)
		local NewService = game:GetService(Index)
		if NewService then
			Self[Index] = NewService
		end
		return NewService
	end
})

local UserInputService = Services.UserInputService
local TweenService = Services.TweenService
local RunService = Services.RunService
local Players = Services.Players
local ReplicatedStorage = Services.ReplicatedStorage

local sprintKey = Enum.KeyCode.LeftShift
local crouchKey = Enum.KeyCode.C
local Player = Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local Humanoid = Character:WaitForChild("Humanoid")
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")
local Camera = workspace.CurrentCamera
local healthBar = Player:WaitForChild("PlayerGui"):WaitForChild("StaminaAndHealthBar"):WaitForChild("Frame"):WaitForChild("HealthBar"):WaitForChild("Bar")
local staminaBar = Player:WaitForChild("PlayerGui"):WaitForChild("StaminaAndHealthBar"):WaitForChild("Frame"):WaitForChild("StaminaBar"):WaitForChild("Bar")

local sprintAnim = ReplicatedStorage:WaitForChild("Animations"):WaitForChild("Player"):WaitForChild("SprintAnim")
local animTrack = Humanoid:LoadAnimation(sprintAnim)
local movementKeys = {Enum.KeyCode.W, Enum.KeyCode.A, Enum.KeyCode.S, Enum.KeyCode.D}
local movementKeysPressed = {}
local shiftPressed, sprinting, isCrouching, isMoving, isSliding = false, false, false, false, false
local canJump = true

local Animations = {
	Forward = Humanoid:LoadAnimation(ReplicatedStorage:WaitForChild("Animations"):WaitForChild("Player"):WaitForChild("FrontDash")),
	Backward = Humanoid:LoadAnimation(ReplicatedStorage:WaitForChild("Animations"):WaitForChild("Player"):WaitForChild("BackDash")),
	Left = Humanoid:LoadAnimation(ReplicatedStorage:WaitForChild("Animations"):WaitForChild("Player"):WaitForChild("LeftDash")),
	Right = Humanoid:LoadAnimation(ReplicatedStorage:WaitForChild("Animations"):WaitForChild("Player"):WaitForChild("RightDash")),
}
local BV = Instance.new("BodyVelocity")

local function tweenFov(duration, fov)
	local tween = TweenService:Create(Camera, TweenInfo.new(duration, Enum.EasingStyle.Quad), { FieldOfView = fov })
	tween:Play()
	tween.Completed:Wait()
	tween:Destroy()
end

local function updateStaminaBar()
	local stamina = StaminaManager.GetStamina()
	local tween = TweenService:Create(staminaBar, TweenInfo.new(0.25, Enum.EasingStyle.Quad), { Size = UDim2.new(stamina / StaminaManager.maxStamina, 0, 1, 0) })
	tween:Play()
end

local function startSprinting()
	if not sprinting and StaminaManager.GetStamina() > 0 and not isCrouching then
		sprinting = true
		StaminaManager.ReduceStamina(staminaDrainRate * RunService.RenderStepped:Wait())
		Humanoid.WalkSpeed = sprintSpeed
		if Humanoid:GetState() ~= Enum.HumanoidStateType.Freefall then
			animTrack:Play()
		end
		tweenFov(0.25, sprintFov)
		updateStaminaBar()
	end
end

local function stopSprinting()
	if sprinting then
		sprinting = false
		Humanoid.WalkSpeed = defaultSpeed
		animTrack:Stop()
		tweenFov(0.25, normalFov)
		updateStaminaBar()
	end
end

local function crouch()
	if not isCrouching and not sprinting then
		if animTrack.IsPlaying then animTrack:Stop() end
		isCrouching, Humanoid.WalkSpeed = true, crouchSpeed
		tweenFov(0.25, crouchFov)
	end
end

local function stand()
	if isCrouching then
		isCrouching, Humanoid.WalkSpeed = false, defaultSpeed
		tweenFov(0.25, normalFov)
	end
end


local function startSliding()
	print("SLIDE TIME")
end


Character.Humanoid:GetPropertyChangedSignal("Health"):Connect(function()
	healthBar.Size = UDim2.new(Humanoid.Health / Humanoid.MaxHealth, 0, 1, 0)
end)

local function dash()
	local Now, DashCooldown = workspace:GetServerTimeNow(), Character:GetAttribute("DashCooldown") or 0
	if DashCooldown > Now or StaminaManager.GetStamina() < Settings.DashStaminaCost then return end

	Character:SetAttribute("DashCooldown", Now + Settings.Cooldown)
	StaminaManager.ReduceStamina(Settings.DashStaminaCost)

	local NewBV = BV:Clone()
	NewBV.MaxForce, NewBV.P = Vector3.new(1e5, 1e5, 1e5), 1250
	local Direction = Humanoid.MoveDirection.Magnitude > 0 and Humanoid.MoveDirection or HumanoidRootPart.CFrame.LookVector
	local RelativeDirection = (CFrame.lookAt(Camera.CFrame.LookVector, Camera.CFrame.LookVector + Direction)).LookVector
	local currentYVelocity = HumanoidRootPart.Velocity.Y / 2
	NewBV.Velocity = Vector3.new(RelativeDirection.X, 0, RelativeDirection.Z) * Settings.DashVelocity + Vector3.new(0, currentYVelocity, 0)
	NewBV.Parent = HumanoidRootPart

	for key, anim in {[Enum.KeyCode.W] = "Forward", [Enum.KeyCode.A] = "Left", [Enum.KeyCode.S] = "Backward", [Enum.KeyCode.D] = "Right"} do
		if UserInputService:IsKeyDown(key) then
			Animations[anim]:Play()
			break
		end
	end

	task.delay(Settings.Lifetime, function() NewBV:Destroy() end)
end

UserInputService.InputBegan:Connect(function(input, processed)
	if processed or Humanoid.Health == 0 then return end
	if input.KeyCode == sprintKey then
		shiftPressed = true
		if next(movementKeysPressed) then
			startSprinting()
		end
	elseif table.find(movementKeys, input.KeyCode) then
		movementKeysPressed[input.KeyCode] = true
		if shiftPressed and StaminaManager.GetStamina() > 0 and not isCrouching then
			startSprinting()
		end
	elseif input.KeyCode == crouchKey then
		if sprinting and StaminaManager.GetStamina() > 0 and isCrouching then
			startSliding()
		else
			crouch()
		end
	elseif input.KeyCode == Enum.KeyCode.E then
		dash()
	end
end)


UserInputService.InputEnded:Connect(function(input)
    if Humanoid.Health == 0 then return end
    if input.KeyCode == sprintKey then
        shiftPressed = false
        stopSprinting()
    elseif table.find(movementKeys, input.KeyCode) then
        movementKeysPressed[input.KeyCode] = nil
        if next(movementKeysPressed) == nil then
            stopSprinting()
        end
    elseif input.KeyCode == crouchKey and not sprinting then
        stand()
    end
end)

RunService.RenderStepped:Connect(function(deltaTime)
    if sprinting and not StaminaManager.ReduceStamina(staminaDrainRate * deltaTime) then
        stopSprinting()
    end
    updateStaminaBar()
end)

Humanoid:GetPropertyChangedSignal("MoveDirection"):Connect(function()
    isMoving = Humanoid.MoveDirection.Magnitude > 0
end)

local playAnim = Humanoid:LoadAnimation(ReplicatedStorage:WaitForChild("Animations"):WaitForChild("Player"):WaitForChild("Land"))

local isLandingAnimationPlaying = false

Humanoid.StateChanged:Connect(function(oldState, newState)
	if (newState == Enum.HumanoidStateType.Jumping) then
		canJump = false
		Humanoid:SetStateEnabled("Jumping", false)
		task.wait(Settings.JumpCooldown)
		canJump = true
		Humanoid:SetStateEnabled("Jumping", true)
    elseif newState == Enum.HumanoidStateType.Freefall then
        animTrack:Stop()
	elseif newState == Enum.HumanoidStateType.Landed then
		if not isLandingAnimationPlaying then
			isLandingAnimationPlaying = true
			animTrack:Stop()
			playAnim:Play()
			playAnim.Stopped:Connect(function()
				isLandingAnimationPlaying = false
				if sprinting then
					animTrack:Play()
				end
			end)
		end
	end
end)

ledge grab:

local UserInputService = game:GetService("UserInputService")
local ContextActionService = game:GetService("ContextActionService")
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")
local Debris = game:GetService("Debris")
local GuiService = game:GetService("GuiService")

local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local camera = workspace.CurrentCamera
local humanoid = character:WaitForChild("Humanoid")
local rootPart = character:WaitForChild("HumanoidRootPart")
local head = character:WaitForChild("Head")

local grabAnim = humanoid:LoadAnimation(game:GetService("ReplicatedStorage"):WaitForChild("Animations"):WaitForChild("Player"):WaitForChild("Grab"))

local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {character}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude

local vaultMoveNumber = 10
local canVault = true
local canMove = true
local vaultConnection = nil

local function partCheck(ledge)
	local vaultPartCheck = workspace:Raycast(ledge.Position + Vector3.new(0, -1, 0) + ledge.LookVector * 1, ledge.UpVector * 3, raycastParams)
	return vaultPartCheck == nil
end

local function vaultMove(direction)
	local headCFrame, headRightVector, headLookVector = head.CFrame, head.CFrame.RightVector, head.CFrame.LookVector
	local moveRay = workspace:Raycast(head.Position, headRightVector * direction + headLookVector * 8, raycastParams)

	if moveRay or workspace:Raycast(head.Position + Vector3.new(0, -1, 0) + headRightVector * direction, headRightVector * -direction + headLookVector * 2, raycastParams) then
	end
end

local function onMoveDirectionChanged()
	if not canMove then return end
	local moveDirection = humanoid.MoveDirection
	local cameraRightVector = camera.CFrame.RightVector
	if moveDirection:Dot(cameraRightVector) > .7 and not canVault then
		vaultMove(vaultMoveNumber)
	elseif moveDirection:Dot(-cameraRightVector) > .7 and not canVault then
		vaultMove(-vaultMoveNumber)
	end
end

local function createLedgePart(ledgeOffset)
	local ledgePart = Instance.new("Part")
	ledgePart.Parent = workspace
	ledgePart.Anchored = true
	ledgePart.Size = Vector3.one
	ledgePart.CFrame = ledgeOffset + Vector3.new(0, -2, 0) + ledgeOffset.LookVector * -1
	ledgePart.CanQuery = false
	ledgePart.CanCollide = false
	ledgePart.CanTouch = false
	ledgePart.Transparency = 1
	return ledgePart
end

local function performVault(ledgePart, ledgeOffset)
	canVault = false
	canMove = false
	
	grabAnim:Play()
	
	vaultConnection = RunService.RenderStepped:Connect(function(dt)
		rootPart.Anchored = true
		humanoid.AutoRotate = false
		rootPart.CFrame = rootPart.CFrame:Lerp(CFrame.lookAt(ledgePart.Position, (ledgePart.CFrame * CFrame.new(0, 0, -1)).Position), .25)
		humanoid:ChangeState(Enum.HumanoidStateType.Seated)
	end)
end

local function detectLedge()
	if (not canVault) or (humanoid:GetState() ~= Enum.HumanoidStateType.Freefall and humanoid:GetState() ~= Enum.HumanoidStateType.Jumping) then
		canVault = true
		canMove = true
		humanoid.AutoRotate = true
		rootPart.Anchored = false
		humanoid:ChangeState(Enum.HumanoidStateType.Jumping)

		if vaultConnection then
			vaultConnection:Disconnect()
		end
		if grabAnim.IsPlaying then
			grabAnim:Stop()
		end
		return
	end

	local vaultCheck = workspace:Raycast(rootPart.CFrame.Position, rootPart.CFrame.LookVector * 5, raycastParams)
	if not vaultCheck or not vaultCheck.Instance then return end

	local localPos = vaultCheck.Instance.CFrame:PointToObjectSpace(vaultCheck.Position)
	local localLedgePos = Vector3.new(localPos.X, vaultCheck.Instance.Size.Y / 2, localPos.Z)
	local ledgePos = vaultCheck.Instance.CFrame:PointToWorldSpace(localLedgePos)
	local ledgeOffset = CFrame.lookAt(ledgePos, ledgePos - vaultCheck.Normal)

	local magnitude = (ledgePos - head.Position).Magnitude
	if magnitude >= 6 then return end
	if not partCheck(ledgeOffset) then return end

	local ledgePart = createLedgePart(ledgeOffset)
	performVault(ledgePart, ledgeOffset)
end

local function setupInputHandlers()
	UserInputService.InputBegan:Connect(function(input, gp)
		if input.KeyCode == Enum.KeyCode.ButtonA or input.KeyCode == Enum.KeyCode.Space then
			detectLedge()
		end
	end)

	if UserInputService.TouchEnabled and not UserInputService.KeyboardEnabled and not UserInputService.MouseEnabled and not UserInputService.GamepadEnabled and not GuiService:IsTenFootInterface() then
		local jumpButton = player.PlayerGui:WaitForChild("TouchGui"):WaitForChild("TouchControlFrame"):WaitForChild("JumpButton")
		jumpButton.Activated:Connect(detectLedge)
	end
end

humanoid:GetPropertyChangedSignal("MoveDirection"):Connect(onMoveDirectionChanged)
setupInputHandlers()


combine these two scripts into one.