Having problems with my climbing system

So, I was trying to make a pipe / ladder climbing system like “DECAY” or parkour reborn, but I can’t get the hooking up right. I also can’t make it work for console (and mobile for now isn’t added, will try to add later.)

I will give the script so you guys can help me inspect it:

local Players = game:GetService(“Players”)
local UserInputService = game:GetService(“UserInputService”)
local RunService = game:GetService(“RunService”)

local player = Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild(“Humanoid”)
local root = character:WaitForChild(“HumanoidRootPart”)

local climbSpeed = 6
local isClimbing = false
local climbDirection = 0

local touchingTrigger = false
local currentTrigger = nil
local currentRail = nil
local verticalOffset = 0

local att0, att1, alignPos, alignOri

local function debug(msg)
print("[CLIMB]: " … msg)
end

local function createAttachment(parent, name, position)
local attachment = Instance.new(“Attachment”)
attachment.Name = name
attachment.Position = position or Vector3.new()
attachment.Parent = parent
return attachment
end

local function setupAligns()
att0 = createAttachment(root, “ClimbAttachment”)
att1 = createAttachment(currentRail, “ClimbTarget”, Vector3.new())

alignPos = Instance.new("AlignPosition")
alignPos.Attachment0 = att0
alignPos.Attachment1 = att1
alignPos.RigidityEnabled = true
alignPos.Responsiveness = 50
alignPos.MaxForce = 10000
alignPos.Parent = root

alignOri = Instance.new("AlignOrientation")
alignOri.Attachment0 = att0
alignOri.Attachment1 = att1
alignOri.RigidityEnabled = true
alignOri.Responsiveness = 50
alignOri.MaxTorque = 10000
alignOri.Parent = root

end

local function cleanupAligns()
if att0 then att0:Destroy() att0 = nil end
if att1 then att1:Destroy() att1 = nil end
if alignPos then alignPos:Destroy() alignPos = nil end
if alignOri then alignOri:Destroy() alignOri = nil end
end

local function startClimbing(trigger)
if isClimbing then return end

currentTrigger = trigger
currentRail = trigger.Parent:FindFirstChild("Rail")
if not currentRail then
	debug("No rail found in model.")
	return
end

isClimbing = true
climbDirection = 0

-- Disable auto rotate
humanoid.AutoRotate = false

local railBottomY = currentRail.Position.Y - currentRail.Size.Y / 2
local playerY = root.Position.Y

-- Clamp vertical offset with a small margin so not snapped on the top
local margin = 0.1
local playerOffset = playerY - railBottomY
verticalOffset = math.clamp(playerOffset, 0, currentRail.Size.Y - margin)

setupAligns()
att0.Position = Vector3.new(0, -currentRail.Size.Y / 2 + verticalOffset, 0)

debug("Started climbing.")

end

local function stopClimbing()
if not isClimbing then return end

isClimbing = false
climbDirection = 0
currentTrigger = nil
currentRail = nil
verticalOffset = 0

humanoid.AutoRotate = true
cleanupAligns()

debug("Stopped climbing.")

end

– Input handling for keyboard and controller buttons
UserInputService.InputBegan:Connect(function(input, gameProcessed)
if gameProcessed then return end

-- Jump inside trigger to start climbing
if (input.KeyCode == Enum.KeyCode.Space or input.KeyCode == Enum.KeyCode.ButtonA) and touchingTrigger then
	debug("Jump pressed inside trigger.")
	startClimbing(currentTrigger)
end

end)

UserInputService.InputEnded:Connect(function(input, gameProcessed)
if gameProcessed then return end
if isClimbing then
– Keyboard up/down key releases reset climbDirection
if (input.KeyCode == Enum.KeyCode.W or input.KeyCode == Enum.KeyCode.Up) and climbDirection == -1 then
climbDirection = 0
elseif (input.KeyCode == Enum.KeyCode.S or input.KeyCode == Enum.KeyCode.Down) and climbDirection == 1 then
climbDirection = 0
end
end
end)

– Detect climbables in workspace
local climbables = workspace:FindFirstChild(“Climbables”)
if climbables then
for _, model in pairs(climbables:GetChildren()) do
if model:IsA(“Model”) then
local trigger = model:FindFirstChild(“Trigger”)
if trigger and trigger:IsA(“BasePart”) then
trigger.Touched:Connect(function(part)
if part:IsDescendantOf(character) then
touchingTrigger = true
currentTrigger = trigger
end
end)

			trigger.TouchEnded:Connect(function(part)
				if part:IsDescendantOf(character) then
					touchingTrigger = false
					currentTrigger = nil
					if isClimbing then
						stopClimbing()
					end
				end
			end)
		end
	end
end

else
debug(“No Climbables folder found in workspace.”)
end

– Heartbeat: update climbing & detect controller thumbstick input
RunService.Heartbeat:Connect(function(dt)
– If not climbing, confirm if player still touching trigger
if not isClimbing and currentTrigger and root then
local touchingParts = currentTrigger:GetTouchingParts()
touchingTrigger = false
for _, part in pairs(touchingParts) do
if part:IsDescendantOf(character) then
touchingTrigger = true
break
end
end
end

if isClimbing and att0 and currentRail then
	-- Handle keyboard keys W/S for climbDirection if no controller input detected
	-- But better to handle controller here:

	-- Get thumbstick Y axis for controller
	local gamepads = Enum.UserInputType.Gamepad1
	local state = UserInputService:GetGamepadState(Enum.UserInputType.Gamepad1)

	local stickY = 0
	for _, input in pairs(state) do
		if input.KeyCode == Enum.KeyCode.Thumbstick1 then
			stickY = input.Position.Y
			break
		end
	end

	-- Deadzone for stick
	local deadzone = 0.2
	if math.abs(stickY) > deadzone then
		climbDirection = -stickY -- invert so stick forward = climb up (negative Y)
	else
		-- If no stick input, keep current climbDirection only if keyboard keys pressed; else zero
		if not UserInputService:IsKeyDown(Enum.KeyCode.W) and not UserInputService:IsKeyDown(Enum.KeyCode.Up) and
			not UserInputService:IsKeyDown(Enum.KeyCode.S) and not UserInputService:IsKeyDown(Enum.KeyCode.Down) then
			climbDirection = 0
		end
	end

	-- Update verticalOffset
	verticalOffset = verticalOffset + climbDirection * climbSpeed * dt
	verticalOffset = math.clamp(verticalOffset, 0, currentRail.Size.Y)

	att0.Position = Vector3.new(0, -currentRail.Size.Y / 2 + verticalOffset, 0)
end

end)

Any help would be highly appreciated!

(btw yes, some parts have gotten modified by AI)