I would use a CFrame value so we can keep this in the cutscene script and be able to tween it. Then, in the cutscene script, put something like this:
local tweenService = game:GetService("TweenService")
local runService = game:GetService("RunService")
local cframeValue = --Path to CFrame value
runService.Heartbeat:Connect(function()
workspace.CurrentCamera.CFrame *= cframeValue.Value
end)
repeat
local newCFrame
local newX
local newY
local newZ
for count = 1, 3 do
local randomInt = math.random(0, 25) --Min/max angle
if count == 1 then
newX = randomInt
elseif count == 2 then
newY = randomInt
else
newZ = randomInt
end
end
newCFrame = CFrame.Angles(math.rad(newX), math.rad(newY), math.rad(newZ))
tweenService:Create(cframeValue, TweenInfo.new(0.3, Enum.EasingStyle.Quad, Enum.EasingDirection.Out), {Value = newCFrame}):Play() -- Replace TweenInfo with whatever looks most like the "camera shake" thing
task.wait(0.3) --Replace time with TweenInfo time
until --Not cutscening
If I were you, I would wrap the repeat until block in a coroutine or just a simple task.spawn to not interfere with the rest of the script. I don’t know what your script looks like though, so I’ll just leave it be.
Hope this helps (and let me know if there are any errors),
Fizzitix
Edit 1: Forgot X, Y, Z properties were read-only. Also added math.rad()