
KeylessUniversal

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 {}



This is cool but this is not GPT right?
@Styear it's roblox studio source code i have to rework