local pi = math.pi local abs = math.abs local clamp = math.clamp local exp = math.exp local rad = math.rad local sign = math.sign local sqrt = math.sqrt local tan = math.tan local ContextActionService = game:GetService("ContextActionService") local Players = game:GetService("Players") local RunService = game:GetService("RunService") local StarterGui = game:GetService("StarterGui") local UserInputService = game:GetService("UserInputService") local Workspace = game:GetService("Workspace") local Settings = UserSettings() local GameSettings = Settings.GameSettings local Lighting = game:GetService("Lighting") local TweenService = game:GetService("TweenService") local GuiService = game:GetService("GuiService") local CoreGui = game:GetService("CoreGui") local LocalPlayer = Players.LocalPlayer if not LocalPlayer then Players:GetPropertyChangedSignal("LocalPlayer"):Wait() LocalPlayer = Players.LocalPlayer end local Camera = Workspace.CurrentCamera Workspace:GetPropertyChangedSignal("CurrentCamera"):Connect(function() local newCamera = Workspace.CurrentCamera if newCamera then Camera = newCamera end end) local freecamGui = Instance.new("ScreenGui") freecamGui.Name = "Freecam" freecamGui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling freecamGui.ResetOnSpawn = false freecamGui.Parent = CoreGui freecamGui.Enabled = true local touchGui = nil local floatingButton = nil local uiMainFrame = nil local FFlagUserExitFreecamBreaksWithShiftlock = false local FFlagUserShowGuiHideToggles = false local FFlagUserFixFreecamDeltaTimeCalculation = false local FFlagUserFixFreecamGuiChangeVisibility = false local FFlagUserFreecamControlSpeed = true local FFlagUserFreecamTiltControl = true local FFlagUserFreecamSmoothnessControl = true local FFlagUserFreecamGuiDestabilization = false local FFlagUserFreecamDepthOfFieldEffect = true local FFlagUserFreecamPlayerLock = true local FFlagUserFreecamPlayerLockResetHeight = false local FFlagUserFreecamCustomGui = true local FREECAM_ENABLED_ATTRIBUTE_NAME = "FreecamEnabled" local TOGGLE_INPUT_PRIORITY = Enum.ContextActionPriority.Low.Value local INPUT_PRIORITY = Enum.ContextActionPriority.High.Value local NAV_GAIN = Vector3.new(1, 1, 1)*64 local PAN_GAIN = Vector2.new(0.75, 1)*8 local FOV_GAIN = 300 local ROLL_GAIN = -pi/2 local PITCH_LIMIT = rad(90) local VEL_STIFFNESS = 1.5 local PAN_STIFFNESS = 1.0 local FOV_STIFFNESS = 4.0 local ROLL_STIFFNESS = 1.0 local VEL_ADJ_STIFFNESS = 0.75 local PAN_ADJ_STIFFNESS = 0.75 local FOV_ADJ_STIFFNESS = 0.75 local ROLL_ADJ_STIFFNESS = 0.75 local VEL_MIN_STIFFNESS = 0.01 local PAN_MIN_STIFFNESS = 0.01 local FOV_MIN_STIFFNESS = 0.01 local ROLL_MIN_STIFFNESS = 0.01 local VEL_MAX_STIFFNESS = 10.0 local PAN_MAX_STIFFNESS = 10.0 local FOV_MAX_STIFFNESS = 10.0 local ROLL_MAX_STIFFNESS = 10.0 local lastPressTime = {} local lastResetTime = 0 local DOUBLE_TAP_TIME_THRESHOLD = 0.25 local DOUBLE_TAP_DEBOUNCE_TIME = 0.1 local postEffects = {} local playerGuiConnection = nil local cameraConnection = nil local lightingConnection = nil local playerAddedConnection = nil local playerRemovingConnection = nil local PLAYER_LOCK_DEFAULT_ZOOM = 20 local PLAYER_LOCK_MIN_ZOOM = 5 local PLAYER_LOCK_MAX_ZOOM = 50 local PLAYER_LOCK_DEFAULT_HEIGHT = 0 local PLAYER_LOCK_HEIGHT_RANGE = 10 local playerLockEnabled = false local playerLockZoom = 20 local playerLockHeight = 0 local playerList = {} local currentTargetIndex = 1 local rootPart = nil local screenGuisEnabled = false local leaderboardEnabled = false local mobileMoveVector = Vector3.new(0, 0, 0) local mobileLookVector = Vector2.new(0, 0) local mobileFovDelta = 0 local mobileNavSpeed = 1 local flyUpActive = false local flyDownActive = false local tiltLeftActive = false local tiltRightActive = false local customTiltLeftKeys = {"Z"} local customTiltRightKeys = {"C"} local mouseSensitivity = 1 local touchLookSensitivity = 1 local fovSensitivity = 1 local Spring = {} Spring.__index = Spring function Spring.new(freq, pos) local self = setmetatable({}, Spring) self.f = freq self.p = pos self.v = pos*0 return self end function Spring:Update(dt, goal) local f = self.f*2*pi local p0 = self.p local v0 = self.v local offset = goal - p0 local decay = exp(-f*dt) local p1 = goal + (v0*dt - offset*(f*dt + 1))*decay local v1 = (f*dt*(offset*f - v0) + v0)*decay self.p = p1 self.v = v1 return p1 end function Spring:SetFreq(freq) self.f = freq end function Spring:Reset(pos) self.p = pos self.v = pos*0 end local cameraPos = Vector3.new() local cameraRot = Vector3.new() local cameraFov = 0 local velSpring = Spring.new(VEL_STIFFNESS, Vector3.new()) local panSpring = Spring.new(PAN_STIFFNESS, Vector2.new()) local fovSpring = Spring.new(FOV_STIFFNESS, 0) local rollSpring = Spring.new(ROLL_STIFFNESS, 0) local tiltLeftActiveKB = false local tiltRightActiveKB = false function CreateFlyButtons(parent) local PADDING = 9 local buttonFrame = Instance.new("Frame") buttonFrame.Name = "FreeCamFlybtn" buttonFrame.BackgroundTransparency = 1 buttonFrame.Parent = parent buttonFrame.ZIndex = 15 local flyDownBtn = Instance.new("ImageButton") flyDownBtn.Name = "FlyDownBtn" flyDownBtn.BackgroundTransparency = 1 flyDownBtn.Image = "rbxasset://textures/ui/Input/TouchControlsSheetV2.png" flyDownBtn.ImageRectOffset = Vector2.new(1, 146) flyDownBtn.ImageRectSize = Vector2.new(144, 144) flyDownBtn.Rotation = 180 flyDownBtn.Parent = buttonFrame flyDownBtn.ZIndex = 15 local flyUpBtn = Instance.new("ImageButton") flyUpBtn.Name = "FlyUpBtn" flyUpBtn.BackgroundTransparency = 1 flyUpBtn.Image = "rbxasset://textures/ui/Input/TouchControlsSheetV2.png" flyUpBtn.ImageRectOffset = Vector2.new(1, 146) flyUpBtn.ImageRectSize = Vector2.new(144, 144) flyUpBtn.Rotation = 0 flyUpBtn.Parent = buttonFrame flyUpBtn.ZIndex = 15 flyDownBtn.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.Touch and input.UserInputState == Enum.UserInputState.Begin then flyDownBtn.ImageRectOffset = Vector2.new(146, 146) flyDownActive = true end end) flyDownBtn.InputEnded:Connect(function(input) if input.UserInputType == Enum.UserInputType.Touch then flyDownBtn.ImageRectOffset = Vector2.new(1, 146) flyDownActive = false end end) flyUpBtn.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.Touch and input.UserInputState == Enum.UserInputState.Begin then flyUpBtn.ImageRectOffset = Vector2.new(146, 146) flyUpActive = true end end) flyUpBtn.InputEnded:Connect(function(input) if input.UserInputType == Enum.UserInputType.Touch then flyUpBtn.ImageRectOffset = Vector2.new(1, 146) flyUpActive = false end end) function updateButtonSize() local screenSize = parent.AbsoluteSize local isSmallScreen = math.min(screenSize.X, screenSize.Y) <= 500 local buttonSize = isSmallScreen and 70 or 90 local totalWidth = (buttonSize * 2) + (PADDING * 3) local totalHeight = buttonSize + (PADDING * 2) buttonFrame.Size = UDim2.new(0, totalWidth, 0, totalHeight) buttonFrame.Position = UDim2.new(1, -(totalWidth + PADDING), 1, -(totalHeight + PADDING)) flyDownBtn.Size = UDim2.new(0, buttonSize, 0, buttonSize) flyDownBtn.Position = UDim2.new(0, PADDING, 0, PADDING) flyUpBtn.Size = UDim2.new(0, buttonSize, 0, buttonSize) flyUpBtn.Position = UDim2.new(0, PADDING + buttonSize + PADDING, 0, PADDING) end parent:GetPropertyChangedSignal("AbsoluteSize"):Connect(updateButtonSize) updateButtonSize() GuiService.MenuOpened:Connect(function() flyDownBtn.ImageRectOffset = Vector2.new(1, 146) flyUpBtn.ImageRectOffset = Vector2.new(1, 146) flyDownActive = false flyUpActive = false end) return buttonFrame, flyDownBtn, flyUpBtn end function CreateTiltButtons(parent) local PADDING = 9 local buttonFrame = Instance.new("Frame") buttonFrame.Name = "TiltButtons" buttonFrame.BackgroundTransparency = 1 buttonFrame.Parent = parent buttonFrame.ZIndex = 15 local tiltLeftBtn = Instance.new("ImageButton") tiltLeftBtn.Name = "TiltLeftBtn" tiltLeftBtn.BackgroundTransparency = 1 tiltLeftBtn.Image = "rbxassetid://138041015580154" tiltLeftBtn.Parent = buttonFrame tiltLeftBtn.ZIndex = 15 local tiltRightBtn = Instance.new("ImageButton") tiltRightBtn.Name = "TiltRightBtn" tiltRightBtn.BackgroundTransparency = 1 tiltRightBtn.Image = "rbxassetid://122289559454004" tiltRightBtn.Parent = buttonFrame tiltRightBtn.ZIndex = 15 tiltLeftBtn.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.Touch and input.UserInputState == Enum.UserInputState.Begin then tiltLeftBtn.ImageTransparency = 0.3 tiltLeftActive = true end end) tiltLeftBtn.InputEnded:Connect(function(input) if input.UserInputType == Enum.UserInputType.Touch then tiltLeftBtn.ImageTransparency = 0 tiltLeftActive = false end end) tiltRightBtn.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.Touch and input.UserInputState == Enum.UserInputState.Begin then tiltRightBtn.ImageTransparency = 0.3 tiltRightActive = true end end) tiltRightBtn.InputEnded:Connect(function(input) if input.UserInputType == Enum.UserInputType.Touch then tiltRightBtn.ImageTransparency = 0 tiltRightActive = false end end) function updateButtonSize() local screenSize = parent.AbsoluteSize local isSmallScreen = math.min(screenSize.X, screenSize.Y) <= 500 local buttonSize = isSmallScreen and 60 or 75 local totalWidth = (buttonSize * 2) + (PADDING * 3) buttonFrame.Size = UDim2.new(0, totalWidth, 0, buttonSize + (PADDING * 2)) buttonFrame.Position = UDim2.new(0, PADDING, 1, -(buttonSize + (PADDING * 2))) tiltLeftBtn.Size = UDim2.new(0, buttonSize, 0, buttonSize) tiltLeftBtn.Position = UDim2.new(0, PADDING, 0, PADDING) tiltRightBtn.Size = UDim2.new(0, buttonSize, 0, buttonSize) tiltRightBtn.Position = UDim2.new(0, PADDING + buttonSize + PADDING, 0, PADDING) end parent:GetPropertyChangedSignal("AbsoluteSize"):Connect(updateButtonSize) updateButtonSize() GuiService.MenuOpened:Connect(function() tiltLeftActive = false tiltRightActive = false tiltLeftBtn.ImageTransparency = 0 tiltRightBtn.ImageTransparency = 0 end) return buttonFrame, tiltLeftBtn, tiltRightBtn end function CreatePlayerLockBar(parent) local PADDING = 10 local barFrame = Instance.new("Frame") barFrame.Name = "PlayerLockBar" barFrame.BackgroundColor3 = Color3.fromRGB(30, 30, 40) barFrame.BackgroundTransparency = 0.2 barFrame.BorderSizePixel = 0 barFrame.Parent = parent barFrame.ZIndex = 15 local barCorner = Instance.new("UICorner") barCorner.CornerRadius = UDim.new(0, 25) barCorner.Parent = barFrame local prevBtn = Instance.new("TextButton") prevBtn.Name = "PrevBtn" prevBtn.Text = "<" prevBtn.TextColor3 = Color3.fromRGB(255, 255, 255) prevBtn.TextSize = 24 prevBtn.Font = Enum.Font.GothamBold prevBtn.BackgroundColor3 = Color3.fromRGB(50, 50, 70) prevBtn.BackgroundTransparency = 0.5 prevBtn.BorderSizePixel = 0 prevBtn.Parent = barFrame prevBtn.ZIndex = 15 local prevCorner = Instance.new("UICorner") prevCorner.CornerRadius = UDim.new(0, 20) prevCorner.Parent = prevBtn local playerLabel = Instance.new("TextLabel") playerLabel.Name = "PlayerLabel" playerLabel.Text = "Player Lock: OFF" playerLabel.TextColor3 = Color3.fromRGB(255, 255, 255) playerLabel.TextSize = 14 playerLabel.Font = Enum.Font.GothamBold playerLabel.BackgroundColor3 = Color3.fromRGB(40, 40, 60) playerLabel.BackgroundTransparency = 0.5 playerLabel.BorderSizePixel = 0 playerLabel.Parent = barFrame playerLabel.ZIndex = 15 local playerCorner = Instance.new("UICorner") playerCorner.CornerRadius = UDim.new(0, 20) playerCorner.Parent = playerLabel local nextBtn = Instance.new("TextButton") nextBtn.Name = "NextBtn" nextBtn.Text = ">" nextBtn.TextColor3 = Color3.fromRGB(255, 255, 255) nextBtn.TextSize = 24 nextBtn.Font = Enum.Font.GothamBold nextBtn.BackgroundColor3 = Color3.fromRGB(50, 50, 70) nextBtn.BackgroundTransparency = 0.5 nextBtn.BorderSizePixel = 0 nextBtn.Parent = barFrame nextBtn.ZIndex = 15 local nextCorner = Instance.new("UICorner") nextCorner.CornerRadius = UDim.new(0, 20) nextCorner.Parent = nextBtn local toggleBtn = Instance.new("TextButton") toggleBtn.Name = "ToggleBtn" toggleBtn.Text = "Lock" toggleBtn.TextColor3 = Color3.fromRGB(255, 255, 255) toggleBtn.TextSize = 12 toggleBtn.Font = Enum.Font.GothamBold toggleBtn.BackgroundColor3 = Color3.fromRGB(100, 200, 255) toggleBtn.BackgroundTransparency = 0.3 toggleBtn.BorderSizePixel = 0 toggleBtn.Parent = barFrame toggleBtn.ZIndex = 15 local toggleCorner = Instance.new("UICorner") toggleCorner.CornerRadius = UDim.new(0, 15) toggleCorner.Parent = toggleBtn function updateBarSize() local screenSize = parent.AbsoluteSize local isSmallScreen = math.min(screenSize.X, screenSize.Y) <= 500 local btnSize = isSmallScreen and 45 or 55 local labelWidth = 160 local totalWidth = btnSize + labelWidth + btnSize + 55 barFrame.Size = UDim2.new(0, totalWidth, 0, btnSize) barFrame.Position = UDim2.new(0.5, -totalWidth/2, 1, -(btnSize + PADDING * 2)) prevBtn.Size = UDim2.new(0, btnSize, 0, btnSize) prevBtn.Position = UDim2.new(0, PADDING, 0, 0) playerLabel.Size = UDim2.new(0, labelWidth, 0, btnSize) playerLabel.Position = UDim2.new(0, btnSize + PADDING * 2, 0, 0) nextBtn.Size = UDim2.new(0, btnSize, 0, btnSize) nextBtn.Position = UDim2.new(1, -(btnSize + PADDING), 0, 0) toggleBtn.Size = UDim2.new(0, 45, 0, btnSize - 10) toggleBtn.Position = UDim2.new(1, -(btnSize + PADDING + 50), 0, 5) end parent:GetPropertyChangedSignal("AbsoluteSize"):Connect(updateBarSize) updateBarSize() local function updatePlayerLabel() if playerLockEnabled and #playerList > 0 then playerLabel.Text = "Lock: " .. playerList[currentTargetIndex].Name toggleBtn.Text = "Unlock" toggleBtn.BackgroundColor3 = Color3.fromRGB(255, 100, 100) else playerLabel.Text = "Player Lock: OFF" toggleBtn.Text = "Lock" toggleBtn.BackgroundColor3 = Color3.fromRGB(100, 200, 255) end end prevBtn.MouseButton1Click:Connect(function() if playerLockEnabled and #playerList > 0 then for i = 1, #playerList do currentTargetIndex = currentTargetIndex - 1 if currentTargetIndex < 1 then currentTargetIndex = #playerList end local targetPlayer = playerList[currentTargetIndex] local targetCharacter = targetPlayer and targetPlayer.Character if targetCharacter then local humanoid = targetCharacter:FindFirstChildOfClass("Humanoid") if humanoid and humanoid.RootPart then rootPart = humanoid.RootPart break end end end updatePlayerLabel() end end) nextBtn.MouseButton1Click:Connect(function() if playerLockEnabled and #playerList > 0 then for i = 1, #playerList do currentTargetIndex = currentTargetIndex + 1 if currentTargetIndex > #playerList then currentTargetIndex = 1 end local targetPlayer = playerList[currentTargetIndex] local targetCharacter = targetPlayer and targetPlayer.Character if targetCharacter then local humanoid = targetCharacter:FindFirstChildOfClass("Humanoid") if humanoid and humanoid.RootPart then rootPart = humanoid.RootPart break end end end updatePlayerLabel() end end) toggleBtn.MouseButton1Click:Connect(function() playerLockEnabled = not playerLockEnabled if playerLockEnabled then playerLockZoom = PLAYER_LOCK_DEFAULT_ZOOM playerLockHeight = PLAYER_LOCK_DEFAULT_HEIGHT if #playerList > 0 then local targetPlayer = playerList[currentTargetIndex] local targetCharacter = targetPlayer and targetPlayer.Character if targetCharacter then local humanoid = targetCharacter:FindFirstChildOfClass("Humanoid") if humanoid and humanoid.RootPart then rootPart = humanoid.RootPart end end end end updatePlayerLabel() end) return barFrame end function CreateTouchControls() local gui = Instance.new("ScreenGui") gui.Name = "FreeCamTouchControll" gui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling gui.ResetOnSpawn = false gui.Parent = LocalPlayer:WaitForChild("PlayerGui") local thumbstickFrame = Instance.new("Frame") thumbstickFrame.Name = "DynamicThumbstickFrame" thumbstickFrame.BorderSizePixel = 0 thumbstickFrame.Visible = true thumbstickFrame.BackgroundTransparency = 1 thumbstickFrame.BackgroundColor3 = Color3.new(0, 0, 0) thumbstickFrame.Active = true thumbstickFrame.Size = UDim2.new(0.4, 0, 0.6666666666666666, 0) thumbstickFrame.Position = UDim2.new(0, 0, 0.3333333333333333, 0) thumbstickFrame.Parent = gui thumbstickFrame.ZIndex = 10 local startImage = Instance.new("ImageLabel") startImage.Name = "ThumbstickStart" startImage.Visible = true startImage.BackgroundTransparency = 1 startImage.Image = "rbxasset://textures/ui/Input/TouchControlsSheetV2.png" startImage.ImageRectOffset = Vector2.new(1, 1) startImage.ImageRectSize = Vector2.new(144, 144) startImage.ImageColor3 = Color3.new(0, 0, 0) startImage.ImageTransparency = 1 startImage.AnchorPoint = Vector2.new(0.5, 0.5) startImage.ZIndex = 10 startImage.Parent = thumbstickFrame local endImage = Instance.new("ImageLabel") endImage.Name = "ThumbstickEnd" endImage.Visible = true endImage.BackgroundTransparency = 1 endImage.Image = "rbxasset://textures/ui/Input/TouchControlsSheetV2.png" endImage.ImageRectOffset = Vector2.new(1, 1) endImage.ImageRectSize = Vector2.new(144, 144) endImage.ImageColor3 = Color3.new(0, 0, 0) endImage.ImageTransparency = 1 endImage.AnchorPoint = Vector2.new(0.5, 0.5) endImage.ZIndex = 10 endImage.Parent = thumbstickFrame local middleImages = {} local originalTransparencies = {0.11, 0.30, 0.40, 0.50, 0.60, 0.70, 0.75} for i = 1, 7 do local middle = Instance.new("ImageLabel") middle.Name = "ThumbstickMiddle" middle.Visible = false middle.BackgroundTransparency = 1 middle.Image = "rbxasset://textures/ui/Input/TouchControlsSheetV2.png" middle.ImageRectOffset = Vector2.new(1, 1) middle.ImageRectSize = Vector2.new(144, 144) middle.ImageTransparency = originalTransparencies[i] middle.AnchorPoint = Vector2.new(0.5, 0.5) middle.ZIndex = 9 middle.Parent = thumbstickFrame middleImages[i] = middle end local thumbstickSize = 45 local thumbstickRingSize = 20 local middleSize = 10 local middleSpacing = 14 local radiusDeadZone = 2 local radiusMaxSpeed = 20 local moveTouchObject = nil local moveTouchStartPosition = nil local moveTouchLockedIn = false local moveTouchFirstChanged = false local isFirstTouch = true function updatePositions() local baseX = thumbstickRingSize * 3.3 local baseY = thumbstickRingSize * 2.8 startImage.Position = UDim2.new(0, baseX, 1, -baseY) startImage.Size = UDim2.new(0, thumbstickRingSize * 3.7, 0, thumbstickRingSize * 3.7) endImage.Position = startImage.Position endImage.Size = UDim2.new(0, thumbstickSize * 0.8, 0, thumbstickSize * 0.8) end thumbstickFrame:GetPropertyChangedSignal("AbsoluteSize"):Connect(updatePositions) task.wait(0.1) updatePositions() function layoutMiddleImages(startPos, endPos) local centerOffset = thumbstickSize / 2 + middleSize local delta = endPos - startPos local dist = delta.Magnitude - thumbstickRingSize / 2 - middleSize local direction = delta.Unit local totalSpacing = middleSpacing * 7 local stepSize = middleSpacing if totalSpacing < dist then stepSize = dist / 7 end for i = 1, 7 do local img = middleImages[i] local startDist = centerOffset + stepSize * (i - 2) local endDist = centerOffset + stepSize * (i - 1) if startDist < dist then local pos = endPos - direction * endDist local alpha = 1 - (endDist - dist) / stepSize local clampedAlpha = math.clamp(alpha, 0, 1) img.Visible = true img.Position = UDim2.new(0, pos.X, 0, pos.Y) img.Size = UDim2.new(0, middleSize * clampedAlpha, 0, middleSize * clampedAlpha) else img.Visible = false end end end function moveStick(touchPos) local startPos = Vector2.new(moveTouchStartPosition.X, moveTouchStartPosition.Y) - thumbstickFrame.AbsolutePosition local endPos = Vector2.new(touchPos.X, touchPos.Y) - thumbstickFrame.AbsolutePosition endImage.Position = UDim2.new(0, endPos.X, 0, endPos.Y) layoutMiddleImages(startPos, endPos) end function doMove(offset) local mag = offset.Magnitude if mag < radiusDeadZone then mobileMoveVector = Vector3.new(0, 0, 0) else local unit = offset.Unit local speedFactor = (radiusMaxSpeed - mag) / radiusMaxSpeed local scaled = unit * (1 - math.max(0, speedFactor)) mobileMoveVector = Vector3.new(scaled.X, 0, scaled.Y) end end function fadeThumbstick(fadeIn) local tweenInfo = TweenInfo.new(0.15, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut) if fadeIn then TweenService:Create(startImage, tweenInfo, {ImageTransparency = 0}):Play() TweenService:Create(endImage, tweenInfo, {ImageTransparency = 0.2}):Play() for i = 1, 7 do TweenService:Create(middleImages[i], tweenInfo, {ImageTransparency = originalTransparencies[i]}):Play() end else TweenService:Create(startImage, tweenInfo, {ImageTransparency = 1}):Play() TweenService:Create(endImage, tweenInfo, {ImageTransparency = 1}):Play() for i = 1, 7 do TweenService:Create(middleImages[i], tweenInfo, {ImageTransparency = 1}):Play() end end end function onInputEnded() moveTouchObject = nil mobileMoveVector = Vector3.new(0, 0, 0) fadeThumbstick(false) end function inputInFrame(touch) local absPos = thumbstickFrame.AbsolutePosition local absSize = thumbstickFrame.AbsoluteSize local touchPos = touch.Position return touchPos.X >= absPos.X and touchPos.Y >= absPos.Y and touchPos.X <= absPos.X + absSize.X and touchPos.Y <= absPos.Y + absSize.Y end function onTouchBegin(touch) if moveTouchObject then return end if not inputInFrame(touch) then return end if isFirstTouch then isFirstTouch = false local growTween = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out) TweenService:Create(startImage, growTween, {Size = UDim2.new(0, 0, 0, 0)}):Play() TweenService:Create(endImage, growTween, { Size = UDim2.new(0, thumbstickSize, 0, thumbstickSize), ImageColor3 = Color3.new(0, 0, 0) }):Play() end moveTouchLockedIn = false moveTouchObject = touch moveTouchStartPosition = touch.Position moveTouchFirstChanged = true end function onTouchMove(touch) if touch ~= moveTouchObject then return end if moveTouchFirstChanged then moveTouchFirstChanged = false local startPosRel = Vector2.new(touch.Position.X - thumbstickFrame.AbsolutePosition.X, touch.Position.Y - thumbstickFrame.AbsolutePosition.Y) startImage.Visible = true startImage.Position = UDim2.new(0, startPosRel.X, 0, startPosRel.Y) endImage.Visible = true endImage.Position = startImage.Position fadeThumbstick(true) moveStick(touch.Position) end moveTouchLockedIn = true local offset = Vector2.new(touch.Position.X - moveTouchStartPosition.X, touch.Position.Y - moveTouchStartPosition.Y) if math.abs(offset.X) > 0 or math.abs(offset.Y) > 0 then doMove(offset) moveStick(touch.Position) end end function onTouchEnd(touch) if touch == moveTouchObject then onInputEnded() end end local beginCon = UserInputService.TouchStarted:Connect(onTouchBegin) local moveCon = UserInputService.TouchMoved:Connect(onTouchMove) local endCon = UserInputService.TouchEnded:Connect(onTouchEnd) GuiService.MenuOpened:Connect(function() if moveTouchObject then onInputEnded() end end) local rightDragActive = false local rightDragStart = nil local rightDragTouch = nil UserInputService.TouchStarted:Connect(function(touch) local screenSize = Camera.ViewportSize if touch.Position.X > screenSize.X / 2 then rightDragActive = true rightDragStart = touch.Position rightDragTouch = touch end end) UserInputService.TouchMoved:Connect(function(touch) if rightDragActive and rightDragTouch == touch and rightDragStart then local delta = touch.Position - rightDragStart mobileLookVector = Vector2.new(-delta.Y * 0.1 * touchLookSensitivity, -delta.X * 0.1 * touchLookSensitivity) rightDragStart = touch.Position end end) UserInputService.TouchEnded:Connect(function(touch) if rightDragTouch == touch then rightDragActive = false rightDragTouch = nil mobileLookVector = Vector2.new(0, 0) end end) local pinchTouch1 = nil local pinchTouch2 = nil local pinchActive = false local lastPinchDistance = 0 UserInputService.TouchStarted:Connect(function(touch) local screenSize = Camera.ViewportSize if touch.Position.X > screenSize.X / 2 then if not pinchTouch1 then pinchTouch1 = touch elseif not pinchTouch2 and touch ~= pinchTouch1 then pinchTouch2 = touch pinchActive = true lastPinchDistance = (pinchTouch1.Position - pinchTouch2.Position).Magnitude end end end) UserInputService.TouchMoved:Connect(function(touch) if pinchActive and pinchTouch1 and pinchTouch2 then if touch == pinchTouch1 then pinchTouch1 = touch elseif touch == pinchTouch2 then pinchTouch2 = touch end local currentDistance = (pinchTouch1.Position - pinchTouch2.Position).Magnitude local delta = currentDistance - lastPinchDistance if math.abs(delta) > 0.5 then mobileFovDelta = -delta * 0.35 * fovSensitivity lastPinchDistance = currentDistance end end end) UserInputService.TouchEnded:Connect(function(touch) if touch == pinchTouch1 then pinchTouch1 = pinchTouch2 pinchTouch2 = nil elseif touch == pinchTouch2 then pinchTouch2 = nil end if not pinchTouch1 or not pinchTouch2 then pinchActive = false lastPinchDistance = 0 end end) local flyButtons = CreateFlyButtons(gui) local tiltButtons = CreateTiltButtons(gui) local playerLockBar = CreatePlayerLockBar(gui) return gui end local Input = {} do local thumbstickCurve do local K_CURVATURE = 2.0 local K_DEADZONE = 0.15 function fCurve(x) return (exp(K_CURVATURE*x) - 1)/(exp(K_CURVATURE) - 1) end function fDeadzone(x) return fCurve((x - K_DEADZONE)/(1 - K_DEADZONE)) end function thumbstickCurve(x) return sign(x)*clamp(fDeadzone(abs(x)), 0, 1) end end local gamepad = { ButtonX = 0, ButtonY = 0, DPadDown = 0, DPadUp = 0, DPadLeft = 0, DPadRight = 0, ButtonL2 = 0, ButtonR2 = 0, ButtonL1 = 0, ButtonR1 = 0, Thumbstick1 = Vector2.new(), Thumbstick2 = Vector2.new(), } local keyboard = { W = 0, A = 0, S = 0, D = 0, E = 0, Q = 0, U = 0, H = 0, J = 0, K = 0, I = 0, Y = 0, Up = 0, Down = 0, Left = 0, Right = 0, LeftShift = 0, RightShift = 0, Z = 0, C = 0, Comma = 0, Period = 0, LeftBracket = 0, RightBracket = 0, Semicolon = 0, Quote = 0, V = 0, B = 0, N = 0, M = 0, BackSlash = 0, Minus = 0, Equals = 0, Slash = 0, R = 0, T = 0, G = 0, X = 0, L = 0 } local mouse = { Delta = Vector2.new(), MouseWheel = 0 } local DEFAULT_FPS = 60 local NAV_GAMEPAD_SPEED = Vector3.new(1, 1, 1) local NAV_KEYBOARD_SPEED = Vector3.new(1, 1, 1) local PAN_MOUSE_SPEED = Vector2.new(1, 1)*(pi/64) local PAN_MOUSE_SPEED_DT = PAN_MOUSE_SPEED/DEFAULT_FPS local PAN_GAMEPAD_SPEED = Vector2.new(1, 1)*(pi/8) local FOV_WHEEL_SPEED = 1.0 local FOV_WHEEL_SPEED_DT = FOV_WHEEL_SPEED/DEFAULT_FPS local FOV_GAMEPAD_SPEED = 0.25 local ROLL_GAMEPAD_SPEED = 1.0 local ROLL_KEYBOARD_SPEED = 1.0 local NAV_ADJ_SPEED = 0.75 local NAV_MIN_SPEED = 0.01 local NAV_MAX_SPEED = 4.0 local NAV_SHIFT_MUL = 0.25 local FOV_ADJ_SPEED = 0.75 local FOV_MIN_SPEED = 0.01 local FOV_MAX_SPEED = 4.0 local ROLL_ADJ_SPEED = 0.75 local ROLL_MIN_SPEED = 0.01 local ROLL_MAX_SPEED = 4.0 local DoFConstants = { FarIntensity = { ADJ = 0.1, MIN = 0.0, MAX = 1.0 }, NearIntensity = { ADJ = 0.1, MIN = 0.0, MAX = 1.0 }, FocusDistance = { ADJ = 20.0, MIN = 0.0, MAX = 200.0 }, FocusRadius = { ADJ = 5.0, MIN = 0.0, MAX = 50.0 }, } local navSpeed = 1 local rollSpeed = 1 local fovSpeed = 1 function Input.Vel(dt) if FFlagUserFreecamControlSpeed then navSpeed = clamp(navSpeed + dt*(keyboard.Up - keyboard.Down + gamepad.DPadUp - gamepad.DPadDown)*NAV_ADJ_SPEED, NAV_MIN_SPEED, NAV_MAX_SPEED) else navSpeed = clamp(navSpeed + dt*(keyboard.Up - keyboard.Down)*NAV_ADJ_SPEED, 0.01, 4) end local flyVertical = 0 if flyUpActive then flyVertical = flyVertical + 1 end if flyDownActive then flyVertical = flyVertical - 1 end local mobileMove = Vector3.new(mobileMoveVector.X, flyVertical, mobileMoveVector.Z) * mobileNavSpeed local kGamepad = Vector3.new( thumbstickCurve(gamepad.Thumbstick1.X), thumbstickCurve(gamepad.ButtonR2) - thumbstickCurve(gamepad.ButtonL2), thumbstickCurve(-gamepad.Thumbstick1.Y) )*NAV_GAMEPAD_SPEED local kKeyboard = Vector3.new( keyboard.D - keyboard.A + keyboard.K - keyboard.H, keyboard.E - keyboard.Q + keyboard.I - keyboard.Y, keyboard.S - keyboard.W + keyboard.J - keyboard.U )*NAV_KEYBOARD_SPEED local shift = UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or UserInputService:IsKeyDown(Enum.KeyCode.RightShift) return (kGamepad + kKeyboard + mobileMove)*(navSpeed*(shift and NAV_SHIFT_MUL or 1)) end function Input.Pan(dt) local mobilePan = mobileLookVector local kGamepad = Vector2.new( thumbstickCurve(gamepad.Thumbstick2.Y), thumbstickCurve(-gamepad.Thumbstick2.X) )*PAN_GAMEPAD_SPEED local kMouse = mouse.Delta*PAN_MOUSE_SPEED * mouseSensitivity if FFlagUserFixFreecamDeltaTimeCalculation then if dt > 0 then kMouse = (mouse.Delta/dt)*PAN_MOUSE_SPEED_DT * mouseSensitivity end end mouse.Delta = Vector2.new() return kGamepad + kMouse + mobilePan end function Input.Fov(dt) if FFlagUserFreecamControlSpeed then fovSpeed = clamp(fovSpeed + dt*(keyboard.Right - keyboard.Left + gamepad.DPadRight - gamepad.DPadLeft)*FOV_ADJ_SPEED, FOV_MIN_SPEED, FOV_MAX_SPEED) end local kGamepad = (gamepad.ButtonX - gamepad.ButtonY)*FOV_GAMEPAD_SPEED local kMouse = mouse.MouseWheel*FOV_WHEEL_SPEED * fovSensitivity local kMobile = mobileFovDelta mobileFovDelta = 0 if FFlagUserFixFreecamDeltaTimeCalculation then if dt > 0 then kMouse = (mouse.MouseWheel/dt)*FOV_WHEEL_SPEED_DT * fovSensitivity end end mouse.MouseWheel = 0 if FFlagUserFreecamControlSpeed then return (kGamepad + kMouse + kMobile)*fovSpeed else return kGamepad + kMouse + kMobile end end function Input.Roll(dt) rollSpeed = clamp(rollSpeed + dt*(keyboard.Period - keyboard.Comma)*ROLL_ADJ_SPEED, ROLL_MIN_SPEED, ROLL_MAX_SPEED) local kGamepad = (gamepad.ButtonR1 - gamepad.ButtonL1)*ROLL_GAMEPAD_SPEED local kKeyboard = (keyboard.C - keyboard.Z)*ROLL_KEYBOARD_SPEED local kTouch = 0 if tiltLeftActive then kTouch = kTouch + 1 end if tiltRightActive then kTouch = kTouch - 1 end local kCustomTilt = 0 if tiltLeftActiveKB then kCustomTilt = kCustomTilt + 1 end if tiltRightActiveKB then kCustomTilt = kCustomTilt - 1 end return (kGamepad + kKeyboard + kTouch + kCustomTilt)*rollSpeed end function Input.SpringControl(dt) if FFlagUserFreecamDepthOfFieldEffect then local shiftIsDown = UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or UserInputService:IsKeyDown(Enum.KeyCode.RightShift) local ctrlIsDown = UserInputService:IsKeyDown(Enum.KeyCode.LeftControl) or UserInputService:IsKeyDown(Enum.KeyCode.RightControl) if shiftIsDown or ctrlIsDown then return end end VEL_STIFFNESS = clamp(VEL_STIFFNESS + dt*(keyboard.RightBracket - keyboard.LeftBracket)*VEL_ADJ_STIFFNESS, VEL_MIN_STIFFNESS, VEL_MAX_STIFFNESS) velSpring:SetFreq(VEL_STIFFNESS) PAN_STIFFNESS = clamp(PAN_STIFFNESS + dt*(keyboard.Quote - keyboard.Semicolon)*PAN_ADJ_STIFFNESS, PAN_MIN_STIFFNESS, PAN_MAX_STIFFNESS) panSpring:SetFreq(PAN_STIFFNESS) FOV_STIFFNESS = clamp(FOV_STIFFNESS + dt*(keyboard.B - keyboard.V)*FOV_ADJ_STIFFNESS, FOV_MIN_STIFFNESS, FOV_MAX_STIFFNESS) fovSpring:SetFreq(FOV_STIFFNESS) ROLL_STIFFNESS = clamp(ROLL_STIFFNESS + dt*(keyboard.M - keyboard.N)*ROLL_ADJ_STIFFNESS, ROLL_MIN_STIFFNESS, ROLL_MAX_STIFFNESS) rollSpring:SetFreq(ROLL_STIFFNESS) end function Input.DoF(dt) local shiftIsDown = UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or UserInputService:IsKeyDown(Enum.KeyCode.RightShift) local ctrlIsDown = UserInputService:IsKeyDown(Enum.KeyCode.LeftControl) or UserInputService:IsKeyDown(Enum.KeyCode.RightControl) if shiftIsDown then FreecamDepthOfField.FarIntensity = clamp( FreecamDepthOfField.FarIntensity + dt * (keyboard.RightBracket - keyboard.LeftBracket) * DoFConstants.FarIntensity.ADJ, DoFConstants.FarIntensity.MIN, DoFConstants.FarIntensity.MAX ) FreecamDepthOfField.InFocusRadius = clamp( FreecamDepthOfField.InFocusRadius + dt * (keyboard.Equals - keyboard.Minus) * DoFConstants.FocusRadius.ADJ, DoFConstants.FocusRadius.MIN, DoFConstants.FocusRadius.MAX ) elseif ctrlIsDown then FreecamDepthOfField.NearIntensity = clamp( FreecamDepthOfField.NearIntensity + dt * (keyboard.RightBracket - keyboard.LeftBracket) * DoFConstants.NearIntensity.ADJ, DoFConstants.NearIntensity.MIN, DoFConstants.NearIntensity.MAX ) else FreecamDepthOfField.FocusDistance = clamp( FreecamDepthOfField.FocusDistance + dt * (keyboard.Equals - keyboard.Minus) * DoFConstants.FocusDistance.ADJ, DoFConstants.FocusDistance.MIN, DoFConstants.FocusDistance.MAX ) end end do local FREECAM_TILT_RESET_GP = { [Enum.KeyCode.ButtonL1] = true, [Enum.KeyCode.ButtonR1] = true, } local FREECAM_TILT_RESET_KB = { [Enum.KeyCode.Z] = true, [Enum.KeyCode.C] = true, } local FREECAM_DOF_TOGGLE = { [Enum.KeyCode.BackSlash] = true, } local FREECAM_PLAYER_LOCK_TOGGLE = { [Enum.KeyCode.Slash] = true, } local FREECAM_PLAYER_LOCK_SWITCH = { [Enum.KeyCode.R] = true, [Enum.KeyCode.T] = true, } local FREECAM_CUSTOM_GUI_TOGGLE = { [Enum.KeyCode.G] = true, } local FREECAM_PLAYER_GUI_TOGGLE = { [Enum.KeyCode.X] = true, } local FREECAM_LEADERBOARD_TOGGLE = { [Enum.KeyCode.L] = true, } function resetKeys(keys, table) for keyEnum, _ in pairs(keys) do if table[keyEnum.Name] then table[keyEnum.Name] = 0 end end end function handleDoubleTapReset(keyCode) local currentTime = os.clock() local previousPressTime = lastPressTime[keyCode] local timeSinceLastPress = previousPressTime and (currentTime - previousPressTime) or -1 if previousPressTime and (timeSinceLastPress <= DOUBLE_TAP_TIME_THRESHOLD) then if (currentTime - lastResetTime) >= DOUBLE_TAP_DEBOUNCE_TIME then cameraRot = Vector3.new(cameraRot.x, cameraRot.y, 0) rollSpring:Reset(0) if FFlagUserFreecamDepthOfFieldEffect then resetKeys(FREECAM_TILT_RESET_GP, gamepad) resetKeys(FREECAM_TILT_RESET_KB, keyboard) else gamepad.ButtonL1 = 0 gamepad.ButtonR1 = 0 keyboard.C = 0 keyboard.Z = 0 end lastResetTime = currentTime end end lastPressTime[keyCode] = currentTime end function findPlayerLockRootPart(switchDirection) if not playerList or #playerList < 1 then return nil end local startIndex = currentTargetIndex for i = 1, #playerList do currentTargetIndex = ((currentTargetIndex - 1) + switchDirection) % #playerList + 1 if currentTargetIndex < 1 then currentTargetIndex = #playerList end local targetPlayer = playerList[currentTargetIndex] local targetCharacter = targetPlayer and targetPlayer.Character if targetCharacter then local humanoid = targetCharacter:FindFirstChildOfClass("Humanoid") if humanoid and humanoid.RootPart then return humanoid.RootPart end end if currentTargetIndex == startIndex then break end end playerLockEnabled = false return nil end function Keypress(action, state, input) keyboard[input.KeyCode.Name] = state == Enum.UserInputState.Begin and 1 or 0 if #customTiltLeftKeys > 0 then for _, keyName in ipairs(customTiltLeftKeys) do if input.KeyCode.Name == keyName then tiltLeftActiveKB = (state == Enum.UserInputState.Begin) end end end if #customTiltRightKeys > 0 then for _, keyName in ipairs(customTiltRightKeys) do if input.KeyCode.Name == keyName then tiltRightActiveKB = (state == Enum.UserInputState.Begin) end end end if FFlagUserFreecamTiltControl then if FREECAM_TILT_RESET_KB[input.KeyCode] and input.UserInputState == Enum.UserInputState.Begin then handleDoubleTapReset(input.KeyCode) end end if FFlagUserFreecamDepthOfFieldEffect then if FREECAM_DOF_TOGGLE[input.KeyCode] and input.UserInputState == Enum.UserInputState.Begin then if not FreecamDepthOfField.Enabled then postEffects = {} for _, effect in ipairs(Camera:GetChildren()) do if effect:IsA("DepthOfFieldEffect") and effect.Enabled then postEffects[#postEffects + 1] = effect effect.Enabled = false end end for _, effect in ipairs(Lighting:GetChildren()) do if effect:IsA("DepthOfFieldEffect") and effect.Enabled then postEffects[#postEffects + 1] = effect effect.Enabled = false end end cameraConnection = Camera.ChildAdded:Connect(function(child) if child:IsA("DepthOfFieldEffect") and child.Enabled then postEffects[#postEffects + 1] = child child.Enabled = false end end) lightingConnection = Lighting.ChildAdded:Connect(function(child) if child:IsA("DepthOfFieldEffect") and child.Enabled then postEffects[#postEffects + 1] = child child.Enabled = false end end) else for _, effect in ipairs(postEffects) do if effect.Parent then effect.Enabled = true end end if cameraConnection then cameraConnection:Disconnect() cameraConnection = nil end if lightingConnection then lightingConnection:Disconnect() lightingConnection = nil end postEffects = {} end FreecamDepthOfField.Enabled = not FreecamDepthOfField.Enabled resetKeys(FREECAM_DOF_TOGGLE, keyboard) end end if FFlagUserFreecamPlayerLock then if FREECAM_PLAYER_LOCK_TOGGLE[input.KeyCode] and input.UserInputState == Enum.UserInputState.Begin then playerLockEnabled = not playerLockEnabled if playerLockEnabled then playerLockZoom = PLAYER_LOCK_DEFAULT_ZOOM if FFlagUserFreecamPlayerLockResetHeight then playerLockHeight = PLAYER_LOCK_DEFAULT_HEIGHT end rootPart = findPlayerLockRootPart(0) end resetKeys(FREECAM_PLAYER_LOCK_TOGGLE, keyboard) end if FREECAM_PLAYER_LOCK_SWITCH[input.KeyCode] and input.UserInputState == Enum.UserInputState.Begin then if playerLockEnabled and #playerList > 0 then local switchDirection = 0 if input.KeyCode == Enum.KeyCode.T then switchDirection = 1 elseif input.KeyCode == Enum.KeyCode.R then switchDirection = -1 end if switchDirection ~= 0 then rootPart = findPlayerLockRootPart(switchDirection) end end resetKeys(FREECAM_PLAYER_LOCK_SWITCH, keyboard) end end if FFlagUserFreecamCustomGui then if FREECAM_CUSTOM_GUI_TOGGLE[input.KeyCode] and input.UserInputState == Enum.UserInputState.Begin then if freecamGui and freecamGui.Parent then freecamGui.Enabled = not freecamGui.Enabled end resetKeys(FREECAM_CUSTOM_GUI_TOGGLE, keyboard) end if FREECAM_PLAYER_GUI_TOGGLE[input.KeyCode] and input.UserInputState == Enum.UserInputState.Begin then screenGuisEnabled = not screenGuisEnabled if PlayerState then local screenGuis = PlayerState.getScreenGuis() for _, gui in pairs(screenGuis) do if gui.Parent and gui ~= freecamGui then gui.Enabled = screenGuisEnabled end end end resetKeys(FREECAM_PLAYER_GUI_TOGGLE, keyboard) end if FREECAM_LEADERBOARD_TOGGLE[input.KeyCode] and input.UserInputState == Enum.UserInputState.Begin then leaderboardEnabled = not leaderboardEnabled StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.PlayerList, leaderboardEnabled) resetKeys(FREECAM_LEADERBOARD_TOGGLE, keyboard) end end return Enum.ContextActionResult.Sink end function GpButton(action, state, input) gamepad[input.KeyCode.Name] = state == Enum.UserInputState.Begin and 1 or 0 if FFlagUserFreecamTiltControl then if FREECAM_TILT_RESET_GP[input.KeyCode] and input.UserInputState == Enum.UserInputState.Begin then handleDoubleTapReset(input.KeyCode) end end return Enum.ContextActionResult.Sink end function MousePan(action, state, input) local delta = input.Delta mouse.Delta = Vector2.new(-delta.y, -delta.x) return Enum.ContextActionResult.Sink end function Thumb(action, state, input) gamepad[input.KeyCode.Name] = input.Position return Enum.ContextActionResult.Sink end function Trigger(action, state, input) gamepad[input.KeyCode.Name] = input.Position.z return Enum.ContextActionResult.Sink end function MouseWheel(action, state, input) mouse[input.UserInputType.Name] = -input.Position.z return Enum.ContextActionResult.Sink end function Zero(t) for k, v in pairs(t) do t[k] = v*0 end end function Input.StartCapture() if FFlagUserFreecamControlSpeed then ContextActionService:BindActionAtPriority("FreecamKeyboard", Keypress, false, INPUT_PRIORITY, Enum.KeyCode.W, Enum.KeyCode.U, Enum.KeyCode.A, Enum.KeyCode.H, Enum.KeyCode.S, Enum.KeyCode.J, Enum.KeyCode.D, Enum.KeyCode.K, Enum.KeyCode.E, Enum.KeyCode.I, Enum.KeyCode.Q, Enum.KeyCode.Y ) ContextActionService:BindActionAtPriority("FreecamKeyboardControlSpeed", Keypress, false, INPUT_PRIORITY, Enum.KeyCode.Up, Enum.KeyCode.Down, Enum.KeyCode.Left, Enum.KeyCode.Right ) ContextActionService:BindActionAtPriority("FreecamGamepadControlSpeed", GpButton, false, INPUT_PRIORITY, Enum.KeyCode.DPadUp, Enum.KeyCode.DPadDown, Enum.KeyCode.DPadLeft, Enum.KeyCode.DPadRight ) else ContextActionService:BindActionAtPriority("FreecamKeyboard", Keypress, false, INPUT_PRIORITY, Enum.KeyCode.W, Enum.KeyCode.U, Enum.KeyCode.A, Enum.KeyCode.H, Enum.KeyCode.S, Enum.KeyCode.J, Enum.KeyCode.D, Enum.KeyCode.K, Enum.KeyCode.E, Enum.KeyCode.I, Enum.KeyCode.Q, Enum.KeyCode.Y, Enum.KeyCode.Up, Enum.KeyCode.Down ) end if FFlagUserFreecamTiltControl then ContextActionService:BindActionAtPriority("FreecamKeyboardTiltControl", Keypress, false, INPUT_PRIORITY, Enum.KeyCode.Z, Enum.KeyCode.C ) ContextActionService:BindActionAtPriority("FreecamGamepadTiltControl", GpButton, false, INPUT_PRIORITY, Enum.KeyCode.ButtonL1, Enum.KeyCode.ButtonR1 ) ContextActionService:BindActionAtPriority("FreecamKeyboardTiltControlSpeed", Keypress, false, INPUT_PRIORITY, Enum.KeyCode.Comma, Enum.KeyCode.Period ) if FFlagUserFreecamSmoothnessControl then ContextActionService:BindActionAtPriority("FreecamKeyboardSmoothnessControl", Keypress, false, INPUT_PRIORITY, Enum.KeyCode.LeftBracket, Enum.KeyCode.RightBracket, Enum.KeyCode.Semicolon, Enum.KeyCode.Quote, Enum.KeyCode.V, Enum.KeyCode.B, Enum.KeyCode.N, Enum.KeyCode.M ) end end if FFlagUserFreecamDepthOfFieldEffect then ContextActionService:BindActionAtPriority("FreecamKeyboardDoFToggle", Keypress, false, INPUT_PRIORITY, Enum.KeyCode.BackSlash) ContextActionService:BindActionAtPriority("FreecamKeyboardDoFControls", Keypress, false, INPUT_PRIORITY, Enum.KeyCode.Minus, Enum.KeyCode.Equals ) end if FFlagUserFreecamPlayerLock then ContextActionService:BindActionAtPriority("FreecamKeyboardPlayerLockToggle", Keypress, false, INPUT_PRIORITY, Enum.KeyCode.Slash) ContextActionService:BindActionAtPriority("FreecamKeyboardPlayerLockSwitch", Keypress, false, INPUT_PRIORITY, Enum.KeyCode.R, Enum.KeyCode.T) end if FFlagUserFreecamCustomGui then ContextActionService:BindActionAtPriority("FreecamKeyboardCustomGuiToggle", Keypress, false, INPUT_PRIORITY, Enum.KeyCode.G) ContextActionService:BindActionAtPriority("FreecamKeyboardPlayerGuiToggle", Keypress, false, INPUT_PRIORITY, Enum.KeyCode.X) ContextActionService:BindActionAtPriority("FreecamKeyboardLeaderboardToggle", Keypress, false, INPUT_PRIORITY, Enum.KeyCode.L) end ContextActionService:BindActionAtPriority("FreecamMousePan", MousePan, false, INPUT_PRIORITY, Enum.UserInputType.MouseMovement) ContextActionService:BindActionAtPriority("FreecamMouseWheel", MouseWheel, false, INPUT_PRIORITY, Enum.UserInputType.MouseWheel) ContextActionService:BindActionAtPriority("FreecamGamepadButton", GpButton, false, INPUT_PRIORITY, Enum.KeyCode.ButtonX, Enum.KeyCode.ButtonY) ContextActionService:BindActionAtPriority("FreecamGamepadTrigger", Trigger, false, INPUT_PRIORITY, Enum.KeyCode.ButtonR2, Enum.KeyCode.ButtonL2) ContextActionService:BindActionAtPriority("FreecamGamepadThumbstick", Thumb, false, INPUT_PRIORITY, Enum.KeyCode.Thumbstick1, Enum.KeyCode.Thumbstick2) end function Input.StopCapture() if not FFlagUserFreecamCustomGui then navSpeed = 1 if FFlagUserFreecamControlSpeed then fovSpeed = 1 end if FFlagUserFreecamTiltControl then rollSpeed = 1 end end tiltLeftActiveKB = false tiltRightActiveKB = false Zero(gamepad) Zero(keyboard) Zero(mouse) ContextActionService:UnbindAction("FreecamKeyboard") if FFlagUserFreecamControlSpeed then ContextActionService:UnbindAction("FreecamKeyboardControlSpeed") ContextActionService:UnbindAction("FreecamGamepadControlSpeed") end if FFlagUserFreecamTiltControl then ContextActionService:UnbindAction("FreecamKeyboardTiltControl") ContextActionService:UnbindAction("FreecamGamepadTiltControl") ContextActionService:UnbindAction("FreecamKeyboardTiltControlSpeed") if FFlagUserFreecamSmoothnessControl then ContextActionService:UnbindAction("FreecamKeyboardSmoothnessControl") end end if FFlagUserFreecamDepthOfFieldEffect then ContextActionService:UnbindAction("FreecamKeyboardDoFToggle") ContextActionService:UnbindAction("FreecamKeyboardDoFControls") end if FFlagUserFreecamPlayerLock then ContextActionService:UnbindAction("FreecamKeyboardPlayerLockToggle") ContextActionService:UnbindAction("FreecamKeyboardPlayerLockSwitch") end if FFlagUserFreecamCustomGui then ContextActionService:UnbindAction("FreecamKeyboardCustomGuiToggle") ContextActionService:UnbindAction("FreecamKeyboardPlayerGuiToggle") ContextActionService:UnbindAction("FreecamKeyboardLeaderboardToggle") end ContextActionService:UnbindAction("FreecamMousePan") ContextActionService:UnbindAction("FreecamMouseWheel") ContextActionService:UnbindAction("FreecamGamepadButton") ContextActionService:UnbindAction("FreecamGamepadTrigger") ContextActionService:UnbindAction("FreecamGamepadThumbstick") end function Input.getNavSpeed() return navSpeed end function Input.getFovSpeed() return fovSpeed end function Input.getRollSpeed() return rollSpeed end end end function StepFreecam(dt) if FFlagUserFreecamSmoothnessControl then Input.SpringControl(dt) end if FFlagUserFreecamDepthOfFieldEffect then if FreecamDepthOfField and FreecamDepthOfField.Parent then Input.DoF(dt) end end local vel = velSpring:Update(dt, Input.Vel(dt)) local pan = panSpring:Update(dt, Input.Pan(dt)) local fov = fovSpring:Update(dt, Input.Fov(dt)) local roll if FFlagUserFreecamTiltControl then roll = rollSpring:Update(dt, Input.Roll(dt)) end local zoomFactor = sqrt(tan(rad(70/2))/tan(rad(cameraFov/2))) cameraFov = clamp(cameraFov + fov*FOV_GAIN*(dt/zoomFactor), 1, 120) local cameraCFrame if FFlagUserFreecamTiltControl then local panVector = pan*PAN_GAIN*(dt/zoomFactor) cameraRot = cameraRot + Vector3.new(panVector.X, panVector.Y, roll*ROLL_GAIN*(dt/zoomFactor)) if FFlagUserFreecamSmoothnessControl then cameraRot = Vector3.new(cameraRot.x%(2*pi), cameraRot.y%(2*pi), cameraRot.z%(2*pi)) else cameraRot = Vector3.new(clamp(cameraRot.x, -PITCH_LIMIT, PITCH_LIMIT), cameraRot.y%(2*pi), cameraRot.z) end cameraCFrame = CFrame.new(cameraPos)*CFrame.fromOrientation(cameraRot.x, cameraRot.y, cameraRot.z)*CFrame.new(vel*NAV_GAIN*dt) else cameraRot = cameraRot + pan*PAN_GAIN*(dt/zoomFactor) cameraRot = Vector2.new(clamp(cameraRot.x, -PITCH_LIMIT, PITCH_LIMIT), cameraRot.y%(2*pi)) cameraCFrame = CFrame.new(cameraPos)*CFrame.fromOrientation(cameraRot.x, cameraRot.y, 0)*CFrame.new(vel*NAV_GAIN*dt) end if FFlagUserFreecamPlayerLock then if playerLockEnabled and rootPart then local zoomDelta = vel.Z * NAV_GAIN.Z * dt local heightDelta = vel.Y * NAV_GAIN.Y * dt playerLockZoom = clamp(playerLockZoom + zoomDelta, PLAYER_LOCK_MIN_ZOOM, PLAYER_LOCK_MAX_ZOOM) playerLockHeight = clamp(playerLockHeight + heightDelta, -PLAYER_LOCK_HEIGHT_RANGE, PLAYER_LOCK_HEIGHT_RANGE) local targetCFrame = CFrame.new(rootPart.Position + Vector3.new(0, playerLockHeight, 0)) local rotationCFrame if FFlagUserFreecamTiltControl then rotationCFrame = CFrame.fromOrientation(cameraRot.x, cameraRot.y, cameraRot.z) else rotationCFrame = CFrame.fromOrientation(cameraRot.x, cameraRot.y, 0) end cameraCFrame = targetCFrame * rotationCFrame * CFrame.new(0, 0, playerLockZoom) end end cameraPos = cameraCFrame.p Camera.CFrame = cameraCFrame Camera.Focus = cameraCFrame Camera.FieldOfView = cameraFov end function CheckMouseLockAvailability() local devAllowsMouseLock = Players.LocalPlayer.DevEnableMouseLock local devMovementModeIsScriptable = Players.LocalPlayer.DevComputerMovementMode == Enum.DevComputerMovementMode.Scriptable local userHasMouseLockModeEnabled = GameSettings.ControlMode == Enum.ControlMode.MouseLockSwitch local userHasClickToMoveEnabled = GameSettings.ComputerMovementMode == Enum.ComputerMovementMode.ClickToMove local MouseLockAvailable = devAllowsMouseLock and userHasMouseLockModeEnabled and not userHasClickToMoveEnabled and not devMovementModeIsScriptable return MouseLockAvailable end PlayerState = {} do local mouseBehavior = nil local mouseIconEnabled = nil local cameraType = nil local cameraFocus = nil local cameraCFrame = nil local cameraFieldOfView = nil local screenGuis = {} local coreGuis = { Backpack = true, Chat = true, Health = true, PlayerList = true } local setCores = { BadgesNotificationsActive = true, PointsNotificationsActive = true } function PlayerState.Push() for name in pairs(coreGuis) do coreGuis[name] = StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType[name]) StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType[name], false) end for name in pairs(setCores) do setCores[name] = StarterGui:GetCore(name) StarterGui:SetCore(name, false) end local playergui = LocalPlayer:FindFirstChildOfClass("PlayerGui") if playergui then local existingGuis = {} for _, gui in pairs(playergui:GetChildren()) do if gui:IsA("ScreenGui") and gui.Enabled and gui.Name ~= "FreeCamTouchControll" then existingGuis[gui] = true table.insert(screenGuis, gui) gui.Enabled = false end end if FFlagUserFixFreecamGuiChangeVisibility then playerGuiConnection = playergui.ChildAdded:Connect(function(child) if child:IsA("ScreenGui") and child.Enabled and child.Name ~= "FreeCamTouchControll" and not existingGuis[child] then table.insert(screenGuis, child) if FFlagUserFreecamCustomGui then child.Enabled = screenGuisEnabled else child.Enabled = false end end end) end end cameraFieldOfView = Camera.FieldOfView Camera.FieldOfView = 70 cameraType = Camera.CameraType Camera.CameraType = Enum.CameraType.Custom cameraCFrame = Camera.CFrame cameraFocus = Camera.Focus mouseIconEnabled = UserInputService.MouseIconEnabled UserInputService.MouseIconEnabled = false if FFlagUserExitFreecamBreaksWithShiftlock and CheckMouseLockAvailability() then mouseBehavior = Enum.MouseBehavior.Default else mouseBehavior = UserInputService.MouseBehavior end UserInputService.MouseBehavior = Enum.MouseBehavior.Default end function PlayerState.Pop() for name, isEnabled in pairs(coreGuis) do if isEnabled ~= nil then pcall(function() StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType[name], isEnabled) end) end end for name, isEnabled in pairs(setCores) do if isEnabled ~= nil then pcall(function() StarterGui:SetCore(name, isEnabled) end) end end for _, gui in pairs(screenGuis) do if gui and gui.Parent then if FFlagUserFreecamCustomGui then if gui ~= freecamGui then pcall(function() gui.Enabled = true end) end else pcall(function() gui.Enabled = true end) end end end if FFlagUserFixFreecamGuiChangeVisibility then if playerGuiConnection then playerGuiConnection:Disconnect() playerGuiConnection = nil end screenGuis = {} end if cameraFieldOfView then pcall(function() Camera.FieldOfView = cameraFieldOfView end) cameraFieldOfView = nil end if cameraType then pcall(function() Camera.CameraType = cameraType end) cameraType = nil end if cameraCFrame then pcall(function() Camera.CFrame = cameraCFrame end) cameraCFrame = nil end if cameraFocus then pcall(function() Camera.Focus = cameraFocus end) cameraFocus = nil end if mouseIconEnabled ~= nil then pcall(function() UserInputService.MouseIconEnabled = mouseIconEnabled end) mouseIconEnabled = nil end if mouseBehavior ~= nil then pcall(function() UserInputService.MouseBehavior = mouseBehavior end) mouseBehavior = nil end end function PlayerState.getScreenGuis() return screenGuis end end function removePlayerFromList(player) for i, p in ipairs(playerList) do if p == player then table.remove(playerList, i) if currentTargetIndex == i and playerLockEnabled then playerLockEnabled = false currentTargetIndex = 1 end if currentTargetIndex > i then currentTargetIndex = currentTargetIndex - 1 end if currentTargetIndex > #playerList or currentTargetIndex < 1 then currentTargetIndex = 1 end break end end end function initializePlayerList() playerList = Players:GetPlayers() for i, p in ipairs(playerList) do if p == LocalPlayer then currentTargetIndex = i break end end playerAddedConnection = Players.PlayerAdded:Connect(function(player) table.insert(playerList, player) end) playerRemovingConnection = Players.PlayerRemoving:Connect(removePlayerFromList) end local customGui = nil local Draggable = {} Draggable.__index = Draggable function Draggable.new(dragFrame, targetFrame, callbacks) local self = setmetatable({}, Draggable) self.dragFrame = dragFrame self.targetFrame = targetFrame self.callbacks = callbacks or {} self.dragData = { dragging = false, dragStart = nil, startPos = nil, dragDistance = 0, isDraggingStarted = false, currentTouch = nil, originalZIndex = targetFrame.ZIndex, DRAG_THRESHOLD = 5 } self.connections = { mouseUp = nil, touchUp = nil, movement = nil, began = nil } self:setup() return self end function Draggable:cleanupConnections() if self.connections.mouseUp then self.connections.mouseUp:Disconnect() end if self.connections.touchUp then self.connections.touchUp:Disconnect() end if self.connections.movement then self.connections.movement:Disconnect() end self.connections.mouseUp = nil self.connections.touchUp = nil self.connections.movement = nil end function Draggable:resetState() self.dragData.dragging = false self.dragData.dragStart = nil self.dragData.startPos = nil self.dragData.dragDistance = 0 self.dragData.isDraggingStarted = false self.dragData.currentTouch = nil self:cleanupConnections() end function Draggable:getDistance(pos1, pos2) return math.sqrt((pos2.X - pos1.X)^2 + (pos2.Y - pos1.Y)^2) end function Draggable:isMouseOverFrame(frame, position) local absPos, absSize = frame.AbsolutePosition, frame.AbsoluteSize return position.X >= absPos.X and position.X <= absPos.X + absSize.X and position.Y >= absPos.Y and position.Y <= absPos.Y + absSize.Y end function Draggable:updatePosition(input) if not self.dragData.dragging or not self.dragData.dragStart then return end local delta = input.Position - self.dragData.dragStart self.dragData.dragDistance = self:getDistance(input.Position, self.dragData.dragStart) self.targetFrame.Position = UDim2.new(self.dragData.startPos.X.Scale, self.dragData.startPos.X.Offset + delta.X, self.dragData.startPos.Y.Scale, self.dragData.startPos.Y.Offset + delta.Y) end function Draggable:onDragEnd() if self.dragData.dragging then local wasDragged = self.dragData.dragDistance > self.dragData.DRAG_THRESHOLD if not wasDragged and self.callbacks.onClick then self.callbacks.onClick() end if self.callbacks.onDragEnd then self.callbacks.onDragEnd(wasDragged) end self:resetState() end end function Draggable:onInputEnded(input) if not self.dragData.dragging then return end if input.UserInputType == Enum.UserInputType.MouseButton1 then self:onDragEnd() elseif input.UserInputType == Enum.UserInputType.Touch and input == self.dragData.currentTouch then self:onDragEnd() end end function Draggable:onMovement(input) if not self.dragData.dragging then return end if input.UserInputType == Enum.UserInputType.MouseMovement or input == self.dragData.currentTouch then if not self.dragData.isDraggingStarted and self.dragData.dragDistance > self.dragData.DRAG_THRESHOLD then self.dragData.isDraggingStarted = true if self.callbacks.onDragStart then self.callbacks.onDragStart() end end self:updatePosition(input) end end function Draggable:onInputBegan(input) local isClick = input.UserInputState == Enum.UserInputState.Begin and (input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch) if isClick and not self.dragData.dragging then if self:isMouseOverFrame(self.dragFrame, input.Position) then self.dragData.dragging = true self.dragData.dragStart = input.Position self.dragData.startPos = self.targetFrame.Position self.dragData.dragDistance = 0 self.dragData.isDraggingStarted = false self.dragData.currentTouch = (input.UserInputType == Enum.UserInputType.Touch) and input or nil self:cleanupConnections() self.connections.mouseUp = UserInputService.InputEnded:Connect(function(endInput) if endInput.UserInputType == Enum.UserInputType.MouseButton1 then self:onInputEnded(endInput) end end) self.connections.touchUp = UserInputService.InputEnded:Connect(function(endInput) if endInput.UserInputType == Enum.UserInputType.Touch then self:onInputEnded(endInput) end end) self.connections.movement = UserInputService.InputChanged:Connect(function(moveInput) if moveInput.UserInputType == Enum.UserInputType.MouseMovement or moveInput.UserInputType == Enum.UserInputType.Touch then self:onMovement(moveInput) end end) end end end function Draggable:setup() self.connections.began = self.dragFrame.InputBegan:Connect(function(input) self:onInputBegan(input) end) end function Draggable:Destroy() self:cleanupConnections() if self.connections.began then self.connections.began:Disconnect() end end local Slider = {} Slider.__index = Slider function Slider.new(sliderBar, sliderHandle, onChange) local self = setmetatable({}, Slider) self.sliderBar = sliderBar self.sliderHandle = sliderHandle self.onChange = onChange self.dragData = { dragging = false, currentTouch = nil, lastValue = nil } self.connections = { began = nil, mouseUp = nil, touchUp = nil, movement = nil } self:setup() return self end function Slider:cleanupConnections() if self.connections.mouseUp then self.connections.mouseUp:Disconnect() end if self.connections.touchUp then self.connections.touchUp:Disconnect() end if self.connections.movement then self.connections.movement:Disconnect() end self.connections.mouseUp = nil self.connections.touchUp = nil self.connections.movement = nil end function Slider:isMouseOverFrame(frame, position) local absPos, absSize = frame.AbsolutePosition, frame.AbsoluteSize return position.X >= absPos.X and position.X <= absPos.X + absSize.X and position.Y >= absPos.Y and position.Y <= absPos.Y + absSize.Y end function Slider:updatePosition(input) if not self.dragData.dragging then return end local mousePos = input.Position.X local barPos = self.sliderBar.AbsolutePosition.X local barWidth = self.sliderBar.AbsoluteSize.X if barWidth <= 0 then return end local newX = math.clamp(mousePos - barPos - 7, -7, barWidth - 7) if not self.dragData.lastValue or math.abs(newX - self.dragData.lastValue) > 0.5 then self.sliderHandle.Position = UDim2.new(0, newX, 0, -5) local normalizedValue = math.clamp((newX + 7) / barWidth, 0, 1) if self.onChange then self.onChange(normalizedValue) end self.dragData.lastValue = newX end end function Slider:onDragEnd() if self.dragData.dragging then self:resetState() end end function Slider:resetState() self.dragData.dragging = false; self.dragData.currentTouch = nil; self.dragData.lastValue = nil; self:cleanupConnections() end function Slider:onInputEnded(input) if not self.dragData.dragging then return end if input.UserInputType == Enum.UserInputType.MouseButton1 then self:onDragEnd() elseif input.UserInputType == Enum.UserInputType.Touch and input == self.dragData.currentTouch then self:onDragEnd() end end function Slider:onMovement(input) if not self.dragData.dragging then return end if input.UserInputType == Enum.UserInputType.MouseMovement or input == self.dragData.currentTouch then self:updatePosition(input) end end function Slider:onInputBegan(input) local isClick = input.UserInputState == Enum.UserInputState.Begin and (input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch) if isClick and not self.dragData.dragging and self:isMouseOverFrame(self.sliderHandle, input.Position) then self.dragData.dragging = true self.dragData.currentTouch = (input.UserInputType == Enum.UserInputType.Touch) and input or nil self:cleanupConnections() self.connections.mouseUp = UserInputService.InputEnded:Connect(function(endInput) if endInput.UserInputType == Enum.UserInputType.MouseButton1 then self:onInputEnded(endInput) end end) self.connections.touchUp = UserInputService.InputEnded:Connect(function(endInput) if endInput.UserInputType == Enum.UserInputType.Touch then self:onInputEnded(endInput) end end) self.connections.movement = UserInputService.InputChanged:Connect(function(moveInput) if moveInput.UserInputType == Enum.UserInputType.MouseMovement or moveInput.UserInputType == Enum.UserInputType.Touch then self:onMovement(moveInput) end end) self:updatePosition(input) end end function Slider:setup() self.connections.began = self.sliderHandle.InputBegan:Connect(function(input) self:onInputBegan(input) end) end function Slider:Destroy() self:cleanupConnections(); if self.connections.began then self.connections.began:Disconnect() end end function Slider:SetValue(normalizedValue) local barWidth = self.sliderBar.AbsoluteSize.X; local newX = math.clamp(normalizedValue * barWidth - 7, -7, barWidth - 7); self.sliderHandle.Position = UDim2.new(0, newX, 0, -5) end local Toggle = {} Toggle.__index = Toggle function Toggle.new(toggleContainer, toggleThumb, onChange) local self = setmetatable({}, Toggle) self.toggleContainer = toggleContainer self.toggleThumb = toggleThumb self.onChange = onChange self.state = false self:setup() return self end function Toggle:animateOn() local tweenInfo = TweenInfo.new(0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out) TweenService:Create(self.toggleContainer, tweenInfo, {BackgroundColor3 = Color3.fromRGB(100, 200, 255)}):Play() TweenService:Create(self.toggleThumb, tweenInfo, {Position = UDim2.new(0, self.toggleContainer.AbsoluteSize.X - 22, 0, 2)}):Play() end function Toggle:animateOff() local tweenInfo = TweenInfo.new(0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out) TweenService:Create(self.toggleContainer, tweenInfo, {BackgroundColor3 = Color3.fromRGB(80, 80, 100)}):Play() TweenService:Create(self.toggleThumb, tweenInfo, {Position = UDim2.new(0, 2, 0, 2)}):Play() end function Toggle:SetState(state) self.state = state; if state then self:animateOn() else self:animateOff() end; if self.onChange then self.onChange(state) end end function Toggle:GetState() return self.state end function Toggle:Toggle() self:SetState(not self.state) end function Toggle:setup() local clickBtn = Instance.new("TextButton"); clickBtn.Size = UDim2.new(1,0,1,0); clickBtn.BackgroundTransparency = 1; clickBtn.Text = ""; clickBtn.AutoButtonColor = false; clickBtn.Parent = self.toggleContainer; clickBtn.MouseButton1Click:Connect(function() self:Toggle() end); self.toggleThumb.MouseButton1Click:Connect(function() self:Toggle() end) end local DummyUI = {} DummyUI.__index = DummyUI function DummyUI.new(title, size) local self = setmetatable({}, DummyUI) self.title = title or "Freecam Control" self.size = size or UDim2.new(0, 300, 0, 380) self.position = UDim2.new(0.5, -150, 0.5, -200) self.tabs = {} self.currentTab = nil self.components = {} self:createUI() self:setupAlwaysOnTop() self:setupDraggable() return self end function DummyUI:createUI() self.mainFrame = Instance.new("Frame") self.mainFrame.Name = "DummyUI" self.mainFrame.Size = self.size self.mainFrame.Position = self.position self.mainFrame.BackgroundColor3 = Color3.fromRGB(25, 25, 35) self.mainFrame.BackgroundTransparency = 0.05 self.mainFrame.BorderSizePixel = 0 self.mainFrame.ClipsDescendants = true self.mainFrame.Active = true self.mainFrame.ZIndex = 1000 self.mainFrame.Parent = freecamGui local mainCorner = Instance.new("UICorner") mainCorner.CornerRadius = UDim.new(0, 12) mainCorner.Parent = self.mainFrame self.topBar = Instance.new("TextButton") self.topBar.Size = UDim2.new(1, 0, 0, 40) self.topBar.Position = UDim2.new(0, 0, 0, 0) self.topBar.BackgroundColor3 = Color3.fromRGB(35, 35, 45) self.topBar.BackgroundTransparency = 0.2 self.topBar.BorderSizePixel = 0 self.topBar.Text = "" self.topBar.AutoButtonColor = false self.topBar.ZIndex = 1001 self.topBar.Parent = self.mainFrame local topCorner = Instance.new("UICorner") topCorner.CornerRadius = UDim.new(0, 12) topCorner.Parent = self.topBar local titleLabel = Instance.new("TextLabel") titleLabel.Size = UDim2.new(1, -50, 1, 0) titleLabel.Position = UDim2.new(0, 15, 0, 0) titleLabel.BackgroundTransparency = 1 titleLabel.TextColor3 = Color3.fromRGB(255, 255, 255) titleLabel.Font = Enum.Font.GothamBold titleLabel.TextSize = 14 titleLabel.Text = " " .. self.title titleLabel.TextXAlignment = Enum.TextXAlignment.Left titleLabel.TextYAlignment = Enum.TextYAlignment.Center titleLabel.Parent = self.topBar self.closeButton = Instance.new("TextButton") self.closeButton.Size = UDim2.new(0, 32, 0, 32) self.closeButton.Position = UDim2.new(1, -38, 0, 4) self.closeButton.BackgroundColor3 = Color3.fromRGB(255, 70, 70) self.closeButton.BackgroundTransparency = 0.8 self.closeButton.TextColor3 = Color3.fromRGB(255, 255, 255) self.closeButton.Font = Enum.Font.GothamBold self.closeButton.TextSize = 16 self.closeButton.Text = "✕" self.closeButton.AutoButtonColor = false self.closeButton.BorderSizePixel = 0 self.closeButton.Parent = self.topBar local closeCorner = Instance.new("UICorner") closeCorner.CornerRadius = UDim.new(0, 16) closeCorner.Parent = self.closeButton self.closeButton.MouseButton1Click:Connect(function() self.mainFrame.Visible = false if floatingButton then floatingButton.Visible = true end end) self.tabScrollingFrame = Instance.new("ScrollingFrame") self.tabScrollingFrame.Size = UDim2.new(1, -20, 0, 40) self.tabScrollingFrame.Position = UDim2.new(0, 10, 0, 48) self.tabScrollingFrame.BackgroundTransparency = 1 self.tabScrollingFrame.BorderSizePixel = 0 self.tabScrollingFrame.ScrollBarThickness = 3 self.tabScrollingFrame.ScrollBarImageColor3 = Color3.fromRGB(80, 80, 100) self.tabScrollingFrame.CanvasSize = UDim2.new(0, 0, 0, 0) self.tabScrollingFrame.ScrollingDirection = Enum.ScrollingDirection.X self.tabScrollingFrame.Parent = self.mainFrame self.tabLayout = Instance.new("UIListLayout") self.tabLayout.FillDirection = Enum.FillDirection.Horizontal self.tabLayout.Padding = UDim.new(0, 8) self.tabLayout.HorizontalAlignment = Enum.HorizontalAlignment.Left self.tabLayout.VerticalAlignment = Enum.VerticalAlignment.Center self.tabLayout.Parent = self.tabScrollingFrame self.tabLayout:GetPropertyChangedSignal("AbsoluteContentSize"):Connect(function() self.tabScrollingFrame.CanvasSize = UDim2.new(0, self.tabLayout.AbsoluteContentSize.X + 20, 0, 0) end) end function DummyUI:setupAlwaysOnTop() self.mainFrame.ZIndex = 1000 local function raiseToTop() local maxZIndex = 0 for _, child in ipairs(self.mainFrame.Parent:GetChildren()) do if child:IsA("Frame") and child ~= self.mainFrame and child.Visible and child.ZIndex then maxZIndex = math.max(maxZIndex, child.ZIndex) end end self.mainFrame.ZIndex = math.max(maxZIndex + 1, 1000) end self.topBar.InputBegan:Connect(raiseToTop) end function DummyUI:setupDraggable() self.draggable = Draggable.new(self.topBar, self.mainFrame) end function DummyUI:AddTab(tabName) local tabButton = Instance.new("TextButton") tabButton.Name = tabName .. "Tab" tabButton.Size = UDim2.new(0, 100, 0, 34) tabButton.BackgroundColor3 = Color3.fromRGB(45, 45, 55) tabButton.TextColor3 = Color3.fromRGB(180, 180, 200) tabButton.Font = Enum.Font.GothamSemibold tabButton.TextSize = 13 tabButton.Text = tabName tabButton.AutoButtonColor = false tabButton.BorderSizePixel = 0 tabButton.Parent = self.tabScrollingFrame local buttonCorner = Instance.new("UICorner") buttonCorner.CornerRadius = UDim.new(0, 17) buttonCorner.Parent = tabButton local tabContent = Instance.new("ScrollingFrame") tabContent.Name = tabName .. "Content" tabContent.Size = UDim2.new(1, -20, 1, -105) tabContent.Position = UDim2.new(0, 10, 0, 96) tabContent.BackgroundTransparency = 1 tabContent.BorderSizePixel = 0 tabContent.ScrollBarThickness = 6 tabContent.ScrollBarImageColor3 = Color3.fromRGB(80, 80, 100) tabContent.CanvasSize = UDim2.new(0, 0, 0, 0) tabContent.Visible = false tabContent.Parent = self.mainFrame local tabLayout = Instance.new("UIListLayout") tabLayout.Padding = UDim.new(0, 12) tabLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center tabLayout.Parent = tabContent tabLayout:GetPropertyChangedSignal("AbsoluteContentSize"):Connect(function() tabContent.CanvasSize = UDim2.new(0, 0, 0, tabLayout.AbsoluteContentSize.Y + 20) end) self.tabs[tabName] = { button = tabButton, content = tabContent, layout = tabLayout } if not self.currentTab then self:SwitchTab(tabName) end tabButton.MouseButton1Click:Connect(function() self:SwitchTab(tabName) end) return tabContent end function DummyUI:SwitchTab(tabName) if not self.tabs[tabName] then return end self.currentTab = tabName local activeColor = Color3.fromRGB(100, 200, 255) local inactiveColor = Color3.fromRGB(45, 45, 55) local activeTextColor = Color3.fromRGB(255, 255, 255) local inactiveTextColor = Color3.fromRGB(180, 180, 200) for name, tab in pairs(self.tabs) do tab.button.BackgroundColor3 = (name == tabName) and activeColor or inactiveColor tab.button.TextColor3 = (name == tabName) and activeTextColor or inactiveTextColor tab.content.Visible = (name == tabName) end end function DummyUI:AddToggle(parent, config) local card = Instance.new("Frame") card.Size = UDim2.new(0, 260, 0, 60) card.BackgroundColor3 = Color3.fromRGB(35, 35, 45) card.BackgroundTransparency = 0.3 card.BorderSizePixel = 0 card.Parent = parent local cardCorner = Instance.new("UICorner") cardCorner.CornerRadius = UDim.new(0, 10) cardCorner.Parent = card local title = Instance.new("TextLabel") title.Size = UDim2.new(1, -20, 0, 24) title.Position = UDim2.new(0, 12, 0, 8) title.BackgroundTransparency = 1 title.TextColor3 = Color3.fromRGB(255, 255, 255) title.Font = Enum.Font.GothamBold title.TextSize = 14 title.Text = config.text or "Toggle" title.TextXAlignment = Enum.TextXAlignment.Left title.Parent = card local toggleContainer = Instance.new("Frame") toggleContainer.Size = UDim2.new(0, 44, 0, 24) toggleContainer.Position = UDim2.new(1, -56, 0, 18) toggleContainer.BackgroundColor3 = Color3.fromRGB(80, 80, 100) toggleContainer.BorderSizePixel = 0 toggleContainer.ClipsDescendants = true toggleContainer.Parent = card local toggleCorner = Instance.new("UICorner") toggleCorner.CornerRadius = UDim.new(0, 12) toggleCorner.Parent = toggleContainer local toggleThumb = Instance.new("TextButton") toggleThumb.Size = UDim2.new(0, 20, 0, 20) toggleThumb.Position = UDim2.new(0, 2, 0, 2) toggleThumb.BackgroundColor3 = Color3.fromRGB(255, 255, 255) toggleThumb.BorderSizePixel = 0 toggleThumb.Text = "" toggleThumb.AutoButtonColor = false toggleThumb.Parent = toggleContainer local thumbCorner = Instance.new("UICorner") thumbCorner.CornerRadius = UDim.new(0, 10) thumbCorner.Parent = toggleThumb local toggle = Toggle.new(toggleContainer, toggleThumb, config.callback) if config.default then toggle:SetState(config.default) end table.insert(self.components, toggle) return toggle end function DummyUI:AddSlider(parent, config) local card = Instance.new("Frame") card.Size = UDim2.new(0, 260, 0, 70) card.BackgroundColor3 = Color3.fromRGB(35, 35, 45) card.BackgroundTransparency = 0.3 card.BorderSizePixel = 0 card.Parent = parent local cardCorner = Instance.new("UICorner") cardCorner.CornerRadius = UDim.new(0, 10) cardCorner.Parent = card local title = Instance.new("TextLabel") title.Size = UDim2.new(1, -20, 0, 24) title.Position = UDim2.new(0, 12, 0, 8) title.BackgroundTransparency = 1 title.TextColor3 = Color3.fromRGB(255, 255, 255) title.Font = Enum.Font.GothamBold title.TextSize = 14 title.Text = config.text or "Slider" title.TextXAlignment = Enum.TextXAlignment.Left title.Parent = card local valueLabel = Instance.new("TextLabel") valueLabel.Size = UDim2.new(0, 50, 0, 24) valueLabel.Position = UDim2.new(1, -62, 0, 8) valueLabel.BackgroundTransparency = 1 valueLabel.TextColor3 = Color3.fromRGB(100, 200, 255) valueLabel.Font = Enum.Font.GothamBold valueLabel.TextSize = 14 valueLabel.Text = tostring(config.default or 0) valueLabel.TextXAlignment = Enum.TextXAlignment.Right valueLabel.Parent = card local sliderBar = Instance.new("Frame") sliderBar.Size = UDim2.new(0, 220, 0, 4) sliderBar.Position = UDim2.new(0, 20, 0, 48) sliderBar.BackgroundColor3 = Color3.fromRGB(60, 60, 80) sliderBar.BorderSizePixel = 0 sliderBar.Parent = card local barCorner = Instance.new("UICorner") barCorner.CornerRadius = UDim.new(0, 2) barCorner.Parent = sliderBar local sliderFill = Instance.new("Frame") local defaultPercent = (config.default or 0) / (config.max or 100) sliderFill.Size = UDim2.new(defaultPercent, 0, 1, 0) sliderFill.BackgroundColor3 = Color3.fromRGB(100, 200, 255) sliderFill.BorderSizePixel = 0 sliderFill.Parent = sliderBar local fillCorner = Instance.new("UICorner") fillCorner.CornerRadius = UDim.new(0, 2) fillCorner.Parent = sliderFill local sliderHandle = Instance.new("TextButton") sliderHandle.Size = UDim2.new(0, 14, 0, 14) sliderHandle.Position = UDim2.new(0, defaultPercent * 220 - 7, 0, -5) sliderHandle.BackgroundColor3 = Color3.fromRGB(255, 255, 255) sliderHandle.Text = "" sliderHandle.AutoButtonColor = false sliderHandle.BorderSizePixel = 0 sliderHandle.Parent = sliderBar local handleCorner = Instance.new("UICorner") handleCorner.CornerRadius = UDim.new(0, 7) handleCorner.Parent = sliderHandle local min = config.min or 0 local max = config.max or 100 local slider = Slider.new(sliderBar, sliderHandle, function(normalized) local value = min + normalized * (max - min) valueLabel.Text = tostring(math.floor(value + 0.5)) sliderFill.Size = UDim2.new(normalized, 0, 1, 0) if config.callback then config.callback(value) end end) table.insert(self.components, slider) return slider end function DummyUI:AddLabel(parent, text) local label = Instance.new("TextLabel") label.Size = UDim2.new(0, 260, 0, 40) label.BackgroundColor3 = Color3.fromRGB(35, 35, 45) label.BackgroundTransparency = 0.3 label.TextColor3 = Color3.fromRGB(200, 200, 220) label.Font = Enum.Font.Gotham label.TextSize = 12 label.Text = text label.TextWrapped = true label.Parent = parent local labelCorner = Instance.new("UICorner") labelCorner.CornerRadius = UDim.new(0, 10) labelCorner.Parent = label return label end function DummyUI:AddKeybind(parent, config) local card = Instance.new("Frame") card.Size = UDim2.new(0, 260, 0, 90) card.BackgroundColor3 = Color3.fromRGB(35, 35, 45) card.BackgroundTransparency = 0.3 card.BorderSizePixel = 0 card.Parent = parent local cardCorner = Instance.new("UICorner") cardCorner.CornerRadius = UDim.new(0, 10) cardCorner.Parent = card local title = Instance.new("TextLabel") title.Size = UDim2.new(1, -20, 0, 24) title.Position = UDim2.new(0, 12, 0, 8) title.BackgroundTransparency = 1 title.TextColor3 = Color3.fromRGB(255, 255, 255) title.Font = Enum.Font.GothamBold title.TextSize = 14 title.Text = config.text or "Keybind" title.TextXAlignment = Enum.TextXAlignment.Left title.Parent = card local desc = Instance.new("TextLabel") desc.Size = UDim2.new(1, -24, 0, 20) desc.Position = UDim2.new(0, 12, 0, 32) desc.BackgroundTransparency = 1 desc.TextColor3 = Color3.fromRGB(150, 150, 170) desc.Font = Enum.Font.Gotham desc.TextSize = 11 desc.Text = "Press to record new key combination (max 3 keys)" desc.TextXAlignment = Enum.TextXAlignment.Left desc.Parent = card local keybindButton = Instance.new("TextButton") keybindButton.Size = UDim2.new(0, 200, 0, 36) keybindButton.Position = UDim2.new(0, 30, 0, 54) keybindButton.BackgroundColor3 = Color3.fromRGB(45, 45, 55) keybindButton.TextColor3 = Color3.fromRGB(255, 255, 255) keybindButton.Font = Enum.Font.GothamBold keybindButton.TextSize = 13 keybindButton.Text = table.concat(config.default or {"Shift", "P"}, "+") keybindButton.AutoButtonColor = false keybindButton.BorderSizePixel = 1 keybindButton.BorderColor3 = Color3.fromRGB(80, 80, 100) keybindButton.Parent = card local keybindCorner = Instance.new("UICorner") keybindCorner.CornerRadius = UDim.new(0, 18) keybindCorner.Parent = keybindButton local selectedKeys = {} local isListening = false local activeConnection = nil local function getKeyName(keyCode) local name = keyCode.Name if name == "LeftControl" or name == "RightControl" then return "Ctrl" elseif name == "LeftAlt" or name == "RightAlt" then return "Alt" elseif name == "LeftShift" or name == "RightShift" then return "Shift" else return name end end local function updateDisplay() local names = {} for _, k in ipairs(selectedKeys) do table.insert(names, getKeyName(k)) end keybindButton.Text = (#names > 0 and table.concat(names, "+")) or "..." if config.onChange then config.onChange(selectedKeys) end end local function startListening() isListening = true selectedKeys = {} keybindButton.Text = "Press keys..." keybindButton.BackgroundColor3 = Color3.fromRGB(70, 70, 90) end local function stopListening() isListening = false keybindButton.BackgroundColor3 = Color3.fromRGB(45, 45, 55) updateDisplay() end if config.default then for _, keyName in ipairs(config.default) do for _, ek in pairs(Enum.KeyCode:GetEnumItems()) do if ek.Name == keyName then table.insert(selectedKeys, ek) break end end end updateDisplay() end keybindButton.MouseButton1Click:Connect(function() if isListening then stopListening() if activeConnection then activeConnection:Disconnect() activeConnection = nil end else startListening() if activeConnection then activeConnection:Disconnect() end activeConnection = UserInputService.InputBegan:Connect(function(input, gameProcessed) if gameProcessed then return end if isListening and input.KeyCode ~= Enum.KeyCode.Unknown then if #selectedKeys < 3 and not table.find(selectedKeys, input.KeyCode) then table.insert(selectedKeys, input.KeyCode) updateDisplay() end task.wait(0.2) if isListening and #selectedKeys > 0 then stopListening() if activeConnection then activeConnection:Disconnect() activeConnection = nil end end end end) end end) table.insert(self.components, {Destroy = function() if activeConnection then activeConnection:Disconnect() end end}) return {GetKeys = function() return selectedKeys end} end function DummyUI:Destroy() if self.draggable then self.draggable:Destroy() end for _, component in ipairs(self.components) do if component.Destroy then component:Destroy() end end if self.mainFrame then self.mainFrame:Destroy() end end local ui = DummyUI.new("Freecam Control", UDim2.new(0, 300, 0, 380)) uiMainFrame = ui.mainFrame floatingButton = Instance.new("TextButton") floatingButton.Name = "OpenFCUI" floatingButton.Size = UDim2.new(0, 120, 0, 40) floatingButton.Position = UDim2.new(0.5, -235, 0.9, -372) floatingButton.Text = "[OpenFC-UI]" floatingButton.TextColor3 = Color3.fromRGB(255, 255, 255) floatingButton.TextSize = 14 floatingButton.Draggable = true floatingButton.Font = Enum.Font.GothamBold floatingButton.BackgroundColor3 = Color3.fromRGB(100, 200, 255) floatingButton.BackgroundTransparency = 0.3 floatingButton.BorderSizePixel = 0 floatingButton.Parent = freecamGui floatingButton.ZIndex = 100 local floatCorner = Instance.new("UICorner") floatCorner.CornerRadius = UDim.new(0, 20) floatCorner.Parent = floatingButton floatingButton.Visible = false floatingButton.MouseButton1Click:Connect(function() if uiMainFrame then uiMainFrame.Visible = true end floatingButton.Visible = false end) local function updateFloatingButtonPosition() local screenSize = freecamGui.AbsoluteSize floatingButton.Position = UDim2.new(0.5, -60, 0.9, 0) end freecamGui:GetPropertyChangedSignal("AbsoluteSize"):Connect(updateFloatingButtonPosition) updateFloatingButtonPosition() local homeTab = ui:AddTab("Home") local freecamToggle = ui:AddToggle(homeTab, { text = "Freecam Enabled", callback = function(state) if state then StartFreecam() else StopFreecam() end end, default = false }) ui:AddSlider(homeTab, { text = "Movement Speed", min = 0.25, max = 4, default = 1, callback = function(val) mobileNavSpeed = val end }) ui:AddSlider(homeTab, { text = "Mouse Sensitivity", min = 0.2, max = 3, default = 1, callback = function(val) mouseSensitivity = val end }) ui:AddSlider(homeTab, { text = "Touch Look Sensitivity", min = 0.2, max = 3, default = 1, callback = function(val) touchLookSensitivity = val end }) ui:AddSlider(homeTab, { text = "FOV Sensitivity", min = 0.2, max = 3, default = 1, callback = function(val) fovSensitivity = val end }) ui:AddSlider(homeTab, { text = "Movement Smoothing", min = 0.1, max = 5, default = 1.5, callback = function(val) VEL_STIFFNESS = val; velSpring:SetFreq(val) end }) ui:AddSlider(homeTab, { text = "Look Smoothing", min = 0.1, max = 5, default = 1, callback = function(val) PAN_STIFFNESS = val; panSpring:SetFreq(val) end }) ui:AddSlider(homeTab, { text = "FOV Smoothing", min = 0.1, max = 5, default = 4, callback = function(val) FOV_STIFFNESS = val; fovSpring:SetFreq(val) end }) ui:AddSlider(homeTab, { text = "Roll Smoothing", min = 0.1, max = 5, default = 1, callback = function(val) ROLL_STIFFNESS = val; rollSpring:SetFreq(val) end }) ui:AddSlider(homeTab, { text = "Tilt Speed", min = 0.2, max = 3, default = 1, callback = function(val) rollSpeed = val end }) ui:AddLabel(homeTab, "Controls:\nWASD / Thumbstick - Move\nMouse/Right Touch - Look\nQ/E - Up/Down\nZ/C - Tilt (Keyboard)\nTilt Buttons (Bottom Left)\nPlayer Lock Bar (Bottom Center)\nShift - Slow mode") local keybindTab = ui:AddTab("Keybind") local customToggleKeys = {"LeftShift", "P"} local customPlayerLockKeys = {"Slash"} local customPlayerLockPrevKeys = {"R"} local customPlayerLockNextKeys = {"T"} local customDoFKeys = {"BackSlash"} local customHideGuiKeys = {"G"} local customHidePlayerGuiKeys = {"X"} local customLeaderboardKeys = {"L"} local customTiltResetKeys = {"Z", "C"} local customTiltLeftKeys = {"Z"} local customTiltRightKeys = {"C"} local function rebuildToggleFreecamKeybind() ContextActionService:UnbindAction("FreecamToggle") if #customToggleKeys >= 1 then local macroKeys = {} for i, keyName in ipairs(customToggleKeys) do for _, ek in pairs(Enum.KeyCode:GetEnumItems()) do if ek.Name == keyName then macroKeys[i] = ek; break end end end if #macroKeys > 0 then local lastKey = macroKeys[#macroKeys] ContextActionService:BindActionAtPriority("FreecamToggle", function(action, state, input) if state == Enum.UserInputState.Begin and input.KeyCode == lastKey then local allDown = true for i = 1, #macroKeys - 1 do if not UserInputService:IsKeyDown(macroKeys[i]) then allDown = false; break end end if allDown then ToggleFreecam() end end return Enum.ContextActionResult.Pass end, false, TOGGLE_INPUT_PRIORITY, lastKey) end end end local function rebuildPlayerLockKeybind() ContextActionService:UnbindAction("FreecamKeyboardPlayerLockToggle") if #customPlayerLockKeys >= 1 then local macroKeys = {} for i, keyName in ipairs(customPlayerLockKeys) do for _, ek in pairs(Enum.KeyCode:GetEnumItems()) do if ek.Name == keyName then macroKeys[i] = ek; break end end end if #macroKeys > 0 then local lastKey = macroKeys[#macroKeys] ContextActionService:BindActionAtPriority("FreecamKeyboardPlayerLockToggle", function(action, state, input) if state == Enum.UserInputState.Begin and input.KeyCode == lastKey then local allDown = true for i = 1, #macroKeys - 1 do if not UserInputService:IsKeyDown(macroKeys[i]) then allDown = false; break end end if allDown then playerLockEnabled = not playerLockEnabled if playerLockEnabled then playerLockZoom = PLAYER_LOCK_DEFAULT_ZOOM playerLockHeight = PLAYER_LOCK_DEFAULT_HEIGHT rootPart = findPlayerLockRootPart(0) end end end return Enum.ContextActionResult.Pass end, false, INPUT_PRIORITY, lastKey) end end end local function rebuildPlayerLockPrevKeybind() ContextActionService:UnbindAction("FreecamKeyboardPlayerLockPrev") if #customPlayerLockPrevKeys >= 1 then local macroKeys = {} for i, keyName in ipairs(customPlayerLockPrevKeys) do for _, ek in pairs(Enum.KeyCode:GetEnumItems()) do if ek.Name == keyName then macroKeys[i] = ek; break end end end if #macroKeys > 0 then local lastKey = macroKeys[#macroKeys] ContextActionService:BindActionAtPriority("FreecamKeyboardPlayerLockPrev", function(action, state, input) if state == Enum.UserInputState.Begin and input.KeyCode == lastKey then local allDown = true for i = 1, #macroKeys - 1 do if not UserInputService:IsKeyDown(macroKeys[i]) then allDown = false; break end end if allDown and playerLockEnabled and #playerList > 0 then rootPart = findPlayerLockRootPart(-1) end end return Enum.ContextActionResult.Pass end, false, INPUT_PRIORITY, lastKey) end end end local function rebuildPlayerLockNextKeybind() ContextActionService:UnbindAction("FreecamKeyboardPlayerLockNext") if #customPlayerLockNextKeys >= 1 then local macroKeys = {} for i, keyName in ipairs(customPlayerLockNextKeys) do for _, ek in pairs(Enum.KeyCode:GetEnumItems()) do if ek.Name == keyName then macroKeys[i] = ek; break end end end if #macroKeys > 0 then local lastKey = macroKeys[#macroKeys] ContextActionService:BindActionAtPriority("FreecamKeyboardPlayerLockNext", function(action, state, input) if state == Enum.UserInputState.Begin and input.KeyCode == lastKey then local allDown = true for i = 1, #macroKeys - 1 do if not UserInputService:IsKeyDown(macroKeys[i]) then allDown = false; break end end if allDown and playerLockEnabled and #playerList > 0 then rootPart = findPlayerLockRootPart(1) end end return Enum.ContextActionResult.Pass end, false, INPUT_PRIORITY, lastKey) end end end local function rebuildDoFKeybind() ContextActionService:UnbindAction("FreecamKeyboardDoFToggle") if #customDoFKeys >= 1 then local macroKeys = {} for i, keyName in ipairs(customDoFKeys) do for _, ek in pairs(Enum.KeyCode:GetEnumItems()) do if ek.Name == keyName then macroKeys[i] = ek; break end end end if #macroKeys > 0 then local lastKey = macroKeys[#macroKeys] ContextActionService:BindActionAtPriority("FreecamKeyboardDoFToggle", function(action, state, input) if state == Enum.UserInputState.Begin and input.KeyCode == lastKey then local allDown = true for i = 1, #macroKeys - 1 do if not UserInputService:IsKeyDown(macroKeys[i]) then allDown = false; break end end if allDown and FreecamDepthOfField then FreecamDepthOfField.Enabled = not FreecamDepthOfField.Enabled end end return Enum.ContextActionResult.Pass end, false, INPUT_PRIORITY, lastKey) end end end local function rebuildHideGuiKeybind() ContextActionService:UnbindAction("FreecamKeyboardCustomGuiToggle") if #customHideGuiKeys >= 1 then local macroKeys = {} for i, keyName in ipairs(customHideGuiKeys) do for _, ek in pairs(Enum.KeyCode:GetEnumItems()) do if ek.Name == keyName then macroKeys[i] = ek; break end end end if #macroKeys > 0 then local lastKey = macroKeys[#macroKeys] ContextActionService:BindActionAtPriority("FreecamKeyboardCustomGuiToggle", function(action, state, input) if state == Enum.UserInputState.Begin and input.KeyCode == lastKey then local allDown = true for i = 1, #macroKeys - 1 do if not UserInputService:IsKeyDown(macroKeys[i]) then allDown = false; break end end if allDown and freecamGui and freecamGui.Parent then freecamGui.Enabled = not freecamGui.Enabled end end return Enum.ContextActionResult.Pass end, false, INPUT_PRIORITY, lastKey) end end end local function rebuildHidePlayerGuiKeybind() ContextActionService:UnbindAction("FreecamKeyboardPlayerGuiToggle") if #customHidePlayerGuiKeys >= 1 then local macroKeys = {} for i, keyName in ipairs(customHidePlayerGuiKeys) do for _, ek in pairs(Enum.KeyCode:GetEnumItems()) do if ek.Name == keyName then macroKeys[i] = ek; break end end end if #macroKeys > 0 then local lastKey = macroKeys[#macroKeys] ContextActionService:BindActionAtPriority("FreecamKeyboardPlayerGuiToggle", function(action, state, input) if state == Enum.UserInputState.Begin and input.KeyCode == lastKey then local allDown = true for i = 1, #macroKeys - 1 do if not UserInputService:IsKeyDown(macroKeys[i]) then allDown = false; break end end if allDown then screenGuisEnabled = not screenGuisEnabled local screenGuis = PlayerState.getScreenGuis() for _, gui in pairs(screenGuis) do if gui.Parent and gui ~= freecamGui then gui.Enabled = screenGuisEnabled end end end end return Enum.ContextActionResult.Pass end, false, INPUT_PRIORITY, lastKey) end end end local function rebuildLeaderboardKeybind() ContextActionService:UnbindAction("FreecamKeyboardLeaderboardToggle") if #customLeaderboardKeys >= 1 then local macroKeys = {} for i, keyName in ipairs(customLeaderboardKeys) do for _, ek in pairs(Enum.KeyCode:GetEnumItems()) do if ek.Name == keyName then macroKeys[i] = ek; break end end end if #macroKeys > 0 then local lastKey = macroKeys[#macroKeys] ContextActionService:BindActionAtPriority("FreecamKeyboardLeaderboardToggle", function(action, state, input) if state == Enum.UserInputState.Begin and input.KeyCode == lastKey then local allDown = true for i = 1, #macroKeys - 1 do if not UserInputService:IsKeyDown(macroKeys[i]) then allDown = false; break end end if allDown then leaderboardEnabled = not leaderboardEnabled StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.PlayerList, leaderboardEnabled) end end return Enum.ContextActionResult.Pass end, false, INPUT_PRIORITY, lastKey) end end end local function rebuildTiltResetKeybind() ContextActionService:UnbindAction("FreecamKeyboardTiltReset") if #customTiltResetKeys >= 1 then local macroKeys = {} for i, keyName in ipairs(customTiltResetKeys) do for _, ek in pairs(Enum.KeyCode:GetEnumItems()) do if ek.Name == keyName then macroKeys[i] = ek; break end end end if #macroKeys > 0 then local lastKey = macroKeys[#macroKeys] ContextActionService:BindActionAtPriority("FreecamKeyboardTiltReset", function(action, state, input) if state == Enum.UserInputState.Begin and input.KeyCode == lastKey then local allDown = true for i = 1, #macroKeys - 1 do if not UserInputService:IsKeyDown(macroKeys[i]) then allDown = false; break end end if allDown then cameraRot = Vector3.new(cameraRot.x, cameraRot.y, 0) rollSpring:Reset(0) end end return Enum.ContextActionResult.Pass end, false, INPUT_PRIORITY, lastKey) end end end ui:AddKeybind(keybindTab, { text = "Toggle Freecam", default = customToggleKeys, onChange = function(keys) customToggleKeys = {}; for _, k in ipairs(keys) do table.insert(customToggleKeys, k.Name) end if #customToggleKeys == 0 then customToggleKeys = {"LeftShift", "P"} end rebuildToggleFreecamKeybind() end }) ui:AddKeybind(keybindTab, { text = "Tilt Left", default = customTiltLeftKeys, onChange = function(keys) customTiltLeftKeys = {}; for _, k in ipairs(keys) do table.insert(customTiltLeftKeys, k.Name) end if #customTiltLeftKeys == 0 then customTiltLeftKeys = {"Z"} end end }) ui:AddKeybind(keybindTab, { text = "Tilt Right", default = customTiltRightKeys, onChange = function(keys) customTiltRightKeys = {}; for _, k in ipairs(keys) do table.insert(customTiltRightKeys, k.Name) end if #customTiltRightKeys == 0 then customTiltRightKeys = {"C"} end end }) ui:AddKeybind(keybindTab, { text = "Player Lock Toggle", default = customPlayerLockKeys, onChange = function(keys) customPlayerLockKeys = {}; for _, k in ipairs(keys) do table.insert(customPlayerLockKeys, k.Name) end if #customPlayerLockKeys == 0 then customPlayerLockKeys = {"Slash"} end rebuildPlayerLockKeybind() end }) ui:AddKeybind(keybindTab, { text = "Player Lock Previous", default = customPlayerLockPrevKeys, onChange = function(keys) customPlayerLockPrevKeys = {}; for _, k in ipairs(keys) do table.insert(customPlayerLockPrevKeys, k.Name) end if #customPlayerLockPrevKeys == 0 then customPlayerLockPrevKeys = {"R"} end rebuildPlayerLockPrevKeybind() end }) ui:AddKeybind(keybindTab, { text = "Player Lock Next", default = customPlayerLockNextKeys, onChange = function(keys) customPlayerLockNextKeys = {}; for _, k in ipairs(keys) do table.insert(customPlayerLockNextKeys, k.Name) end if #customPlayerLockNextKeys == 0 then customPlayerLockNextKeys = {"T"} end rebuildPlayerLockNextKeybind() end }) ui:AddKeybind(keybindTab, { text = "Depth of Field Toggle", default = customDoFKeys, onChange = function(keys) customDoFKeys = {}; for _, k in ipairs(keys) do table.insert(customDoFKeys, k.Name) end if #customDoFKeys == 0 then customDoFKeys = {"BackSlash"} end rebuildDoFKeybind() end }) ui:AddKeybind(keybindTab, { text = "Hide Freecam UI", default = customHideGuiKeys, onChange = function(keys) customHideGuiKeys = {}; for _, k in ipairs(keys) do table.insert(customHideGuiKeys, k.Name) end if #customHideGuiKeys == 0 then customHideGuiKeys = {"G"} end rebuildHideGuiKeybind() end }) ui:AddKeybind(keybindTab, { text = "Hide Player GUI", default = customHidePlayerGuiKeys, onChange = function(keys) customHidePlayerGuiKeys = {}; for _, k in ipairs(keys) do table.insert(customHidePlayerGuiKeys, k.Name) end if #customHidePlayerGuiKeys == 0 then customHidePlayerGuiKeys = {"X"} end rebuildHidePlayerGuiKeybind() end }) ui:AddKeybind(keybindTab, { text = "Toggle Leaderboard", default = customLeaderboardKeys, onChange = function(keys) customLeaderboardKeys = {}; for _, k in ipairs(keys) do table.insert(customLeaderboardKeys, k.Name) end if #customLeaderboardKeys == 0 then customLeaderboardKeys = {"L"} end rebuildLeaderboardKeybind() end }) ui:AddKeybind(keybindTab, { text = "Tilt Reset", default = customTiltResetKeys, onChange = function(keys) customTiltResetKeys = {}; for _, k in ipairs(keys) do table.insert(customTiltResetKeys, k.Name) end if #customTiltResetKeys == 0 then customTiltResetKeys = {"Z", "C"} end rebuildTiltResetKeybind() end }) ui:AddLabel(keybindTab, "Click any keybind button to record\na new key combination (max 3 keys)") rebuildToggleFreecamKeybind() rebuildPlayerLockKeybind() rebuildPlayerLockPrevKeybind() rebuildPlayerLockNextKeybind() rebuildDoFKeybind() rebuildHideGuiKeybind() rebuildHidePlayerGuiKeybind() rebuildLeaderboardKeybind() rebuildTiltResetKeybind() function StartFreecam() if FFlagUserFreecamPlayerLock then initializePlayerList() end if not FFlagUserFreecamGuiDestabilization then if FFlagUserShowGuiHideToggles then script:SetAttribute(FREECAM_ENABLED_ATTRIBUTE_NAME, true) end end local cameraCFrame = Camera.CFrame if FFlagUserFreecamTiltControl then cameraRot = Vector3.new(cameraCFrame:toEulerAnglesYXZ()) else cameraRot = Vector2.new(cameraCFrame:toEulerAnglesYXZ()) end cameraPos = cameraCFrame.p cameraFov = Camera.FieldOfView velSpring:Reset(Vector3.new()) panSpring:Reset(Vector2.new()) fovSpring:Reset(0) if FFlagUserFreecamTiltControl then rollSpring:Reset(0) end if FFlagUserFreecamCustomGui then if not touchGui then touchGui = CreateTouchControls() end end PlayerState.Push() if FFlagUserFreecamDepthOfFieldEffect then if not FreecamDepthOfField or not FreecamDepthOfField.Parent then FreecamDepthOfField = Instance.new("DepthOfFieldEffect") FreecamDepthOfField.Enabled = false FreecamDepthOfField.Name = "FreecamDepthOfField" FreecamDepthOfField.Parent = Camera end end RunService:BindToRenderStep("Freecam", Enum.RenderPriority.Camera.Value, StepFreecam) Input.StartCapture() end function DestroyAllUI() if touchGui then touchGui:Destroy() touchGui = nil end if customGui then customGui:Destroy() customGui = nil end end function StopFreecam() if not FFlagUserFreecamGuiDestabilization then if FFlagUserShowGuiHideToggles then script:SetAttribute(FREECAM_ENABLED_ATTRIBUTE_NAME, false) end end if FFlagUserFreecamPlayerLock then if playerAddedConnection then playerAddedConnection:Disconnect() playerAddedConnection = nil end if playerRemovingConnection then playerRemovingConnection:Disconnect() playerRemovingConnection = nil end playerLockEnabled = false currentTargetIndex = 1 playerList = {} end if FFlagUserFreecamDepthOfFieldEffect then if FreecamDepthOfField and FreecamDepthOfField.Parent then if FreecamDepthOfField.Enabled then for _, effect in ipairs(postEffects) do if effect.Parent then effect.Enabled = true end end if cameraConnection then cameraConnection:Disconnect() cameraConnection = nil end if lightingConnection then lightingConnection:Disconnect() lightingConnection = nil end postEffects = {} end FreecamDepthOfField.Enabled = false end end if FFlagUserFreecamCustomGui then DestroyAllUI() screenGuisEnabled = false leaderboardEnabled = false end Input.StopCapture() pcall(function() RunService:UnbindFromRenderStep("Freecam") end) PlayerState.Pop() end do local enabled = false function ToggleFreecam() if enabled then StopFreecam() else StartFreecam() end enabled = not enabled if FFlagUserFreecamGuiDestabilization then script:SetAttribute(FREECAM_ENABLED_ATTRIBUTE_NAME, enabled) end if freecamToggle and freecamToggle.SetState then freecamToggle:SetState(enabled) end end if FFlagUserFreecamGuiDestabilization or FFlagUserShowGuiHideToggles then script:SetAttribute(FREECAM_ENABLED_ATTRIBUTE_NAME, enabled) script:GetAttributeChangedSignal(FREECAM_ENABLED_ATTRIBUTE_NAME):Connect(function() local attributeValue = script:GetAttribute(FREECAM_ENABLED_ATTRIBUTE_NAME) if typeof(attributeValue) ~= "boolean" then script:SetAttribute(FREECAM_ENABLED_ATTRIBUTE_NAME, enabled) return end if attributeValue ~= enabled then if attributeValue then StartFreecam() enabled = true else StopFreecam() enabled = false end if freecamToggle and freecamToggle.SetState then freecamToggle:SetState(enabled) end end end) end end return {}