# Changelog
All notable changes to this project are documented here. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/).
## [0.11.0] — April 20th, 2026
### Added
* Add :chroma_ceiling option and expose :gamut in tonal visualizer.
* Drop seed label on gamut plot and add white-point legend entry.
* Propagate palette gamut and ceiling between tonal and gamut tabs
## [0.10.0] — April 19th, 2026
### Added
* Add `Color.Rec2020` and `Color.AppleRGB` spaces and extend `Color.Spectral` with B, C, F2, F7, F11 illuminants and blackbody/1.
## [0.9.0] — April 16th, 2026
### Bug Fixes
* Add the seed as a URL param so the seed travels to each tab in the visualizer.
## [0.8.0] — April 16th, 2026
### Bug Fixes
* Smooth the tonal lightness gradient for the palette.
### Changed
* Generate Tailwind 4 classes, not Tailwind 3.
## [0.7.0] — April 16th, 2026
### Changed
* Generate Tailwind 4 classes, not Tailwind 3.
## [0.6.0] — April 15th, 2026
### Added
* `Color.Palette.semantic/3` and `semantic_categories/0` — synthesise a colour in a chosen category (semantic `:success`, `:danger`, `:warning`, `:info`, `:neutral`, or raw hue `:red`, `:orange`, `:yellow`, `:green`, `:teal`, `:blue`, `:purple`, `:pink`) from a seed while preserving the seed's Oklch lightness and chroma. Lets a brand colour drive a matched set of semantic accents — a success green that feels like the same palette as the brand blue — without hand-picking every one. Options: `:chroma_factor` to mute, `:lightness` to override, `:gamut` to target a non-sRGB display. Canonical workflow is `semantic/3` → any palette generator (`tonal/2`, `theme/2`, `contrast/2`, `contrast_scale/2`) to produce a full scale for the role.
* Palette gamut checks. `Color.Palette.in_gamut?/2` and `Color.Palette.gamut_report/2` answer "is every stop in this palette inside the chosen RGB working space?", with `gamut_report/2` returning a per-stop breakdown listing exactly which stops failed.
* Public APIs for designer-tool integrations.
* `Color.Palette.Tonal.to_css/2` and `Color.Palette.ContrastScale.to_css/2` emit CSS custom-property blocks (selector and name prefix configurable).
* `Color.Palette.Tonal.to_tailwind/2` and `Color.Palette.ContrastScale.to_tailwind/2` emit `theme.extend.colors` fragments ready for `tailwind.config.js`.
* `Color.Gamut.SVG.render/1` renders a complete chromaticity-diagram SVG — projection, gamut overlays, Planckian locus, seed / palette overlays, sizing, and colour overrides all under a single keyword-list API.
* `Color.Gamut.Diagram` — pure-data module for chromaticity diagrams.
* `Color.Palette.Visualizer` gains a `/gamut` tab rendering an inline SVG chromaticity diagram.
* `Color.Palette.ContrastScale` — a fourth palette algorithm, inspired by Matt Ström-Awn's [Generating colour palettes with math](https://mattstromawn.com/writing/generating-color-palettes/).
* `Color.DesignTokens` — encode and decode W3C [Design Tokens Community Group](https://www.designtokens.org/tr/2025.10/color/) color tokens (2025.10 draft).
* `Color.Palette.Tonal.to_tokens/2`, `Color.Palette.Theme.to_tokens/2`, and `Color.Palette.Contrast.to_tokens/2` emit each palette type as a DTCG-compliant token map ready for `:json.encode/1`.
* `Color.Palette.Visualizer` Tonal and Theme views now include a "Design Tokens (W3C DTCG)" export block alongside the existing CSS custom properties and Tailwind config blocks, showing the palette as pretty-printed JSON ready to copy into a `tokens.json` file.
* `Color.Palette.Visualizer` seed input is now a native `<input type="color">` paired with a text input. Clicking the picker opens the OS colour picker; typing a named colour, `oklch(...)`, or any other CSS syntax still works via the text field. On submit the server prefers the text field if it was changed, otherwise uses the picker's value. The picker is pre-initialised to the resolved hex of whatever the current seed is, so `seed=rebeccapurple` opens the picker on `#663399`.
## [0.5.0] — April 14th, 2026
### Added
* `Color.Palette` module with three palette-generation algorithms for design systems and web sites.
* `Color.Palette.Visualizer` — a Plug-based web UI for previewing the three palette algorithms. Three views modelled on [UI Colors](https://uicolors.app/generate) (Tonal), [Material Theme Builder](https://material-foundation.github.io/material-theme-builder/) (Theme), and [Adobe Leonardo](https://leonardocolor.io/) (Contrast).
## [0.4.0]
### Added
* `Color.LED` module with support for multi-channel addressable LED pixels that include extra white channels. `Color.LED.RGBW` covers four-channel pixels (R, G, B, W) used by WS2814 and SK6812-RGBW. `Color.LED.RGBWW` covers five-channel RGB+CCT pixels (R, G, B, WW, CW) used by WS2805 and several SK6812 variants. Both provide `from_srgb/2`, `to_srgb/1`, and `to_xyz/1`. `Color.LED.chip_options/1` returns recommended extraction options for common chip variants (`:ws2814_ww`, `:ws2814_nw`, `:ws2814_cw`, `:sk6812_ww`, `:sk6812_nw`, `:sk6812_cw`, `:ws2805`).
* `Color.ANSI` module for parsing and emitting ANSI SGR colour escape sequences. Supports 16-colour, 256-colour indexed, and 24-bit truecolor forms, with perceptual nearest-palette matching (CIEDE2000) when encoding to the 16- or 256-colour palette. Includes `parse/1`, `to_string/2`, `wrap/3`, `nearest_256/1`, `nearest_16/1`, `palette_256/0`, `palette_16/0`, and a typed `Color.ANSI.ParseError` exception.
* Top-level `Color.to_hex/1`, `Color.to_css/1,2`, and `Color.to_ansi/1,2` convenience functions that accept any input `Color.new/1` accepts and raise a typed exception on failure.
### Changed
* Changed the module `Color.CSSNames` to `Color.CSS.Names`
* Changed all colorspace module names to be the closest possible match to their standard names.
## [0.3.0]
### Added
* Twenty-one color-space struct modules covering CIE, modern perceptual, HDR, video, device, and web spaces: `Color.SRGB`, `Color.AdobeRGB`, `Color.RGB` (linear, in any of 24 named working spaces), `Color.Lab`, `Color.LCHab`, `Color.Luv`, `Color.LCHuv`, `Color.XYZ`, `Color.XyY`, `Color.Oklab`, `Color.Oklch`, `Color.HSLuv`, `Color.HPLuv`, `Color.HSL`, `Color.HSV`, `Color.CMYK`, `Color.YCbCr`, `Color.JzAzBz`, `Color.ICtCp`, `Color.IPT`, `Color.CAM16UCS`.
* Top-level `Color.new/1,2`, `Color.convert/2,3,4`, `Color.convert_many/2,3,4`, `Color.luminance/1`, `Color.sort/2`, `Color.premultiply/1`, `Color.unpremultiply/1`.
* Chromatic adaptation (`Color.XYZ.adapt/3`) with six methods: `:bradford`, `:xyz_scaling`, `:von_kries`, `:sharp`, `:cmccat2000`, `:cat02`. `Color.XYZ.apply_bpc/3` for black point compensation.
* ICC rendering intents wired into `Color.convert/3,4`: `:relative_colorimetric` (default), `:absolute_colorimetric`, `:perceptual`, `:saturation`. Optional `bpc: true` and `adaptation:` method override.
* `Color.ICC.Profile` matrix-profile reader covering ICC v2/v4 RGB→XYZ profiles with `curv` LUT and `para` parametric (types 0–4) tone response curves; `load/1`, `parse/1`, `to_xyz/2`, `from_xyz/2`.
* Color difference metrics (`Color.Distance`): CIE76, CIE94, CIEDE2000 (verified against Sharma 2005), and CMC l:c.
* Contrast (`Color.Contrast`): WCAG 2.x relative luminance and contrast ratio, APCA W3 0.1.9, contrast-aware `pick_contrasting/2`.
* Color mixing and gradients (`Color.Mix`) with the default Oklab interpolation space and CSS Color 4 hue-interpolation modes.
* Gamut checking and mapping (`Color.Gamut`) with both `:clip` and the CSS Color 4 Oklch binary-search perceptual algorithm.
* Color harmonies (`Color.Harmony`) — complementary, analogous, triadic, tetradic, split-complementary — in any cylindrical space.
* Color temperature (`Color.Temperature`): McCamy CCT, Planckian and CIE daylight loci, `xyz/2`.
* CSS Color Module Level 4 / 5 parser and serialiser (`Color.CSS`): hex, named colors, all standard color functions, `color()` with display-p3 / a98-rgb / prophoto-rgb / rec2020 / xyz, `device-cmyk()`, `color-mix()`, relative color syntax, `none`, and `calc()` expressions.
* CSS named colors (`Color.CSSNames`): all 148 CSS Color Module Level 4 names plus `chromagreen` and `chromablue`. Atom and snake-case input. Reverse `nearest/1` lookup via CIEDE2000.
* `~COLOR` sigil (`Color.Sigil`) for compile-time color literals, compile-fenced behind Elixir 1.15.
* Spectral pipeline (`Color.Spectral` + `Color.Spectral.Tables`): CIE 1931 2° and CIE 1964 10° standard observer CMFs, D65 / D50 / A / E illuminant SPDs, emissive and reflective integration, metamerism index.
* All sixteen CSS Compositing Level 1 blend modes (`Color.Blend`).
* Transfer functions (`Color.Conversion.Lindbloom`): sRGB, gamma 2.2 / 1.8, L*, BT.709, BT.2020, PQ (SMPTE ST 2084), HLG, Adobe RGB γ.
* Typed exception modules under `Color.*Error` for every fallible function. Every error returns `{:ok, _}` or `{:error, %SomeError{...}}` with semantic fields.
* Public `Color.Behaviour` declaring the `to_xyz/1` and `from_xyz/1` contract that every color-space struct module satisfies.
* `Color.is_color/1` and `Color.is_css_name/1` compile-time guards plus `Color.color?/1`, `Color.css_name?/1`, and `Color.validate_transparency/1` migration helpers.
* `@type t` on every public color-space struct module and `@spec` annotations across the public API.
* Benchee benchmark suite under `bench/` covering single-color conversions, batch vs `Enum.map`, and the `:persistent_term` working-space cache.
* Property-based test suite (`test/property_test.exs`) covering round-trip identity, alpha preservation, hue wrap-around, gamut-mapping invariance, ΔE symmetry, mix endpoint identity, and WCAG contrast bounds across every supported space.
### Performance
* `Color.RGB.WorkingSpace.rgb_conversion_matrix/1` results are cached in `:persistent_term` so repeated lookups for the same named space are constant-time after the first call.