Dynamics/ColorDynamics.cs
using System;
using Sandbox;

namespace Andicraft.SecondOrderDynamics;

/// <summary>
/// Helper class that lets you run dynamics on a Color.
/// </summary>
public class ColorDynamics
{
	private FloatDynamics _h;
	private Vector2Dynamics _sv;
	private FloatDynamics _alpha;

	private Vector3 _currentHsv;
	private Color _currentColor;

	public Color CurrentValue => _currentColor;
	public float CurrentAlpha => _currentColor.a;

	public ColorDynamics(float frequency, float damping, float response, Color startingValue)
	{
		_currentHsv = startingValue.ToOkHsv();

		_h = new(frequency, damping, response, _currentHsv.x)
		{
			MinWrapValue = 0f,
			MaxWrapValue = 1f
		};

		_sv = new Vector2Dynamics(frequency, damping, response, new Vector2(_currentHsv.z, _currentHsv.y));

		_alpha = new FloatDynamics(frequency, damping, response, startingValue.a);
	}

	public void SetFrequency(float f)
	{
		_h.SetFrequency(f);
		_sv.SetFrequency(f);
		_alpha.SetFrequency(f);
	}

	public void SetDamping(float d)
	{
		_h.SetDamping(d);
		_sv.SetDamping(d);
		_alpha.SetDamping(d);
	}

	public void SetResponse(float r)
	{
		_h.SetResponse(r);
		_sv.SetResponse(r);
		_alpha.SetResponse(r);
	}

	public void Reset(Color value)
	{
		var targetColor = value.ToOkHsv();
		_currentColor = value;
		_currentHsv = targetColor;

		_h.Reset(_currentHsv.x);
		_sv.Reset(new Vector2(_currentHsv.y, _currentHsv.z));
		_alpha.Reset(value.a);
	}

	public Color Update(float deltaTime, Color target, bool setVelocity = false, Vector4 velocity = default)
	{
		var targetHsv = target.ToOkHsv();
		var h = _h.Update(deltaTime, targetHsv.x, setVelocity, velocity.x);
		var sv = _sv.Update(deltaTime, new Vector2(targetHsv.y, targetHsv.z), setVelocity,
			new Vector2(velocity.y, velocity.z));
		var a = _alpha.Update(deltaTime, target.a, setVelocity, velocity.w);
		_currentHsv = new Vector3(h, sv.x.Saturate(), sv.y.Saturate());

		var col = OkColor.OkHsvToColor(_currentHsv);
		col.a = a.Saturate();
		_currentColor = col;
		return _currentColor;
	}
}