diff --git a/pycardium/modules/py/color.py b/pycardium/modules/py/color.py
index 00717987efd45d0f62bd014da240caa69d489658..470e382aed9d68c6d397ff93c2b6060d8ec15d62 100644
--- a/pycardium/modules/py/color.py
+++ b/pycardium/modules/py/color.py
@@ -127,6 +127,360 @@ class Color(_ColorTuple):
             return round(f(x) * 255)
         return cls(f2(0), f2(8), f2(4))
 
+    def __to_hsx(self, hsv=True):
+        """
+        Code via https://en.wikipedia.org/wiki/HSL_and_HSV#From_RGB
+        """
+        xr = self.red   / 255
+        xg = self.green / 255
+        xb = self.blue  / 255
+        if xr == xg and xr == xb:
+            h = 0
+            c_max = xr
+            c_min = xr
+            x_max = self.red
+            x_min = self.red
+        else:
+            c_max = max(xr, xg, xb)
+            c_min = min(xr, xg, xb)
+            x_max = max(self.red, self.green, self.blue)
+            x_min = min(self.red, self.green, self.blue)
+            if self.red == x_max:
+                h = 60 * (0 + (xg - xb) / (c_max - c_min))
+            elif self.green == x_max:
+                h = 60 * (2 + (xb - xr) / (c_max - c_min))
+            elif self.blue == x_max:
+                h = 60 * (4 + (xr - xg) / (c_max - c_min))
+            else:
+                h = 0
+        while h < 0:
+            h = h + 360
+
+        if hsv:
+            if x_max == 0:
+                s = 0
+            else:
+                s = (c_max - c_min) / c_max
+            v = c_max
+            return [round(h), round(s, 2), round(v, 2)]
+        else:
+            l = ((c_max + c_min) / 2)
+            if x_max == 0:
+                s = 0
+            elif x_min == 1:
+                s = 0
+            else:
+                s = (c_max - l) / min(l, 1 - l)
+            return [round(h), round(s, 2), round(l, 2)]
+
+    def to_hsv(self):
+        """
+        Create a HSV tuple (hue, saturation, value) from this color.
+
+        **Example**:
+
+        .. code-block:: python
+
+            from color import Color
+
+            # orange
+            c = Color.from_hex(0xff9900)
+            print(c.to_hsv())
+            # [36, 1.0, 1.0]
+
+        """
+        return self.__to_hsx(True)
+
+    def to_hsl(self):
+        """
+        Create a HSL tuple (hue, saturation, lightness) from this color.
+
+        **Example**:
+
+        .. code-block:: python
+
+            from color import Color
+
+            # orange
+            c = Color.from_hex(0xff9900)
+            print(c.to_hsl())
+            # [36, 1.0, 0.5]
+
+        """
+        return self.__to_hsx(False)
+
+    def __change_sat(self, change, to_fn, from_fn):
+        hsx = to_fn()
+        sat = hsx[1] + change
+        if sat > 1:
+            sat = 1
+        if sat < 0:
+            sat = 0
+        rv = from_fn(hsx[0], sat, hsx[2])
+        self.red   = rv.red
+        self.green = rv.green
+        self.blue  = rv.blue
+
+    def __change_vlx(self, change, to_fn, from_fn):
+        hsx = to_fn()
+        vlx = hsx[2] + change
+        if vlx > 1:
+            vlx = 1
+        if vlx < 0:
+            vlx = 0
+        rv = from_fn(hsx[0], hsx[1], vlx)
+        self.red   = rv.red
+        self.green = rv.green
+        self.blue  = rv.blue
+
+    def change_hue(self, change):
+        """
+        Change the hue of this color (doesn't matter if HSL or HSV).
+        Hue is always between 0 and 360.
+
+        **Example**:
+
+        .. code-block:: python
+
+            from color import Color
+
+            # red
+            c = Color.from_hex(0xff0000)
+            print(c)
+            # #ff0000
+            c.change_hue(90)
+            print(c)
+            # #80ff00
+
+        """
+        hsx = self.to_hsl()
+        hue = hsx[0] + change
+        hue = hue % 360
+        rv = self.from_hsl(hue, hsx[1], hsx[2])
+        self.red   = rv.red
+        self.green = rv.green
+        self.blue  = rv.blue
+
+    def change_saturation_hsv(self, change):
+        """
+        Change the saturation of this color (in HSV).
+        Saturation is always between 0 and 1.
+
+        **Example**:
+
+        .. code-block:: python
+
+            from color import Color
+
+            # red
+            c = Color.from_hex(0xff0000)
+            print(c)
+            # #ff0000
+            c.change_saturation_hsv(-0.5)
+            print(c)
+            # #ff8080
+
+        """
+        return self.__change_sat(change, self.to_hsv, self.from_hsv)
+
+    def change_saturation_hsl(self, change):
+        """
+        Change the saturation of this color (in HSL).
+        Saturation is always between 0 and 1.
+
+        **Example**:
+
+        .. code-block:: python
+
+            from color import Color
+
+            # red
+            c = Color.from_hex(0xff0000)
+            print(c)
+            # #ff0000
+            c.change_saturation_hsl(-0.5)
+            print(c)
+            # #bf4040
+
+        """
+        return self.__change_sat(change, self.to_hsl, self.from_hsl)
+
+    def change_value(self, change):
+        """
+        Change the value of this color (in HSV).
+        Value is always between 0 and 1.
+
+        **Example**:
+
+        .. code-block:: python
+
+            from color import Color
+
+            # red
+            c = Color.from_hex(0xff0000)
+            print(c)
+            # #ff0000
+            c.change_value(-0.5)
+            print(c)
+            # #800000
+
+        """
+        return self.__change_vlx(change, self.to_hsv, self.from_hsv)
+
+    def change_lightness(self, change):
+        """
+        Change the lightness of this color (in HSL).
+        Lightness is always between 0 and 1.
+
+        **Example**:
+
+        .. code-block:: python
+
+            from color import Color
+
+            # red
+            c = Color.from_hex(0xff0000)
+            print(c)
+            # #ff0000
+            c.change_value(-0.25)
+            print(c)
+            # #800000
+
+        """
+        return self.__change_vlx(change, self.to_hsl, self.from_hsl)
+
+    def get_complementary(self):
+        """
+        Get the complementary color of this color.
+
+        **Example**:
+
+        .. code-block:: python
+
+            from color import Color
+
+            # red
+            c = Color.from_hex(0xff0000)
+            print(c)
+            # #ff0000
+            c.get_complementary()
+            print(c)
+            # #00ffff
+
+        """
+        rv = self.to_hsl()
+        h = (rv[0] + 180) % 360
+        return Color.from_hsl(round(h), round(rv[1], 2), round(rv[2], 2))
+
+    def darken(self, change):
+        """
+        Darken a color. Uses change_saturation_hsl.
+        """
+        self.change_saturation_hsl(0 - abs(change))
+
+    def brighten(self, change):
+        """
+        Brighten a color. Uses change_saturation_hsl.
+        """
+        self.change_saturation_hsl(0 + abs(change))
+
+    def __get_bounded(self, r, g, b):
+        if r < 0:
+            r = 0
+        if r > 255:
+            r = 255
+        if g < 0:
+            g = 0
+        if b > 255:
+            b = 255
+        return Color(r, g, b)
+
+    def __mul__(self, other):
+        """
+        Multiply with a scalar to dim the color.
+
+        **Example**:
+
+        .. code-block:: python
+
+            from color import Color
+
+            # red
+            c = Color.from_hex(0x0000ff)
+            print(c)
+            # #0000ff
+            c2 = c1 * 0.5
+            print(c2)
+            # #000080
+
+        """
+        try:
+            other = float(other)
+        except ValueError:
+            return NotImplemented
+        r = self.red   * other
+        g = self.green * other
+        b = self.blue  * other
+        return self.__get_bounded(round(r), round(g), round(b))
+
+    def __add__(self, other):
+        """
+        Add two colors to add their respective color values.
+
+        **Example**:
+
+        .. code-block:: python
+
+            from color import Color
+
+            # two shades of grey
+            c1 = Color.from_hex(0x323232)
+            c2 = Color.from_hex(0x646464)
+            print(c1)
+            # #323232
+            print(c2)
+            # #646464
+            c3 = c1 + c2
+            print(c3)
+            # #969696
+
+        """
+        if not isinstance(other, Color):
+            return NotImplemented
+        r = self.red   + other.red
+        g = self.green + other.green
+        b = self.blue  + other.blue
+        return self.__get_bounded(r, g, b)
+
+    def __sub__(self, other):
+        """
+        Subtract two colors to subtract their respective color values.
+
+        **Example**:
+
+        .. code-block:: python
+
+            from color import Color
+
+            # two shades of grey
+            c1 = Color.from_hex(0x969696)
+            c2 = Color.from_hex(0x646464)
+            print(c1)
+            # #969696
+            print(c2)
+            # #646464
+            c3 = c1 - c2
+            print(c3)
+            # #323232
+
+        """
+        if not isinstance(other, Color):
+            return NotImplemented
+        r = self.red   - other.red
+        g = self.green - other.green
+        b = self.blue  - other.blue
+        return self.__get_bounded(r, g, b)
+
     def __str__(self):
         # Return the color in hex
         return "#{:02x}{:02x}{:02x}".format(