-- // Services \\ --
local UIS = game:GetService("UserInputService")
local ContextActionService = game:GetService("ContextActionService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
 
-- // Local Player & Character Variables \\ --
local localPlr = Players.LocalPlayer
local character = localPlr.Character or localPlr.CharacterAdded:Wait()
local HRP = character:WaitForChild("HumanoidRootPart")
local Hum = character:WaitForChild("Humanoid")
local head = character:WaitForChild("Head")
 
local ClimbAnimation = Instance.new("Animation")
ClimbAnimation.AnimationId = "rbxassetid:// -- put ur anim Id here"
local Climb = Hum.Animator:LoadAnimation(ClimbAnimation)
Climb.Priority = Enum.AnimationPriority.Action2
 
local GrabAnimation = Instance.new("Animation")
GrabAnimation.AnimationId = "rbxassetid:// -- put ur anim Id here"
local Grab = Hum.Animator:LoadAnimation(GrabAnimation)
Grab.Priority = Enum.AnimationPriority.Action2
 
local JumpBack = Instance.new("Animation")
JumpBack.AnimationId = "rbxassetid:// -- put ur anim Id here"
local Jump = Hum.Animator:LoadAnimation(JumpBack)
Jump.Priority = Enum.AnimationPriority.Action2
 
-- Climbing Constants
local MaxUpwardsVel = 30
local ClimbDuration = 1 -- Time to decrease upward velocity to 0
local MaxDistance = 10
 
-- Climbing State variables
local isClimbing = false
local climbStartTime = 0
local Vel = nil
local UpwardsVel = MaxUpwardsVel
local climbingSurface = nil
local canClimbAgain = true
 
local function stopClimbing()
    if isClimbing then
        isClimbing = false
        canClimbAgain = false
 
        if Climb.IsPlaying then
            Climb:Stop()
        end
        if Vel then
            Vel:Destroy()
            Vel = nil
        end
        climbingSurface = nil
    end
end
 
local function JumpBack()
    if isClimbing then
        isClimbing = false
        canClimbAgain = false
 
        if Climb.IsPlaying then
            Climb:Stop()
        end
        if Vel then
            Vel:Destroy()
            Vel = nil
        end
        climbingSurface = nil
        
        
        Jump:Play()
        
        local newVel = Instance.new("BodyVelocity")
        newVel.Name = "Hello"
        newVel.Parent = HRP
        newVel.MaxForce = Vector3.new(math.huge, math.huge, math.huge)
        newVel.Velocity = Vector3.new(0, 20, 0) + HRP.CFrame.LookVector * -30
        task.wait(0.1)
        newVel:Destroy()
 
    end
end
 
-- Ledge grabbing logic
local function LedgeGrab()
    if isClimbing then
        isClimbing = false
        canClimbAgain = false
 
        if Climb.IsPlaying then
            Climb:Stop()
        end
        if Vel then
            Vel:Destroy()
            Vel = nil
        end
        climbingSurface = nil
    end
    Grab:Play()
    local newVel = Instance.new("BodyVelocity")
    newVel.Name = "Hello"
    newVel.Parent = HRP
    newVel.MaxForce = Vector3.new(math.huge, math.huge, math.huge)
    newVel.Velocity = Vector3.new(0, 35, 0) + HRP.CFrame.lookVector * 20
    task.wait(0.1)
    newVel:Destroy()
print("Works")
end
 
-- Helper function to start climbing
local function startClimbing(hitPart, hitPosition, hitNormal)
    if isClimbing or not canClimbAgain then return end -- Prevents repeated activation
 
    isClimbing = true
    climbStartTime = tick()
    UpwardsVel = MaxUpwardsVel
    climbingSurface = hitPart
 
    -- Snap character to the climbing surface
    local offset = hitNormal * (character.HumanoidRootPart.Size.Z / 2 + 0.5)
    local newPosition = hitPosition + offset
 
    local Properties = {CFrame = CFrame.new(newPosition, newPosition - hitNormal) }
    local Info = TweenInfo.new(0.1, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut)
    local T = game:GetService("TweenService"):Create(HRP, Info, Properties)
    T:Play()
    repeat wait() until T.Completed
    HRP.CFrame = CFrame.new(newPosition, newPosition - hitNormal)
 
    Vel = Instance.new("BodyVelocity")
    Vel.Parent = HRP
    Vel.MaxForce = Vector3.new(math.huge, math.huge, math.huge)
    Vel.Velocity = Vector3.new(0, UpwardsVel, 0)
 
    Climb:Play()
end
 
-- Update climb velocity over time (smooth deceleration)
local function updateIntermittentVelocity()
    if isClimbing and Vel then
        local elapsedTime = tick() - climbStartTime
        local progress = math.min(elapsedTime / ClimbDuration, 1)
        UpwardsVel = MaxUpwardsVel * (1 - progress)
        Vel.Velocity = Vector3.new(0, UpwardsVel, 0)
        Climb:AdjustSpeed(UpwardsVel / MaxUpwardsVel)
        if progress >= 1 then
            stopClimbing()
        end
    end
end
 
Hum.StateChanged:Connect(function(_, newState)
    if newState == Enum.HumanoidStateType.Landed then
        canClimbAgain = true
    end
end)
 
-- Check if climbing conditions are met (raycasting)
local function canClimb()
    local BodyRayOrigin = HRP.Position + Vector3.new(0, 0, 0) -- Slightly below HumanoidRootPart for body detection.
    local HeadRayOrigin = head.Position + Vector3.new(0, 2.5, 0) -- Slightly above the head for ledge detection.
    local NeckRayOrigin = head.Position + Vector3.new(0,-1,0)
    local RayDirection = HRP.CFrame.LookVector * (MaxDistance)
 
    local raycastParams = RaycastParams.new()
    raycastParams.FilterDescendantsInstances = {script.Parent}
    raycastParams.IgnoreWater = true
 
    local BodyRaycastResult = workspace:Raycast(BodyRayOrigin, RayDirection, raycastParams)
    local HeadRaycastResult = workspace:Raycast(HeadRayOrigin, RayDirection, raycastParams)
    local NeckRaycastResult = workspace:Raycast(NeckRayOrigin, RayDirection, raycastParams)
 
    if BodyRaycastResult and HeadRaycastResult and NeckRaycastResult then
        return true, false, BodyRaycastResult.Instance, BodyRaycastResult.Position, BodyRaycastResult.Normal
    elseif BodyRaycastResult and not HeadRaycastResult then
        return false, true, BodyRaycastResult.Instance, BodyRaycastResult.Position, BodyRaycastResult.Normal
    end
    return false, false
end
 
RunService:BindToRenderStep("Climbing", Enum.RenderPriority.Input.Value, function()
    local canClimbResult, canLedgeGrab, hitPart, hitPosition, hitNormal = canClimb()
 
    if UIS:IsKeyDown(Enum.KeyCode.Space) and canClimbResult and canClimbAgain and hitPart.Transparency == 0 and not isClimbing then
        startClimbing(hitPart, hitPosition, hitNormal)
    elseif UIS:IsKeyDown(Enum.KeyCode.Space) and canLedgeGrab and not canClimbResult and isClimbing then
        LedgeGrab()
    elseif not UIS:IsKeyDown(Enum.KeyCode.Space) then
        JumpBack()
    end
 
    updateIntermittentVelocity()
end)
 
character.AncestryChanged:Connect(function(_, parent)
    if not parent then
        stopClimbing()
    end
end)  i have this script over here that makes me climb walls and grab (and climb of course) the ledge so i can get on top of stuff, but the grab is a little buggy and sometimes flings me back down , so i came here to see if you can fix it