Mobile Camera Movement Coding

Ok, so I am working on a build mode that allows you to build things on pc and on mobile. I have it working perfectly for pc, but it very difficult to figure out how to make it work on mobile. Whenever I move the joystick, it doesn’t move based on the lookvector, but rather the regular x,z,y on roblox studio, I have no idea how to have this work with mobile, and I don’t overly understand camera manipulation that much. It would also be a lot of help if you guys could help me figure out how to zoom with pinching and using the scrolling button on mouse. Thank you for your time!

Code:

local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")

local player = Players.LocalPlayer
local camera = workspace.CurrentCamera
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local cameraBounds = workspace:WaitForChild("ExampleBase")

-- Settings
local cameraSpeed = 1.5
local rotationSpeed = 0.2
local maxY, minY = 50, 1.5

-- State
local freeCamEnabled = false
local cameraCFrame
local yaw, pitch = 0, 0
local lastTouchPosition = nil
local movementKeys = {}
local isRightMouseDown = false

-- Freeze player
local function freezeCharacter()
	humanoid.WalkSpeed = 0
	humanoid.JumpPower = 0
end

local function unfreezeCharacter()
	humanoid.WalkSpeed = 16
	humanoid.JumpPower = 50
end

-- Toggle FreeCam using BindableEvent
local toggleEvent = script.Parent.ConnectFly

toggleEvent.Event:Connect(function()
	freeCamEnabled = not freeCamEnabled

	if freeCamEnabled then
		camera.CameraType = Enum.CameraType.Scriptable
		cameraCFrame = camera.CFrame

		local lookVec = cameraCFrame.LookVector
		yaw = math.deg(math.atan2(-lookVec.X, -lookVec.Z))
		pitch = math.deg(math.asin(lookVec.Y))

		freezeCharacter()
		UserInputService.MouseBehavior = Enum.MouseBehavior.Default
	else
		camera.CameraType = Enum.CameraType.Custom
		unfreezeCharacter()
		UserInputService.MouseBehavior = Enum.MouseBehavior.Default
	end
end)

-- Handle keyboard movement and right mouse button (PC)
UserInputService.InputBegan:Connect(function(input, gameProcessed)
	if gameProcessed or not freeCamEnabled then return end

	if input.UserInputType == Enum.UserInputType.Keyboard then
		movementKeys[input.KeyCode] = true

	elseif input.UserInputType == Enum.UserInputType.MouseButton2 then
		isRightMouseDown = true
		-- Lock mouse *at its current position* on RMB down
		UserInputService.MouseBehavior = Enum.MouseBehavior.LockCurrentPosition
	end
end)

UserInputService.InputEnded:Connect(function(input)
	if input.UserInputType == Enum.UserInputType.Keyboard then
		movementKeys[input.KeyCode] = false

	elseif input.UserInputType == Enum.UserInputType.MouseButton2 then
		isRightMouseDown = false
		-- Release mouse lock on RMB up
		UserInputService.MouseBehavior = Enum.MouseBehavior.Default
	end
end)

-- Mouse camera rotation (PC)
UserInputService.InputChanged:Connect(function(input)
	if not freeCamEnabled then return end
	if input.UserInputType == Enum.UserInputType.MouseMovement and isRightMouseDown then
		yaw = yaw - input.Delta.X * rotationSpeed
		pitch = math.clamp(pitch - input.Delta.Y * rotationSpeed, -89, 89)
	end
end)

-- Touch camera rotation (mobile)
UserInputService.TouchMoved:Connect(function(input)
	if not freeCamEnabled then return end
	if lastTouchPosition then
		local delta = input.Position - lastTouchPosition
		yaw = yaw - delta.X * rotationSpeed * 0.5
		pitch = math.clamp(pitch - delta.Y * rotationSpeed * 0.5, -89, 89)
	end
	lastTouchPosition = input.Position
end)

UserInputService.TouchEnded:Connect(function()
	lastTouchPosition = nil
end)

-- Get movement direction from keyboard or joystick
local function getMoveDirection()
	if UserInputService.TouchEnabled or UserInputService.GamepadEnabled then
		return humanoid.MoveDirection
	end

	local direction = Vector3.zero
	if movementKeys[Enum.KeyCode.W] then direction += Vector3.new(0, 0, -1) end
	if movementKeys[Enum.KeyCode.S] then direction += Vector3.new(0, 0, 1) end
	if movementKeys[Enum.KeyCode.A] then direction += Vector3.new(-1, 0, 0) end
	if movementKeys[Enum.KeyCode.D] then direction += Vector3.new(1, 0, 0) end
	if movementKeys[Enum.KeyCode.E] then direction += Vector3.new(0, 1, 0) end
	if movementKeys[Enum.KeyCode.Q] then direction += Vector3.new(0, -1, 0) end
	return direction
end

-- Update camera position and rotation
RunService.RenderStepped:Connect(function()
	if not freeCamEnabled then return end

	-- Rotation
	local rotCFrame = CFrame.Angles(0, math.rad(yaw), 0) * CFrame.Angles(math.rad(pitch), 0, 0)

	-- Movement
	local direction = getMoveDirection()
	if direction.Magnitude > 0 then
		direction = direction.Unit
		local move = (rotCFrame:VectorToWorldSpace(direction)) * cameraSpeed
		cameraCFrame = cameraCFrame + move
	end

	-- Clamp position
	local bounds = cameraBounds
	local center = bounds.Position
	local halfSize = bounds.Size / 2
	local pos = cameraCFrame.Position

	local clampedX = math.clamp(pos.X, center.X - halfSize.X, center.X + halfSize.X)
	local clampedY = math.clamp(pos.Y, minY, maxY)
	local clampedZ = math.clamp(pos.Z, center.Z - halfSize.Z, center.Z + halfSize.Z)

	cameraCFrame = CFrame.new(Vector3.new(clampedX, clampedY, clampedZ)) * rotCFrame
	camera.CFrame = cameraCFrame
end)