universal freecam open src
Key RequiredUniversal

universal freecam open src

Universal Scriptindistiputedindistiputed 841 views 20.8K executesUpdated Sep 22, 2026
5.0/ 5(1 votes)
10100% Positive
Lua Script•520 lines (8681 chars)
local P = game:GetService("Players")
local UIS = game:GetService("UserInputService")
local RS = game:GetService("RunService")
local TS = game:GetService("TweenService")

local plr = P.LocalPlayer
local cam = workspace.CurrentCamera
local ps = plr:WaitForChild("PlayerScripts")
local pm = ps:WaitForChild("PlayerModule")

local ok, mod = pcall(require, pm)
local ctl

if ok and mod and mod.GetControls then
	pcall(function()
		ctl = mod:GetControls()
	end)
end

local mob = UIS.TouchEnabled and not UIS.KeyboardEnabled

local on = false
local keys = {}

local pos
local yaw = 0
local pit = 0

local oldType
local oldSub
local oldCf
local oldMouse

local oldCtl = false

local spd = 70
local spr = 180
local ls = 0.0025
local ts = 0.006

local lt
local lp
local rt

local stm = 0
local lastPos

local ui = Instance.new("ScreenGui")
ui.Name = "FreecamUI"
ui.ResetOnSpawn = false
ui.IgnoreGuiInset = true
ui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling

pcall(function()
	ui.Parent = game:GetService("CoreGui")
end)

if not ui.Parent then
	ui.Parent = plr:WaitForChild("PlayerGui")
end

local btn
local stroke
local hint

local function root()
	local c = plr.Character
	return c and c:FindFirstChild("HumanoidRootPart")
end

local function look()
	local v = cam.CFrame.LookVector

	yaw = math.atan2(-v.X, -v.Z)
	pit = math.asin(math.clamp(v.Y, -1, 1))
end

local function vis(v)
	if not btn then
		return
	end

	TS:Create(
		btn,
		TweenInfo.new(0.15, Enum.EasingStyle.Quad, Enum.EasingDirection.Out),
		{
			BackgroundColor3 = v
				and Color3.fromRGB(95, 60, 155)
				or Color3.fromRGB(20, 20, 24)
		}
	):Play()

	TS:Create(
		stroke,
		TweenInfo.new(0.15, Enum.EasingStyle.Quad, Enum.EasingDirection.Out),
		{
			Color = v
				and Color3.fromRGB(175, 125, 255)
				or Color3.fromRGB(55, 55, 62)
		}
	):Play()
end

local function st()
	if on then
		return
	end

	local r = root()

	if not r then
		return
	end

	cam = workspace.CurrentCamera

	oldType = cam.CameraType
	oldSub = cam.CameraSubject
	oldCf = cam.CFrame
	oldMouse = UIS.MouseBehavior

	pos = cam.CFrame.Position
	look()

	if ctl then
		oldCtl = true
		pcall(function()
			ctl:Disable()
		end)
	end

	cam.CameraType = Enum.CameraType.Scriptable

	if not mob then
		UIS.MouseBehavior = Enum.MouseBehavior.LockCurrentPosition
	end

	on = true
	stm = 0
	lastPos = nil

	vis(true)

	pcall(function()
		plr:RequestStreamAroundAsync(pos, 2)
	end)

	lastPos = pos
end

local function sp()
	if not on then
		return
	end

	on = false

	lt = nil
	rt = nil
	lp = nil

	cam = workspace.CurrentCamera

	cam.CameraType = oldType or Enum.CameraType.Custom
	cam.CameraSubject = oldSub

	if oldCf then
		cam.CFrame = oldCf
	end

	UIS.MouseBehavior = oldMouse or Enum.MouseBehavior.Default

	if ctl and oldCtl then
		pcall(function()
			ctl:Enable()
		end)
	end

	oldCtl = false

	pos = nil
	lastPos = nil

	vis(false)
end

local function tg()
	if on then
		sp()
	else
		st()
	end
end

if mob then
	btn = Instance.new("Frame")
	btn.Name = "Toggle"
	btn.Size = UDim2.fromOffset(58, 58)
	btn.Position = UDim2.new(1, -78, 1, -94)
	btn.BackgroundColor3 = Color3.fromRGB(20, 20, 24)
	btn.BorderSizePixel = 0
	btn.Active = true
	btn.ZIndex = 20
	btn.Parent = ui

	local cr = Instance.new("UICorner")
	cr.CornerRadius = UDim.new(0, 15)
	cr.Parent = btn

	stroke = Instance.new("UIStroke")
	stroke.Thickness = 1.5
	stroke.Color = Color3.fromRGB(55, 55, 62)
	stroke.Parent = btn

	local ic = Instance.new("ImageLabel")
	ic.Size = UDim2.fromOffset(25, 25)
	ic.Position = UDim2.fromScale(0.5, 0.5)
	ic.AnchorPoint = Vector2.new(0.5, 0.5)
	ic.BackgroundTransparency = 1
	ic.Image = "rbxassetid://7733708692"
	ic.ImageColor3 = Color3.fromRGB(230, 230, 235)
	ic.ZIndex = 21
	ic.Parent = btn

	local us = Instance.new("UIScale")
	us.Parent = btn

	local drag
	local start
	local moved = false

	btn.InputBegan:Connect(function(i)
		if i.UserInputType ~= Enum.UserInputType.Touch
			and i.UserInputType ~= Enum.UserInputType.MouseButton1 then
			return
		end

		drag = i.Position
		start = btn.Position
		moved = false
	end)

	btn.InputChanged:Connect(function(i)
		if i.UserInputType ~= Enum.UserInputType.Touch
			and i.UserInputType ~= Enum.UserInputType.MouseMovement then
			return
		end

		local c

		c = UIS.InputChanged:Connect(function(x)
			if x ~= i then
				return
			end

			if not drag or not start then
				c:Disconnect()
				return
			end

			local d = x.Position - drag

			if d.Magnitude > 8 then
				moved = true
			end

			btn.Position = UDim2.new(
				start.X.Scale,
				start.X.Offset + d.X,
				start.Y.Scale,
				start.Y.Offset + d.Y
			)
		end)
	end)

	btn.InputEnded:Connect(function(i)
		if i.UserInputType ~= Enum.UserInputType.Touch
			and i.UserInputType ~= Enum.UserInputType.MouseButton1 then
			return
		end

		if not moved then
			TS:Create(
				us,
				TweenInfo.new(0.08, Enum.EasingStyle.Quad, Enum.EasingDirection.Out),
				{Scale = 0.9}
			):Play()

			task.delay(0.08, function()
				if us.Parent then
					TS:Create(
						us,
						TweenInfo.new(0.1, Enum.EasingStyle.Quad, Enum.EasingDirection.Out),
						{Scale = 1}
					):Play()
				end
			end)

			tg()
		end

		drag = nil
		start = nil
		moved = false
	end)
else
	hint = Instance.new("TextLabel")
	hint.Name = "Hint"
	hint.AnchorPoint = Vector2.new(1, 0)
	hint.Position = UDim2.new(1, -18, 0, 18)
	hint.Size = UDim2.fromOffset(145, 24)
	hint.BackgroundTransparency = 1
	hint.Text = "use f to freecam"
	hint.TextSize = 14
	hint.Font = Enum.Font.GothamMedium
	hint.TextXAlignment = Enum.TextXAlignment.Right
	hint.ZIndex = 10
	hint.Parent = ui
end

UIS.InputBegan:Connect(function(i, p)
	if not mob then
		if i.KeyCode == Enum.KeyCode.F and not p then
			tg()
			return
		end

		if on and i.UserInputType == Enum.UserInputType.Keyboard then
			keys[i.KeyCode] = true
		end
	else
		if not on then
			return
		end

		if i.UserInputType == Enum.UserInputType.Touch then
			local vp = cam.ViewportSize
			local x = i.Position.X
			local y = i.Position.Y

			local bx = btn.AbsolutePosition
			local bs = btn.AbsoluteSize

			local inBtn =
				x >= bx.X
				and x <= bx.X + bs.X
				and y >= bx.Y
				and y <= bx.Y + bs.Y

			if inBtn then
				return
			end

			if x < vp.X * 0.45 and y > vp.Y * 0.45 and not lt then
				lt = i
				lp = i.Position
			elseif x >= vp.X * 0.38 and not rt then
				rt = i
			end
		end
	end
end)

UIS.InputEnded:Connect(function(i)
	if i.UserInputType == Enum.UserInputType.Keyboard then
		keys[i.KeyCode] = nil
	end

	if i == lt then
		lt = nil
		lp = nil
	end

	if i == rt then
		rt = nil
	end
end)

UIS.InputChanged:Connect(function(i)
	if not on then
		return
	end

	if not mob then
		if i.UserInputType == Enum.UserInputType.MouseMovement then
			yaw -= i.Delta.X * ls
			pit -= i.Delta.Y * ls
			pit = math.clamp(pit, -math.rad(89), math.rad(89))
		end
	else
		if i.UserInputType == Enum.UserInputType.Touch then
			if i == rt then
				yaw -= i.Delta.X * ts
				pit -= i.Delta.Y * ts

				pit = math.clamp(
					pit,
					-math.rad(89),
					math.rad(89)
				)
			end
		end
	end
end)

local rtick = 0

RS.RenderStepped:Connect(function(dt)
	if hint then
		rtick += dt * 0.25

		hint.TextColor3 = Color3.fromHSV(
			rtick % 1,
			0.8,
			1
		)
	end

	if not on then
		return
	end

	cam = workspace.CurrentCamera

	if not pos then
		pos = cam.CFrame.Position
	end

	local cr = CFrame.Angles(0, yaw, 0) * CFrame.Angles(pit, 0, 0)

	local mv = Vector3.zero

	if mob then
		if lt and lp then
			local d = lt.Position - lp
			local v = Vector2.new(
				math.clamp(d.X / 70, -1, 1),
				math.clamp(d.Y / 70, -1, 1)
			)

			mv += cr.RightVector * v.X
			mv += cr.LookVector * -v.Y
		end
	else
		local f = 0
		local r = 0
		local u = 0

		if keys[Enum.KeyCode.W] then
			f += 1
		end

		if keys[Enum.KeyCode.S] then
			f -= 1
		end

		if keys[Enum.KeyCode.A] then
			r -= 1
		end

		if keys[Enum.KeyCode.D] then
			r += 1
		end

		if keys[Enum.KeyCode.U] then
			u += 1
		end

		if keys[Enum.KeyCode.D] then
			u -= 1
		end

		mv += cr.LookVector * f
		mv += cr.RightVector * r
		mv += Vector3.yAxis * u
	end

	if mv.Magnitude > 1 then
		mv = mv.Unit
	end

	local speed = spd

	if keys[Enum.KeyCode.LeftShift]
		or keys[Enum.KeyCode.RightShift] then
		speed = spr
	end

	pos += mv * speed * dt

	stm += dt

	if stm >= 0.5 then
		stm = 0

		if not lastPos or (pos - lastPos).Magnitude >= 64 then
			lastPos = pos

			task.spawn(function()
				pcall(function()
					plr:RequestStreamAroundAsync(pos, 2)
				end)
			end)
		end
	end

	local cf =
		CFrame.new(pos)
		* CFrame.Angles(0, yaw, 0)
		* CFrame.Angles(pit, 0, 0)

	cam.CFrame = cf
	cam.Focus = CFrame.new(pos)
end)

plr.CharacterAdded:Connect(function()
	if on then
		sp()
	end
end)

Features & Information

allows you to use freecam on mobile and pc pretty cool PC controls: wasd to move press "f" key to toggle freecam on and off, and press "u" key to go up while using freecam.
#freecam#camera#universal#fc#free camera

Community Comments (1)

NeptronNeptronSep 27, 2026

Goonable

More Scripts for Universal Scripts