Color computations for numberscope
To facilitate color manipulations in visualizers or in formula
parameters to visualizers, the frontscope provides a Chroma class
based on the npm package chroma-js.
You can use this class for color mixing and creating palettes and
so on, and then convert the resulting color objects (for example) to
hex strings to use as arguments to the p5 sketch color method.
The Chroma color class supports all of the methods documented for the chroma-js api. Additional functions and facilities for manipulating Chroma colors are documented below.
All of the chroma-js api and operations documented here are also available
in mathjs formulas. For example, you can darken a color x an
amount controlled by a number x by writing c.darken(x), or desaturate it
by writing c.desaturate(x), etc.
In addition, all of the named colors (like
red or chartreuse, including all CSS (Cascading Style Sheets) named colors)
are available as pre-defined constant symbols, as are the color brewer
palettes, like RdBu or Set1. Note the palettes are arrays of colors,
so to get a specific color from them in a formula you need to index them
with a 1-based index, e.g., Set1[5].
chroma(...)
Rather than directly using a Chroma constructor, the recommended basic way
to create a new Chroma object is via the chroma() function, which can
understand a wide assortment of different argument types for flexible
creation of colors. In addition to the possibilities detailed in the
chroma-js api, the numberscope chroma()
also supports:
chroma()returns opaque blackchroma([r: number, g: number, b: number, a: number])gives a color with the four channels specified as numbers between 0 and 1 inclusive.chroma(l: number)whenlis between 0 and 1 produces an opaque greyscale color from black to white, respectively. (Note whenlis an integer larger than one, this reverts to the usual chroma-js api meaning, in which the number is converted to a hex string and then interpreted as a color code.)chroma(name: string, a: number)produces the same color aschroma(name)but with its alpha channel set to a.- If all of the arguments to the usual
chroma(r: number, g: number, b: number, a?:number)signature are numbers between 0 and 1, they are interpreted on that scale, rather than the default [0...255] scale.
All of the other functions below also return Chroma objects unless otherwise noted.
rainbow(hue: bigint | number, opacity?: number)
This function conveniently allows creation of an opaque color from just a "hue angle" in color space, periodically interpreted with the main period from 0 to 360. Optionally, you can also specify an opacity for the resulting color, from 1 to 0. It uses the "oklch" color space provided by chromajs to ensure that all of the colors it returns will have approximately the same apparent lightness and hue saturation (and hopefully these levels have been selected to produce attractive colors).
isChroma(x: unknown): x is Chroma
A TypeScript type guard to discern Chroma objects.
overlay(bottom: Chroma, top: Chroma)
Returns the result of alpha-compositing top on top of bottom. For example,
if top is opaque (has alpha channel equal to one), this will just give
top back. This operation is available in mathjs formulas using the ordinary
addition operator +, but note that it is not commutative.
ply(color: Chroma, plies: number)
Returns a newly-created Chroma object the same as color except it represents
overlaying plies many times with that color. Equivalently, the
chromatic components of color are left alone, and the new opacity value
is given by 1 - (1 - alpha)^plies, where alpha is the opacity of color.
This operation is available in mathjs formulas using the ordinary
multiplication operator *, and in such formulas, the color and factor
may appear in either order. With these definitions and conventions, we have
such expected identities as c + c == 2*c and so on.
Combining the previous two operations in a linear combination in a
mathjs formula such as red + x*chroma(blue, 0.01) provides one reasonable
way to morph geometrically from red to blue as x goes from 1 to infinity,
but note that when the colors used as endpoints are on opposite sides of the
color wheel, the colors in the "middle" of this trajectory will be rather
greyish/muddy. See the chroma-js api
for other ways of creating color scales if direct alpha-compositing produces
undesirable results.
dilute(color: Chroma, factor: number)
Returns a newly-created Chroma object the same as color except that its alpha value has been multiplied by factor.
Combining this with addition as in red + dilute(blue, x) provides one
reasonable way to morph linearly from red to blue as x goes from
0 to 1, with the same caveats about greyish/muddy colors in the middle of
the trajectory.