local Players = game:GetService("Players") local RunService = game:GetService("RunService") local UserInputService = game:GetService("UserInputService") local localPlayer = Players.LocalPlayer local isLocked = false local lockedPart = nil local relativeCFrame = nil local localShipUp = Vector3.yAxis local connections = {} local isJumping = false local verticalVelocity = 0 local jumpRequested = false local idleTrack = nil local walkTrack = nil local jumpTrack = nil local guiParent = (gethui and gethui()) or game:GetService("CoreGui") if guiParent:FindFirstChild("SurfaceLockGUI") then guiParent.SurfaceLockGUI:Destroy() end local screenGui = Instance.new("ScreenGui") screenGui.Name = "SurfaceLockGUI" screenGui.ResetOnSpawn = false screenGui.Parent = guiParent local mainFrame = Instance.new("Frame") mainFrame.Size = UDim2.new(0, 180, 0, 80) mainFrame.Position = UDim2.new(0.8, 0, 0.4, 0) mainFrame.BackgroundColor3 = Color3.fromRGB(25, 25, 30) mainFrame.BorderSizePixel = 0 mainFrame.Active = true mainFrame.Parent = screenGui local uiCorner = Instance.new("UICorner") uiCorner.CornerRadius = UDim.new(0, 8) uiCorner.Parent = mainFrame local titleLabel = Instance.new("TextLabel") titleLabel.Size = UDim2.new(1, 0, 0, 28) titleLabel.BackgroundTransparency = 1 titleLabel.Text = "Magnet Boots" titleLabel.TextColor3 = Color3.fromRGB(200, 200, 210) titleLabel.Font = Enum.Font.GothamBold titleLabel.TextSize = 14 titleLabel.Parent = mainFrame local toggleBtn = Instance.new("TextButton") toggleBtn.Size = UDim2.new(0.85, 0, 0, 36) toggleBtn.Position = UDim2.new(0.075, 0, 0, 34) toggleBtn.BackgroundColor3 = Color3.fromRGB(180, 50, 50) toggleBtn.Text = "OFF" toggleBtn.TextColor3 = Color3.fromRGB(255, 255, 255) toggleBtn.Font = Enum.Font.GothamBold toggleBtn.TextSize = 14 toggleBtn.Parent = mainFrame local btnCorner = Instance.new("UICorner") btnCorner.CornerRadius = UDim.new(0, 6) btnCorner.Parent = toggleBtn local dragging, dragInput, dragStart, startPos mainFrame.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then dragging = true dragStart = input.Position startPos = mainFrame.Position input.Changed:Connect(function() if input.UserInputState == Enum.UserInputState.End then dragging = false end end) end end) mainFrame.InputChanged:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch then dragInput = input end end) UserInputService.InputChanged:Connect(function(input) if input == dragInput and dragging then local delta = input.Position - dragStart mainFrame.Position = UDim2.new( startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y ) end end) local function getStandingHeight(hrp, hum) if hum.RigType == Enum.HumanoidRigType.R15 then local hip = hum.HipHeight > 0 and hum.HipHeight or 2 return hip + (hrp.Size.Y * 0.5) end return 3 end local function getClosestUpAxis(partCF) local axes = { Vector3.new(1, 0, 0), Vector3.new(-1, 0, 0), Vector3.new(0, 1, 0), Vector3.new(0, -1, 0), Vector3.new(0, 0, 1), Vector3.new(0, 0, -1) } local bestAxis = Vector3.new(0, 1, 0) local bestDot = -1 for _, axis in ipairs(axes) do local worldAxis = partCF:VectorToWorldSpace(axis) local dot = worldAxis:Dot(Vector3.yAxis) if dot > bestDot then bestDot = dot bestAxis = axis end end return bestAxis end local function isIgnoredPart(part) if not part or not part:IsA("BasePart") then return true end if part == workspace.Terrain then return true end if not part.CanCollide then return true end if part:FindFirstAncestorOfClass("Accessory") or part:FindFirstAncestorOfClass("Tool") then return true end local model = part:FindFirstAncestorOfClass("Model") if model and model:FindFirstChildOfClass("Humanoid") then return true end local nameLower = string.lower(part.Name) if string.find(nameLower, "water") or string.find(nameLower, "ocean") or string.find(nameLower, "sea") or string.find(nameLower, "wave") or string.find(nameLower, "zone") or string.find(nameLower, "hitbox") then return true end return false end local function castToSolidSurface(origin, direction) local ignoreList = {} for _, plr in ipairs(Players:GetPlayers()) do if plr.Character then table.insert(ignoreList, plr.Character) end end local rayParams = RaycastParams.new() rayParams.FilterType = Enum.RaycastFilterType.Exclude rayParams.IgnoreWater = true rayParams.RespectCanCollide = true for _ = 1, 12 do rayParams.FilterDescendantsInstances = ignoreList local result = workspace:Raycast(origin, direction, rayParams) if not result or not result.Instance then return nil end if isIgnoredPart(result.Instance) then table.insert(ignoreList, result.Instance) else return result end end return nil end local function setupCustomAnimations(char, hum, enable) if not char or not hum then return end local animateScript = char:FindFirstChild("Animate") local animator = hum:FindFirstChildOfClass("Animator") if enable then if animateScript and animateScript:IsA("LocalScript") then animateScript.Disabled = true end if animator then for _, track in ipairs(animator:GetPlayingAnimationTracks()) do track:Stop(0) end local idleAnim = animateScript and animateScript:FindFirstChild("idle") and animateScript.idle:FindFirstChildOfClass("Animation") local runAnim = animateScript and ( (animateScript:FindFirstChild("run") and animateScript.run:FindFirstChildOfClass("Animation")) or (animateScript:FindFirstChild("walk") and animateScript.walk:FindFirstChildOfClass("Animation")) ) local jumpAnim = animateScript and ( (animateScript:FindFirstChild("jump") and animateScript.jump:FindFirstChildOfClass("Animation")) or (animateScript:FindFirstChild("fall") and animateScript.fall:FindFirstChildOfClass("Animation")) ) if idleAnim then local ok, track = pcall(function() return animator:LoadAnimation(idleAnim) end) if ok and track then idleTrack = track idleTrack.Priority = Enum.AnimationPriority.Movement idleTrack.Looped = true idleTrack:Play(0.1) end end if runAnim then local ok, track = pcall(function() return animator:LoadAnimation(runAnim) end) if ok and track then walkTrack = track walkTrack.Priority = Enum.AnimationPriority.Movement walkTrack.Looped = true end end if jumpAnim then local ok, track = pcall(function() return animator:LoadAnimation(jumpAnim) end) if ok and track then jumpTrack = track jumpTrack.Priority = Enum.AnimationPriority.Action jumpTrack.Looped = true end end end else for _, track in pairs({idleTrack, walkTrack, jumpTrack}) do if track then pcall(function() track:Stop(0.1) track:Destroy() end) end end idleTrack, walkTrack, jumpTrack = nil, nil, nil if animateScript and animateScript:IsA("LocalScript") then animateScript.Disabled = false end end end local function updateAnimations(hum, isMoving, inAir) local animator = hum:FindFirstChildOfClass("Animator") if not animator then return end for _, track in ipairs(animator:GetPlayingAnimationTracks()) do if track ~= idleTrack and track ~= walkTrack and track ~= jumpTrack then track:Stop(0) end end if inAir then if idleTrack and idleTrack.IsPlaying then idleTrack:Stop(0.1) end if walkTrack and walkTrack.IsPlaying then walkTrack:Stop(0.1) end if jumpTrack and not jumpTrack.IsPlaying then jumpTrack:Play(0.1) end elseif isMoving then if jumpTrack and jumpTrack.IsPlaying then jumpTrack:Stop(0.15) end if idleTrack and idleTrack.IsPlaying then idleTrack:Stop(0.15) end if walkTrack then if not walkTrack.IsPlaying then walkTrack:Play(0.15) end walkTrack:AdjustSpeed(math.max(hum.WalkSpeed / 16, 0.5)) end else if jumpTrack and jumpTrack.IsPlaying then jumpTrack:Stop(0.15) end if walkTrack and walkTrack.IsPlaying then walkTrack:Stop(0.15) end if idleTrack and not idleTrack.IsPlaying then idleTrack:Play(0.15) end end end local function setHumanoidProtection(hum, state) if not hum then return end pcall(function() hum:SetStateEnabled(Enum.HumanoidStateType.FallingDown, not state) hum:SetStateEnabled(Enum.HumanoidStateType.Ragdoll, not state) hum:SetStateEnabled(Enum.HumanoidStateType.Freefall, not state) hum:SetStateEnabled(Enum.HumanoidStateType.Jumping, not state) end) end local function switchLockedPart(newPart, currentShipUp) if newPart ~= lockedPart then lockedPart = newPart localShipUp = lockedPart.CFrame:VectorToObjectSpace(currentShipUp).Unit toggleBtn.Text = "ON (" .. string.sub(lockedPart.Name, 1, 10) .. ")" end end local function disableLock() isLocked = false lockedPart = nil relativeCFrame = nil isJumping = false verticalVelocity = 0 jumpRequested = false for _, conn in ipairs(connections) do conn:Disconnect() end table.clear(connections) local char = localPlayer.Character local hum = char and char:FindFirstChildOfClass("Humanoid") setHumanoidProtection(hum, false) setupCustomAnimations(char, hum, false) toggleBtn.BackgroundColor3 = Color3.fromRGB(180, 50, 50) toggleBtn.Text = "OFF" end local function stepMovement(dt) dt = math.min(dt, 0.1) if not isLocked or not lockedPart or not lockedPart.Parent then disableLock() return end local char = localPlayer.Character local hrp = char and char:FindFirstChild("HumanoidRootPart") local hum = char and char:FindFirstChildOfClass("Humanoid") if not hrp or not hum or hum.Health <= 0 then disableLock() return end local standHeight = getStandingHeight(hrp, hum) local currentWorldCF = lockedPart.CFrame:ToWorldSpace(relativeCFrame) local shipUp = lockedPart.CFrame:VectorToWorldSpace(localShipUp).Unit local currentPos = currentWorldCF.Position local currentLook = currentWorldCF.LookVector local rawMove = hum.MoveDirection local planarMove = rawMove - (shipUp * rawMove:Dot(shipUp)) local isMoving = planarMove.Magnitude > 0.05 if (jumpRequested or UserInputService:IsKeyDown(Enum.KeyCode.Space)) and not isJumping then isJumping = true local jumpVel = hum.UseJumpPower and hum.JumpPower or math.sqrt(2 * workspace.Gravity * hum.JumpHeight) verticalVelocity = math.max(jumpVel, 45) end jumpRequested = false updateAnimations(hum, isMoving, isJumping) local nextPos = currentPos if isMoving then local moveDir = planarMove.Unit local stepDist = hum.WalkSpeed * dt local kneeCheckOrigin = currentPos - (shipUp * (standHeight - 2.35)) local headCheckOrigin = currentPos + (shipUp * 1.2) local rayLength = stepDist + 1.5 local wallHit = castToSolidSurface(kneeCheckOrigin, moveDir * rayLength) or castToSolidSurface(headCheckOrigin, moveDir * rayLength) if wallHit then local wallNormal = wallHit.Normal local slideVec = moveDir - (wallNormal * moveDir:Dot(wallNormal)) slideVec = slideVec - (shipUp * slideVec:Dot(shipUp)) if slideVec.Magnitude > 0.05 then local slideDir = slideVec.Unit local secondCheck = castToSolidSurface(kneeCheckOrigin, slideDir * rayLength) or castToSolidSurface(headCheckOrigin, slideDir * rayLength) if not secondCheck then nextPos = currentPos + (slideDir * stepDist) end end else nextPos = currentPos + (moveDir * stepDist) end currentLook = currentLook:Lerp(moveDir, math.clamp(dt * 14, 0, 1)) end local cam = workspace.CurrentCamera if cam and (UserInputService.MouseBehavior == Enum.MouseBehavior.LockCenter) then local camLook = cam.CFrame.LookVector local planarCamLook = camLook - (shipUp * camLook:Dot(shipUp)) if planarCamLook.Magnitude > 0.05 then currentLook = planarCamLook.Unit end end if isJumping then local grav = math.clamp(workspace.Gravity, 80, 250) verticalVelocity = verticalVelocity - (grav * dt) local vertStep = verticalVelocity * dt if vertStep > 0 then local ceilHit = castToSolidSurface(currentPos, shipUp * (vertStep + 2.2)) if ceilHit then vertStep = math.max(0, (ceilHit.Position - currentPos):Dot(shipUp) - 2.0) verticalVelocity = 0 end end nextPos = nextPos + (shipUp * vertStep) local floorHit = castToSolidSurface(nextPos + (shipUp * 2), -shipUp * 55) if floorHit and floorHit.Instance then switchLockedPart(floorHit.Instance, shipUp) local landPos = floorHit.Position + (shipUp * standHeight) local distToFloor = (nextPos - landPos):Dot(shipUp) if distToFloor <= 0 and verticalVelocity <= 0 then nextPos = landPos isJumping = false verticalVelocity = 0 end else nextPos = currentPos + (shipUp * vertStep) local safeFloor = castToSolidSurface(nextPos + (shipUp * 2), -shipUp * 55) if safeFloor and safeFloor.Instance then switchLockedPart(safeFloor.Instance, shipUp) local landPos = safeFloor.Position + (shipUp * standHeight) if (nextPos - landPos):Dot(shipUp) <= 0 and verticalVelocity <= 0 then nextPos = landPos isJumping = false verticalVelocity = 0 end end end else local rayOrigin = nextPos + (shipUp * 2.6) local floorHit = castToSolidSurface(rayOrigin, -shipUp * 20) if floorHit and floorHit.Instance then local targetPos = floorHit.Position + (shipUp * standHeight) local heightDiff = (targetPos - nextPos):Dot(shipUp) if heightDiff > 2.45 then nextPos = currentPos elseif heightDiff < -3.5 then switchLockedPart(floorHit.Instance, shipUp) isJumping = true verticalVelocity = 0 else switchLockedPart(floorHit.Instance, shipUp) local smoothFactor = 1 - math.exp(-16 * dt) nextPos = nextPos + (shipUp * (heightDiff * smoothFactor)) end else nextPos = currentPos local fallbackHit = castToSolidSurface(currentPos + (shipUp * 2.6), -shipUp * 20) if fallbackHit and fallbackHit.Instance then switchLockedPart(fallbackHit.Instance, shipUp) local targetPos = fallbackHit.Position + (shipUp * standHeight) local heightDiff = (targetPos - nextPos):Dot(shipUp) local smoothFactor = 1 - math.exp(-16 * dt) nextPos = nextPos + (shipUp * (heightDiff * smoothFactor)) end end end shipUp = lockedPart.CFrame:VectorToWorldSpace(localShipUp).Unit local rightVec = currentLook:Cross(shipUp) if rightVec.Magnitude < 0.01 then rightVec = lockedPart.CFrame.RightVector else rightVec = rightVec.Unit end local finalLook = shipUp:Cross(rightVec).Unit local finalWorldCF = CFrame.fromMatrix(nextPos, rightVec, shipUp, -finalLook) relativeCFrame = lockedPart.CFrame:ToObjectSpace(finalWorldCF) hrp.CFrame = finalWorldCF hrp.AssemblyLinearVelocity = Vector3.zero hrp.AssemblyAngularVelocity = Vector3.zero end local function enforceLock() if not isLocked or not lockedPart or not lockedPart.Parent or not relativeCFrame then return end local char = localPlayer.Character local hrp = char and char:FindFirstChild("HumanoidRootPart") if hrp then hrp.CFrame = lockedPart.CFrame:ToWorldSpace(relativeCFrame) hrp.AssemblyLinearVelocity = Vector3.zero hrp.AssemblyAngularVelocity = Vector3.zero end end local function enableLock() local char = localPlayer.Character local hrp = char and char:FindFirstChild("HumanoidRootPart") local hum = char and char:FindFirstChildOfClass("Humanoid") if not hrp or not hum then return end local result = castToSolidSurface(hrp.Position + (hrp.CFrame.UpVector * 2), -hrp.CFrame.UpVector * 25) or castToSolidSurface(hrp.Position + Vector3.new(0, 2, 0), Vector3.new(0, -25, 0)) if result and result.Instance then lockedPart = result.Instance localShipUp = getClosestUpAxis(lockedPart.CFrame) local shipUp = lockedPart.CFrame:VectorToWorldSpace(localShipUp).Unit local standHeight = getStandingHeight(hrp, hum) local snappedPos = result.Position + (shipUp * standHeight) local lookVec = hrp.CFrame.LookVector local rightVec = lookVec:Cross(shipUp) if rightVec.Magnitude < 0.01 then rightVec = lockedPart.CFrame.RightVector else rightVec = rightVec.Unit end local finalLook = shipUp:Cross(rightVec).Unit local initialCFrame = CFrame.fromMatrix(snappedPos, rightVec, shipUp, -finalLook) relativeCFrame = lockedPart.CFrame:ToObjectSpace(initialCFrame) isLocked = true isJumping = false verticalVelocity = 0 setHumanoidProtection(hum, true) setupCustomAnimations(char, hum, true) toggleBtn.BackgroundColor3 = Color3.fromRGB(45, 160, 75) toggleBtn.Text = "ON (" .. string.sub(lockedPart.Name, 1, 10) .. ")" table.insert(connections, UserInputService.JumpRequest:Connect(function() if isLocked and not isJumping then jumpRequested = true end end)) table.insert(connections, RunService.Stepped:Connect(enforceLock)) table.insert(connections, RunService.Heartbeat:Connect(stepMovement)) table.insert(connections, RunService.RenderStepped:Connect(enforceLock)) else toggleBtn.Text = "NO SURFACE!" task.delay(1, function() if not isLocked then toggleBtn.Text = "OFF" end end) end end toggleBtn.MouseButton1Click:Connect(function() if isLocked then disableLock() else enableLock() end end) localPlayer.CharacterAdded:Connect(function() disableLock() end)