Essentially my goal is to make the camera rotate the same way the default camera script does when a player right-clicks their mouse, but what’s happening is instead of the camera orbiting around the PrimaryPart, the camera itself is rotating in-place at the offset

This is the code so far:

local speed = 10
local offset = Vector3.new(0, 4, 8)
local userInputService = game.UserInputService
local characterAdded = game.Players.LocalPlayer.CharacterAdded
local primaryPart = characterAdded:Wait().PrimaryPart
local currentCamera = workspace.CurrentCamera
local x, y = 0, 0
local zeroVector2 = Vector2.zero
local lookAt = CFrame.lookAt
local fromOrientation = CFrame.fromEulerAnglesYXZ
local rad = math.rad
characterAdded:Connect(function(character)
primaryPart = character.PrimaryPart
end)
characterAdded = nil
game["Run Service"]:BindToRenderStep("Camera", 1, function(deltaTime)
local mouseDelta = userInputService:GetMouseDelta()
if mouseDelta ~= zeroVector2 then
x += mouseDelta.X * deltaTime * speed
y += mouseDelta.Y * deltaTime * speed
end
local position = primaryPart.Position
local cframe = lookAt(position + offset, position) * fromOrientation(-rad(y), -rad(x), 0)
currentCamera.CFrame = cframe
currentCamera.Focus = cframe
end)

What I did is push the camera back with the magnitude of a variable called distance, and the direction being from the camera’s look vector to the camera’s position. For some reason it starts freaking out around the poles but you can figure that out lol (or I’ll try to fix it when I have time).

Also I didn’t really know what you wanted to do with the offsets so I just didn’t include it in the code:

local speed = 15
local offset = Vector3.new(0, 4, 8)
local userInputService = game.UserInputService
local currentCamera = workspace.CurrentCamera
local x, y = 0, 0
local zeroVector2 = Vector2.zero
local lookAt = CFrame.lookAt
local fromOrientation = CFrame.fromEulerAnglesYXZ
local rad = math.rad
local plr = game.Players.LocalPlayer
plr.CharacterAdded:Wait();
repeat wait() until plr.Character.PrimaryPart ~= nil;
local primaryPart = plr.Character.PrimaryPart
currentCamera.CameraType = Enum.CameraType.Scriptable;
local distance = 10;
game:GetService("RunService").RenderStepped:Connect(function(deltaTime)
userInputService.MouseBehavior = Enum.MouseBehavior.LockCenter;
local mouseDelta = userInputService:GetMouseDelta()
if mouseDelta ~= zeroVector2 then
x += mouseDelta.X * deltaTime * speed
y += mouseDelta.Y * deltaTime * speed
end
local position = primaryPart.Position
local camCF = currentCamera.CFrame;
local cframe = CFrame.new(primaryPart.Position) * CFrame.fromAxisAngle(camCF.RightVector , -math.rad(y)) * CFrame.fromAxisAngle(Vector3.yAxis,-math.rad(x)) ;
local newPos = (cframe.Position - cframe.LookVector * distance);
local newCF = CFrame.lookAt(newPos, position);
currentCamera.CFrame = newCF
currentCamera.Focus = newCF
end)

Thank you for your help! I did some experimenting myself and found out that a big part of the issues I was having was because I didn’t realise how important the order of CFrame math is. The result is as follows:

local primaryPartCFrame = CFrame.new(primaryPart.Position)
currentCamera.CFrame = primaryPartCFrame * fromOrientation(-rad(y), -rad(x), 0) * offset -- Offset is now == CFrame.new(0, 4, 8)
currentCamera.Focus = primaryPartCFrame

The above is very close to my target and doesn’t have the issues around the poles, but there’s one last finishing touch I need help to implement, which is how to make it so that the offset is angled towards the PrimaryPart (the way I tried using lookAt caused unexpected results unfortunately)

local speed = 10
local offset = CFrame.new(0, 4, 8)
local userInputService = game.UserInputService
local characterAdded = game.Players.LocalPlayer.CharacterAdded
local primaryPart = characterAdded:Wait().PrimaryPart
local currentCamera = workspace.CurrentCamera
local x, y = 0, 0
local zeroVector2 = Vector2.zero
local lookAt = CFrame.lookAt
local fromOrientation = CFrame.fromEulerAnglesYXZ
local rad = math.rad
characterAdded:Connect(function(character)
primaryPart = character.PrimaryPart
end)
characterAdded = nil
game["Run Service"]:BindToRenderStep("Camera", 1, function(deltaTime)
local mouseDelta = userInputService:GetMouseDelta()
if mouseDelta ~= zeroVector2 then
x += mouseDelta.X * deltaTime * speed
y += mouseDelta.Y * deltaTime * speed
end
local position = primaryPart.Position
local cframe = CFrame.new(position) * fromOrientation(-rad(y), -rad(x), 0) * offset
local test = lookAt(cframe.Position, position)
currentCamera.CFrame = test
currentCamera.Focus = CFrame.new(position)
end)