function Spring.__index(V,g)if Spring[g]then return Spring[g]elseif g=="\086\097\108\117\101"or g=="\080\111\115\105\116\105\111\110"or g=="\112"then local g,j=V:_positionVelocity(V._clock())return g elseif g=="\086\101\108\111\099\105\116\121"or g=="\118"then local g,j=V:_positionVelocity(V._clock())return j elseif g=="\084\097\114\103\101\116"or g=="\116"then return V._target elseif g=="\068\097\109\112\101\114"or g=="\100"then return V._damper elseif g=="\083\112\101\101\100"or g=="\115"then return V._speed elseif g=="\067\108\111\099\107"then return V._clock else error(("\037\113 \105\115 \110\111\116 \097 \118\097\108\105\100 \109\101\109\098\101\114 \111\102 \083\112\114\105\110\103"):format(tostring(g)),2)end end function Spring.__newindex(j,g,V)local O=j._clock()if g=="\086\097\108\117\101"or g=="\080\111\115\105\116\105\111\110"or g=="\112"then local g,f=j:_positionVelocity(O)j._position0=V j._velocity0=f j._time0=O elseif g=="\086\101\108\111\099\105\116\121"or g=="\118"then local g,f=j:_positionVelocity(O)j._position0=g j._velocity0=V j._time0=O elseif g=="\084\097\114\103\101\116"or g=="\116"then local g,f=j:_positionVelocity(O)j._position0=g j._velocity0=f j._target=V j._time0=O elseif g=="\068\097\109\112\101\114"or g=="\100"then local g,f=j:_positionVelocity(O)j._position0=g j._velocity0=f j._damper=V j._time0=O elseif g=="\083\112\101\101\100"or g=="\115"then local g,f=j:_positionVelocity(O)j._position0=g j._velocity0=f j._speed=V<0 and 0 or V j._time0=O elseif g=="\067\108\111\099\107"then local g,f=j:_positionVelocity(O)j._position0=g j._velocity0=f j._clock=V j._time0=V()else error(("\037\113 \105\115 \110\111\116 \097 \118\097\108\105\100 \109\101\109\098\101\114 \111\102 \083\112\114\105\110\103"):format(tostring(g)),2)end end function Spring._positionVelocity(V,g)local j=V._position0 local O=V._velocity0 local f=V._target local n=V._damper local c=V._speed local R=c*(g-V._time0)local o=n*n local p,Q,C if o<1 then p=math.sqrt(1-o)local g=math.exp(-n*R)/p C,Q=g*math.cos(p*R),g*math.sin(p*R)elseif o==1 then p=1 local g=math.exp(-n*R)/p C,Q=g,g*R else p=math.sqrt(o-1)local g=math.exp((-n+p)*R)/(2*p)local V=math.exp((-n-p)*R)/(2*p)C,Q=g+V,g-V end local d=p*C+n*Q local E=1-(p*C+n*Q)local P=Q/c local q=-c*Q local H=c*Q local h=p*C-n*Q return(d*j+E*f)+P*O,(q*j+H*f)+h*O end return Spring
--[=[
	The current position at the given clock time. Assigning the position will change the spring to have that position.

	```lua
	local spring = Spring.new(0)
	print(spring.Position) --> 0
	```

	@prop Position T
	@within Spring
]=]
--[=[
	Alias for [Spring.Position](/api/Spring#Position)

	@prop p T
	@within Spring
]=]
--[=[
	The current velocity. Assigning the velocity will change the spring to have that velocity.

	```lua
	local spring = Spring.new(0)
	print(spring.Velocity) --> 0
	```

	@prop Velocity T
	@within Spring
]=]
--[=[
	Alias for [Spring.Velocity](/api/Spring#Velocity)

	@prop v T
	@within Spring
]=]
--[=[
	The current target. Assigning the target will change the spring to have that target.

	```lua
	local spring = Spring.new(0)
	print(spring.Target) --> 0
	```

	@prop Target T
	@within Spring
]=]
--[=[
	Alias for [Spring.Target](/api/Spring#Target)
	@prop t T
	@within Spring
]=]
--[=[
	The current damper, defaults to 1. At 1 the spring is critically damped. At less than 1, it
	will be underdamped, and thus, bounce, and at over 1, it will be critically damped.

	@prop Damper number
	@within Spring
]=]
--[=[
	Alias for [Spring.Damper](/api/Spring#Damper)

	@prop d number
	@within Spring
]=]
--[=[
	The speed, defaults to 1, but should be between [0, infinity)

	@prop Speed number
	@within Spring
]=]
--[=[
	Alias for [Spring.Speed](/api/Spring#Speed)

	@prop s number
	@within Spring
]=]
--[=[
	The current clock object to syncronize the spring against.

	@prop Clock () -> number
	@within Spring
]=]
function Spring:__index(index)
	if Spring[index] then
		return Spring[index]
	elseif index == "Value" or index == "Position" or index == "p" then
		local position, _ = self:_positionVelocity(self._clock())
		return position
	elseif index == "Velocity" or index == "v" then
		local _, velocity = self:_positionVelocity(self._clock())
		return velocity
	elseif index == "Target" or index == "t" then
		return self._target
	elseif index == "Damper" or index == "d" then
		return self._damper
	elseif index == "Speed" or index == "s" then
		return self._speed
	elseif index == "Clock" then
		return self._clock
	else
		error(("%q is not a valid member of Spring"):format(tostring(index)), 2)
	end
end

function Spring:__newindex(index, value)
	local now = self._clock()

	if index == "Value" or index == "Position" or index == "p" then
		local _, velocity = self:_positionVelocity(now)
		self._position0 = value
		self._velocity0 = velocity
		self._time0 = now
	elseif index == "Velocity" or index == "v" then
		local position, _ = self:_positionVelocity(now)
		self._position0 = position
		self._velocity0 = value
		self._time0 = now
	elseif index == "Target" or index == "t" then
		local position, velocity = self:_positionVelocity(now)
		self._position0 = position
		self._velocity0 = velocity
		self._target = value
		self._time0 = now
	elseif index == "Damper" or index == "d" then
		local position, velocity = self:_positionVelocity(now)
		self._position0 = position
		self._velocity0 = velocity
		self._damper = value
		self._time0 = now
	elseif index == "Speed" or index == "s" then
		local position, velocity = self:_positionVelocity(now)
		self._position0 = position
		self._velocity0 = velocity
		self._speed = value < 0 and 0 or value
		self._time0 = now
	elseif index == "Clock" then
		local position, velocity = self:_positionVelocity(now)
		self._position0 = position
		self._velocity0 = velocity
		self._clock = value
		self._time0 = value()
	else
		error(("%q is not a valid member of Spring"):format(tostring(index)), 2)
	end
end

function Spring:_positionVelocity(now)
	local p0 = self._position0
	local v0 = self._velocity0
	local p1 = self._target
	local d = self._damper
	local s = self._speed

	local t = s * (now - self._time0)
	local d2 = d * d

	local h, si, co
	if d2 < 1 then
		h = math.sqrt(1 - d2)
		local ep = math.exp(-d * t) / h
		co, si = ep * math.cos(h * t), ep * math.sin(h * t)
	elseif d2 == 1 then
		h = 1
		local ep = math.exp(-d * t) / h
		co, si = ep, ep * t
	else
		h = math.sqrt(d2 - 1)
		local u = math.exp((-d + h) * t) / (2 * h)
		local v = math.exp((-d - h) * t) / (2 * h)
		co, si = u + v, u - v
	end

	local a0 = h * co + d * si
	local a1 = 1 - (h * co + d * si)
	local a2 = si / s

	local b0 = -s * si
	local b1 = s * si
	local b2 = h * co - d * si

	return a0 * p0 + a1 * p1 + a2 * v0, b0 * p0 + b1 * p1 + b2 * v0
end

return Spring
