you can use something like an orbiting camera with bizarre parameters and custom acceleration factors

local repl = game:GetService('ReplicatedStorage')
local plr_svc = game:GetService('Players')
local tween_svc = game:GetService('TweenService')
local run_svc = game:GetService('RunService')
local plr = plr_svc.LocalPlayer
local ch = plr.Character or plr.CharacterAdded:Wait()
local hum = ch:WaitForChild('Humanoid')
local cam = workspace.CurrentCamera
cam.CameraType = Enum.CameraType.Scriptable
local CHEX = 255
function create_dummy(size_v)
local dm = Instance.new('Part')
dm.Name = 'dummy'
dm.Color = Color3.fromRGB(1*CHEX, 0*CHEX, 0*CHEX)
dm.Size = size_v
dm.CanCollide = false
dm.Anchored = true
dm.Parent = workspace
return dm
end
local target = nil
local cam_dummy = nil
function setup()
target = create_dummy(Vector3.new(2, 2, 2))
target:PivotTo(CFrame.new(0, 5, -32))
cam_dummy = create_dummy(Vector3.new(0.25, 0.25, 0.25))
end
setup()
local ORBIT_T = {['from'] = 0, ['to'] = 10, ['by'] = 0.032, ['value'] = nil}
local CAM_R = {['from'] = 32, ['to'] = 4, ['by'] = nil, ['value'] = nil}
local CAM_ELEV = {['from'] = 20, ['to'] = 0, ['by'] = nil, ['value'] = nil}
local CAM_ROTSPEED = {['from'] = -60, ['to'] = -15, ['by'] = nil, ['value'] = nil}
local DUMMYPOS_X = {['from'] = 24, ['to'] = 0, ['by'] = nil, ['value'] = nil}
local DUMMYPOS_Y = {['from'] = 8, ['to'] = 0, ['by'] = nil, ['value'] = nil}
local DUMMYPOS_Z = {['from'] = 2.5, ['to'] = 0, ['by'] = nil, ['value'] = nil}
local flag_cutscene_pending = false
function run()
flag_cutscene_pending = true
local function init_values()
ORBIT_T['value'] = ORBIT_T['from']
ORBIT_T['n_steps'] = (ORBIT_T['to'] - ORBIT_T['from']) / ORBIT_T['by']
CAM_R['value'] = CAM_R['from']
CAM_R['by'] = (CAM_R['to'] - CAM_R['from']) / ORBIT_T['n_steps']
CAM_ELEV['value'] = CAM_ELEV['from']
CAM_ELEV['by'] = (CAM_ELEV['to'] - CAM_ELEV['from']) / ORBIT_T['n_steps']
CAM_ROTSPEED['value'] = CAM_ROTSPEED['from']
CAM_ROTSPEED['by'] = (CAM_ROTSPEED['to'] - CAM_ROTSPEED['from']) / ORBIT_T['n_steps']
DUMMYPOS_X['value'] = DUMMYPOS_X['from']
DUMMYPOS_X['by'] = (DUMMYPOS_X['to'] - DUMMYPOS_X['from']) / ORBIT_T['n_steps']
DUMMYPOS_Y['value'] = DUMMYPOS_Y['from']
DUMMYPOS_Y['by'] = (DUMMYPOS_Y['to'] - DUMMYPOS_Y['from']) / ORBIT_T['n_steps']
DUMMYPOS_Z['value'] = DUMMYPOS_Z['from']
DUMMYPOS_Z['by'] = (DUMMYPOS_Z['to'] - DUMMYPOS_Z['from']) / ORBIT_T['n_steps']
end
local function incr_values()
ORBIT_T['value'] += ORBIT_T['by']
CAM_R['value'] += CAM_R['by']
CAM_ELEV['value'] += CAM_ELEV['by']
CAM_ROTSPEED['value'] += CAM_ROTSPEED['by']
DUMMYPOS_X['value'] += DUMMYPOS_X['by']
DUMMYPOS_Y['value'] += DUMMYPOS_Y['by']
DUMMYPOS_Z['value'] += DUMMYPOS_Z['by']
cam_dummy:PivotTo(target:GetPivot() + CFrame.new(DUMMYPOS_X['value'], DUMMYPOS_Y['value'], DUMMYPOS_Z['value']).Position)
end
local function has_moresteps()
if math.abs(ORBIT_T['value'] - ORBIT_T['to']) <= ORBIT_T['by'] then
return false
else
return true
end
end
init_values()
local co = coroutine.create(function()
while (flag_cutscene_pending) do
orbit_step(cam_dummy, ORBIT_T['value'], CAM_R['value'], CAM_ELEV['value'], CAM_ROTSPEED['value'])
task.wait(ORBIT_T['by'])
incr_values()
if not has_moresteps() then
flag_cutscene_pending = false
end
end
end)
coroutine.resume(co)
end
function orbit_step(target, t, radius, elevation, rot_speed)
local t_cf = target:GetPivot()
local yaw = math.sin(math.rad(rot_speed) * t) * radius
local pitch = elevation
local roll = math.cos(math.rad(rot_speed) * t) * radius
cam.CFrame = CFrame.lookAt((t_cf + Vector3.new(yaw, pitch, roll)).Position, t_cf.Position)
end
run()