How would i be able to write a gun recoil system using a spring module

how would i be able to write a gun recoil system using a spring module

well ive been trying to write a fps framework and ive run into a problem, recoil ive tried using lerp functions and looking for solutions on the dev forum, all of them were really glitchy, i have tried writing down the recoil on a seperate local script so it doesnt interfere whit the main framework

a tutorial would be helpful

--my current empty script
local repSTORE = game:GetService("ReplicatedStorage")
local isRecoiling = false
local isDamp
local camera = game.Workspace.CurrentCamera
local camearLastCf = CFrame.new()
local recoil2 = nil
local runservice = game:GetService("RunService")
local called1 = false
local called2 = false


repSTORE.Events.RecoilGun.Event:Connect(function(recoil)
	
	called1 = false
	called2 = false
	
	recoil2 = recoil
	isRecoiling = true
	wait(0.1)
	isRecoiling = false	
end)

((this is my first topic sorry if its a pain lol

note that the is recoiling values are when to stop the recoil, might change that so it adds only the recoil value of the gun in the settings modules instead of doing it in a specific ammount of time

Spring Module Script

local Spring = {}
Spring.__index = Spring

function Spring.new(damping, speed)
    local spring = {}
    spring.position = 0
    spring.velocity = 0
    spring.damping = damping or 0.8
    spring.speed = speed or 15
    setmetatable(spring, Spring)
    return spring
end

function Spring:Update(dt, targetPosition)
    local acceleration = (targetPosition - self.position) * self.speed
    self.velocity = (self.velocity + acceleration * dt) * self.damping
    self.position = self.position + self.velocity * dt
    return self.position
end

return Spring

Integration Into Recoil Script

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local Spring = require(ReplicatedStorage:WaitForChild("Spring")) -- Assuming the module is in ReplicatedStorage

local camera = workspace.CurrentCamera
local recoilSpring = Spring.new(0.85, 15) -- Damping, Speed

local recoilAmount = 0 -- Amount of recoil to apply
local isRecoiling = false

-- Event to listen for recoil trigger (e.g., gun shot)
ReplicatedStorage.Events.RecoilGun.OnClientEvent:Connect(function(recoil)
    recoilAmount = recoil -- Pass the recoil value from the server or weapon script
    isRecoiling = true
end)

RunService.RenderStepped:Connect(function(dt)
    if isRecoiling then
        -- Update the spring with the current delta time
        local recoilOffset = recoilSpring:Update(dt, recoilAmount)

        -- Apply the recoil effect to the camera CFrame
        camera.CFrame = camera.CFrame * CFrame.Angles(math.rad(-recoilOffset), 0, 0)

        -- Stop recoiling after it has settled back
        if math.abs(recoilOffset) < 0.01 then
            isRecoiling = false
        end
    end
end)

You can adjust the recoil as needed here
Randomized example

-- For example, on a weapon fire event
local recoilValue = math.random(1, 5) -- Variable recoil amount
ReplicatedStorage.Events.RecoilGun:FireClient(player, recoilValue)