Try doing something like this:
task.wait(5)
local Spring = require(game.ReplicatedStorage.Spring)
local RunService = game:GetService("RunService")
local Camera = workspace.CurrentCamera
local recoilSpring = Spring.fromFrequency(1, 5, 2)
local initRot = Camera.CFrame.Rotation
recoilSpring:AddVelocity(16.5)
local maxAngle = math.rad(30)
RunService:BindToRenderStep("Camera", Enum.RenderPriority.Camera.Value + 1, function(dt)
Camera.CFrame *= CFrame.Angles(maxAngle*recoilSpring.Velocity*dt, 0, 0)
end)
-- OR
task.spawn(function()
local dt = 0
while Equipped do
Camera.CFrame *= CFrame.Angles(maxAngle*RecoilSpring.Velocity*dt, 0, 0)
dt = RunService.PreRender:Wait()
end
end)
Gives pretty good results in a blank baseplate test
Edit: you also need to stop updating the camera after the spring has a very low velocity. you could add a check for the velocity, something like
if ( recoilSpring.Velocity < 0.01 ) then
stopShowingRecoil()
end