Colors (spec/04 §1): parsing, construction in RGB, HSL, Lab, HCL, OKLab and OKLCH, conversion, manipulation and interpolation.
color = Macaw.Layers.Color.parse("steelblue")
color |> Macaw.Layers.Color.darker() |> Macaw.Layers.Color.to_hex()
#=> "#044279"parse/1 reads untrusted text and answers nil for anything it does not read; it never
raises. Lab is CIE L*a*b* against D50 with d3-color's constants, so lab/4 of
to_lab/1 is the color again; OKLab is Ottosson's, and a color built from OKLab or
OKLCH is brought into sRGB by CSS Color 4's gamut mapping (Macaw.Layers.Color.Ok).
Macaw.Layers.Color.Vision simulates the dichromacies.
Ported from visualize's Visualize.Color and Visualize.Color.OK.
Summary
Types
A color as a design names it (spec/04 §1.3): a name of the theme's color table, a series or a ramp position, a literal string, or a transform of colors.
Functions
The color c at opacity a in 0..1, whatever its opacity was (spec/04 §1.3).
The colors mixed in OKLab, each weighted by its intensity/2 (1 without one), as CSS's
color-mix mixes them: weights summing below 1 leave the remainder transparent, and
above 1 are scaled to sum to 1 (spec/04 §1.3).
Returns a brighter copy of the color.
The color name of the theme's color table (spec/04 §1.3, §2.2): the library's names are
atoms, and a color a theme declares may be named by its string.
The readable ink over whatever the text is drawn on (spec/04 §3.2): a mark's inline label inks against its element's fill, any other text against the theme's background.
The readable ink over c: the theme's text or background, else black or white,
whichever contrasts more (spec/04 §1.4, §3.2).
Returns the contrast ratio between two colors (1-21)
The color c moved toward black by t in 0..1, in OKLCH lightness (spec/04 §1.3).
Returns a darker copy of the color.
ΔEOK, the distance between two colors in OKLab, their opacities aside.
Returns a desaturated copy (in HSL space)
Returns a grayscale version of the color
Creates a color from HCL values (h: 0-360, c: 0-~230, l: 0-100)
Creates a color from HSL values (h: 0-360, s: 0-100, l: 0-100)
How much of the color c is present, t in 0..1; the rest is transparent. On its own
it is c at t of its alpha; in blend/1 it is the color's weight (spec/04 §1.3).
Interpolates between two colors in HCL space (perceptually uniform)
Interpolates between two colors in HSL space
Interpolates between two colors in Lab space
Interpolates between two colors in RGB space
Inverts the color
Creates a color from Lab values (l: 0-100, a: -128 to 127, b: -128 to 127)
The color c moved toward white by t in 0..1, in OKLCH lightness (spec/04 §1.3).
Returns the relative luminance (0-1)
Mixes two colors equally (in RGB space)
Gets a named color's hex value
Returns all named color names
A color from OKLab, brought into sRGB by CSS Color 4's gamut mapping (spec/04 §1.2). Channels are left unrounded.
A color from OKLCH (h in degrees), gamut-mapped as oklab/4 is.
Parses a color string into a Color struct.
The color at t in 0..1 along the theme's ramp name (spec/04 §2.3).
A color value resolved against a theme in mode (spec/04 §1.4, §3.2): a name, a series
or a ramp position exactly as Macaw.Layers.Theme.resolve/3 resolves the slot, a literal as
written, and a transform as the literal it computes to, #rrggbb or #rrggbbaa.
Creates a color from RGB values (0-255)
Rotates the hue by the specified degrees
On a %Macaw.Layers.Color{}, a saturated copy: HSL saturation multiplied by amount
(default 1.2).
The step n of c's scale, n in 0..1000 as designers number them (spec/04 §1.3):
500 is c, 0 near white and 1000 near black, on one OKLCH curve that keeps the hue and
eases the chroma toward the ends. A step the theme pins of a name is the pinned color.
Converts to HCL map %{h: h, c: c, l: l, opacity: opacity}
Converts to hex string
Converts to HSL map %{h: h, s: s, l: l, opacity: a}
Converts to Lab map %{l: l, a: a, b: b, opacity: opacity}
The color in OKLab (spec/04 §1.2): %{l, a, b, opacity}, l in 0..1.
The color in OKLCH (spec/04 §1.2): %{l, c, h, opacity}, h in degrees [0, 360).
Converts to RGB tuple {r, g, b}
Converts to RGBA tuple {r, g, b, a}
Converts to CSS string
Whether a term is a color value (spec/04 §1.3), every operand of a transform included.
Returns a copy with the specified opacity
Types
@type value() :: String.t() | {:color, atom()} | {:series, pos_integer()} | {:ramp, atom(), number()} | {:intensity | :alpha | :lighten | :darken | :saturate | :shade, value(), number()} | {:blend, [value(), ...]} | {:contrast, value() | :under}
A color as a design names it (spec/04 §1.3): a name of the theme's color table, a series or a ramp position, a literal string, or a transform of colors.
Functions
The color c at opacity a in 0..1, whatever its opacity was (spec/04 §1.3).
iex> Macaw.Layers.Color.color(:red) |> Macaw.Layers.Color.alpha(0.5)
{:alpha, {:color, :red}, 0.5}
The colors mixed in OKLab, each weighted by its intensity/2 (1 without one), as CSS's
color-mix mixes them: weights summing below 1 leave the remainder transparent, and
above 1 are scaled to sum to 1 (spec/04 §1.3).
iex> import Macaw.Layers.Color, only: [color: 1, intensity: 2, blend: 1, alpha: 2]
iex> [color(:blue) |> intensity(0.65), color(:red) |> intensity(0.3)] |> blend() |> alpha(0.65)
{:alpha, {:blend, [{:intensity, {:color, :blue}, 0.65}, {:intensity, {:color, :red}, 0.3}]}, 0.65}
Returns a brighter copy of the color.
k=1 is one "unit" brighter (default). k=2 is two units, etc.
The color name of the theme's color table (spec/04 §1.3, §2.2): the library's names are
atoms, and a color a theme declares may be named by its string.
iex> Macaw.Layers.Color.color(:red)
{:color, :red}
@spec contrast() :: value()
The readable ink over whatever the text is drawn on (spec/04 §3.2): a mark's inline label inks against its element's fill, any other text against the theme's background.
iex> Macaw.Layers.Color.contrast()
{:contrast, :under}
The readable ink over c: the theme's text or background, else black or white,
whichever contrasts more (spec/04 §1.4, §3.2).
iex> Macaw.Layers.Color.color(:bad) |> Macaw.Layers.Color.contrast()
{:contrast, {:color, :bad}}
Returns the contrast ratio between two colors (1-21)
The color c moved toward black by t in 0..1, in OKLCH lightness (spec/04 §1.3).
iex> Macaw.Layers.Color.color(:red) |> Macaw.Layers.Color.darken(0.3)
{:darken, {:color, :red}, 0.3}
Returns a darker copy of the color.
k=1 is one "unit" darker (default). k=2 is two units, etc.
ΔEOK, the distance between two colors in OKLab, their opacities aside.
iex> Macaw.Layers.Color.delta_eok(Macaw.Layers.Color.parse("#fff"), Macaw.Layers.Color.parse("#000"))
...> |> Float.round(6)
1.0
Returns a desaturated copy (in HSL space)
Returns a grayscale version of the color
Creates a color from HCL values (h: 0-360, c: 0-~230, l: 0-100)
Creates a color from HSL values (h: 0-360, s: 0-100, l: 0-100)
How much of the color c is present, t in 0..1; the rest is transparent. On its own
it is c at t of its alpha; in blend/1 it is the color's weight (spec/04 §1.3).
iex> Macaw.Layers.Color.color(:blue) |> Macaw.Layers.Color.intensity(0.65)
{:intensity, {:color, :blue}, 0.65}
Interpolates between two colors in HCL space (perceptually uniform)
Interpolates between two colors in HSL space
Interpolates between two colors in Lab space
Interpolates between two colors in RGB space
Inverts the color
Creates a color from Lab values (l: 0-100, a: -128 to 127, b: -128 to 127)
The color c moved toward white by t in 0..1, in OKLCH lightness (spec/04 §1.3).
iex> Macaw.Layers.Color.color(:red) |> Macaw.Layers.Color.lighten(0.3)
{:lighten, {:color, :red}, 0.3}
Returns the relative luminance (0-1)
Mixes two colors equally (in RGB space)
Gets a named color's hex value
@spec named_colors() :: [String.t()]
Returns all named color names
A color from OKLab, brought into sRGB by CSS Color 4's gamut mapping (spec/04 §1.2). Channels are left unrounded.
A color from OKLCH (h in degrees), gamut-mapped as oklab/4 is.
Parses a color string into a Color struct.
Supports:
- Hex: "#rgb", "#rrggbb", "#rgba", "#rrggbbaa"
- RGB: "rgb(r, g, b)", "rgba(r, g, b, a)"
- HSL: "hsl(h, s%, l%)", "hsla(h, s%, l%, a)"
- Named colors: "steelblue", "red", etc.
The color at t in 0..1 along the theme's ramp name (spec/04 §2.3).
iex> Macaw.Layers.Color.ramp(:thermal, 0.7)
{:ramp, :thermal, 0.7}
@spec resolve(value() | atom(), Macaw.Layers.Theme.t(), Macaw.Layers.Theme.mode()) :: String.t()
A color value resolved against a theme in mode (spec/04 §1.4, §3.2): a name, a series
or a ramp position exactly as Macaw.Layers.Theme.resolve/3 resolves the slot, a literal as
written, and a transform as the literal it computes to, #rrggbb or #rrggbbaa.
iex> theme = Macaw.Layers.Theme.default()
iex> Macaw.Layers.Color.resolve(Macaw.Layers.Color.color(:axis), theme, :css)
"var(--mw-axis, #666666)"
iex> Macaw.Layers.Color.resolve({:intensity, "#ff0000", 0.5}, theme, :literal)
"#ff000080"
Creates a color from RGB values (0-255)
Rotates the hue by the specified degrees
On a %Macaw.Layers.Color{}, a saturated copy: HSL saturation multiplied by amount
(default 1.2).
On a color value (spec/04 §1.3), the transform {:saturate, c, t}: chroma moved toward
full in OKLCH by t in 0..1, resolved against the theme.
iex> Macaw.Layers.Color.color(:red) |> Macaw.Layers.Color.saturate(0.2)
{:saturate, {:color, :red}, 0.2}
The step n of c's scale, n in 0..1000 as designers number them (spec/04 §1.3):
500 is c, 0 near white and 1000 near black, on one OKLCH curve that keeps the hue and
eases the chroma toward the ends. A step the theme pins of a name is the pinned color.
iex> Macaw.Layers.Color.color(:red) |> Macaw.Layers.Color.shade(100)
{:shade, {:color, :red}, 100}
Converts to HCL map %{h: h, c: c, l: l, opacity: opacity}
Converts to hex string
Converts to HSL map %{h: h, s: s, l: l, opacity: a}
Converts to Lab map %{l: l, a: a, b: b, opacity: opacity}
The color in OKLab (spec/04 §1.2): %{l, a, b, opacity}, l in 0..1.
iex> %{l: l} = Macaw.Layers.Color.to_oklab(Macaw.Layers.Color.parse("#ffffff"))
iex> Float.round(l, 4)
1.0
The color in OKLCH (spec/04 §1.2): %{l, c, h, opacity}, h in degrees [0, 360).
Converts to RGB tuple {r, g, b}
Converts to RGBA tuple {r, g, b, a}
Converts to CSS string
Whether a term is a color value (spec/04 §1.3), every operand of a transform included.
iex> Macaw.Layers.Color.value?({:alpha, {:color, :red}, 0.5})
true
iex> Macaw.Layers.Color.value?(:red)
false
Returns a copy with the specified opacity