local q={}do q.__index=q function q.new(U,Q)return setmetatable({freq=U,goal=Q;pos=Q;vel=0},q)end function q.step(U,q)local Q=(U.freq*2)*math.pi local T=U.goal local R=U.pos local D=U.vel local L=R-T local Z=math.exp(-Q*q)local e=(L*(1+Q*q)+D*q)*Z+T local J=(D*(1-Q*q)-L*((Q*Q)*q))*Z U.pos=e U.vel=J return e end end CameraUtils.Spring=q
-- Critically damped spring class for fluid motion effects
local Spring = {}
do
	Spring.__index = Spring

	-- Initialize to a given undamped frequency and default position
	function Spring.new(freq, pos)
		return setmetatable({
			freq = freq,
			goal = pos,
			pos = pos,
			vel = 0,
		}, Spring)
	end

	-- Advance the spring simulation by `dt` seconds
	function Spring:step(dt)
		local f = self.freq * 2 * math.pi
		local g = self.goal
		local p0 = self.pos
		local v0 = self.vel

		local offset = p0 - g
		local decay = math.exp(-f * dt)

		local p1 = (offset * (1 + f * dt) + v0 * dt) * decay + g
		local v1 = (v0 * (1 - f * dt) - offset * (f * f * dt)) * decay

		self.pos = p1
		self.vel = v1

		return p1
	end
end

CameraUtils.Spring = Spring
