--[[---------------------------------------------------------------------------- VOID TOGGLE v2 // sky-hide, live camera v2: camera is no longer bolted. An invisible rig takes the CameraSubject seat at your old spot — rotate / zoom / pinch / gamepad all run native. Drop : any executor | Studio/live: LocalScript in StarterPlayerScripts UI : black "Void" button — tap to toggle, drag to move (mouse + touch) ------------------------------------------------------------------------------]] local Players = game:GetService("Players") local RunService = game:GetService("RunService") local Workspace = game:GetService("Workspace") local LocalPlayer = Players.LocalPlayer --// config -------------------------------------------------------------------- local SKY_OFFSET = 1500 -- studs above the press point local PLATFORM_SIZE = Vector3.new(1024, 2, 1024) -- can't fall off an edge you can't find local STAND_HEIGHT = 3.2 -- root-part clearance above the pad local CAM_PIVOT_LIFT = 1.6 -- orbit pivot ≈ head height over the old spot local BUTTON_SIZE = UDim2.fromOffset(120, 44) local BUTTON_POSITION = UDim2.new(0, 16, 0.4, 0) local DRAG_DEADZONE = 6 -- px before a tap counts as a drag --// state --------------------------------------------------------------------- local voided = false local suppressToggle = false local savedPivot = nil local savedCameraType = nil local savedCameraCFrame = nil local savedCameraSubject = nil local platform = nil local camRig = nil local safetyConnection = nil --// re-execute hygiene: kill any v1 leftovers so two builds never fight ------- pcall(function() RunService:UnbindFromRenderStep("VoidCameraHold") end) for _, partName in ipairs({ "VoidPad", "VoidCamRig" }) do local stale = Workspace:FindFirstChild(partName) if stale then stale:Destroy() end end --// gui parent: gethui on executors, CoreGui if writable, PlayerGui as floor --- local guiParent if type(gethui) == "function" then local ok, hui = pcall(gethui) if ok then guiParent = hui end end if not guiParent then local probe = Instance.new("Folder") local ok = pcall(function() probe.Parent = game:GetService("CoreGui") end) if ok then guiParent = game:GetService("CoreGui") probe:Destroy() end end if not guiParent then guiParent = LocalPlayer:WaitForChild("PlayerGui") end local old = guiParent:FindFirstChild("VoidToggleGui") -- re-executing shouldn't stack GUIs if old then old:Destroy() end --// gui ----------------------------------------------------------------------- local screenGui = Instance.new("ScreenGui") screenGui.Name = "VoidToggleGui" screenGui.ResetOnSpawn = false screenGui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling screenGui.DisplayOrder = 9999 local button = Instance.new("TextButton") button.Name = "VoidButton" button.Size = BUTTON_SIZE button.Position = BUTTON_POSITION button.BackgroundColor3 = Color3.fromRGB(8, 8, 8) button.Text = "Void" button.Font = Enum.Font.GothamBold button.TextSize = 16 button.TextColor3 = Color3.fromRGB(255, 255, 255) button.Parent = screenGui local corner = Instance.new("UICorner") corner.CornerRadius = UDim.new(0, 8) corner.Parent = button local stroke = Instance.new("UIStroke") stroke.Thickness = 1.5 stroke.Color = Color3.fromRGB(70, 70, 70) stroke.ApplyStrokeMode = Enum.ApplyStrokeMode.Border stroke.Parent = button screenGui.Parent = guiParent --// drag (touch + mouse), deadzone so repositions don't fire the toggle ------- do local dragging = false local dragStart, startPos button.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then dragging = true suppressToggle = false dragStart = input.Position startPos = button.Position input.Changed:Connect(function() if input.UserInputState == Enum.UserInputState.End then dragging = false end end) end end) button.InputChanged:Connect(function(input) if not dragging then return end if input.UserInputType ~= Enum.UserInputType.MouseMovement and input.UserInputType ~= Enum.UserInputType.Touch then return end local delta = input.Position - dragStart if delta.Magnitude > DRAG_DEADZONE then suppressToggle = true end button.Position = UDim2.new( startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y ) end) end --// helpers ------------------------------------------------------------------- local function getCharRootHumanoid() local char = LocalPlayer.Character if not char then return nil end local root = char:FindFirstChild("HumanoidRootPart") local hum = char:FindFirstChildOfClass("Humanoid") if not (root and hum) then return nil end return char, root, hum end --// enter --------------------------------------------------------------------- local function enterVoid() local char, root, hum = getCharRootHumanoid() if not char then return false end local camera = Workspace.CurrentCamera if not camera then return false end savedPivot = char:GetPivot() savedCameraType = camera.CameraType savedCameraCFrame = camera.CFrame savedCameraSubject = camera.CameraSubject if savedCameraSubject and savedCameraSubject.Name == "VoidCamRig" then savedCameraSubject = nil -- never snapshot our own rig end platform = Instance.new("Part") platform.Name = "VoidPad" platform.Size = PLATFORM_SIZE platform.Anchored = true platform.CanCollide = true platform.CanQuery = false -- local ground-check raycasts slide right through it platform.CanTouch = false platform.CastShadow = false platform.Transparency = 1 platform.CFrame = CFrame.new(savedPivot.Position + Vector3.new(0, SKY_OFFSET, 0)) platform.Parent = Workspace local standCFrame = platform.CFrame * CFrame.new(0, PLATFORM_SIZE.Y * 0.5 + STAND_HEIGHT, 0) root.AssemblyLinearVelocity = Vector3.new() root.AssemblyAngularVelocity = Vector3.new() char:PivotTo(standCFrame) -- the swap: invisible anchored rig inherits the CameraSubject seat at the -- old spot. Roblox's own camera module orbits/zooms/pans it — touch drag, -- pinch, right-mouse, gamepad stick, all native, zero input code. camRig = Instance.new("Part") camRig.Name = "VoidCamRig" camRig.Size = Vector3.new(1, 1, 1) camRig.Transparency = 1 camRig.Anchored = true camRig.CanCollide = false camRig.CanQuery = false camRig.CanTouch = false camRig.CastShadow = false camRig.CFrame = CFrame.new(savedPivot.Position + Vector3.new(0, CAM_PIVOT_LIFT, 0)) camRig.Parent = Workspace camera.CameraSubject = camRig camera.CameraType = Enum.CameraType.Custom camera.CFrame = savedCameraCFrame -- settle: open on the exact frame we left -- floor check: slip under the pad and you're put back on it local floorY = platform.Position.Y + PLATFORM_SIZE.Y * 0.5 safetyConnection = RunService.Heartbeat:Connect(function() local c, r, h = getCharRootHumanoid() if not c or h.Health <= 0 then return end if r.Position.Y < floorY - 4 then r.AssemblyLinearVelocity = Vector3.new() c:PivotTo(platform.CFrame * CFrame.new(0, PLATFORM_SIZE.Y * 0.5 + STAND_HEIGHT, 0)) end end) return true end --// exit ---------------------------------------------------------------------- local function exitVoid(restorePivot) if safetyConnection then safetyConnection:Disconnect() safetyConnection = nil end if platform then platform:Destroy() platform = nil end if camRig then camRig:Destroy() camRig = nil end local camera = Workspace.CurrentCamera local char, root, hum = getCharRootHumanoid() if camera then local subject = savedCameraSubject if not (subject and subject:IsDescendantOf(Workspace)) then subject = hum -- old subject died or was ours; aim at the live body end if subject then camera.CameraSubject = subject end camera.CameraType = savedCameraType or Enum.CameraType.Custom end if restorePivot and savedPivot and char and hum.Health > 0 then root.AssemblyLinearVelocity = Vector3.new() root.AssemblyAngularVelocity = Vector3.new() char:PivotTo(savedPivot) end savedPivot = nil end --// toggle -------------------------------------------------------------------- local function setVoid(on) if on == voided then return end if on then if not enterVoid() then return end voided = true stroke.Color = Color3.fromRGB(0, 255, 140) button.TextColor3 = Color3.fromRGB(0, 255, 140) else voided = false exitVoid(true) stroke.Color = Color3.fromRGB(70, 70, 70) button.TextColor3 = Color3.fromRGB(255, 255, 255) end end button.Activated:Connect(function() -- Activated covers touch taps and mouse clicks if suppressToggle then suppressToggle = false return end setVoid(not voided) end) LocalPlayer.CharacterAdded:Connect(function() if voided then voided = false exitVoid(false) -- fresh spawn stays at spawn; unbolt the camera, clear the pad and rig stroke.Color = Color3.fromRGB(70, 70, 70) button.TextColor3 = Color3.fromRGB(255, 255, 255) end end)