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
local camera = workspace.CurrentCamera
local humanoid = character:WaitForChild("Humanoid")
local rootPart = character:WaitForChild("HumanoidRootPart")
local head = character:WaitForChild("Head")

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 ledgePart = nil



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

local function vaultMove(direction, anim)
	local moveRay = workspace:Raycast(head.CFrame.Position, head.CFrame.RightVector * direction + head.CFrame.LookVector * 8, raycastParams)
	if moveRay then
		if moveRay.Instance then
		end
	else
		local turnRay = workspace:Raycast(head.CFrame.Position + Vector3.new(0, -1, 0) + head.CFrame.RightVector * direction, head.CFrame.RightVector * -direction + head.CFrame.LookVector * 2, raycastParams)
		if turnRay then
			if turnRay.Instance then
			end
		end
	end
end

humanoid:GetPropertyChangedSignal("MoveDirection"):Connect(function()
	if canMove then
		if (humanoid.MoveDirection:Dot(camera.CFrame.RightVector) > .7) and not canVault then
			vaultMove(vaultMoveNumber, "Right")
		end

		if (humanoid.MoveDirection:Dot(-camera.CFrame.RightVector) > .7) and not canVault then
			vaultMove(-vaultMoveNumber, "Left")
		end
	end
end)

local function detectLedge()
	if canVault and (humanoid:GetState() == Enum.HumanoidStateType.Freefall or humanoid:GetState() == Enum.HumanoidStateType.Jumping) then
		local vaultCheck = workspace:Raycast(rootPart.CFrame.Position, rootPart.CFrame.LookVector * 5, raycastParams)
		if vaultCheck then
			if vaultCheck.Instance then			
				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 < 5 then
					if partCheck(ledgeOffset) then
						canVault = false
						canMove = false

						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

						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
				end
			end
		end
	elseif not canVault then
		canVault = true
		canMove = true
		humanoid.AutoRotate = true
		rootPart.Anchored = false
		humanoid:ChangeState(Enum.HumanoidStateType.Jumping)

		if vaultConnection then
			vaultConnection:Disconnect()
		end

		if ledgePart then
			ledgePart:Destroy()
		end
	end
end

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(function()
		detectLedge()
	end)
end


tell me the ways you could improve the script (for example, how you could optimize it, how you could redunce redundancy etc.) and i'll tell you which options to do.