Code/Animator/ColorInterpolator.cs
using CrosshairMaker.Helpers;
using Sandbox;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CrosshairMaker.Animator
{
	public enum ColorInterpolationMode : byte
	{
		RGB = 0,
		RGBA = 1,
		HSV = 2,
		HSVA = 3,
	}
	public static class ColorInterpolator
	{
		public static bool HasAlpha(ColorInterpolationMode cim) => (cim & (ColorInterpolationMode)1) != 0;
		public static bool HsvMode( ColorInterpolationMode cim) => (cim & (ColorInterpolationMode)2) != 0;
		
		public static Color Interpolate( Color Start , Color End, float time , ColorInterpolationMode cim = ColorInterpolationMode.HSV )
		{
			if(Start.Equals(End)) return Start;
			Color result = default;
			if ( HasAlpha( cim ) )
			{
				float deltaA = End.a - Start.a;
				deltaA = deltaA * time;
				result.a = deltaA + Start.a;
			}
			else result.a = 1;

			if ( HsvMode(cim) )
			{
				ColorHsv startH = Start.ToHsv(), endH = End.ToHsv();
				Vector3 delta = new Vector3(
					endH.Hue - startH.Hue,
					endH.Saturation - startH.Saturation,
					endH.Value - startH.Value
					);
				delta.x = ((delta.x + 180f) % 360f) - 180f; // normalizes angle
				delta.x *= time;

				delta.y *= time;
				delta.z *= time;

				delta.x += startH.Hue;
				delta.y += startH.Saturation;
				delta.z += startH.Value;

				delta.x = (delta.x + 360) % 360;
				delta.y = Math.Clamp( delta.y, 0f, 1f );
				delta.z = Math.Clamp( delta.z, 0f, 1f );

				ColorHsv hsvRes = new ColorHsv( delta.x, delta.y, delta.z );
				float alpha = result.a; //stores previously calculated alpha
				result = hsvRes.ToColor(); // override result with HSV color
				result.a = alpha; // re sets alpha value
			}
			else
			{
				Vector3 delta = End.ToRgbVector() - Start.ToRgbVector();
				delta *= time;
				delta += Start;
				result.r = delta.x;
				result.g = delta.y;
				result.b = delta.z;
			}
			return result;
		}
	}
	public struct InterpolatableColor
	{
		public InterpolatableColor()
		{
			Color = Color.Black;
			Interp = ColorInterpolationMode.HSV;
		}
		public InterpolatableColor(Color c,ColorInterpolationMode i = ColorInterpolationMode.HSV )
		{
			Color = c;
			Interp = i;
		}
		[KeyProperty]
		[ColorUsage]
		public readonly Color Color;
		[KeyProperty]
		public readonly ColorInterpolationMode Interp;

		public static explicit operator(Color,ColorInterpolationMode) (InterpolatableColor self ) => (self.Color,self.Interp);
		public static implicit operator InterpolatableColor ((Color c, ColorInterpolationMode i) t) => new( t.c,t.i);
		
	}
}