Liking cljdoc? Tell your friends :D

dk.simongray.colour-coded

Colours as maps, converted between the colour spaces of CSS Color 4.

A colour is a map of its :space, its :coords and its :alpha, e.g. {:space :oklch :coords [0.44 0.085 158.0] :alpha 1.0}, the shape that Colour.js uses. A missing component, which CSS writes as none, is nil. Every function of the library takes a CSS colour as well, e.g. "#24476b" or "oklch(44% 0.085 158)", which syntax/parse reads.

The spaces are those of CSS Color 4, by these ids: :srgb, :srgb-linear, :display-p3, :display-p3-linear, :a98-rgb, :prophoto-rgb, :rec2020, :xyz-d65, :xyz-d50, :lab, :lch, :oklab, :oklch, :hsl and :hwb. Their coordinates have the ranges of CSS's sample code: red, green and blue from 0 to 1, the saturation and lightness of HSL from 0 to 100, the lightness of Lab and LCH from 0 to 100, and of Oklab and OKLCH from 0 to 1, and hues in degrees.

The other namespaces build on this one:

  • space, syntax, gamut, contrast, difference and mix, the rest of the core
  • choose, harmony, tone and target, ways to choose and generate colours
  • quantise and image, the colours of an image
  • vision, colours as people with a colour vision deficiency see them
  • theme, the colours of a site or an app, from one colour or one image
Colours as maps, converted between the colour spaces of CSS Color 4.

A colour is a map of its :space, its :coords and its :alpha, e.g.
{:space :oklch :coords [0.44 0.085 158.0] :alpha 1.0}, the shape that
Colour.js uses. A missing component, which CSS writes as none, is nil. Every function of
the library takes a CSS colour as well, e.g. "#24476b" or
"oklch(44% 0.085 158)", which syntax/parse reads.

The spaces are those of CSS Color 4, by these ids: :srgb, :srgb-linear,
:display-p3, :display-p3-linear, :a98-rgb, :prophoto-rgb, :rec2020,
:xyz-d65, :xyz-d50, :lab, :lch, :oklab, :oklch, :hsl and :hwb. Their
coordinates have the ranges of CSS's sample code: red, green and blue
from 0 to 1, the saturation and lightness of HSL from 0 to 100, the
lightness of Lab and LCH from 0 to 100, and of Oklab and OKLCH from 0 to
1, and hues in degrees.

The other namespaces build on this one:

- space, syntax, gamut, contrast, difference and mix, the rest of the
  core
- choose, harmony, tone and target, ways to choose and generate colours
- quantise and image, the colours of an image
- vision, colours as people with a colour vision deficiency see them
- theme, the colours of a site or an app, from one colour or one image
raw docstring

dk.simongray.colour-coded.choose

Colours chosen from among others, e.g. from the palette of an image or from colours that a designer made.

Colours chosen from among others, e.g. from the palette of an image or
from colours that a designer made.
raw docstring

dk.simongray.colour-coded.contrast

The contrast of two colours by WCAG 2.2, and the text colour that reads best on one.

WCAG 2.2 asks for these contrast ratios:

  • 4.5 for text, and 3 for large text, i.e. 18 points, or 14 points bold (success criterion 1.4.3)
  • 3 for the parts of a control and for graphics (1.4.11)
  • 7 and 4.5 at level AAA (1.4.6)

The ratio overstates the contrast of dark colours, which APCA addresses. APCA's licence forbids changing it and using it commercially, so it isn't here, but any function of two colours can stand in for ratio where an app wants its own measure.

https://www.w3.org/TR/WCAG22/#dfn-contrast-ratio

The contrast of two colours by WCAG 2.2, and the text colour that reads
best on one.

WCAG 2.2 asks for these contrast ratios:

- 4.5 for text, and 3 for large text, i.e. 18 points, or 14 points bold
  (success criterion 1.4.3)
- 3 for the parts of a control and for graphics (1.4.11)
- 7 and 4.5 at level AAA (1.4.6)

The ratio overstates the contrast of dark colours, which APCA addresses.
APCA's licence forbids changing it and using it commercially, so it isn't
here, but any function of two colours can stand in for ratio where an app
wants its own measure.

https://www.w3.org/TR/WCAG22/#dfn-contrast-ratio
raw docstring

dk.simongray.colour-coded.difference

How different two colours look, by the measures of colour difference that CSS Color 4 gives, in section 20.

  • delta-e, the distance in Oklab, ΔEOK, of which 0.02 is about the least difference that shows
  • delta-e-ok2, ΔEOK with a and b doubled, which Ottosson found to fit the data of perceived differences better
  • delta-e-76, the distance in CIELAB, CIE76, of which 2.3 is about the least that shows (Sharma and Trussell 1997)
  • delta-e-2000, CIEDE2000, the standard of the CIE, of which 1 to 2 is about the least that shows

https://www.w3.org/TR/css-color-4/#color-difference

How different two colours look, by the measures of colour difference
that CSS Color 4 gives, in section 20.

- delta-e, the distance in Oklab, ΔEOK, of which 0.02 is about the least
  difference that shows
- delta-e-ok2, ΔEOK with a and b doubled, which Ottosson found to fit
  the data of perceived differences better
- delta-e-76, the distance in CIELAB, CIE76, of which 2.3 is about the
  least that shows (Sharma and Trussell 1997)
- delta-e-2000, CIEDE2000, the standard of the CIE, of which 1 to 2 is
  about the least that shows

https://www.w3.org/TR/css-color-4/#color-difference
raw docstring

dk.simongray.colour-coded.gamut

Whether a colour lies in the gamut of a space, and the nearest colour that does.

There are three ways to bring a colour into a gamut:

  • to-gamut, the gamut mapping of CSS Color 4, lowers its chroma in OKLCH at the same lightness and hue
  • clip clamps each channel, which shifts the lightness and the hue a little, but is what browsers still do (csswg-drafts issue 9449)
  • reduce-chroma lowers its chroma in a polar space of your choice, e.g. LCH, and keeps that space's lightness and hue exactly

https://www.w3.org/TR/css-color-4/#gamut-mapping

Whether a colour lies in the gamut of a space, and the nearest colour
that does.

There are three ways to bring a colour into a gamut:

- to-gamut, the gamut mapping of CSS Color 4, lowers its chroma in OKLCH
  at the same lightness and hue
- clip clamps each channel, which shifts the lightness and the hue a
  little, but is what browsers still do (csswg-drafts issue 9449)
- reduce-chroma lowers its chroma in a polar space of your choice, e.g.
  LCH, and keeps that space's lightness and hue exactly

https://www.w3.org/TR/css-color-4/#gamut-mapping
raw docstring

dk.simongray.colour-coded.harmony

Colours of related hues: the classical harmonies of the colour wheel, turned in OKLCH unless a space is given.

The harmonies go back to Itten (The Art of Color, 1961), whose wheel is the painter's. Turned in OKLCH, a colour keeps its lightness and its chroma, while a turn of HSL's hue changes how light a colour looks (Ottosson, A perceptual color space for image processing, 2020). The evidence for the harmonies is mixed: Schloss and Palmer (2011) found that people rate pairs of similar hues as more harmonious, but prefer a figure whose hue contrasts with its ground. https://bottosson.github.io/posts/oklab/ https://pmc.ncbi.nlm.nih.gov/articles/PMC3037488

Colours of related hues: the classical harmonies of the colour wheel,
turned in OKLCH unless a space is given.

The harmonies go back to Itten (The Art of Color, 1961), whose wheel is
the painter's. Turned in OKLCH, a colour keeps its lightness and its
chroma, while a turn of HSL's hue changes how light a colour looks
(Ottosson, A perceptual color space for image processing, 2020). The
evidence for the harmonies is mixed: Schloss and Palmer (2011) found that
people rate pairs of similar hues as more harmonious, but prefer a figure
whose hue contrasts with its ground.
https://bottosson.github.io/posts/oklab/
https://pmc.ncbi.nlm.nih.gov/articles/PMC3037488
raw docstring

dk.simongray.colour-coded.image

The colours of an image, e.g. a podcast's artwork, from the bytes of its file, for an app to colour its UI by, and small copies of the image.

The platform decodes the image at a small size: ImageIO on the JVM, and the browser's own decoder in ClojureScript. On the JVM each function returns its result, and in ClojureScript a promise of it. The result is nil where the platform can't decode the image, e.g. WebP on the JVM, or anything in Node, which has no decoder, and for an image that's all transparent.

(cc/hex (image/seed bytes))   ; e.g. "#24476b"

For the theme of a whole site or app from an image, see theme/from-image. For small copies of an image, e.g. of artwork for a list, see thumbnails.

The colours of an image, e.g. a podcast's artwork, from the bytes of its
file, for an app to colour its UI by, and small copies of the image.

The platform decodes the image at a small size: ImageIO on the JVM, and
the browser's own decoder in ClojureScript. On the JVM each function
returns its result, and in ClojureScript a promise of it. The result is
nil where the platform can't decode the image, e.g. WebP on the JVM, or
anything in Node, which has no decoder, and for an image that's all
transparent.

    (cc/hex (image/seed bytes))   ; e.g. "#24476b"

For the theme of a whole site or app from an image, see
theme/from-image. For small copies of an image, e.g. of artwork for a
list, see thumbnails.
raw docstring

dk.simongray.colour-coded.impl

The conversion and interpolation of colour maps by the rules of CSS Color 4, which syntax uses for color-mix(), and mix for the rest.

A colour here is a map of its :space, :coords and :alpha, which these functions don't check. https://www.w3.org/TR/css-color-4/#interpolation

The conversion and interpolation of colour maps by the rules of CSS Color
4, which syntax uses for color-mix(), and mix for the rest.

A colour here is a map of its :space, :coords and :alpha, which these
functions don't check.
https://www.w3.org/TR/css-color-4/#interpolation
raw docstring

dk.simongray.colour-coded.mix

Colours between colours, interpolated by the rules that CSS Color 4 gives gradients and color-mix():

  • in Oklab, unless a space is given
  • with premultiplied alpha
  • with a missing component taken from the other colour
  • with a hue that turns the shorter way round, unless a method says otherwise

https://www.w3.org/TR/css-color-4/#interpolation

Colours between colours, interpolated by the rules that CSS Color 4
gives gradients and color-mix():

- in Oklab, unless a space is given
- with premultiplied alpha
- with a missing component taken from the other colour
- with a hue that turns the shorter way round, unless a method says
  otherwise

https://www.w3.org/TR/css-color-4/#interpolation
raw docstring

dk.simongray.colour-coded.quantise

The few colours that stand for the many pixels of an image.

The pixels are a sequence of vectors of red, green, blue and alpha from 0 to 255, as image/pixels, a canvas or ImageIO gives them. Only the opaque ones count, with an alpha of 128 or more. Each function returns maps of a :colour and its :share of the opaque pixels, the largest share first.

The few colours that stand for the many pixels of an image.

The pixels are a sequence of vectors of red, green, blue and alpha from 0
to 255, as image/pixels, a canvas or ImageIO gives them. Only the opaque
ones count, with an alpha of 128 or more. Each function returns maps of
a :colour and its :share of the opaque pixels, the largest share first.
raw docstring

dk.simongray.colour-coded.space

The colour spaces of CSS Color 4 as data, and the conversion of coordinates between them.

A space is a map of its :id, its :coords, its :base, and the functions :to-base and :from-base, which convert a vector of coordinates to and from those of the base. Each space's chain of bases ends at xyz-d65, the only space without a base. A conversion goes up one space's chain to the first space that the other's chain shares, then down the other's.

Each coordinate is a map of these:

  • :id
  • :range, which a percentage of CSS is a share of
  • :category, the coordinates of other spaces it's analogous to, which interpolation uses
  • :angle?, true for a hue

The matrices and transfer functions are those of CSS Color 4's sample code, section 19, under the W3C Software and Document License: https://www.w3.org/TR/css-color-4/#color-conversion-code

The colour spaces of CSS Color 4 as data, and the conversion of
coordinates between them.

A space is a map of its :id, its :coords, its :base, and the functions
:to-base and :from-base, which convert a vector of coordinates to and
from those of the base. Each space's chain of bases ends at xyz-d65, the
only space without a base. A conversion goes up one space's chain to the
first space that the other's chain shares, then down the other's.

Each coordinate is a map of these:

- :id
- :range, which a percentage of CSS is a share of
- :category, the coordinates of other spaces it's analogous to, which
  interpolation uses
- :angle?, true for a hue

The matrices and transfer functions are those of CSS Color 4's sample
code, section 19, under the W3C Software and Document License:
https://www.w3.org/TR/css-color-4/#color-conversion-code
raw docstring

dk.simongray.colour-coded.syntax

CSS colours, parsed from the syntax of CSS Color 4 and 5, and serialised by the rules of CSS Color 4.

The parser reads:

  • hex colours, the named colours and transparent
  • rgb(), rgba(), hsl(), hsla(), hwb(), lab(), lch(), oklab(), oklch() and color(), in the modern syntax and the legacy one with commas, with none for a missing component
  • color-mix(), of any number of colours

It doesn't read relative colours, calc() or system colours. https://www.w3.org/TR/css-color-4/ https://www.w3.org/TR/css-color-5/#color-mix

CSS colours, parsed from the syntax of CSS Color 4 and 5, and serialised
by the rules of CSS Color 4.

The parser reads:

- hex colours, the named colours and transparent
- rgb(), rgba(), hsl(), hsla(), hwb(), lab(), lch(), oklab(), oklch()
  and color(), in the modern syntax and the legacy one with commas, with
  none for a missing component
- color-mix(), of any number of colours

It doesn't read relative colours, calc() or system colours.
https://www.w3.org/TR/css-color-4/
https://www.w3.org/TR/css-color-5/#color-mix
raw docstring

dk.simongray.colour-coded.target

Colours found by the contrast that they should have, by the method of Adobe's Leonardo: a search for the lightness at which a colour has the contrast asked for with a background, since the same lightness has a different contrast at each hue. https://github.com/adobe/leonardo

Colours found by the contrast that they should have, by the method of
Adobe's Leonardo: a search for the lightness at which a colour has the
contrast asked for with a background, since the same lightness has a
different contrast at each hue.
https://github.com/adobe/leonardo
raw docstring

dk.simongray.colour-coded.theme

The colours of a site or an app from one colour or one image, light and dark, checked for contrast, as CSS or as hex.

(def t (from-seed "#24476b"))  ; or (from-image bytes)
(css t)               ; custom properties for a web page
(:dark (hex t))       ; a map of hex colours, e.g. for React Native
(remove :ok? (report t))

A theme has ten roles, in words that a beginner knows:

  • :background, the page, and :surface, a panel or a card on it
  • :text, and :text-muted for what matters less, e.g. a date
  • :border, the edge of a control, e.g. a field, and :divider, a line between parts that marks nothing
  • :accent, the fill of the main control, e.g. a button, and :on-accent, the text on it
  • :link, the colour of a link, and :focus, the ring of the focused control

Each role is a token of tone in LCH, so its lightness is CIELAB's L*, like the tones of Material 3. Each pair that must contrast keeps its contrast, to within a few percent, whatever the seed's hue, and the lightness of each role leaves a margin for that. The accent, the link and the focus ring take the seed's hue and chroma, and the rest a hint of its hue, like the greys that Radix pairs with an accent.

There are two levels of contrast, :standard and :more, like those of Material 3 and Apple. The function css writes :more for prefers-contrast: more.

A theme is plain data, so you can set a role by hand, e.g. with assoc-in, and report checks it again. https://github.com/material-foundation/material-color-utilities/blob/main/concepts/contrast_for_accessibility.md https://www.radix-ui.com/themes/docs/theme/color

The colours of a site or an app from one colour or one image, light and
dark, checked for contrast, as CSS or as hex.

    (def t (from-seed "#24476b"))  ; or (from-image bytes)
    (css t)               ; custom properties for a web page
    (:dark (hex t))       ; a map of hex colours, e.g. for React Native
    (remove :ok? (report t))

A theme has ten roles, in words that a beginner knows:

- :background, the page, and :surface, a panel or a card on it
- :text, and :text-muted for what matters less, e.g. a date
- :border, the edge of a control, e.g. a field, and :divider, a line
  between parts that marks nothing
- :accent, the fill of the main control, e.g. a button, and :on-accent,
  the text on it
- :link, the colour of a link, and :focus, the ring of the focused
  control

Each role is a token of tone in LCH, so its lightness is CIELAB's L*,
like the tones of Material 3. Each pair that must contrast keeps its
contrast, to within a few percent, whatever the seed's hue, and the
lightness of each role leaves a margin for that. The accent, the link and
the focus ring take the seed's hue and chroma, and the rest a hint of its
hue, like the greys that Radix pairs with an accent.

There are two levels of contrast, :standard and :more, like those of
Material 3 and Apple. The function css writes :more for
prefers-contrast: more.

A theme is plain data, so you can set a role by hand, e.g. with assoc-in,
and report checks it again.
https://github.com/material-foundation/material-color-utilities/blob/main/concepts/contrast_for_accessibility.md
https://www.radix-ui.com/themes/docs/theme/color
raw docstring

dk.simongray.colour-coded.tone

Colours from one seed, each at a fixed lightness, so that their contrast holds whatever the seed's hue.

A token is a map of these, e.g. {:l 0.33 :c 0.1 :turn 180}, which CSS writes as oklch(from var(--seed) 33% min(c, 0.1) calc(h + 180)):

  • :space, its polar space, by default :oklch
  • :l, its lightness in that space
  • :c, the most chroma that it takes from the seed
  • :turn, the degrees that its hue turns from the seed's

In :lch, the lightness is CIELAB's L*, like the tones of Material 3. L* follows WCAG's luminance, but for CIELAB's adaptation to the white of D50, so a pair of tokens keeps its contrast at every hue, to within a few percent for vivid colours and less for near-greys. In :oklch, the hues look more even, but the contrast varies more with the hue. The function worst-contrast says how far it goes. https://github.com/material-foundation/material-color-utilities/blob/main/typescript/hct/hct.ts

Colours from one seed, each at a fixed lightness, so that their contrast
holds whatever the seed's hue.

A token is a map of these, e.g. {:l 0.33 :c 0.1 :turn 180}, which CSS
writes as oklch(from var(--seed) 33% min(c, 0.1) calc(h + 180)):

- :space, its polar space, by default :oklch
- :l, its lightness in that space
- :c, the most chroma that it takes from the seed
- :turn, the degrees that its hue turns from the seed's

In :lch, the lightness is CIELAB's L*, like the tones of Material 3. L*
follows WCAG's luminance, but for CIELAB's adaptation to the white of
D50, so a pair of tokens keeps its contrast at every hue, to within a few
percent for vivid colours and less for near-greys. In :oklch, the hues
look more even, but the contrast varies more with the hue. The function
worst-contrast says how far it goes.
https://github.com/material-foundation/material-color-utilities/blob/main/typescript/hct/hct.ts
raw docstring

dk.simongray.colour-coded.vision

Colours as people with a colour vision deficiency see them, by the model of Machado, Oliveira and Fernandes.

The model shifts how one kind of cone responds to light: the L cones for a protan deficiency, the M cones for a deutan one, and the S cones for a tritan one. Its severity runs from 0, normal colour vision, to 1. At 1, the protan and deutan simulations are those of dichromats, who lack the cone. The paper treats its tritan simulation as an approximation, and doesn't simulate tritanopia, since the causes of tritan deficiencies aren't well known.

Red-green deficiencies, protan and deutan, affect about 8% of men and 0.4% of women of European descent, while tritan ones are much rarer (the paper, after Sharpe et al.).

The paper derives each matrix from the spectra of a display's primaries, so the matrices apply to linear light, and the namespace applies them in linear sRGB.

Machado, Oliveira and Fernandes, A physiologically-based model for simulation of color vision deficiency, IEEE Transactions on Visualization and Computer Graphics 15(6), 2009, pp. 1291–1298 https://www.inf.ufrgs.br/~oliveira/pubs_files/CVD_Simulation/CVD_Simulation.html

Colours as people with a colour vision deficiency see them, by the model
of Machado, Oliveira and Fernandes.

The model shifts how one kind of cone responds to light: the L cones for
a protan deficiency, the M cones for a deutan one, and the S cones for a
tritan one. Its severity runs from 0, normal colour vision, to 1. At 1,
the protan and deutan simulations are those of dichromats, who lack the
cone. The paper treats its tritan simulation as an approximation, and
doesn't simulate tritanopia, since the causes of tritan deficiencies
aren't well known.

Red-green deficiencies, protan and deutan, affect about 8% of men and
0.4% of women of European descent, while tritan ones are much rarer (the
paper, after Sharpe et al.).

The paper derives each matrix from the spectra of a display's primaries,
so the matrices apply to linear light, and the namespace applies them in
linear sRGB.

Machado, Oliveira and Fernandes, A physiologically-based model for
simulation of color vision deficiency, IEEE Transactions on
Visualization and Computer Graphics 15(6), 2009, pp. 1291–1298
https://www.inf.ufrgs.br/~oliveira/pubs_files/CVD_Simulation/CVD_Simulation.html
raw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
←Move to previous article
→Move to next article
Ctrl+/Jump to the search field
× close