What started as a personal experiment to explore color theory during some
downtime has evolved into a robust toolset. As I delved deeper, I realized the
TypeScript ecosystem lacked a modern, type-safe library capable of handling the
complexities of High Dynamic Range (HDR) and the newest perceptual color spaces
without bloating the final application bundle.
This library is the result of that realization: a tool designed to bridge the
gap between legacy web standards and the future of color management.
Design Philosophy
The architecture is built upon five core pillars to ensure performance,
correctness, and flexibility.
1. Immutability
All color classes are immutable. Operations that modify a color (e.g.,
setL(), setComponsnts()) always return a new instance.
Why: This prevents side effects, makes data flow predictable, and aligns
with modern functional programming patterns (like Redux or React state), leading
to cleaner and more reliable code.
2. Aggressive Tree-Shaking
The library is modular by design. The core classes contain only essential data
structures. All non-fundamental operations (like mixing, contrast calculation,
or tone mapping) are externalized into dedicated helper classes/functions.
Why: You pay only for what you use. If you only need Rgb and Oklch,
your final bundle will not include the logic for Cmyk or Hsl.
Impact: This approach significantly reduces bundle size, making it ideal
for performance-critical applications like web browsers or mobile apps.
Implementation: The library uses TypeScript's module system and
bundler-specific optimizations to ensure unused code is eliminated during
the build process.
3. XYZ as the Central Hub
The CIE XYZ color space acts as the universal connector for all conversions.
To convert from Space A to Space B, the library internally performs
A -> XYZ -> B.
Trade-off: While a direct mathematical formula from A to B might
theoretically offer slightly higher floating-point precision, it would
require $N^2$ conversion functions.
Benefit: By using a hub, we reduce complexity to $O(N)$. This is the only
scalable way to support 28+ color spaces while keeping the bundle size
minimal. The floating-point error introduced by the intermediate step is
negligible for all practical and scientific applications.
4. Modern & Comprehensive
The library supports 28+ color spaces, ranging from the standard web legacy
to the cutting edge of color science.
Legacy: RGB, HSL, HSV, CMYK.
Broadcast/Cinema: Rec.709, Rec.2020, P3, ACEScg.
Perceptual: Oklch, Oklab, ICtCp, JzAzBz (solving issues like hue shifts
and uneven lightness perception).
Base conversions are purely mathematical and unopinionated.
When converting between spaces, the library performs no automatic clipping,
no tone mapping, and no gamut mapping implicitly.
Why: Automatic clipping destroys data (especially in HDR workflows). By
keeping values "raw" (even if they go out of bounds or become negative), we
minimize accumulation errors during intermediate steps.
Control: The user has full control over when and how to apply clipping or
tone mapping using dedicated methods (e.g., clipSdr(), clipHdr(),
ToneMapping).
Precision: The library maintains high precision throughout all
calculations, using 64-bit floating-point arithmetic for all color
components.
6. First-Class HDR Support
The library assumes High Dynamic Range (HDR) by default. Components are not
clamped to the traditional 0-255 or 0-1 ranges unless explicitly requested.
Exceptions: To maintain logical consistency, the Alpha channel is
always clamped between 0 and 1, and polar coordinates (Hue) are
normalized to 0°-360°.
7. Type Safety and Generics
The library leverages TypeScript's advanced type system to provide compile-time
safety and flexibility. Key features include:
Generic Color Operations: Methods like to() and setComponents() use
generic types to ensure type safety when working with different color
spaces.
Component Index Safety: The library provides type-safe access to color
components using named indices, preventing incorrect property access.
Runtime Type Checking: The ColorMeta class provides runtime type
information, enabling dynamic color space handling and validation.
Precision: The library uses 64-bit floating-point arithmetic for all color
components, ensuring high precision even for HDR values.
Flexibility: While the library supports HDR by default, it also provides
methods to convert to SDR ranges when needed, such as clipSdr().