diff --git a/wpilibc/robotpy_pybind_build_info.bzl b/wpilibc/robotpy_pybind_build_info.bzl index 1de9af9097..7b82c03f43 100644 --- a/wpilibc/robotpy_pybind_build_info.bzl +++ b/wpilibc/robotpy_pybind_build_info.bzl @@ -984,26 +984,6 @@ def wpilib_extension(srcs = [], header_to_dat_deps = [], extra_hdrs = [], includ ("wpi::Alert", "wpi__Alert.hpp"), ], ), - struct( - class_name = "Color", - yml_file = "semiwrap/Color.yml", - header_root = "$(execpath :robotpy-native-wpilib.copy_headers)", - header_file = "$(execpath :robotpy-native-wpilib.copy_headers)/wpi/util/Color.hpp", - tmpl_class_names = [], - trampolines = [ - ("wpi::Color", "wpi__Color.hpp"), - ], - ), - struct( - class_name = "Color8Bit", - yml_file = "semiwrap/Color8Bit.yml", - header_root = "$(execpath :robotpy-native-wpilib.copy_headers)", - header_file = "$(execpath :robotpy-native-wpilib.copy_headers)/wpi/util/Color8Bit.hpp", - tmpl_class_names = [], - trampolines = [ - ("wpi::Color8Bit", "wpi__Color8Bit.hpp"), - ], - ), struct( class_name = "Preferences", yml_file = "semiwrap/Preferences.yml", diff --git a/wpilibc/src/main/native/cpp/hardware/led/AddressableLED.cpp b/wpilibc/src/main/native/cpp/hardware/led/AddressableLED.cpp index 5db686f67e..3aec5cdc0c 100644 --- a/wpilibc/src/main/native/cpp/hardware/led/AddressableLED.cpp +++ b/wpilibc/src/main/native/cpp/hardware/led/AddressableLED.cpp @@ -75,5 +75,5 @@ void AddressableLED::SetGlobalData(int start, ColorOrder colorOrder, } void AddressableLED::LEDData::SetHSV(int h, int s, int v) { - SetLED(Color::FromHSV(h, s, v)); + SetLED(wpi::util::Color::FromHSV(h, s, v)); } diff --git a/wpilibc/src/main/native/cpp/hardware/led/LEDPattern.cpp b/wpilibc/src/main/native/cpp/hardware/led/LEDPattern.cpp index c4b05d5ecb..e738ba3d43 100644 --- a/wpilibc/src/main/native/cpp/hardware/led/LEDPattern.cpp +++ b/wpilibc/src/main/native/cpp/hardware/led/LEDPattern.cpp @@ -17,24 +17,29 @@ using namespace wpi; -LEDPattern::LEDPattern(std::function)> - impl) +LEDPattern::LEDPattern( + std::function)> + impl) : m_impl(std::move(impl)) {} -void LEDPattern::ApplyTo(LEDPattern::LEDReader reader, - std::function writer) const { +void LEDPattern::ApplyTo( + LEDPattern::LEDReader reader, + std::function writer) const { m_impl(reader, writer); } -void LEDPattern::ApplyTo(std::span data, - std::function writer) const { +void LEDPattern::ApplyTo( + std::span data, + std::function writer) const { ApplyTo(LEDPattern::LEDReader{[=](size_t i) { return data[i]; }, data.size()}, writer); } void LEDPattern::ApplyTo(std::span data) const { - ApplyTo(data, [&](int index, Color color) { data[index].SetLED(color); }); + ApplyTo(data, [&](int index, wpi::util::Color color) { + data[index].SetLED(color); + }); } LEDPattern LEDPattern::MapIndex( @@ -44,7 +49,9 @@ LEDPattern LEDPattern::MapIndex( self.ApplyTo( LEDPattern::LEDReader{ [=](auto i) { return data[indexMapper(bufLen, i)]; }, bufLen}, - [&](int i, Color color) { writer(indexMapper(bufLen, i), color); }); + [&](int i, wpi::util::Color color) { + writer(indexMapper(bufLen, i), color); + }); }}; } @@ -131,7 +138,7 @@ LEDPattern LEDPattern::Breathe(wpi::units::second_t period) { auto periodMicros = wpi::units::microsecond_t{period}; return LEDPattern{[periodMicros, self = *this](auto data, auto writer) { - self.ApplyTo(data, [&writer, periodMicros](int i, Color color) { + self.ApplyTo(data, [&writer, periodMicros](int i, wpi::util::Color color) { double t = (wpi::util::Now() % periodMicros.to()) / periodMicros.to(); double phase = t * 2 * std::numbers::pi; @@ -140,7 +147,8 @@ LEDPattern LEDPattern::Breathe(wpi::units::second_t period) { // Use cosine so the period starts at 100% brightness double dim = (std::cos(phase) + 1) / 2.0; - writer(i, Color{color.red * dim, color.green * dim, color.blue * dim}); + writer(i, wpi::util::Color{color.red * dim, color.green * dim, + color.blue * dim}); }); }}; } @@ -151,7 +159,7 @@ LEDPattern LEDPattern::OverlayOn(const LEDPattern& base) { base.ApplyTo(data, writer); // ... then, overwrite with illuminated LEDs from the overlay - self.ApplyTo(data, [&](int i, Color color) { + self.ApplyTo(data, [&](int i, wpi::util::Color color) { if (color.red > 0 || color.green > 0 || color.blue > 0) { writer(i, color); } @@ -164,12 +172,12 @@ LEDPattern LEDPattern::Blend(const LEDPattern& other) { // Apply the current pattern down as normal... self.ApplyTo(data, writer); - other.ApplyTo(data, [&](int i, Color color) { + other.ApplyTo(data, [&](int i, wpi::util::Color color) { // ... then read the result and average it with the output from the other // pattern - writer(i, Color{(data[i].r / 255.0 + color.red) / 2, - (data[i].g / 255.0 + color.green) / 2, - (data[i].b / 255.0 + color.blue) / 2}); + writer(i, wpi::util::Color{(data[i].r / 255.0 + color.red) / 2, + (data[i].g / 255.0 + color.green) / 2, + (data[i].b / 255.0 + color.blue) / 2}); }); }}; } @@ -179,23 +187,24 @@ LEDPattern LEDPattern::Mask(const LEDPattern& mask) { // Apply the current pattern down as normal... self.ApplyTo(data, writer); - mask.ApplyTo(data, [&](int i, Color color) { + mask.ApplyTo(data, [&](int i, wpi::util::Color color) { auto currentColor = data[i]; // ... then perform a bitwise AND operation on each channel to apply the // mask - writer(i, Color{currentColor.r & static_cast(255 * color.red), - currentColor.g & static_cast(255 * color.green), - currentColor.b & static_cast(255 * color.blue)}); + writer(i, wpi::util::Color{ + currentColor.r & static_cast(255 * color.red), + currentColor.g & static_cast(255 * color.green), + currentColor.b & static_cast(255 * color.blue)}); }); }}; } LEDPattern LEDPattern::AtBrightness(double relativeBrightness) { return LEDPattern{[relativeBrightness, self = *this](auto data, auto writer) { - self.ApplyTo(data, [&](int i, Color color) { - writer(i, Color{color.red * relativeBrightness, - color.green * relativeBrightness, - color.blue * relativeBrightness}); + self.ApplyTo(data, [&](int i, wpi::util::Color color) { + writer(i, wpi::util::Color{color.red * relativeBrightness, + color.green * relativeBrightness, + color.blue * relativeBrightness}); }); }}; } @@ -203,10 +212,10 @@ LEDPattern LEDPattern::AtBrightness(double relativeBrightness) { // Static constants and functions LEDPattern LEDPattern::Off() { - return LEDPattern::Solid(Color::kBlack); + return LEDPattern::Solid(wpi::util::Color::kBlack); } -LEDPattern LEDPattern::Solid(const Color color) { +LEDPattern LEDPattern::Solid(const wpi::util::Color color) { return LEDPattern{[=](auto data, auto writer) { auto bufLen = data.size(); for (size_t i = 0; i < bufLen; i++) { @@ -223,15 +232,16 @@ LEDPattern LEDPattern::ProgressMaskLayer( size_t max = bufLen * progress; for (size_t led = 0; led < max; led++) { - writer(led, Color::kWhite); + writer(led, wpi::util::Color::kWhite); } for (size_t led = max; led < bufLen; led++) { - writer(led, Color::kBlack); + writer(led, wpi::util::Color::kBlack); } }}; } -LEDPattern LEDPattern::Steps(std::span> steps) { +LEDPattern LEDPattern::Steps( + std::span> steps) { if (steps.size() == 0) { // no colors specified return LEDPattern::Off(); @@ -247,12 +257,12 @@ LEDPattern LEDPattern::Steps(std::span> steps) { // precompute relevant positions for this buffer so we don't need to do a // check on every single LED index - std::unordered_map stopPositions; + std::unordered_map stopPositions; for (auto step : steps) { stopPositions[std::floor(step.first * bufLen)] = step.second; } - auto currentColor = Color::kBlack; + auto currentColor = wpi::util::Color::kBlack; for (size_t led = 0; led < bufLen; led++) { if (stopPositions.contains(led)) { currentColor = stopPositions[led]; @@ -263,12 +273,12 @@ LEDPattern LEDPattern::Steps(std::span> steps) { } LEDPattern LEDPattern::Steps( - std::initializer_list> steps) { + std::initializer_list> steps) { return Steps(std::span{steps.begin(), steps.end()}); } LEDPattern LEDPattern::Gradient(GradientType type, - std::span colors) { + std::span colors) { if (colors.size() == 0) { // no colors specified return LEDPattern::Off(); @@ -300,16 +310,17 @@ LEDPattern LEDPattern::Gradient(GradientType type, auto color = colors[colorIndex]; auto nextColor = colors[nextColorIndex]; - Color gradientColor{wpi::util::Lerp(color.red, nextColor.red, t), - wpi::util::Lerp(color.green, nextColor.green, t), - wpi::util::Lerp(color.blue, nextColor.blue, t)}; + wpi::util::Color gradientColor{ + wpi::util::Lerp(color.red, nextColor.red, t), + wpi::util::Lerp(color.green, nextColor.green, t), + wpi::util::Lerp(color.blue, nextColor.blue, t)}; writer(led, gradientColor); } }}; } -LEDPattern LEDPattern::Gradient(GradientType type, - std::initializer_list colors) { +LEDPattern LEDPattern::Gradient( + GradientType type, std::initializer_list colors) { return Gradient(type, std::span{colors.begin(), colors.end()}); } @@ -318,7 +329,7 @@ LEDPattern LEDPattern::Rainbow(int saturation, int value) { auto bufLen = data.size(); for (size_t led = 0; led < bufLen; led++) { int hue = ((led * 180) / bufLen) % 180; - writer(led, Color::FromHSV(hue, saturation, value)); + writer(led, wpi::util::Color::FromHSV(hue, saturation, value)); } }}; } diff --git a/wpilibc/src/main/native/cpp/smartdashboard/Mechanism2d.cpp b/wpilibc/src/main/native/cpp/smartdashboard/Mechanism2d.cpp index 6de4b3cca0..b2afeca9d2 100644 --- a/wpilibc/src/main/native/cpp/smartdashboard/Mechanism2d.cpp +++ b/wpilibc/src/main/native/cpp/smartdashboard/Mechanism2d.cpp @@ -15,7 +15,7 @@ static constexpr std::string_view kBackgroundColor = "backgroundColor"; static constexpr std::string_view kDims = "dims"; Mechanism2d::Mechanism2d(double width, double height, - const Color8Bit& backgroundColor) + const wpi::util::Color8Bit& backgroundColor) : m_width{width}, m_height{height} { SetBackgroundColor(backgroundColor); } @@ -30,7 +30,7 @@ MechanismRoot2d* Mechanism2d::GetRoot(std::string_view name, double x, return &it->second; } -void Mechanism2d::SetBackgroundColor(const Color8Bit& color) { +void Mechanism2d::SetBackgroundColor(const wpi::util::Color8Bit& color) { m_color = color.HexString(); if (m_colorPub) { m_colorPub.Set(m_color); diff --git a/wpilibc/src/main/native/cpp/smartdashboard/MechanismLigament2d.cpp b/wpilibc/src/main/native/cpp/smartdashboard/MechanismLigament2d.cpp index 56ed27b834..c1182ecae4 100644 --- a/wpilibc/src/main/native/cpp/smartdashboard/MechanismLigament2d.cpp +++ b/wpilibc/src/main/native/cpp/smartdashboard/MechanismLigament2d.cpp @@ -17,7 +17,7 @@ static constexpr std::string_view kSmartDashboardType = "line"; MechanismLigament2d::MechanismLigament2d(std::string_view name, double length, wpi::units::degree_t angle, double lineWeight, - const wpi::Color8Bit& color) + const wpi::util::Color8Bit& color) : MechanismObject2d{name}, m_length{length}, m_angle{angle.value()}, @@ -42,7 +42,7 @@ void MechanismLigament2d::UpdateEntries( m_lengthEntry.Set(m_length); } -void MechanismLigament2d::SetColor(const Color8Bit& color) { +void MechanismLigament2d::SetColor(const wpi::util::Color8Bit& color) { std::scoped_lock lock(m_mutex); wpi::util::format_to_n_c_str(m_color, sizeof(m_color), "#{:02X}{:02X}{:02X}", @@ -69,7 +69,7 @@ void MechanismLigament2d::SetLineWeight(double lineWidth) { } } -Color8Bit MechanismLigament2d::GetColor() { +wpi::util::Color8Bit MechanismLigament2d::GetColor() { std::scoped_lock lock(m_mutex); if (m_colorEntry) { auto color = m_colorEntry.Get(); diff --git a/wpilibc/src/main/native/include/wpi/hardware/led/AddressableLED.hpp b/wpilibc/src/main/native/include/wpi/hardware/led/AddressableLED.hpp index f616294b99..8a08741e65 100644 --- a/wpilibc/src/main/native/include/wpi/hardware/led/AddressableLED.hpp +++ b/wpilibc/src/main/native/include/wpi/hardware/led/AddressableLED.hpp @@ -79,7 +79,7 @@ class AddressableLED { * * @param color The color of the LED */ - void SetLED(const Color& color) { + void SetLED(const wpi::util::Color& color) { this->r = color.red * 255; this->g = color.green * 255; this->b = color.blue * 255; @@ -90,7 +90,7 @@ class AddressableLED { * * @param color The color of the LED */ - void SetLED(const Color8Bit& color) { + void SetLED(const wpi::util::Color8Bit& color) { this->r = color.red; this->g = color.green; this->b = color.blue; diff --git a/wpilibc/src/main/native/include/wpi/hardware/led/LEDPattern.hpp b/wpilibc/src/main/native/include/wpi/hardware/led/LEDPattern.hpp index 6385fa5945..1d36517189 100644 --- a/wpilibc/src/main/native/include/wpi/hardware/led/LEDPattern.hpp +++ b/wpilibc/src/main/native/include/wpi/hardware/led/LEDPattern.hpp @@ -41,12 +41,13 @@ class LEDPattern { size_t m_size; }; - explicit LEDPattern(std::function)> - impl); + explicit LEDPattern( + std::function)> + impl); void ApplyTo(LEDReader reader, - std::function writer) const; + std::function writer) const; /** * Writes the pattern to an LED buffer. Dynamic animations should be called @@ -62,7 +63,7 @@ class LEDPattern { * @param writer data writer for setting new LED colors on the LED strip */ void ApplyTo(std::span data, - std::function writer) const; + std::function writer) const; /** * Writes the pattern to an LED buffer. Dynamic animations should be called @@ -199,8 +200,8 @@ class LEDPattern { /** * Creates a pattern that plays this pattern overlaid on another. Anywhere - * this pattern sets an LED to off (or {@link wpi::Color::kBlack}), the base - * pattern will be displayed instead. + * this pattern sets an LED to off (or {@link wpi::util::Color::kBlack}), the + * base pattern will be displayed instead. * * @param base the base pattern to overlay on top of * @return the combined overlay pattern @@ -256,10 +257,10 @@ class LEDPattern { * *
    *   // Solid red, but at 50% brightness
-   *   wpi::LEDPattern::Solid(wpi::Color::kRed).AtBrightness(0.5);
+   *   wpi::LEDPattern::Solid(wpi::util::Color::kRed).AtBrightness(0.5);
    *
    *   // Solid white, but at only 10% (i.e. ~0.5V)
-   *   wpi::LEDPattern::Solid(frc:Color::kWhite).AtBrightness(0.1);
+   *   wpi::LEDPattern::Solid(wpi::util::Color::kWhite).AtBrightness(0.1);
    * 
* * @param relativeBrightness the multiplier to apply to all channels to modify @@ -279,7 +280,7 @@ class LEDPattern { * @param color the color to display * @return the pattern */ - static LEDPattern Solid(const Color color); + static LEDPattern Solid(const wpi::util::Color color); /** * Creates a pattern that works as a mask layer for {@link @@ -296,8 +297,8 @@ class LEDPattern { * *
    * wpi::LEDPattern basePattern =
-   *   wpi::LEDPattern::Gradient(wpi::Color::kRed, wpi::Color::kBlue);
-   * wpi::LEDPattern progressPattern =
+   *   wpi::LEDPattern::Gradient(wpi::util::Color::kRed,
+   * wpi::util::Color::kBlue); wpi::LEDPattern progressPattern =
    *   basePattern.Mask(wpi::LEDPattern::ProgressMaskLayer([&]() {
    *     return elevator.GetHeight() / elevator.MaxHeight();
    *   });
@@ -322,7 +323,8 @@ class LEDPattern {
    * position along the LED strip
    * @return a motionless step pattern
    */
-  static LEDPattern Steps(std::span> steps);
+  static LEDPattern Steps(
+      std::span> steps);
 
   /**
    * Display a set of colors in steps across the length of the LED strip. No
@@ -337,7 +339,7 @@ class LEDPattern {
    * @return a motionless step pattern
    */
   static LEDPattern Steps(
-      std::initializer_list> steps);
+      std::initializer_list> steps);
 
   /** Types of gradients. */
   enum GradientType {
@@ -368,7 +370,8 @@ class LEDPattern {
    * @param colors the colors to display in the gradient
    * @return a motionless gradient pattern
    */
-  static LEDPattern Gradient(GradientType type, std::span colors);
+  static LEDPattern Gradient(GradientType type,
+                             std::span colors);
 
   /**
    * Creates a pattern that displays a non-animated gradient of colors across
@@ -384,7 +387,7 @@ class LEDPattern {
    * @return a motionless gradient pattern
    */
   static LEDPattern Gradient(GradientType type,
-                             std::initializer_list colors);
+                             std::initializer_list colors);
 
   /**
    * Creates an LED pattern that displays a rainbow across the color wheel. The
@@ -398,7 +401,7 @@ class LEDPattern {
 
  private:
   std::function)>
+                     std::function)>
       m_impl;
 };
 }  // namespace wpi
diff --git a/wpilibc/src/main/native/include/wpi/smartdashboard/Mechanism2d.hpp b/wpilibc/src/main/native/include/wpi/smartdashboard/Mechanism2d.hpp
index 53cf37455d..541bdbcc25 100644
--- a/wpilibc/src/main/native/include/wpi/smartdashboard/Mechanism2d.hpp
+++ b/wpilibc/src/main/native/include/wpi/smartdashboard/Mechanism2d.hpp
@@ -52,7 +52,7 @@ class Mechanism2d : public wpi::nt::NTSendable,
    * @param backgroundColor the background color
    */
   Mechanism2d(double width, double height,
-              const Color8Bit& backgroundColor = {0, 0, 32});
+              const wpi::util::Color8Bit& backgroundColor = {0, 0, 32});
 
   /**
    * Get or create a root in this Mechanism2d with the given name and
@@ -73,7 +73,7 @@ class Mechanism2d : public wpi::nt::NTSendable,
    *
    * @param color the new background color
    */
-  void SetBackgroundColor(const Color8Bit& color);
+  void SetBackgroundColor(const wpi::util::Color8Bit& color);
 
   void InitSendable(wpi::nt::NTSendableBuilder& builder) override;
 
diff --git a/wpilibc/src/main/native/include/wpi/smartdashboard/MechanismLigament2d.hpp b/wpilibc/src/main/native/include/wpi/smartdashboard/MechanismLigament2d.hpp
index c980601361..579b85880a 100644
--- a/wpilibc/src/main/native/include/wpi/smartdashboard/MechanismLigament2d.hpp
+++ b/wpilibc/src/main/native/include/wpi/smartdashboard/MechanismLigament2d.hpp
@@ -27,21 +27,21 @@ class MechanismLigament2d : public MechanismObject2d {
  public:
   MechanismLigament2d(std::string_view name, double length,
                       wpi::units::degree_t angle, double lineWidth = 6,
-                      const wpi::Color8Bit& color = {235, 137, 52});
+                      const wpi::util::Color8Bit& color = {235, 137, 52});
 
   /**
    * Set the ligament color.
    *
    * @param color the color of the line
    */
-  void SetColor(const Color8Bit& color);
+  void SetColor(const wpi::util::Color8Bit& color);
 
   /**
    * Get the ligament color.
    *
    * @return the color of the line
    */
-  Color8Bit GetColor();
+  wpi::util::Color8Bit GetColor();
 
   /**
    * Set the ligament's length.
diff --git a/wpilibc/src/main/python/pyproject.toml b/wpilibc/src/main/python/pyproject.toml
index 99afb6cb87..391098dbbf 100644
--- a/wpilibc/src/main/python/pyproject.toml
+++ b/wpilibc/src/main/python/pyproject.toml
@@ -210,8 +210,6 @@ Watchdog = "wpi/system/Watchdog.hpp"
 
 # wpi/util
 Alert = "wpi/util/Alert.hpp"
-Color = "wpi/util/Color.hpp"
-Color8Bit = "wpi/util/Color8Bit.hpp"
 Preferences = "wpi/util/Preferences.hpp"
 SensorUtil = "wpi/util/SensorUtil.hpp"
 
diff --git a/wpilibc/src/main/python/semiwrap/AddressableLED.yml b/wpilibc/src/main/python/semiwrap/AddressableLED.yml
index 7c77d2c1e5..ac6b1ec16c 100644
--- a/wpilibc/src/main/python/semiwrap/AddressableLED.yml
+++ b/wpilibc/src/main/python/semiwrap/AddressableLED.yml
@@ -39,6 +39,6 @@ classes:
       SetHSV:
       SetLED:
         overloads:
-          const Color&:
-          const Color8Bit&:
+          const wpi::util::Color&:
+          const wpi::util::Color8Bit&:
 
diff --git a/wpilibc/src/main/python/semiwrap/LEDPattern.yml b/wpilibc/src/main/python/semiwrap/LEDPattern.yml
index 5b7d0c5bf8..de0c58bfec 100644
--- a/wpilibc/src/main/python/semiwrap/LEDPattern.yml
+++ b/wpilibc/src/main/python/semiwrap/LEDPattern.yml
@@ -8,8 +8,8 @@ classes:
       ApplyTo:
         overloads:
           std::span [const]:
-          LEDReader, std::function [const]:
-          std::span, std::function [const]:
+          LEDReader, std::function [const]:
+          std::span, std::function [const]:
       Reversed:
       OffsetBy:
       ScrollAtRelativeSpeed:
@@ -28,13 +28,13 @@ classes:
       ProgressMaskLayer:
       Steps:
         overloads:
-          std::span>:
-          std::initializer_list>:
+          std::span>:
+          std::initializer_list>:
             ignore: true
       Gradient:
         overloads:
-          GradientType, std::span:
-          GradientType, std::initializer_list:
+          GradientType, std::span:
+          GradientType, std::initializer_list:
             ignore: true
       Rainbow:
       MapIndex:
diff --git a/wpilibc/src/main/python/semiwrap/MechanismObject2d.yml b/wpilibc/src/main/python/semiwrap/MechanismObject2d.yml
index bdd8cf2ef5..c6b2bab37d 100644
--- a/wpilibc/src/main/python/semiwrap/MechanismObject2d.yml
+++ b/wpilibc/src/main/python/semiwrap/MechanismObject2d.yml
@@ -21,11 +21,11 @@ inline_code: |-
   cls_MechanismObject2d
     .def("appendLigament", [](MechanismObject2d *self,
       std::string_view name, double length, wpi::units::degree_t angle,
-      double lineWidth, const wpi::Color8Bit& color) {
+      double lineWidth, const wpi::util::Color8Bit& color) {
         return self->Append(name, length, angle, lineWidth, color);
       },
       py::arg("name"), py::arg("length"), py::arg("angle"),
-      py::arg("lineWidth") = 6, py::arg("color") = wpi::Color8Bit{235, 137, 52},
+      py::arg("lineWidth") = 6, py::arg("color") = wpi::util::Color8Bit{235, 137, 52},
       "Append a ligament node",
       py::return_value_policy::reference_internal)
     ;
diff --git a/wpilibc/src/main/python/semiwrap/MechanismRoot2d.yml b/wpilibc/src/main/python/semiwrap/MechanismRoot2d.yml
index d4f8215d04..acf7ff1225 100644
--- a/wpilibc/src/main/python/semiwrap/MechanismRoot2d.yml
+++ b/wpilibc/src/main/python/semiwrap/MechanismRoot2d.yml
@@ -20,11 +20,11 @@ inline_code: |-
     .def("getName", [](MechanismRoot2d *self) { return self->GetName(); }, release_gil())
     .def("appendLigament", [](MechanismRoot2d *self,
       std::string_view name, double length, wpi::units::degree_t angle,
-      double lineWidth, const wpi::Color8Bit& color) {
+      double lineWidth, const wpi::util::Color8Bit& color) {
         return self->Append(name, length, angle, lineWidth, color);
       },
       py::arg("name"), py::arg("length"), py::arg("angle"),
-      py::arg("lineWidth") = 6, py::arg("color") = wpi::Color8Bit{235, 137, 52},
+      py::arg("lineWidth") = 6, py::arg("color") = wpi::util::Color8Bit{235, 137, 52},
       release_gil(), "Append a ligament node",
       py::return_value_policy::reference_internal)
     ;
diff --git a/wpilibc/src/main/python/wpilib/__init__.py b/wpilibc/src/main/python/wpilib/__init__.py
index 527a166a1e..35fd9041c2 100644
--- a/wpilibc/src/main/python/wpilib/__init__.py
+++ b/wpilibc/src/main/python/wpilib/__init__.py
@@ -14,8 +14,6 @@ from ._wpilib import (
     AnalogPotentiometer,
     CAN,
     CANStatus,
-    Color,
-    Color8Bit,
     Compressor,
     CompressorConfigType,
     DSControlWord,
@@ -106,8 +104,6 @@ __all__ = [
     "AnalogPotentiometer",
     "CAN",
     "CANStatus",
-    "Color",
-    "Color8Bit",
     "Compressor",
     "CompressorConfigType",
     "DSControlWord",
diff --git a/wpilibc/src/test/native/cpp/LEDPatternTest.cpp b/wpilibc/src/test/native/cpp/LEDPatternTest.cpp
index cc9219e4ec..94c329d78d 100644
--- a/wpilibc/src/test/native/cpp/LEDPatternTest.cpp
+++ b/wpilibc/src/test/native/cpp/LEDPatternTest.cpp
@@ -16,150 +16,170 @@ static LEDPattern whiteYellowPurple{[](auto data, auto writer) {
   for (size_t led = 0; led < data.size(); led++) {
     switch (led % 3) {
       case 0:
-        writer(led, Color::kWhite);
+        writer(led, wpi::util::Color::kWhite);
         break;
       case 1:
-        writer(led, Color::kYellow);
+        writer(led, wpi::util::Color::kYellow);
         break;
       case 2:
-        writer(led, Color::kPurple);
+        writer(led, wpi::util::Color::kPurple);
         break;
     }
   }
 }};
 
 void AssertIndexColor(std::span data, int index,
-                      Color color);
-Color LerpColors(Color a, Color b, double t);
+                      wpi::util::Color color);
+wpi::util::Color LerpColors(wpi::util::Color a, wpi::util::Color b, double t);
 
 TEST(LEDPatternTest, SolidColor) {
-  LEDPattern pattern = LEDPattern::Solid(Color::kYellow);
+  LEDPattern pattern = LEDPattern::Solid(wpi::util::Color::kYellow);
   std::array buffer;
 
   // prefill
   for (int i = 0; i < 5; i++) {
-    buffer[i].SetLED(Color::kPurple);
+    buffer[i].SetLED(wpi::util::Color::kPurple);
   }
 
   pattern.ApplyTo(buffer);
   for (int i = 0; i < 5; i++) {
-    AssertIndexColor(buffer, i, Color::kYellow);
+    AssertIndexColor(buffer, i, wpi::util::Color::kYellow);
   }
 }
 
 TEST(LEDPatternTest, EmptyGradientSetsToBlack) {
-  std::array colors;
+  std::array colors;
   LEDPattern pattern =
       LEDPattern::Gradient(LEDPattern::GradientType::kContinuous, colors);
   std::array buffer;
   pattern.ApplyTo(buffer);
   for (int i = 0; i < 5; i++) {
-    AssertIndexColor(buffer, i, Color::kBlack);
+    AssertIndexColor(buffer, i, wpi::util::Color::kBlack);
   }
 }
 
 TEST(LEDPatternTest, SingleColorGradientSetsSolid) {
-  std::array colors{Color::kYellow};
+  std::array colors{wpi::util::Color::kYellow};
   LEDPattern pattern =
       LEDPattern::Gradient(LEDPattern::GradientType::kContinuous, colors);
   std::array buffer;
   pattern.ApplyTo(buffer);
   for (int i = 0; i < 5; i++) {
-    AssertIndexColor(buffer, i, Color::kYellow);
+    AssertIndexColor(buffer, i, wpi::util::Color::kYellow);
   }
 }
 
 TEST(LEDPatternTest, Gradient2Colors) {
-  std::array colors{Color::kYellow, Color::kPurple};
+  std::array colors{wpi::util::Color::kYellow,
+                                         wpi::util::Color::kPurple};
   LEDPattern pattern =
       LEDPattern::Gradient(LEDPattern::GradientType::kContinuous, colors);
   std::array buffer;
   pattern.ApplyTo(buffer);
-  AssertIndexColor(buffer, 0, Color::kYellow);
+  AssertIndexColor(buffer, 0, wpi::util::Color::kYellow);
   AssertIndexColor(buffer, 25,
-                   LerpColors(Color::kYellow, Color::kPurple, 25 / 49.0));
-  AssertIndexColor(buffer, 49, Color::kPurple);
+                   LerpColors(wpi::util::Color::kYellow,
+                              wpi::util::Color::kPurple, 25 / 49.0));
+  AssertIndexColor(buffer, 49, wpi::util::Color::kPurple);
   AssertIndexColor(buffer, 74,
-                   LerpColors(Color::kPurple, Color::kYellow, 25 / 49.0));
-  AssertIndexColor(buffer, 98, Color::kYellow);
+                   LerpColors(wpi::util::Color::kPurple,
+                              wpi::util::Color::kYellow, 25 / 49.0));
+  AssertIndexColor(buffer, 98, wpi::util::Color::kYellow);
 }
 
 TEST(LEDPatternTest, DiscontinuousGradient2Colors) {
-  std::array colors{Color::kYellow, Color::kPurple};
+  std::array colors{wpi::util::Color::kYellow,
+                                         wpi::util::Color::kPurple};
   LEDPattern pattern =
       LEDPattern::Gradient(LEDPattern::GradientType::kDiscontinuous, colors);
   std::array buffer;
   pattern.ApplyTo(buffer);
-  AssertIndexColor(buffer, 0, Color::kYellow);
-  AssertIndexColor(buffer, 49, LerpColors(Color::kYellow, Color::kPurple, 0.5));
-  AssertIndexColor(buffer, 98, Color::kPurple);
+  AssertIndexColor(buffer, 0, wpi::util::Color::kYellow);
+  AssertIndexColor(
+      buffer, 49,
+      LerpColors(wpi::util::Color::kYellow, wpi::util::Color::kPurple, 0.5));
+  AssertIndexColor(buffer, 98, wpi::util::Color::kPurple);
 }
 
 TEST(LEDPatternTest, Gradient3Colors) {
-  std::array colors{Color::kYellow, Color::kPurple, Color::kWhite};
+  std::array colors{wpi::util::Color::kYellow,
+                                         wpi::util::Color::kPurple,
+                                         wpi::util::Color::kWhite};
   LEDPattern pattern =
       LEDPattern::Gradient(LEDPattern::GradientType::kContinuous, colors);
   std::array buffer;
   pattern.ApplyTo(buffer);
 
-  AssertIndexColor(buffer, 0, Color::kYellow);
+  AssertIndexColor(buffer, 0, wpi::util::Color::kYellow);
   AssertIndexColor(buffer, 25,
-                   LerpColors(Color::kYellow, Color::kPurple, 25 / 33.0));
-  AssertIndexColor(buffer, 33, Color::kPurple);
+                   LerpColors(wpi::util::Color::kYellow,
+                              wpi::util::Color::kPurple, 25 / 33.0));
+  AssertIndexColor(buffer, 33, wpi::util::Color::kPurple);
   AssertIndexColor(buffer, 58,
-                   LerpColors(Color::kPurple, Color::kWhite, 25 / 33.0));
-  AssertIndexColor(buffer, 66, Color::kWhite);
+                   LerpColors(wpi::util::Color::kPurple,
+                              wpi::util::Color::kWhite, 25 / 33.0));
+  AssertIndexColor(buffer, 66, wpi::util::Color::kWhite);
   AssertIndexColor(buffer, 91,
-                   LerpColors(Color::kWhite, Color::kYellow, 25 / 33.0));
+                   LerpColors(wpi::util::Color::kWhite,
+                              wpi::util::Color::kYellow, 25 / 33.0));
   AssertIndexColor(buffer, 98,
-                   LerpColors(Color::kWhite, Color::kYellow, 32 / 33.0));
+                   LerpColors(wpi::util::Color::kWhite,
+                              wpi::util::Color::kYellow, 32 / 33.0));
 }
 
 TEST(LEDPatternTest, DiscontinuousGradient3Colors) {
-  std::array colors{Color::kYellow, Color::kPurple, Color::kWhite};
+  std::array colors{wpi::util::Color::kYellow,
+                                         wpi::util::Color::kPurple,
+                                         wpi::util::Color::kWhite};
   LEDPattern pattern =
       LEDPattern::Gradient(LEDPattern::GradientType::kDiscontinuous, colors);
   std::array buffer;
   pattern.ApplyTo(buffer);
 
-  AssertIndexColor(buffer, 0, Color::kYellow);
-  AssertIndexColor(buffer, 25, LerpColors(Color::kYellow, Color::kPurple, 0.5));
-  AssertIndexColor(buffer, 50, Color::kPurple);
-  AssertIndexColor(buffer, 75, LerpColors(Color::kPurple, Color::kWhite, 0.5));
-  AssertIndexColor(buffer, 100, Color::kWhite);
+  AssertIndexColor(buffer, 0, wpi::util::Color::kYellow);
+  AssertIndexColor(
+      buffer, 25,
+      LerpColors(wpi::util::Color::kYellow, wpi::util::Color::kPurple, 0.5));
+  AssertIndexColor(buffer, 50, wpi::util::Color::kPurple);
+  AssertIndexColor(
+      buffer, 75,
+      LerpColors(wpi::util::Color::kPurple, wpi::util::Color::kWhite, 0.5));
+  AssertIndexColor(buffer, 100, wpi::util::Color::kWhite);
 }
 
 TEST(LEDPatternTest, EmptyStepsSetsToBlack) {
-  std::array, 0> steps;
+  std::array, 0> steps;
   LEDPattern pattern = LEDPattern::Steps(steps);
   std::array buffer;
 
   // prefill
   for (int i = 0; i < 5; i++) {
-    buffer[i].SetLED(Color::kPurple);
+    buffer[i].SetLED(wpi::util::Color::kPurple);
   }
 
   pattern.ApplyTo(buffer);
 
   for (int i = 0; i < 5; i++) {
-    AssertIndexColor(buffer, i, Color::kBlack);
+    AssertIndexColor(buffer, i, wpi::util::Color::kBlack);
   }
 }
 
 TEST(LEDPatternTest, SingleStepSetsSolid) {
-  std::array, 1> steps{std::pair{0.0, Color::kYellow}};
+  std::array, 1> steps{
+      std::pair{0.0, wpi::util::Color::kYellow}};
   LEDPattern pattern = LEDPattern::Steps(steps);
   std::array buffer;
 
   pattern.ApplyTo(buffer);
 
   for (int i = 0; i < 5; i++) {
-    AssertIndexColor(buffer, i, Color::kYellow);
+    AssertIndexColor(buffer, i, wpi::util::Color::kYellow);
   }
 }
 
 TEST(LEDPatternTest, SingleHalfStepSetsHalfOffHalfColor) {
-  std::array, 1> steps{std::pair{0.5, Color::kYellow}};
+  std::array, 1> steps{
+      std::pair{0.5, wpi::util::Color::kYellow}};
   LEDPattern pattern = LEDPattern::Steps(steps);
   std::array buffer;
 
@@ -167,12 +187,12 @@ TEST(LEDPatternTest, SingleHalfStepSetsHalfOffHalfColor) {
 
   // [0, 48] should be black...
   for (int i = 0; i < 49; i++) {
-    AssertIndexColor(buffer, i, Color::kBlack);
+    AssertIndexColor(buffer, i, wpi::util::Color::kBlack);
   }
 
   // ... and [49, ] should be the color that was set
   for (int i = 49; i < 99; i++) {
-    AssertIndexColor(buffer, i, Color::kYellow);
+    AssertIndexColor(buffer, i, wpi::util::Color::kYellow);
   }
 }
 
@@ -181,7 +201,7 @@ TEST(LEDPatternTest, ScrollRelativeForward) {
   LEDPattern pattern = LEDPattern{[=](auto data, auto writer) {
     for (size_t led = 0; led < data.size(); led++) {
       int ch = static_cast(led % 256);
-      writer(led, Color{ch, ch, ch});
+      writer(led, wpi::util::Color{ch, ch, ch});
     }
   }};
   std::array buffer;
@@ -212,7 +232,7 @@ TEST(LEDPatternTest, ScrollRelativeForward) {
       // t=255, channel value = (1, 2, 3, ..., 255, 0)
       // t=256, channel value = (0, 1, 2, ..., 254, 255)
       int ch = wpi::math::FloorMod(static_cast(led - time), 256);
-      AssertIndexColor(buffer, led, Color{ch, ch, ch});
+      AssertIndexColor(buffer, led, wpi::util::Color{ch, ch, ch});
     }
   }
 
@@ -224,7 +244,7 @@ TEST(LEDPatternTest, ScrollRelativeBackward) {
   LEDPattern pattern = LEDPattern{[=](auto data, auto writer) {
     for (size_t led = 0; led < data.size(); led++) {
       int ch = static_cast(led % 256);
-      writer(led, Color{ch, ch, ch});
+      writer(led, wpi::util::Color{ch, ch, ch});
     }
   }};
   std::array buffer;
@@ -255,7 +275,7 @@ TEST(LEDPatternTest, ScrollRelativeBackward) {
       // t=255, channel value = (1, 2, 3, ..., 255, 0)
       // t=256, channel value = (0, 1, 2, ..., 254, 255)
       int ch = wpi::math::FloorMod(static_cast(led + time), 256);
-      AssertIndexColor(buffer, led, Color{ch, ch, ch});
+      AssertIndexColor(buffer, led, wpi::util::Color{ch, ch, ch});
     }
   }
 
@@ -267,7 +287,7 @@ TEST(LEDPatternTest, ScrollAbsoluteForward) {
   LEDPattern pattern = LEDPattern{[](auto data, auto writer) {
     for (size_t led = 0; led < data.size(); led++) {
       int ch = static_cast(led % 256);
-      writer(led, Color{ch, ch, ch});
+      writer(led, wpi::util::Color{ch, ch, ch});
     }
   }};
   std::array buffer;
@@ -299,7 +319,7 @@ TEST(LEDPatternTest, ScrollAbsoluteForward) {
       // t=255, channel value = (1, 2, 3, ..., 255, 0)
       // t=256, channel value = (0, 1, 2, ..., 254, 255)
       int ch = wpi::math::FloorMod(static_cast(led - time), 256);
-      AssertIndexColor(buffer, led, Color{ch, ch, ch});
+      AssertIndexColor(buffer, led, wpi::util::Color{ch, ch, ch});
     }
   }
 
@@ -311,7 +331,7 @@ TEST(LEDPatternTest, ScrollAbsoluteBackward) {
   LEDPattern pattern = LEDPattern{[](auto data, auto writer) {
     for (size_t led = 0; led < data.size(); led++) {
       int ch = static_cast(led % 256);
-      writer(led, Color{ch, ch, ch});
+      writer(led, wpi::util::Color{ch, ch, ch});
     }
   }};
   std::array buffer;
@@ -343,7 +363,7 @@ TEST(LEDPatternTest, ScrollAbsoluteBackward) {
       // t=255, channel value = (1, 2, 3, ..., 255, 0)
       // t=256, channel value = (0, 1, 2, ..., 254, 255)
       int ch = wpi::math::FloorMod(static_cast(led + time), 256);
-      AssertIndexColor(buffer, led, Color{ch, ch, ch});
+      AssertIndexColor(buffer, led, wpi::util::Color{ch, ch, ch});
     }
   }
 
@@ -358,7 +378,8 @@ TEST(LEDPatternTest, RainbowFullSize) {
   pattern.ApplyTo(buffer);
 
   for (int led = 0; led < 180; led++) {
-    AssertIndexColor(buffer, led, Color::FromHSV(led, saturation, value));
+    AssertIndexColor(buffer, led,
+                     wpi::util::Color::FromHSV(led, saturation, value));
   }
 }
 
@@ -370,7 +391,8 @@ TEST(LEDPatternTest, RainbowHalfSize) {
   pattern.ApplyTo(buffer);
 
   for (int led = 0; led < 90; led++) {
-    AssertIndexColor(buffer, led, Color::FromHSV(led * 2, saturation, value));
+    AssertIndexColor(buffer, led,
+                     wpi::util::Color::FromHSV(led * 2, saturation, value));
   }
 }
 
@@ -383,7 +405,8 @@ TEST(LEDPatternTest, RainbowThirdSize) {
 
   for (int led = 0; led < 60; led++) {
     SCOPED_TRACE(fmt::format("LED {} of 60", led + 1));
-    AssertIndexColor(buffer, led, Color::FromHSV(led * 3, saturation, value));
+    AssertIndexColor(buffer, led,
+                     wpi::util::Color::FromHSV(led * 3, saturation, value));
   }
 }
 
@@ -396,7 +419,8 @@ TEST(LEDPatternTest, RainbowDoubleSize) {
 
   for (int led = 0; led < 360; led++) {
     SCOPED_TRACE(fmt::format("LED {} of 360", led + 1));
-    AssertIndexColor(buffer, led, Color::FromHSV(led / 2, saturation, value));
+    AssertIndexColor(buffer, led,
+                     wpi::util::Color::FromHSV(led / 2, saturation, value));
   }
 }
 
@@ -410,15 +434,15 @@ TEST(LEDPatternTest, RainbowOddSize) {
 
   for (int led = 0; led < 127; led++) {
     SCOPED_TRACE(fmt::format("LED {} of 127", led + 1));
-    AssertIndexColor(
-        buffer, led,
-        Color::FromHSV(static_cast(led * scale), saturation, value));
+    AssertIndexColor(buffer, led,
+                     wpi::util::Color::FromHSV(static_cast(led * scale),
+                                               saturation, value));
   }
 }
 
 TEST(LEDPatternTest, ReverseSolid) {
   std::array buffer;
-  const auto color = Color::kRosyBrown;
+  const auto color = wpi::util::Color::kRosyBrown;
 
   auto solid = LEDPattern::Solid(color);
   auto pattern = solid.Reversed();
@@ -427,14 +451,15 @@ TEST(LEDPatternTest, ReverseSolid) {
 
   for (int led = 0; led < 90; led++) {
     SCOPED_TRACE(fmt::format("LED {} of 90", led + 1));
-    AssertIndexColor(buffer, led, Color::kRosyBrown);
+    AssertIndexColor(buffer, led, wpi::util::Color::kRosyBrown);
   }
 }
 
 TEST(LEDPatternTest, ReverseSteps) {
   std::array buffer;
-  std::array, 2> steps{std::pair{0.0, Color::kPlum},
-                                                std::pair{0.5, Color::kYellow}};
+  std::array, 2> steps{
+      std::pair{0.0, wpi::util::Color::kPlum},
+      std::pair{0.5, wpi::util::Color::kYellow}};
   auto stepPattern = LEDPattern::Steps(steps);
   auto pattern = stepPattern.Reversed();
 
@@ -443,11 +468,11 @@ TEST(LEDPatternTest, ReverseSteps) {
   // colors should be swapped; yellow first, then plum
   for (int led = 0; led < 50; led++) {
     SCOPED_TRACE(fmt::format("LED {} of 100", led + 1));
-    AssertIndexColor(buffer, led, Color::kYellow);
+    AssertIndexColor(buffer, led, wpi::util::Color::kYellow);
   }
   for (int led = 50; led < 100; led++) {
     SCOPED_TRACE(fmt::format("LED {} of 100", led + 1));
-    AssertIndexColor(buffer, led, Color::kPlum);
+    AssertIndexColor(buffer, led, wpi::util::Color::kPlum);
   }
 }
 
@@ -460,13 +485,13 @@ TEST(LEDPatternTest, OffsetPositive) {
     SCOPED_TRACE(fmt::format("LED {} of 21", led + 1));
     switch (led % 3) {
       case 0:
-        AssertIndexColor(buffer, led, Color::kPurple);
+        AssertIndexColor(buffer, led, wpi::util::Color::kPurple);
         break;
       case 1:
-        AssertIndexColor(buffer, led, Color::kWhite);
+        AssertIndexColor(buffer, led, wpi::util::Color::kWhite);
         break;
       case 2:
-        AssertIndexColor(buffer, led, Color::kYellow);
+        AssertIndexColor(buffer, led, wpi::util::Color::kYellow);
         break;
     }
   }
@@ -481,13 +506,13 @@ TEST(LEDPatternTest, OffsetNegative) {
     SCOPED_TRACE(fmt::format("LED {} of 21", led + 1));
     switch (led % 3) {
       case 0:
-        AssertIndexColor(buffer, led, Color::kYellow);
+        AssertIndexColor(buffer, led, wpi::util::Color::kYellow);
         break;
       case 1:
-        AssertIndexColor(buffer, led, Color::kPurple);
+        AssertIndexColor(buffer, led, wpi::util::Color::kPurple);
         break;
       case 2:
-        AssertIndexColor(buffer, led, Color::kWhite);
+        AssertIndexColor(buffer, led, wpi::util::Color::kWhite);
         break;
     }
   }
@@ -502,13 +527,13 @@ TEST(LEDPatternTest, OffsetZero) {
     SCOPED_TRACE(fmt::format("LED {} of 21", led + 1));
     switch (led % 3) {
       case 0:
-        AssertIndexColor(buffer, led, Color::kWhite);
+        AssertIndexColor(buffer, led, wpi::util::Color::kWhite);
         break;
       case 1:
-        AssertIndexColor(buffer, led, Color::kYellow);
+        AssertIndexColor(buffer, led, wpi::util::Color::kYellow);
         break;
       case 2:
-        AssertIndexColor(buffer, led, Color::kPurple);
+        AssertIndexColor(buffer, led, wpi::util::Color::kPurple);
         break;
     }
   }
@@ -516,7 +541,7 @@ TEST(LEDPatternTest, OffsetZero) {
 
 TEST(LEDPatternTest, BlinkSymmetric) {
   std::array buffer;
-  auto white = LEDPattern::Solid(Color::kWhite);
+  auto white = LEDPattern::Solid(wpi::util::Color::kWhite);
 
   // on for 2 seconds, off for 2 seconds
   auto pattern = white.Blink(2_s);
@@ -533,13 +558,13 @@ TEST(LEDPatternTest, BlinkSymmetric) {
       case 1:
       case 4:
       case 5:
-        AssertIndexColor(buffer, 0, Color::kWhite);
+        AssertIndexColor(buffer, 0, wpi::util::Color::kWhite);
         break;
       case 2:
       case 3:
       case 6:
       case 7:
-        AssertIndexColor(buffer, 0, Color::kBlack);
+        AssertIndexColor(buffer, 0, wpi::util::Color::kBlack);
         break;
     }
   }
@@ -549,7 +574,7 @@ TEST(LEDPatternTest, BlinkSymmetric) {
 
 TEST(LEDPatternTest, BlinkAsymmetric) {
   std::array buffer;
-  auto white = LEDPattern::Solid(Color::kWhite);
+  auto white = LEDPattern::Solid(wpi::util::Color::kWhite);
 
   // on for 3 seconds, off for 1 second
   auto pattern = white.Blink(3_s, 1_s);
@@ -568,11 +593,11 @@ TEST(LEDPatternTest, BlinkAsymmetric) {
       case 4:
       case 5:
       case 6:  // second period
-        AssertIndexColor(buffer, 0, Color::kWhite);
+        AssertIndexColor(buffer, 0, wpi::util::Color::kWhite);
         break;
       case 3:
       case 7:
-        AssertIndexColor(buffer, 0, Color::kBlack);
+        AssertIndexColor(buffer, 0, wpi::util::Color::kBlack);
         break;
     }
   }
@@ -582,7 +607,7 @@ TEST(LEDPatternTest, BlinkAsymmetric) {
 
 TEST(LEDPatternTest, BlinkInSync) {
   std::array buffer;
-  auto white = LEDPattern::Solid(Color::kWhite);
+  auto white = LEDPattern::Solid(wpi::util::Color::kWhite);
 
   bool flag = false;
   auto condition = [&flag]() { return flag; };
@@ -591,23 +616,23 @@ TEST(LEDPatternTest, BlinkInSync) {
 
   SCOPED_TRACE("Flag off");
   pattern.ApplyTo(buffer);
-  AssertIndexColor(buffer, 0, Color::kBlack);
+  AssertIndexColor(buffer, 0, wpi::util::Color::kBlack);
 
   SCOPED_TRACE("Flag on");
   flag = true;
   pattern.ApplyTo(buffer);
-  AssertIndexColor(buffer, 0, Color::kWhite);
+  AssertIndexColor(buffer, 0, wpi::util::Color::kWhite);
 
   SCOPED_TRACE("Flag off");
   flag = false;
   pattern.ApplyTo(buffer);
-  AssertIndexColor(buffer, 0, Color::kBlack);
+  AssertIndexColor(buffer, 0, wpi::util::Color::kBlack);
 }
 
 TEST(LEDPatternTest, Breathe) {
-  Color midGray{0.5, 0.5, 0.5};
+  wpi::util::Color midGray{0.5, 0.5, 0.5};
   std::array buffer;
-  auto white = LEDPattern::Solid(Color::kWhite);
+  auto white = LEDPattern::Solid(wpi::util::Color::kWhite);
   auto pattern = white.Breathe(4_us);
 
   static uint64_t now = 0ull;
@@ -618,7 +643,7 @@ TEST(LEDPatternTest, Breathe) {
     SCOPED_TRACE(fmt::format("Time {}", now));
 
     pattern.ApplyTo(buffer);
-    AssertIndexColor(buffer, 0, Color::kWhite);
+    AssertIndexColor(buffer, 0, wpi::util::Color::kWhite);
   }
   {
     now = 1ull;  // midway (down)
@@ -632,7 +657,7 @@ TEST(LEDPatternTest, Breathe) {
     SCOPED_TRACE(fmt::format("Time {}", now));
 
     pattern.ApplyTo(buffer);
-    AssertIndexColor(buffer, 0, Color::kBlack);
+    AssertIndexColor(buffer, 0, wpi::util::Color::kBlack);
   }
   {
     now = 3ull;  // midway (up)
@@ -646,7 +671,7 @@ TEST(LEDPatternTest, Breathe) {
     SCOPED_TRACE(fmt::format("Time {}", now));
 
     pattern.ApplyTo(buffer);
-    AssertIndexColor(buffer, 0, Color::kWhite);
+    AssertIndexColor(buffer, 0, wpi::util::Color::kWhite);
   }
   WPI_SetNowImpl(nullptr);  // cleanup
 }
@@ -654,61 +679,63 @@ TEST(LEDPatternTest, Breathe) {
 TEST(LEDPatternTest, OverlaySolidOnSolid) {
   std::array buffer;
 
-  auto base = LEDPattern::Solid(Color::kWhite);
-  auto overlay = LEDPattern::Solid(Color::kYellow);
+  auto base = LEDPattern::Solid(wpi::util::Color::kWhite);
+  auto overlay = LEDPattern::Solid(wpi::util::Color::kYellow);
   auto pattern = overlay.OverlayOn(base);
   pattern.ApplyTo(buffer);
 
-  AssertIndexColor(buffer, 0, Color::kYellow);
+  AssertIndexColor(buffer, 0, wpi::util::Color::kYellow);
 }
 
 TEST(LEDPatternTest, OverlayNearlyBlack) {
   std::array buffer;
 
-  auto base = LEDPattern::Solid(Color::kWhite);
-  auto overlay = LEDPattern::Solid(Color{1, 0, 0});
+  auto base = LEDPattern::Solid(wpi::util::Color::kWhite);
+  auto overlay = LEDPattern::Solid(wpi::util::Color{1, 0, 0});
   auto pattern = overlay.OverlayOn(base);
   pattern.ApplyTo(buffer);
 
-  AssertIndexColor(buffer, 0, Color{1, 0, 0});
+  AssertIndexColor(buffer, 0, wpi::util::Color{1, 0, 0});
 }
 
 TEST(LEDPatternTest, OverlayMixed) {
   std::array buffer;
 
-  auto base = LEDPattern::Solid(Color::kWhite);
-  std::array, 2> steps{std::pair{0.0, Color::kYellow},
-                                                std::pair{0.5, Color::kBlack}};
+  auto base = LEDPattern::Solid(wpi::util::Color::kWhite);
+  std::array, 2> steps{
+      std::pair{0.0, wpi::util::Color::kYellow},
+      std::pair{0.5, wpi::util::Color::kBlack}};
   auto overlay = LEDPattern::Steps(steps);
   auto pattern = overlay.OverlayOn(base);
   pattern.ApplyTo(buffer);
 
-  AssertIndexColor(buffer, 0, Color::kYellow);
-  AssertIndexColor(buffer, 1, Color::kWhite);
+  AssertIndexColor(buffer, 0, wpi::util::Color::kYellow);
+  AssertIndexColor(buffer, 1, wpi::util::Color::kWhite);
 }
 
 TEST(LEDPatternTest, Blend) {
   std::array buffer;
 
-  auto pattern1 = LEDPattern::Solid(Color::kBlue);
-  auto pattern2 = LEDPattern::Solid(Color::kRed);
+  auto pattern1 = LEDPattern::Solid(wpi::util::Color::kBlue);
+  auto pattern2 = LEDPattern::Solid(wpi::util::Color::kRed);
   auto blend = pattern1.Blend(pattern2);
   blend.ApplyTo(buffer);
 
   // Individual RGB channels are averaged
   // #0000FF blended with #FF0000 yields #7F007F
-  AssertIndexColor(buffer, 0, Color{127, 0, 127});
+  AssertIndexColor(buffer, 0, wpi::util::Color{127, 0, 127});
 }
 
 TEST(LEDPatternTest, BinaryMask) {
   std::array buffer;
 
-  Color color{123, 123, 123};
+  wpi::util::Color color{123, 123, 123};
   auto base = LEDPattern::Solid(color);
 
   // first 50% mask on, last 50% mask off
-  std::array, 2> steps{std::pair{0.0, Color::kWhite},
-                                                std::pair{0.5, Color::kBlack}};
+  std::array, 2> steps{
+      std::pair{0.0, wpi::util::Color::kWhite},
+      std::pair{0.5, wpi::util::Color::kBlack}};
   auto mask = LEDPattern::Steps(steps);
   auto masked = base.Mask(mask);
   masked.ApplyTo(buffer);
@@ -718,27 +745,28 @@ TEST(LEDPatternTest, BinaryMask) {
   }
 
   for (int i = 5; i < 10; i++) {
-    AssertIndexColor(buffer, i, Color::kBlack);
+    AssertIndexColor(buffer, i, wpi::util::Color::kBlack);
   }
 }
 
 TEST(LEDPatternTest, ChannelwiseMask) {
   std::array buffer;
 
-  Color baseColor{123, 123, 123};
-  Color halfGray{0.5, 0.5, 0.5};
+  wpi::util::Color baseColor{123, 123, 123};
+  wpi::util::Color halfGray{0.5, 0.5, 0.5};
   auto base = LEDPattern::Solid(baseColor);
-  std::array, 5> steps{
-      std::pair{0.0, Color::kRed}, std::pair{0.2, Color::kLime},
-      std::pair{0.4, Color::kBlue}, std::pair{0.6, halfGray},
-      std::pair{0.8, Color::kWhite}};
+  std::array, 5> steps{
+      std::pair{0.0, wpi::util::Color::kRed},
+      std::pair{0.2, wpi::util::Color::kLime},
+      std::pair{0.4, wpi::util::Color::kBlue}, std::pair{0.6, halfGray},
+      std::pair{0.8, wpi::util::Color::kWhite}};
   auto mask = LEDPattern::Steps(steps);
   auto masked = base.Mask(mask);
   masked.ApplyTo(buffer);
 
-  AssertIndexColor(buffer, 0, Color{123, 0, 0});
-  AssertIndexColor(buffer, 1, Color{0, 123, 0});
-  AssertIndexColor(buffer, 2, Color{0, 0, 123});
+  AssertIndexColor(buffer, 0, wpi::util::Color{123, 0, 0});
+  AssertIndexColor(buffer, 1, wpi::util::Color{0, 123, 0});
+  AssertIndexColor(buffer, 2, wpi::util::Color{0, 0, 123});
 
   // mask channels are all 0b00111111, base is 0b00111011,
   // so the AND should give us the unmodified base color
@@ -761,11 +789,11 @@ TEST(LEDPatternTest, ProcessMaskLayer) {
     int lastMaskedLED = static_cast(t * 100);
     for (int i = 0; i < lastMaskedLED; i++) {
       SCOPED_TRACE(fmt::format("LED {}", i));
-      AssertIndexColor(buffer, i, Color::kWhite);
+      AssertIndexColor(buffer, i, wpi::util::Color::kWhite);
     }
     for (int i = lastMaskedLED; i < 100; i++) {
       SCOPED_TRACE(fmt::format("LED {}", i));
-      AssertIndexColor(buffer, i, Color::kBlack);
+      AssertIndexColor(buffer, i, wpi::util::Color::kBlack);
     }
   }
 }
@@ -773,55 +801,58 @@ TEST(LEDPatternTest, ProcessMaskLayer) {
 TEST(LEDPatternTest, ZeroBrightness) {
   std::array buffer;
 
-  auto base = LEDPattern::Solid(Color::kRed);
+  auto base = LEDPattern::Solid(wpi::util::Color::kRed);
   auto pattern = base.AtBrightness(0);
   pattern.ApplyTo(buffer);
-  AssertIndexColor(buffer, 0, Color::kBlack);
+  AssertIndexColor(buffer, 0, wpi::util::Color::kBlack);
 }
 
 TEST(LEDPatternTest, SameBrightness) {
   std::array buffer;
 
-  auto base = LEDPattern::Solid(Color::kMagenta);
+  auto base = LEDPattern::Solid(wpi::util::Color::kMagenta);
   auto pattern = base.AtBrightness(1.0);
   pattern.ApplyTo(buffer);
-  AssertIndexColor(buffer, 0, Color::kMagenta);
+  AssertIndexColor(buffer, 0, wpi::util::Color::kMagenta);
 }
 
 TEST(LEDPatternTest, HigherBrightness) {
   std::array buffer;
 
-  auto base = LEDPattern::Solid(Color::kMagenta);
+  auto base = LEDPattern::Solid(wpi::util::Color::kMagenta);
   auto pattern = base.AtBrightness(4 / 3.0);
   pattern.ApplyTo(buffer);
-  AssertIndexColor(buffer, 0, Color::kMagenta);
+  AssertIndexColor(buffer, 0, wpi::util::Color::kMagenta);
 }
 
 TEST(LEDPatternTest, NegativeBrightness) {
   std::array buffer;
 
-  auto base = LEDPattern::Solid(Color::kWhite);
+  auto base = LEDPattern::Solid(wpi::util::Color::kWhite);
   auto pattern = base.AtBrightness(-1.0);
   pattern.ApplyTo(buffer);
-  AssertIndexColor(buffer, 0, Color::kBlack);
+  AssertIndexColor(buffer, 0, wpi::util::Color::kBlack);
 }
 
 TEST(LEDPatternTest, ClippingBrightness) {
   std::array buffer;
-  auto base = LEDPattern::Solid(Color::kMidnightBlue);
+  auto base = LEDPattern::Solid(wpi::util::Color::kMidnightBlue);
   auto pattern = base.AtBrightness(100);
   pattern.ApplyTo(buffer);
-  AssertIndexColor(buffer, 0, Color::kWhite);
+  AssertIndexColor(buffer, 0, wpi::util::Color::kWhite);
 }
 
 TEST(LEDPatternTest, ReverseMask) {
   std::array buffer;
 
-  std::array, 4> colorSteps{
-      std::pair{0.0, Color::kRed}, std::pair{0.25, Color::kBlue},
-      std::pair{0.5, Color::kYellow}, std::pair{0.75, Color::kGreen}};
-  std::array, 2> maskSteps{
-      std::pair{0, Color::kWhite}, std::pair{0.5, Color::kBlack}};
+  std::array, 4> colorSteps{
+      std::pair{0.0, wpi::util::Color::kRed},
+      std::pair{0.25, wpi::util::Color::kBlue},
+      std::pair{0.5, wpi::util::Color::kYellow},
+      std::pair{0.75, wpi::util::Color::kGreen}};
+  std::array, 2> maskSteps{
+      std::pair{0, wpi::util::Color::kWhite},
+      std::pair{0.5, wpi::util::Color::kBlack}};
 
   auto pattern = LEDPattern::Steps(colorSteps)
                      .Mask(LEDPattern::Steps(maskSteps))
@@ -829,24 +860,27 @@ TEST(LEDPatternTest, ReverseMask) {
 
   pattern.ApplyTo(buffer);
 
-  AssertIndexColor(buffer, 7, Color::kRed);
-  AssertIndexColor(buffer, 6, Color::kRed);
-  AssertIndexColor(buffer, 5, Color::kBlue);
-  AssertIndexColor(buffer, 4, Color::kBlue);
-  AssertIndexColor(buffer, 3, Color::kBlack);
-  AssertIndexColor(buffer, 2, Color::kBlack);
-  AssertIndexColor(buffer, 1, Color::kBlack);
-  AssertIndexColor(buffer, 0, Color::kBlack);
+  AssertIndexColor(buffer, 7, wpi::util::Color::kRed);
+  AssertIndexColor(buffer, 6, wpi::util::Color::kRed);
+  AssertIndexColor(buffer, 5, wpi::util::Color::kBlue);
+  AssertIndexColor(buffer, 4, wpi::util::Color::kBlue);
+  AssertIndexColor(buffer, 3, wpi::util::Color::kBlack);
+  AssertIndexColor(buffer, 2, wpi::util::Color::kBlack);
+  AssertIndexColor(buffer, 1, wpi::util::Color::kBlack);
+  AssertIndexColor(buffer, 0, wpi::util::Color::kBlack);
 }
 
 TEST(LEDPatternTest, OffsetMask) {
   std::array buffer;
 
-  std::array, 4> colorSteps{
-      std::pair{0.0, Color::kRed}, std::pair{0.25, Color::kBlue},
-      std::pair{0.5, Color::kYellow}, std::pair{0.75, Color::kGreen}};
-  std::array, 2> maskSteps{
-      std::pair{0, Color::kWhite}, std::pair{0.5, Color::kBlack}};
+  std::array, 4> colorSteps{
+      std::pair{0.0, wpi::util::Color::kRed},
+      std::pair{0.25, wpi::util::Color::kBlue},
+      std::pair{0.5, wpi::util::Color::kYellow},
+      std::pair{0.75, wpi::util::Color::kGreen}};
+  std::array, 2> maskSteps{
+      std::pair{0, wpi::util::Color::kWhite},
+      std::pair{0.5, wpi::util::Color::kBlack}};
 
   auto pattern = LEDPattern::Steps(colorSteps)
                      .Mask(LEDPattern::Steps(maskSteps))
@@ -854,24 +888,27 @@ TEST(LEDPatternTest, OffsetMask) {
 
   pattern.ApplyTo(buffer);
 
-  AssertIndexColor(buffer, 0, Color::kBlack);
-  AssertIndexColor(buffer, 1, Color::kBlack);
-  AssertIndexColor(buffer, 2, Color::kBlack);
-  AssertIndexColor(buffer, 3, Color::kBlack);
-  AssertIndexColor(buffer, 4, Color::kRed);
-  AssertIndexColor(buffer, 5, Color::kRed);
-  AssertIndexColor(buffer, 6, Color::kBlue);
-  AssertIndexColor(buffer, 7, Color::kBlue);
+  AssertIndexColor(buffer, 0, wpi::util::Color::kBlack);
+  AssertIndexColor(buffer, 1, wpi::util::Color::kBlack);
+  AssertIndexColor(buffer, 2, wpi::util::Color::kBlack);
+  AssertIndexColor(buffer, 3, wpi::util::Color::kBlack);
+  AssertIndexColor(buffer, 4, wpi::util::Color::kRed);
+  AssertIndexColor(buffer, 5, wpi::util::Color::kRed);
+  AssertIndexColor(buffer, 6, wpi::util::Color::kBlue);
+  AssertIndexColor(buffer, 7, wpi::util::Color::kBlue);
 }
 
 TEST(LEDPatternTest, RelativeScrollingMask) {
   std::array buffer;
 
-  std::array, 4> colorSteps{
-      std::pair{0.0, Color::kRed}, std::pair{0.25, Color::kBlue},
-      std::pair{0.5, Color::kYellow}, std::pair{0.75, Color::kGreen}};
-  std::array, 2> maskSteps{
-      std::pair{0, Color::kWhite}, std::pair{0.5, Color::kBlack}};
+  std::array, 4> colorSteps{
+      std::pair{0.0, wpi::util::Color::kRed},
+      std::pair{0.25, wpi::util::Color::kBlue},
+      std::pair{0.5, wpi::util::Color::kYellow},
+      std::pair{0.75, wpi::util::Color::kGreen}};
+  std::array, 2> maskSteps{
+      std::pair{0, wpi::util::Color::kWhite},
+      std::pair{0.5, wpi::util::Color::kBlack}};
 
   auto pattern = LEDPattern::Steps(colorSteps)
                      .Mask(LEDPattern::Steps(maskSteps))
@@ -888,14 +925,14 @@ TEST(LEDPatternTest, RelativeScrollingMask) {
 
     pattern.ApplyTo(buffer);
 
-    AssertIndexColor(buffer, 0, Color::kRed);
-    AssertIndexColor(buffer, 1, Color::kRed);
-    AssertIndexColor(buffer, 2, Color::kBlue);
-    AssertIndexColor(buffer, 3, Color::kBlue);
-    AssertIndexColor(buffer, 4, Color::kBlack);
-    AssertIndexColor(buffer, 5, Color::kBlack);
-    AssertIndexColor(buffer, 6, Color::kBlack);
-    AssertIndexColor(buffer, 7, Color::kBlack);
+    AssertIndexColor(buffer, 0, wpi::util::Color::kRed);
+    AssertIndexColor(buffer, 1, wpi::util::Color::kRed);
+    AssertIndexColor(buffer, 2, wpi::util::Color::kBlue);
+    AssertIndexColor(buffer, 3, wpi::util::Color::kBlue);
+    AssertIndexColor(buffer, 4, wpi::util::Color::kBlack);
+    AssertIndexColor(buffer, 5, wpi::util::Color::kBlack);
+    AssertIndexColor(buffer, 6, wpi::util::Color::kBlack);
+    AssertIndexColor(buffer, 7, wpi::util::Color::kBlack);
   }
   {
     now = 1ull;
@@ -903,14 +940,14 @@ TEST(LEDPatternTest, RelativeScrollingMask) {
 
     pattern.ApplyTo(buffer);
 
-    AssertIndexColor(buffer, 0, Color::kBlack);
-    AssertIndexColor(buffer, 1, Color::kRed);
-    AssertIndexColor(buffer, 2, Color::kRed);
-    AssertIndexColor(buffer, 3, Color::kBlue);
-    AssertIndexColor(buffer, 4, Color::kBlue);
-    AssertIndexColor(buffer, 5, Color::kBlack);
-    AssertIndexColor(buffer, 6, Color::kBlack);
-    AssertIndexColor(buffer, 7, Color::kBlack);
+    AssertIndexColor(buffer, 0, wpi::util::Color::kBlack);
+    AssertIndexColor(buffer, 1, wpi::util::Color::kRed);
+    AssertIndexColor(buffer, 2, wpi::util::Color::kRed);
+    AssertIndexColor(buffer, 3, wpi::util::Color::kBlue);
+    AssertIndexColor(buffer, 4, wpi::util::Color::kBlue);
+    AssertIndexColor(buffer, 5, wpi::util::Color::kBlack);
+    AssertIndexColor(buffer, 6, wpi::util::Color::kBlack);
+    AssertIndexColor(buffer, 7, wpi::util::Color::kBlack);
   }
   {
     now = 2ull;
@@ -918,14 +955,14 @@ TEST(LEDPatternTest, RelativeScrollingMask) {
 
     pattern.ApplyTo(buffer);
 
-    AssertIndexColor(buffer, 0, Color::kBlack);
-    AssertIndexColor(buffer, 1, Color::kBlack);
-    AssertIndexColor(buffer, 2, Color::kRed);
-    AssertIndexColor(buffer, 3, Color::kRed);
-    AssertIndexColor(buffer, 4, Color::kBlue);
-    AssertIndexColor(buffer, 5, Color::kBlue);
-    AssertIndexColor(buffer, 6, Color::kBlack);
-    AssertIndexColor(buffer, 7, Color::kBlack);
+    AssertIndexColor(buffer, 0, wpi::util::Color::kBlack);
+    AssertIndexColor(buffer, 1, wpi::util::Color::kBlack);
+    AssertIndexColor(buffer, 2, wpi::util::Color::kRed);
+    AssertIndexColor(buffer, 3, wpi::util::Color::kRed);
+    AssertIndexColor(buffer, 4, wpi::util::Color::kBlue);
+    AssertIndexColor(buffer, 5, wpi::util::Color::kBlue);
+    AssertIndexColor(buffer, 6, wpi::util::Color::kBlack);
+    AssertIndexColor(buffer, 7, wpi::util::Color::kBlack);
   }
   {
     now = 3ull;
@@ -933,14 +970,14 @@ TEST(LEDPatternTest, RelativeScrollingMask) {
 
     pattern.ApplyTo(buffer);
 
-    AssertIndexColor(buffer, 0, Color::kBlack);
-    AssertIndexColor(buffer, 1, Color::kBlack);
-    AssertIndexColor(buffer, 2, Color::kBlack);
-    AssertIndexColor(buffer, 3, Color::kRed);
-    AssertIndexColor(buffer, 4, Color::kRed);
-    AssertIndexColor(buffer, 5, Color::kBlue);
-    AssertIndexColor(buffer, 6, Color::kBlue);
-    AssertIndexColor(buffer, 7, Color::kBlack);
+    AssertIndexColor(buffer, 0, wpi::util::Color::kBlack);
+    AssertIndexColor(buffer, 1, wpi::util::Color::kBlack);
+    AssertIndexColor(buffer, 2, wpi::util::Color::kBlack);
+    AssertIndexColor(buffer, 3, wpi::util::Color::kRed);
+    AssertIndexColor(buffer, 4, wpi::util::Color::kRed);
+    AssertIndexColor(buffer, 5, wpi::util::Color::kBlue);
+    AssertIndexColor(buffer, 6, wpi::util::Color::kBlue);
+    AssertIndexColor(buffer, 7, wpi::util::Color::kBlack);
   }
 
   WPI_SetNowImpl(nullptr);  // cleanup
@@ -949,11 +986,14 @@ TEST(LEDPatternTest, RelativeScrollingMask) {
 TEST(LEDPatternTest, AbsoluteScrollingMask) {
   std::array buffer;
 
-  std::array, 4> colorSteps{
-      std::pair{0.0, Color::kRed}, std::pair{0.25, Color::kBlue},
-      std::pair{0.5, Color::kYellow}, std::pair{0.75, Color::kGreen}};
-  std::array, 2> maskSteps{
-      std::pair{0, Color::kWhite}, std::pair{0.5, Color::kBlack}};
+  std::array, 4> colorSteps{
+      std::pair{0.0, wpi::util::Color::kRed},
+      std::pair{0.25, wpi::util::Color::kBlue},
+      std::pair{0.5, wpi::util::Color::kYellow},
+      std::pair{0.75, wpi::util::Color::kGreen}};
+  std::array, 2> maskSteps{
+      std::pair{0, wpi::util::Color::kWhite},
+      std::pair{0.5, wpi::util::Color::kBlack}};
 
   auto pattern = LEDPattern::Steps(colorSteps)
                      .Mask(LEDPattern::Steps(maskSteps))
@@ -970,14 +1010,14 @@ TEST(LEDPatternTest, AbsoluteScrollingMask) {
 
     pattern.ApplyTo(buffer);
 
-    AssertIndexColor(buffer, 0, Color::kRed);
-    AssertIndexColor(buffer, 1, Color::kRed);
-    AssertIndexColor(buffer, 2, Color::kBlue);
-    AssertIndexColor(buffer, 3, Color::kBlue);
-    AssertIndexColor(buffer, 4, Color::kBlack);
-    AssertIndexColor(buffer, 5, Color::kBlack);
-    AssertIndexColor(buffer, 6, Color::kBlack);
-    AssertIndexColor(buffer, 7, Color::kBlack);
+    AssertIndexColor(buffer, 0, wpi::util::Color::kRed);
+    AssertIndexColor(buffer, 1, wpi::util::Color::kRed);
+    AssertIndexColor(buffer, 2, wpi::util::Color::kBlue);
+    AssertIndexColor(buffer, 3, wpi::util::Color::kBlue);
+    AssertIndexColor(buffer, 4, wpi::util::Color::kBlack);
+    AssertIndexColor(buffer, 5, wpi::util::Color::kBlack);
+    AssertIndexColor(buffer, 6, wpi::util::Color::kBlack);
+    AssertIndexColor(buffer, 7, wpi::util::Color::kBlack);
   }
   {
     now = 1000000ull;
@@ -985,14 +1025,14 @@ TEST(LEDPatternTest, AbsoluteScrollingMask) {
 
     pattern.ApplyTo(buffer);
 
-    AssertIndexColor(buffer, 0, Color::kBlack);
-    AssertIndexColor(buffer, 1, Color::kRed);
-    AssertIndexColor(buffer, 2, Color::kRed);
-    AssertIndexColor(buffer, 3, Color::kBlue);
-    AssertIndexColor(buffer, 4, Color::kBlue);
-    AssertIndexColor(buffer, 5, Color::kBlack);
-    AssertIndexColor(buffer, 6, Color::kBlack);
-    AssertIndexColor(buffer, 7, Color::kBlack);
+    AssertIndexColor(buffer, 0, wpi::util::Color::kBlack);
+    AssertIndexColor(buffer, 1, wpi::util::Color::kRed);
+    AssertIndexColor(buffer, 2, wpi::util::Color::kRed);
+    AssertIndexColor(buffer, 3, wpi::util::Color::kBlue);
+    AssertIndexColor(buffer, 4, wpi::util::Color::kBlue);
+    AssertIndexColor(buffer, 5, wpi::util::Color::kBlack);
+    AssertIndexColor(buffer, 6, wpi::util::Color::kBlack);
+    AssertIndexColor(buffer, 7, wpi::util::Color::kBlack);
   }
   {
     now = 2000000ull;
@@ -1000,14 +1040,14 @@ TEST(LEDPatternTest, AbsoluteScrollingMask) {
 
     pattern.ApplyTo(buffer);
 
-    AssertIndexColor(buffer, 0, Color::kBlack);
-    AssertIndexColor(buffer, 1, Color::kBlack);
-    AssertIndexColor(buffer, 2, Color::kRed);
-    AssertIndexColor(buffer, 3, Color::kRed);
-    AssertIndexColor(buffer, 4, Color::kBlue);
-    AssertIndexColor(buffer, 5, Color::kBlue);
-    AssertIndexColor(buffer, 6, Color::kBlack);
-    AssertIndexColor(buffer, 7, Color::kBlack);
+    AssertIndexColor(buffer, 0, wpi::util::Color::kBlack);
+    AssertIndexColor(buffer, 1, wpi::util::Color::kBlack);
+    AssertIndexColor(buffer, 2, wpi::util::Color::kRed);
+    AssertIndexColor(buffer, 3, wpi::util::Color::kRed);
+    AssertIndexColor(buffer, 4, wpi::util::Color::kBlue);
+    AssertIndexColor(buffer, 5, wpi::util::Color::kBlue);
+    AssertIndexColor(buffer, 6, wpi::util::Color::kBlack);
+    AssertIndexColor(buffer, 7, wpi::util::Color::kBlack);
   }
   {
     now = 3000000ull;
@@ -1015,31 +1055,31 @@ TEST(LEDPatternTest, AbsoluteScrollingMask) {
 
     pattern.ApplyTo(buffer);
 
-    AssertIndexColor(buffer, 0, Color::kBlack);
-    AssertIndexColor(buffer, 1, Color::kBlack);
-    AssertIndexColor(buffer, 2, Color::kBlack);
-    AssertIndexColor(buffer, 3, Color::kRed);
-    AssertIndexColor(buffer, 4, Color::kRed);
-    AssertIndexColor(buffer, 5, Color::kBlue);
-    AssertIndexColor(buffer, 6, Color::kBlue);
-    AssertIndexColor(buffer, 7, Color::kBlack);
+    AssertIndexColor(buffer, 0, wpi::util::Color::kBlack);
+    AssertIndexColor(buffer, 1, wpi::util::Color::kBlack);
+    AssertIndexColor(buffer, 2, wpi::util::Color::kBlack);
+    AssertIndexColor(buffer, 3, wpi::util::Color::kRed);
+    AssertIndexColor(buffer, 4, wpi::util::Color::kRed);
+    AssertIndexColor(buffer, 5, wpi::util::Color::kBlue);
+    AssertIndexColor(buffer, 6, wpi::util::Color::kBlue);
+    AssertIndexColor(buffer, 7, wpi::util::Color::kBlack);
   }
 
   WPI_SetNowImpl(nullptr);  // cleanup
 }
 
 void AssertIndexColor(std::span data, int index,
-                      Color color) {
-  wpi::Color8Bit color8bit{color};
+                      wpi::util::Color color) {
+  wpi::util::Color8Bit color8bit{color};
 
   EXPECT_EQ(color8bit.red, data[index].r & 0xFF);
   EXPECT_EQ(color8bit.green, data[index].g & 0xFF);
   EXPECT_EQ(color8bit.blue, data[index].b & 0xFF);
 }
 
-Color LerpColors(Color a, Color b, double t) {
-  return Color{wpi::util::Lerp(a.red, b.red, t),
-               wpi::util::Lerp(a.green, b.green, t),
-               wpi::util::Lerp(a.blue, b.blue, t)};
+wpi::util::Color LerpColors(wpi::util::Color a, wpi::util::Color b, double t) {
+  return wpi::util::Color{wpi::util::Lerp(a.red, b.red, t),
+                          wpi::util::Lerp(a.green, b.green, t),
+                          wpi::util::Lerp(a.blue, b.blue, t)};
 }
 }  // namespace wpi
diff --git a/wpilibc/src/test/native/cpp/smartdashboard/Mechanism2dTest.cpp b/wpilibc/src/test/native/cpp/smartdashboard/Mechanism2dTest.cpp
index 6c8f00612c..e30c5d0ca2 100644
--- a/wpilibc/src/test/native/cpp/smartdashboard/Mechanism2dTest.cpp
+++ b/wpilibc/src/test/native/cpp/smartdashboard/Mechanism2dTest.cpp
@@ -60,7 +60,7 @@ TEST(Mechanism2dTest, Ligament) {
   wpi::MechanismRoot2d* root = mechanism.GetRoot("root", 1, 2);
   wpi::MechanismLigament2d* ligament = root->Append(
       "ligament", 3, wpi::units::degree_t{90}, 1,
-      wpi::Color8Bit{255, 255, 255});
+      wpi::util::Color8Bit{255, 255, 255});
   wpi::SmartDashboard::PutData("mechanism", &mechanism);
   EXPECT_EQ(ligament->GetAngle(), angleEntry.GetDouble(0.0));
   EXPECT_EQ(ligament->GetColor().HexString(), colorEntry.GetString(""));
diff --git a/wpilibcExamples/src/main/cpp/examples/ArmSimulation/include/subsystems/Arm.hpp b/wpilibcExamples/src/main/cpp/examples/ArmSimulation/include/subsystems/Arm.hpp
index bb3e7dcd46..cc0a266dd2 100644
--- a/wpilibcExamples/src/main/cpp/examples/ArmSimulation/include/subsystems/Arm.hpp
+++ b/wpilibcExamples/src/main/cpp/examples/ArmSimulation/include/subsystems/Arm.hpp
@@ -61,7 +61,9 @@ class Arm {
   wpi::MechanismRoot2d* m_armBase = m_mech2d.GetRoot("ArmBase", 30, 30);
   wpi::MechanismLigament2d* m_armTower =
       m_armBase->Append(
-          "Arm Tower", 30, -90_deg, 6, wpi::Color8Bit{wpi::Color::kBlue});
+          "Arm Tower", 30, -90_deg, 6,
+          wpi::util::Color8Bit{wpi::util::Color::kBlue});
   wpi::MechanismLigament2d* m_arm = m_armBase->Append(
-      "Arm", 30, m_armSim.GetAngle(), 6, wpi::Color8Bit{wpi::Color::kYellow});
+      "Arm", 30, m_armSim.GetAngle(), 6,
+      wpi::util::Color8Bit{wpi::util::Color::kYellow});
 };
diff --git a/wpilibcExamples/src/main/cpp/examples/Mechanism2d/cpp/Robot.cpp b/wpilibcExamples/src/main/cpp/examples/Mechanism2d/cpp/Robot.cpp
index 6191acce96..57c149e21c 100644
--- a/wpilibcExamples/src/main/cpp/examples/Mechanism2d/cpp/Robot.cpp
+++ b/wpilibcExamples/src/main/cpp/examples/Mechanism2d/cpp/Robot.cpp
@@ -66,7 +66,8 @@ class Robot : public wpi::TimedRobot {
       m_root->Append("elevator", 1, 90_deg);
   wpi::MechanismLigament2d* m_wrist =
       m_elevator->Append(
-          "wrist", 0.5, 90_deg, 6, wpi::Color8Bit{wpi::Color::kPurple});
+          "wrist", 0.5, 90_deg, 6,
+          wpi::util::Color8Bit{wpi::util::Color::kPurple});
 };
 
 #ifndef RUNNING_WPILIB_TESTS
diff --git a/wpiutil/robotpy_pybind_build_info.bzl b/wpiutil/robotpy_pybind_build_info.bzl
index 7c366273bb..15af0fa32f 100644
--- a/wpiutil/robotpy_pybind_build_info.bzl
+++ b/wpiutil/robotpy_pybind_build_info.bzl
@@ -8,6 +8,26 @@ load("//shared/bazel/rules/robotpy:semiwrap_tool_helpers.bzl", "scan_headers", "
 
 def wpiutil_extension(srcs = [], header_to_dat_deps = [], extra_hdrs = [], includes = [], extra_pyi_deps = []):
     WPIUTIL_HEADER_GEN = [
+        struct(
+            class_name = "Color",
+            yml_file = "semiwrap/Color.yml",
+            header_root = "$(execpath :robotpy-native-wpiutil.copy_headers)",
+            header_file = "$(execpath :robotpy-native-wpiutil.copy_headers)/wpi/util/Color.hpp",
+            tmpl_class_names = [],
+            trampolines = [
+                ("wpi::util::Color", "wpi__util__Color.hpp"),
+            ],
+        ),
+        struct(
+            class_name = "Color8Bit",
+            yml_file = "semiwrap/Color8Bit.yml",
+            header_root = "$(execpath :robotpy-native-wpiutil.copy_headers)",
+            header_file = "$(execpath :robotpy-native-wpiutil.copy_headers)/wpi/util/Color8Bit.hpp",
+            tmpl_class_names = [],
+            trampolines = [
+                ("wpi::util::Color8Bit", "wpi__util__Color8Bit.hpp"),
+            ],
+        ),
         struct(
             class_name = "StackTrace",
             yml_file = "semiwrap/StackTrace.yml",
diff --git a/wpilibj/src/main/java/org/wpilib/util/Color.java b/wpiutil/src/main/java/org/wpilib/util/Color.java
similarity index 99%
rename from wpilibj/src/main/java/org/wpilib/util/Color.java
rename to wpiutil/src/main/java/org/wpilib/util/Color.java
index b3113c4e0d..1895c2a07b 100644
--- a/wpilibj/src/main/java/org/wpilib/util/Color.java
+++ b/wpiutil/src/main/java/org/wpilib/util/Color.java
@@ -5,7 +5,6 @@
 package org.wpilib.util;
 
 import java.util.Objects;
-import org.wpilib.math.util.MathUtil;
 
 /**
  * Represents colors.
@@ -197,6 +196,10 @@ public class Color {
     return Math.clamp(Math.ceil(value * (1 << 12)) / (1 << 12), 0.0, 1.0);
   }
 
+  private static int lerp(int a, int b, double t) {
+    return (int) (a + (b - a) * t);
+  }
+
   // Helper methods
 
   /**
@@ -369,10 +372,7 @@ public class Color {
    * @return the interpolated color, packed in a 32-bit integer
    */
   public static int lerpRGB(int r1, int g1, int b1, int r2, int g2, int b2, double t) {
-    return packRGB(
-        (int) MathUtil.lerp(r1, r2, t),
-        (int) MathUtil.lerp(g1, g2, t),
-        (int) MathUtil.lerp(b1, b2, t));
+    return packRGB(lerp(r1, r2, t), lerp(g1, g2, t), lerp(b1, b2, t));
   }
 
   /*
diff --git a/wpilibj/src/main/java/org/wpilib/util/Color8Bit.java b/wpiutil/src/main/java/org/wpilib/util/Color8Bit.java
similarity index 100%
rename from wpilibj/src/main/java/org/wpilib/util/Color8Bit.java
rename to wpiutil/src/main/java/org/wpilib/util/Color8Bit.java
diff --git a/wpilibc/src/main/native/include/wpi/util/Color.hpp b/wpiutil/src/main/native/include/wpi/util/Color.hpp
similarity index 97%
rename from wpilibc/src/main/native/include/wpi/util/Color.hpp
rename to wpiutil/src/main/native/include/wpi/util/Color.hpp
index 338a565430..d099c17683 100644
--- a/wpilibc/src/main/native/include/wpi/util/Color.hpp
+++ b/wpiutil/src/main/native/include/wpi/util/Color.hpp
@@ -11,12 +11,28 @@
 #include 
 
 #include 
-#include 
 
 #include "wpi/util/StringExtras.hpp"
 #include "wpi/util/ct_string.hpp"
 
-namespace wpi {
+namespace wpi::util {
+
+// replicate ceil from gcem to avoid gcem dependency here
+namespace detail {
+constexpr double ceil_int(double x, double x_whole) noexcept {
+  return (x_whole + ((x > 0) && (x > x_whole)));
+}
+
+constexpr double ceil(double x) noexcept {
+  if (std::is_constant_evaluated()) {
+    return ((x < 0.0 ? -x : x) >= 4503599627370496.
+                ? x
+                : ceil_int(x, static_cast(static_cast(x))));
+  } else {
+    return std::ceil(x);
+  }
+}
+}  // namespace detail
 
 /**
  * Represents colors that can be used with Addressable LEDs.
@@ -906,7 +922,7 @@ class Color {
 
  private:
   static constexpr double roundAndClamp(double value) {
-    return std::clamp(gcem::ceil(value * (1 << 12)) / (1 << 12), 0.0, 1.0);
+    return std::clamp(detail::ceil(value * (1 << 12)) / (1 << 12), 0.0, 1.0);
   }
 };
 
@@ -1083,4 +1099,4 @@ inline constexpr Color Color::kWhiteSmoke{0.9607843f, 0.9607843f, 0.9607843f};
 inline constexpr Color Color::kYellow{1.0f, 1.0f, 0.0f};
 inline constexpr Color Color::kYellowGreen{0.6039216f, 0.8039216f, 0.19607843f};
 
-}  // namespace wpi
+}  // namespace wpi::util
diff --git a/wpilibc/src/main/native/include/wpi/util/Color8Bit.hpp b/wpiutil/src/main/native/include/wpi/util/Color8Bit.hpp
similarity index 98%
rename from wpilibc/src/main/native/include/wpi/util/Color8Bit.hpp
rename to wpiutil/src/main/native/include/wpi/util/Color8Bit.hpp
index 6be64a9252..5a929ebb56 100644
--- a/wpilibc/src/main/native/include/wpi/util/Color8Bit.hpp
+++ b/wpiutil/src/main/native/include/wpi/util/Color8Bit.hpp
@@ -15,7 +15,7 @@
 #include "wpi/util/StringExtras.hpp"
 #include "wpi/util/ct_string.hpp"
 
-namespace wpi {
+namespace wpi::util {
 
 /**
  * Represents colors that can be used with Addressable LEDs.
@@ -131,4 +131,4 @@ class Color8Bit {
   int blue = 0;
 };
 
-}  // namespace wpi
+}  // namespace wpi::util
diff --git a/wpiutil/src/main/python/pyproject.toml b/wpiutil/src/main/python/pyproject.toml
index 8d5d8aa2c9..9591848853 100644
--- a/wpiutil/src/main/python/pyproject.toml
+++ b/wpiutil/src/main/python/pyproject.toml
@@ -67,6 +67,8 @@ depends = ["wpiutil-casters"]
 
 [tool.semiwrap.extension_modules."wpiutil._wpiutil".headers]
 # wpi
+Color = "wpi/util/Color.hpp"
+Color8Bit = "wpi/util/Color8Bit.hpp"
 StackTrace = "wpi/util/StackTrace.hpp"
 Synchronization = "wpi/util/Synchronization.h"
 RawFrame = "wpi/util/RawFrame.h"
diff --git a/wpilibc/src/main/python/semiwrap/Color.yml b/wpiutil/src/main/python/semiwrap/Color.yml
similarity index 97%
rename from wpilibc/src/main/python/semiwrap/Color.yml
rename to wpiutil/src/main/python/semiwrap/Color.yml
index 508d71e6f7..6428d18c9a 100644
--- a/wpilibc/src/main/python/semiwrap/Color.yml
+++ b/wpiutil/src/main/python/semiwrap/Color.yml
@@ -2,7 +2,7 @@ extra_includes:
 - pybind11/operators.h
 
 classes:
-  wpi::Color:
+  wpi::util::Color:
     force_type_casters:
     - wpi::util::ct_string
     attributes:
@@ -173,6 +173,12 @@ classes:
       HexString:
       operator==:
 
+functions:
+  ceil_int:
+    ignore: true
+  ceil:
+    ignore: true
+
 inline_code: |
   cls_Color
     .def("__hash__", [](Color *self) -> size_t {
diff --git a/wpilibc/src/main/python/semiwrap/Color8Bit.yml b/wpiutil/src/main/python/semiwrap/Color8Bit.yml
similarity index 91%
rename from wpilibc/src/main/python/semiwrap/Color8Bit.yml
rename to wpiutil/src/main/python/semiwrap/Color8Bit.yml
index bebd9c3a0c..5adf60750c 100644
--- a/wpilibc/src/main/python/semiwrap/Color8Bit.yml
+++ b/wpiutil/src/main/python/semiwrap/Color8Bit.yml
@@ -2,7 +2,7 @@ extra_includes:
 - pybind11/operators.h
 
 classes:
-  wpi::Color8Bit:
+  wpi::util::Color8Bit:
     force_type_casters:
     - wpi::util::ct_string
     attributes:
@@ -32,7 +32,7 @@ classes:
 
 inline_code: |
   cls_Color8Bit
-    .def("toColor", [](const Color8Bit &self) -> wpi::Color {
+    .def("toColor", [](const Color8Bit &self) -> wpi::util::Color {
       return self;
     })
     .def("__hash__", [](Color8Bit *self) -> size_t {
diff --git a/wpiutil/src/main/python/wpiutil/__init__.py b/wpiutil/src/main/python/wpiutil/__init__.py
index 6f5e8ab43c..15f1359a85 100644
--- a/wpiutil/src/main/python/wpiutil/__init__.py
+++ b/wpiutil/src/main/python/wpiutil/__init__.py
@@ -2,6 +2,8 @@ from . import _init__wpiutil
 
 # autogenerated by 'semiwrap create-imports wpiutil wpiutil._wpiutil'
 from ._wpiutil import (
+    Color,
+    Color8Bit,
     Sendable,
     SendableBuilder,
     SendableRegistry,
@@ -11,6 +13,8 @@ from ._wpiutil import (
 )
 
 __all__ = [
+    "Color",
+    "Color8Bit",
     "Sendable",
     "SendableBuilder",
     "SendableRegistry",
diff --git a/wpilibj/src/test/java/org/wpilib/util/Color8BitTest.java b/wpiutil/src/test/java/org/wpilib/util/Color8BitTest.java
similarity index 100%
rename from wpilibj/src/test/java/org/wpilib/util/Color8BitTest.java
rename to wpiutil/src/test/java/org/wpilib/util/Color8BitTest.java
diff --git a/wpilibj/src/test/java/org/wpilib/util/ColorTest.java b/wpiutil/src/test/java/org/wpilib/util/ColorTest.java
similarity index 100%
rename from wpilibj/src/test/java/org/wpilib/util/ColorTest.java
rename to wpiutil/src/test/java/org/wpilib/util/ColorTest.java
diff --git a/wpilibc/src/test/native/cpp/util/Color8BitTest.cpp b/wpiutil/src/test/native/cpp/Color8BitTest.cpp
similarity index 68%
rename from wpilibc/src/test/native/cpp/util/Color8BitTest.cpp
rename to wpiutil/src/test/native/cpp/Color8BitTest.cpp
index a836e31dc8..16b21831b9 100644
--- a/wpilibc/src/test/native/cpp/util/Color8BitTest.cpp
+++ b/wpiutil/src/test/native/cpp/Color8BitTest.cpp
@@ -9,7 +9,7 @@
 #include 
 
 TEST(Color8BitTest, ConstructDefault) {
-  constexpr wpi::Color8Bit color;
+  constexpr wpi::util::Color8Bit color;
 
   EXPECT_EQ(0, color.red);
   EXPECT_EQ(0, color.green);
@@ -17,7 +17,7 @@ TEST(Color8BitTest, ConstructDefault) {
 }
 
 TEST(Color8BitTest, ConstructFromInts) {
-  constexpr wpi::Color8Bit color{255, 128, 64};
+  constexpr wpi::util::Color8Bit color{255, 128, 64};
 
   EXPECT_EQ(255, color.red);
   EXPECT_EQ(128, color.green);
@@ -25,7 +25,7 @@ TEST(Color8BitTest, ConstructFromInts) {
 }
 
 TEST(Color8BitTest, ConstructFromColor) {
-  constexpr wpi::Color8Bit color{wpi::Color{255, 128, 64}};
+  constexpr wpi::util::Color8Bit color{wpi::util::Color{255, 128, 64}};
 
   EXPECT_EQ(255, color.red);
   EXPECT_EQ(128, color.green);
@@ -33,24 +33,24 @@ TEST(Color8BitTest, ConstructFromColor) {
 }
 
 TEST(Color8BitTest, ConstructFromHexString) {
-  constexpr wpi::Color8Bit color{"#FF8040"};
+  constexpr wpi::util::Color8Bit color{"#FF8040"};
 
   EXPECT_EQ(255, color.red);
   EXPECT_EQ(128, color.green);
   EXPECT_EQ(64, color.blue);
 
   // No leading #
-  EXPECT_THROW(wpi::Color8Bit{"112233"}, std::invalid_argument);
+  EXPECT_THROW(wpi::util::Color8Bit{"112233"}, std::invalid_argument);
 
   // Too long
-  EXPECT_THROW(wpi::Color8Bit{"#11223344"}, std::invalid_argument);
+  EXPECT_THROW(wpi::util::Color8Bit{"#11223344"}, std::invalid_argument);
 
   // Invalid hex characters
-  EXPECT_THROW(wpi::Color8Bit{"#$$$$$$"}, std::invalid_argument);
+  EXPECT_THROW(wpi::util::Color8Bit{"#$$$$$$"}, std::invalid_argument);
 }
 
 TEST(Color8BitTest, ImplicitConversionToColor) {
-  wpi::Color color = wpi::Color8Bit{255, 128, 64};
+  wpi::util::Color color = wpi::util::Color8Bit{255, 128, 64};
 
   EXPECT_NEAR(1.0, color.red, 1e-2);
   EXPECT_NEAR(0.5, color.green, 1e-2);
@@ -58,13 +58,13 @@ TEST(Color8BitTest, ImplicitConversionToColor) {
 }
 
 TEST(Color8BitTest, ToHexString) {
-  constexpr wpi::Color8Bit color1{255, 128, 64};
+  constexpr wpi::util::Color8Bit color1{255, 128, 64};
   EXPECT_EQ("#FF8040", color1.HexString());
 
   // Ensure conversion to std::string works
   [[maybe_unused]]
   std::string str = color1.HexString();
 
-  wpi::Color8Bit color2{255, 128, 64};
+  wpi::util::Color8Bit color2{255, 128, 64};
   EXPECT_EQ("#FF8040", color2.HexString());
 }
diff --git a/wpilibc/src/test/native/cpp/util/ColorTest.cpp b/wpiutil/src/test/native/cpp/ColorTest.cpp
similarity index 63%
rename from wpilibc/src/test/native/cpp/util/ColorTest.cpp
rename to wpiutil/src/test/native/cpp/ColorTest.cpp
index 7174a5447e..77a34a9d1e 100644
--- a/wpilibc/src/test/native/cpp/util/ColorTest.cpp
+++ b/wpiutil/src/test/native/cpp/ColorTest.cpp
@@ -9,7 +9,7 @@
 #include 
 
 TEST(ColorTest, ConstructDefault) {
-  constexpr wpi::Color color;
+  constexpr wpi::util::Color color;
 
   EXPECT_DOUBLE_EQ(0.0, color.red);
   EXPECT_DOUBLE_EQ(0.0, color.green);
@@ -18,7 +18,7 @@ TEST(ColorTest, ConstructDefault) {
 
 TEST(ColorTest, ConstructFromDoubles) {
   {
-    constexpr wpi::Color color{1.0, 0.5, 0.25};
+    constexpr wpi::util::Color color{1.0, 0.5, 0.25};
 
     EXPECT_NEAR(1.0, color.red, 1e-2);
     EXPECT_NEAR(0.5, color.green, 1e-2);
@@ -26,7 +26,7 @@ TEST(ColorTest, ConstructFromDoubles) {
   }
 
   {
-    constexpr wpi::Color color{1.0, 0.0, 0.0};
+    constexpr wpi::util::Color color{1.0, 0.0, 0.0};
 
     // Check for exact match to ensure round-and-clamp is correct
     EXPECT_EQ(1.0, color.red);
@@ -36,7 +36,7 @@ TEST(ColorTest, ConstructFromDoubles) {
 }
 
 TEST(ColorTest, ConstructFromInts) {
-  constexpr wpi::Color color{255, 128, 64};
+  constexpr wpi::util::Color color{255, 128, 64};
 
   EXPECT_NEAR(1.0, color.red, 1e-2);
   EXPECT_NEAR(0.5, color.green, 1e-2);
@@ -44,46 +44,50 @@ TEST(ColorTest, ConstructFromInts) {
 }
 
 TEST(ColorTest, FromHexString) {
-  constexpr wpi::Color color = wpi::Color::FromString("#FF8040");
+  constexpr wpi::util::Color color = wpi::util::Color::FromString("#FF8040");
 
   EXPECT_NEAR(1.0, color.red, 1e-2);
   EXPECT_NEAR(0.5, color.green, 1e-2);
   EXPECT_NEAR(0.25, color.blue, 1e-2);
 
   // No leading #
-  EXPECT_THROW(wpi::Color::FromString("112233"), std::invalid_argument);
+  EXPECT_THROW(wpi::util::Color::FromString("112233"), std::invalid_argument);
 
   // Too long
-  EXPECT_THROW(wpi::Color::FromString("#11223344"), std::invalid_argument);
+  EXPECT_THROW(wpi::util::Color::FromString("#11223344"),
+               std::invalid_argument);
 
   // Invalid hex characters
-  EXPECT_THROW(wpi::Color::FromString("#$$$$$$"), std::invalid_argument);
+  EXPECT_THROW(wpi::util::Color::FromString("#$$$$$$"), std::invalid_argument);
 }
 
 TEST(ColorTest, FromRGBString) {
-  constexpr wpi::Color color = wpi::Color::FromString("rgb(255, 128, 64)");
+  constexpr wpi::util::Color color =
+      wpi::util::Color::FromString("rgb(255, 128, 64)");
 
   EXPECT_NEAR(1.0, color.red, 1e-2);
   EXPECT_NEAR(0.5, color.green, 1e-2);
   EXPECT_NEAR(0.25, color.blue, 1e-2);
 
   // Missing rgb()
-  EXPECT_THROW(wpi::Color::FromString("255, 128, 64"), std::invalid_argument);
+  EXPECT_THROW(wpi::util::Color::FromString("255, 128, 64"),
+               std::invalid_argument);
 
   // Too few components
-  EXPECT_THROW(wpi::Color::FromString("rgb(255, 128)"), std::invalid_argument);
+  EXPECT_THROW(wpi::util::Color::FromString("rgb(255, 128)"),
+               std::invalid_argument);
 
   // Too many components
-  EXPECT_THROW(wpi::Color::FromString("rgb(255, 128, 64, 32)"),
+  EXPECT_THROW(wpi::util::Color::FromString("rgb(255, 128, 64, 32)"),
                std::invalid_argument);
 
   // Non-integer component
-  EXPECT_THROW(wpi::Color::FromString("rgb(255, abc, 64)"),
+  EXPECT_THROW(wpi::util::Color::FromString("rgb(255, abc, 64)"),
                std::invalid_argument);
 }
 
 TEST(ColorTest, FromHSV) {
-  constexpr wpi::Color color = wpi::Color::FromHSV(90, 128, 64);
+  constexpr wpi::util::Color color = wpi::util::Color::FromHSV(90, 128, 64);
 
   EXPECT_DOUBLE_EQ(0.125732421875, color.red);
   EXPECT_DOUBLE_EQ(0.251220703125, color.green);
@@ -91,13 +95,13 @@ TEST(ColorTest, FromHSV) {
 }
 
 TEST(ColorTest, ToHexString) {
-  constexpr wpi::Color color1{255, 128, 64};
+  constexpr wpi::util::Color color1{255, 128, 64};
   EXPECT_EQ("#FF8040", color1.HexString());
 
   // Ensure conversion to std::string works
   [[maybe_unused]]
   std::string str = color1.HexString();
 
-  wpi::Color color2{255, 128, 64};
+  wpi::util::Color color2{255, 128, 64};
   EXPECT_EQ("#FF8040", color2.HexString());
 }