local M={}do local O do local M=2.0 local y=.15 local function K(O)return(exp(M*O)-1)/(exp(M)-1)end local function e(M)return K((M-y)/(1-y))end function O(M)return sign(M)*clamp(e(abs(M)),0,1)end end local y={ButtonX=0;ButtonY=0;DPadDown=0;DPadUp=0;ButtonL2=0;ButtonR2=0;Thumbstick1=Vector2.new(),Thumbstick2=Vector2.new()}local K={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;LeftShift=0;RightShift=0}local e={Delta=Vector2.new();MouseWheel=0}local d=Vector3.new(1,1,1)local P=Vector3.new(1,1,1)local h=Vector2.new(1,1)*(pi/64)local o=Vector2.new(1,1)*(pi/8)local i=1.0 local v=.25 local C=.75 local L=.25 local X=1 function M.Vel(M)X=clamp(X+(M*(K.Up-K.Down))*C,.01,4)local e=Vector3.new(O(y.Thumbstick1.X),O(y.ButtonR2)-O(y.ButtonL2),O(-y.Thumbstick1.Y))*d local h=Vector3.new(((K.D-K.A)+K.K)-K.H,((K.E-K.Q)+K.I)-K.Y,((K.S-K.W)+K.J)-K.U)*P local o=UserInputService:IsKeyDown(Enum.KeyCode.LeftShift)or UserInputService:IsKeyDown(Enum.KeyCode.RightShift)return(e+h)*(X*(o and L or 1))end function M.Pan(M)local K=Vector2.new(O(y.Thumbstick2.Y),O(-y.Thumbstick2.X))*o local d=e.Delta*h e.Delta=Vector2.new()return K+d end function M.Fov(M)local O=(y.ButtonX-y.ButtonY)*v local K=e.MouseWheel*i e.MouseWheel=0 return O+K end do local function O(M,O,y)K[y.KeyCode.Name]=O==Enum.UserInputState.Begin and 1 or 0 return Enum.ContextActionResult.Sink end local function d(M,O,K)y[K.KeyCode.Name]=O==Enum.UserInputState.Begin and 1 or 0 return Enum.ContextActionResult.Sink end local function P(M,O,y)local K=y.Delta e.Delta=Vector2.new(-K.y,-K.x)return Enum.ContextActionResult.Sink end local function h(M,O,K)y[K.KeyCode.Name]=K.Position return Enum.ContextActionResult.Sink end local function o(M,O,K)y[K.KeyCode.Name]=K.Position.z return Enum.ContextActionResult.Sink end local function i(M,O,y)e[y.UserInputType.Name]=-y.Position.z return Enum.ContextActionResult.Sink end local function v(M)for O,y in pairs(M)do M[O]=y*0 end end function M.StartCapture()ContextActionService:BindActionAtPriority("\070\114\101\101\099\097\109\075\101\121\098\111\097\114\100",O,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)ContextActionService:BindActionAtPriority("\070\114\101\101\099\097\109\077\111\117\115\101\080\097\110",P,false,INPUT_PRIORITY,Enum.UserInputType.MouseMovement)ContextActionService:BindActionAtPriority("\070\114\101\101\099\097\109\077\111\117\115\101\087\104\101\101\108",i,false,INPUT_PRIORITY,Enum.UserInputType.MouseWheel)ContextActionService:BindActionAtPriority("\070\114\101\101\099\097\109\071\097\109\101\112\097\100\066\117\116\116\111\110",d,false,INPUT_PRIORITY,Enum.KeyCode.ButtonX,Enum.KeyCode.ButtonY)ContextActionService:BindActionAtPriority("\070\114\101\101\099\097\109\071\097\109\101\112\097\100\084\114\105\103\103\101\114",o,false,INPUT_PRIORITY,Enum.KeyCode.ButtonR2,Enum.KeyCode.ButtonL2)ContextActionService:BindActionAtPriority("\070\114\101\101\099\097\109\071\097\109\101\112\097\100\084\104\117\109\098\115\116\105\099\107",h,false,INPUT_PRIORITY,Enum.KeyCode.Thumbstick1,Enum.KeyCode.Thumbstick2)end function M.StopCapture()X=1 v(y)v(K)v(e)ContextActionService:UnbindAction("\070\114\101\101\099\097\109\075\101\121\098\111\097\114\100")ContextActionService:UnbindAction("\070\114\101\101\099\097\109\077\111\117\115\101\080\097\110")ContextActionService:UnbindAction("\070\114\101\101\099\097\109\077\111\117\115\101\087\104\101\101\108")ContextActionService:UnbindAction("\070\114\101\101\099\097\109\071\097\109\101\112\097\100\066\117\116\116\111\110")ContextActionService:UnbindAction("\070\114\101\101\099\097\109\071\097\109\101\112\097\100\084\114\105\103\103\101\114")ContextActionService:UnbindAction("\070\114\101\101\099\097\109\071\097\109\101\112\097\100\084\104\117\109\098\115\116\105\099\107")end end end local function O(M)local O=.1 local y=Camera.ViewportSize local K=2*tan(cameraFov/2)local e=(y.x/y.y)*K local d=M.rightVector local P=M.upVector local h=M.lookVector local o=Vector3.new()local i=512 for y=0,1,.5 do for v=0,1,.5 do local C=(y-.5)*e local L=(v-.5)*K local X=(d*C-P*L)+h local A=M.p+X*O local R,c=Workspace:FindPartOnRay(Ray.new(A,X.unit*i))local j=(c-A).magnitude if i>j then i=j o=X.unit end end end return h:Dot(o)*i end
------------------------------------------------------------------------

local Input = {}
do
	local thumbstickCurve
	do
		local K_CURVATURE = 2.0
		local K_DEADZONE = 0.15

		local function fCurve(x)
			return (exp(K_CURVATURE * x) - 1) / (exp(K_CURVATURE) - 1)
		end

		local 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,
		ButtonL2 = 0,
		ButtonR2 = 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,
		LeftShift = 0,
		RightShift = 0,
	}

	local mouse = {
		Delta = Vector2.new(),
		MouseWheel = 0,
	}

	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_GAMEPAD_SPEED = Vector2.new(1, 1) * (pi / 8)
	local FOV_WHEEL_SPEED = 1.0
	local FOV_GAMEPAD_SPEED = 0.25
	local NAV_ADJ_SPEED = 0.75
	local NAV_SHIFT_MUL = 0.25

	local navSpeed = 1

	function Input.Vel(dt)
		navSpeed = clamp(navSpeed + dt * (keyboard.Up - keyboard.Down) * NAV_ADJ_SPEED, 0.01, 4)

		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) * (navSpeed * (shift and NAV_SHIFT_MUL or 1))
	end

	function Input.Pan(dt)
		local kGamepad = Vector2.new(thumbstickCurve(gamepad.Thumbstick2.Y), thumbstickCurve(-gamepad.Thumbstick2.X))
			* PAN_GAMEPAD_SPEED
		local kMouse = mouse.Delta * PAN_MOUSE_SPEED
		mouse.Delta = Vector2.new()
		return kGamepad + kMouse
	end

	function Input.Fov(dt)
		local kGamepad = (gamepad.ButtonX - gamepad.ButtonY) * FOV_GAMEPAD_SPEED
		local kMouse = mouse.MouseWheel * FOV_WHEEL_SPEED
		mouse.MouseWheel = 0
		return kGamepad + kMouse
	end

	do
		local function Keypress(action, state, input)
			keyboard[input.KeyCode.Name] = state == Enum.UserInputState.Begin and 1 or 0
			return Enum.ContextActionResult.Sink
		end

		local function GpButton(action, state, input)
			gamepad[input.KeyCode.Name] = state == Enum.UserInputState.Begin and 1 or 0
			return Enum.ContextActionResult.Sink
		end

		local function MousePan(action, state, input)
			local delta = input.Delta
			mouse.Delta = Vector2.new(-delta.y, -delta.x)
			return Enum.ContextActionResult.Sink
		end

		local function Thumb(action, state, input)
			gamepad[input.KeyCode.Name] = input.Position
			return Enum.ContextActionResult.Sink
		end

		local function Trigger(action, state, input)
			gamepad[input.KeyCode.Name] = input.Position.z
			return Enum.ContextActionResult.Sink
		end

		local function MouseWheel(action, state, input)
			mouse[input.UserInputType.Name] = -input.Position.z
			return Enum.ContextActionResult.Sink
		end

		local function Zero(t)
			for k, v in pairs(t) do
				t[k] = v * 0
			end
		end

		function Input.StartCapture()
			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
			)
			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()
			navSpeed = 1
			Zero(gamepad)
			Zero(keyboard)
			Zero(mouse)
			ContextActionService:UnbindAction("FreecamKeyboard")
			ContextActionService:UnbindAction("FreecamMousePan")
			ContextActionService:UnbindAction("FreecamMouseWheel")
			ContextActionService:UnbindAction("FreecamGamepadButton")
			ContextActionService:UnbindAction("FreecamGamepadTrigger")
			ContextActionService:UnbindAction("FreecamGamepadThumbstick")
		end
	end
end

local function GetFocusDistance(cameraFrame)
	local znear = 0.1
	local viewport = Camera.ViewportSize
	local projy = 2 * tan(cameraFov / 2)
	local projx = viewport.x / viewport.y * projy
	local fx = cameraFrame.rightVector
	local fy = cameraFrame.upVector
	local fz = cameraFrame.lookVector

	local minVect = Vector3.new()
	local minDist = 512

	for x = 0, 1, 0.5 do
		for y = 0, 1, 0.5 do
			local cx = (x - 0.5) * projx
			local cy = (y - 0.5) * projy
			local offset = fx * cx - fy * cy + fz
			local origin = cameraFrame.p + offset * znear
			local _, hit = Workspace:FindPartOnRay(Ray.new(origin, offset.unit * minDist))
			local dist = (hit - origin).magnitude
			if minDist > dist then
				minDist = dist
				minVect = offset.unit
			end
		end
	end

	return fz:Dot(minVect) * minDist
end
