diff --git a/Seraphina/ColorHelper.cs b/Seraphina/ColorHelper.cs
new file mode 100644
index 0000000..3dd3e40
--- /dev/null
+++ b/Seraphina/ColorHelper.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Text;
+
+namespace Seraphina
+{
+ public static class ColorHelper
+ {
+ public static void ColorToHSV(Color color, out double hue, out double saturation, out double value)
+ {
+ int max = Math.Max(color.R, Math.Max(color.G, color.B));
+ int min = Math.Min(color.R, Math.Min(color.G, color.B));
+
+ hue = color.GetHue();
+ saturation = (max == 0) ? 0 : 1d - (1d * min / max);
+ value = max / 255d;
+ }
+
+ public static Color ColorFromHSV(double hue, double saturation = 1, double value = 1)
+ {
+ int hi = Convert.ToInt32(Math.Floor(hue / 60)) % 6;
+ double f = hue / 60 - Math.Floor(hue / 60);
+
+ value *= 255;
+ int v = Convert.ToInt32(value);
+ int p = Convert.ToInt32(value * (1 - saturation));
+ int q = Convert.ToInt32(value * (1 - f * saturation));
+ int t = Convert.ToInt32(value * (1 - (1 - f) * saturation));
+
+ return hi switch
+ {
+ 0 => Color.FromArgb(v, t, p),
+ 1 => Color.FromArgb(q, v, p),
+ 2 => Color.FromArgb(p, v, t),
+ 3 => Color.FromArgb(p, q, v),
+ 4 => Color.FromArgb(t, p, v),
+ _ => Color.FromArgb(v, p, q),
+ };
+ }
+
+ ///
+ /// Gets a colour from the provided HSL values.
+ ///
+ /// The hue, from 0 to 360.
+ /// The saturation, from 0 to 1.
+ /// The lightness, from 0 to 1.
+ ///
+ public static Color ColorFromHSL(double hue, double sat = 1, double lightness = 0.5)
+ {
+ if (sat == 0)
+ {
+ int L = (int)lightness;
+ return Color.FromArgb(255, L, L, L);
+ }
+
+ double min, max, h;
+ h = hue / 360d;
+
+ max = lightness < 0.5d ? lightness * (1 + sat) : (lightness + sat) - (lightness * sat);
+ min = (lightness * 2d) - max;
+
+ return Color.FromArgb(255, (int)(255 * RGBChannelFromHue(min, max, h + 1 / 3d)),
+ (int)(255 * RGBChannelFromHue(min, max, h)),
+ (int)(255 * RGBChannelFromHue(min, max, h - 1 / 3d)));
+ }
+
+ static double RGBChannelFromHue(double m1, double m2, double h)
+ {
+ h = (h + 1d) % 1d;
+ if (h < 0) h += 1;
+ if (h * 6 < 1) return m1 + (m2 - m1) * 6 * h;
+ else if (h * 2 < 1) return m2;
+ else if (h * 3 < 2) return m1 + (m2 - m1) * 6 * (2d / 3d - h);
+ else return m1;
+
+ }
+ }
+}
diff --git a/Seraphina/PlayerHealthColor.cs b/Seraphina/PlayerHealthColor.cs
new file mode 100644
index 0000000..ff097fc
--- /dev/null
+++ b/Seraphina/PlayerHealthColor.cs
@@ -0,0 +1,45 @@
+using Seraphina.Core;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Text;
+
+namespace Seraphina
+{
+ public static class PlayerHealthColor
+ {
+
+ const int MinHp = 100;
+ const int MaxHp = 500;
+ const int HpDiff = MaxHp - MinHp;
+
+ const int MinHue = 100;
+ const int MaxHue = 300;
+ const int HueDiff = MaxHue - MinHue;
+ static readonly Color ZeroHp = Color.FromArgb(0, 255, 0, 0);
+ public static Color GetColor(HitPoint numerator, HitPoint denominator)
+ {
+ if (numerator <= 0) return ZeroHp; // Transparent red, for calculation consistency.
+ // XXX: Calculate the colour before rendering it transparent? Would it be a waste?
+
+ // Scale the HitPoint based on its percentage.
+ double pct = numerator.Value * 1.0 / denominator.Value;
+ if (denominator < MinHp)
+ {
+ return ColorHelper.ColorFromHSV(pct * 100);
+ }
+
+ // Scale the maximum hue by dividing anything over 100 by 2.
+ // ie 100 => 100, 200 => 150, 300 => 200, 500 => 300
+ var maxHue = ((denominator.Value - MinHp) / 2) + MinHp;
+
+ // Cap at 300 hue if max HitPoint is over 500 for some reason.
+ maxHue = Math.Min(MaxHue, maxHue);
+
+ var color = ColorHelper.ColorFromHSV(maxHue * pct);
+
+ return color;
+ }
+
+ }
+}
diff --git a/Seraphina/PlayerManaColor.cs b/Seraphina/PlayerManaColor.cs
new file mode 100644
index 0000000..55d58cf
--- /dev/null
+++ b/Seraphina/PlayerManaColor.cs
@@ -0,0 +1,39 @@
+using Seraphina.Core;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Text;
+
+namespace Seraphina
+{
+ public static class PlayerManaColor
+ {
+ // NOTE to more future self: change these around to tweak mana colour.
+ const double minLightness = 0.2;
+ const double maxLightness = 0.8;
+ const double range = maxLightness - minLightness;
+ const int BlueHue = 210;
+
+ public static Color GetColor(ManaPoint current, ManaPoint max)
+ {
+ // NOTE to future self:
+ // Mana could use HSL scale with blue.
+ // The L value coudl follow this formula, assuming 100 max mana:
+ // (mana / 100 * 0.8) + 0.1
+ // Basically, get the mana percentage, multiply it by 80%,
+ // and add 0.1. This will Make the minimum lightness 0.1 and the max 0.9/
+ // This will leave some nice dark and light blues for the mana bar.
+
+ var pct = GetBrightnessValue(current, max);
+
+ return ColorHelper.ColorFromHSL(BlueHue, lightness: pct);
+ }
+
+ public static double GetBrightnessValue(ManaPoint num, ManaPoint denom)
+ {
+ var pct = num.Value * 1.0 / denom.Value;
+ pct *= range;
+ return pct + minLightness;
+ }
+ }
+}