I’m trying to make a recoil system like CSGO (where the camera goes back down after a bit)

and I don’t know how to do it.

I would suggest using springs for this, BlackShibe’s fps framework 2020 uses his spring module

Look through that when he makes gun sway, the usage for the spring module is explained in the article above.

I would suggest making a RenderStepped bind and do

```
local Recoil = CamSpring:update(dt)--<<deltatime is the only thing passed into RenderStepped
game.Workspace.CurrentCamera.CFrame *= CFrame.Angles(Recoil.X, Recoil.Y, Recoil.Z)
```

Couldnt you just play an animation instead of offset the camera?

No, I want the camera to move without animations since animations are only set in one way it won’t be the same as making it procedurally.

Here is a function I made for you that works for models, baseparts or any PVInstance (Have a location in the world) and also respects the new pivot feature!

```
local function offsetObjectRotation(object : PVInstance | Camera, rotationOffsetXYZ : Vector3)
if object:IsA("PVInstance") then
local oldCFrame = object:GetPivot()
local newCFrame = oldCFrame * CFrame.Angles(rotationOffsetXYZ.X, rotationOffsetXYZ.Y, rotationOffsetXYZ.Z)
object:PivotTo(newCFrame)
elseif object:IsA("Camera") then
local oldCFrame = object.CFrame
local newCFrame = oldCFrame * CFrame.Angles(rotationOffsetXYZ.X, rotationOffsetXYZ.Y, rotationOffsetXYZ.Z)
object.CFrame = newCFrame
else
error("Cannot rotate the object of class name "..object.ClassName)
end
end
```

Here is an example on how to use it

The following code offset the rotation of it’s parent part by 45 degrees along the local X axis of the object.

```
offsetObjectRotation(script.Parent, Vector3.new(math.rad(45), 0, 0))
```

Before running the example code

After running the example code

Enjoy!

That’s cool but, how would it work on the camera?

The camera doesn’t have a pivot unless I stand corrected

```
local camera = workspace.CurrentCamera
camera .CameraType = Enum.CameraType.Scriptable
function Recoil()
camera.CFrame = camera.CFrame:ToWorldSpace(CFrame.Angles(math.rad(0.05), math.rad(0.1), 0)
end
```

You will prob need to change values since i put random numbers, put thats how I would do some recoil

If you want it to be smooth recoil instead of jittery recoil springs would be the way to go.

Edit: they require a bit more implementation but i think its worth it

```
offsetObjectRotation(camera, Vector3.new(angleX, angleY, angleZ))
```

If you need more information, let me know!

Ohhhh okay thanks I’ll try that out

As I thought, the camera doesn’t have a pivot

15:10:45.118 GetPivot is not a valid member of Camera “Workspace.Camera” - Client - Framework:314

15:10:45.118 Stack Begin - Studio

15:10:45.118 Script ‘Workspace.TruestBlu.Framework’, Line 314 - function offsetObjectRotation - Studio - Framework:314

15:10:45.118 Script ‘Workspace.TruestBlu.Framework’, Line 353 - Studio - Framework:353

15:10:45.119 Stack End - Studio

I think thats because camera isnt a BasePart

Alright, let me fix that, didn’t know that the camera doesn’t have a PVInstance

I’ve replaced them with cframe so hopefully it’ll work

Okay so I want the camera to move correspondingly to a number, lets say hmmm it’s 4. When that number goes down I also want the camera to move down with it and vice versa.

You shouldn’t use a direct offset then, maybe you should store an offset and apply it to the camera. as a cframe is basically a mathematical matrix.

and then you can always edit that stored offset.

for that, I’ll try to come up with something for you real quick

Alright so here is a quick prototype that works

```
local oldOffset = CFrame.new() -- Don't edit this!
local offset = CFrame.new()
-- (Optional): Will accumulate the time in seconds since the script started
local t = 0
game:GetService("RunService").RenderStepped:Connect(function(delta)
-- (Optional): Accumulate the time in seconds
t += delta
-- Cancel out the offset we applied in the previous frame
cam.CFrame *= oldOffset:Inverse()
-- Apply the new offset
cam.CFrame *= offset
-- Store the offset we have applied so we cancel it in the next frame
oldOffset = offset
-- Update the offset that will applied!
offset = CFrame.Angles(math.sin(t), 0, 0) --You can change this however you want!
-- Proof (Optional): You can update the original cframe without affecting the offset
cam.CFrame *= CFrame.new(math.sin(t)*10, 0, 0) --You can change this however you want!
end)
```

This gives you a relative cframe that you can play with without overriding the original camera cframe.

If you’re interested, I can make it as a robust function for you!

Thank you so much and no, it’s alright.

EDIT: Added comments to help you understand the code!