Color
Ripl includes a complete color toolkit for parsing, converting, and serializing colors across multiple color spaces. Every supported color space — hexadecimal and the functional notations — plus the CSS named colors is parsed automatically when you pass it to fill or stroke, but you can also use the color utilities directly for programmatic color manipulation, palette generation, and animation.
NOTE
For the full API, see the Color API Reference.
Demo
Type or pick a color to see it parsed into every supported color space in real time.
Supported Color Spaces
| Space | Parse | Serialize | Example |
|---|---|---|---|
| HEX | parseHEX | serializeHEX | #3a86ff, #3a86ff80 |
| RGB | parseRGB | serializeRGB | rgb(58, 134, 255) |
| RGBA | parseRGBA | serializeRGBA | rgba(58, 134, 255, 0.5) |
| HSL | parseHSL | serializeHSL | hsl(216, 100%, 61%) |
| HSLA | parseHSLA | serializeHSLA | hsla(216, 100%, 61%, 0.5) |
| HSV | parseHSV | serializeHSV | hsv(216, 77%, 100%) |
| HSVA | parseHSVA | serializeHSVA | hsva(216, 77%, 100%, 0.5) |
Named Colors
The CSS Color Module Level 4 keywords — red, rebeccapurple, transparent — are accepted anywhere a color string is, and parseKeyword resolves one directly. They are a keyword lookup rather than a color space: there is no ColorSpace identifier for them, getColorParser does not match them, and there is no serializer — a color rarely lands back on a keyword's exact value. Matching is case-insensitive, and transparent resolves to rgba(0, 0, 0, 0).
Parsing Colors
parseColor auto-detects the format and returns an RGBA tuple [r, g, b, a]:
import {
parseColor,
} from '@ripl/web';
parseColor('#3a86ff'); // [58, 134, 255, 1]
parseColor('rgb(58, 134, 255)'); // [58, 134, 255, 1]
parseColor('hsl(216, 100%, 61%)'); // [58, 134, 255, 1]
parseColor('red'); // [255, 0, 0, 1]
parseColor('transparent'); // [0, 0, 0, 0]
parseColor('currentColor'); // undefinedFor a specific format, use the named parser:
import {
parseHEX,
parseRGB,
} from '@ripl/web';
parseHEX('#ff006e'); // [255, 0, 110, 1]
parseRGB('rgb(255, 0, 110)'); // [255, 0, 110, 1]Serializing Colors
Serializers convert RGBA channel values back to a color string:
import {
serializeHEX,
serializeRGBA,
} from '@ripl/web';
serializeHEX(58, 134, 255, 1); // '#3a86ff'
serializeRGBA(58, 134, 255, 1); // 'rgba(58, 134, 255, 1)'Color Space Conversion
Convert between color spaces using the conversion utilities:
import {
hslToRGBA,
hsvToRGBA,
rgbaToHSL,
rgbaToHSV,
} from '@ripl/web';
rgbaToHSL(58, 134, 255); // [216, 100, 61, 1]
hslToRGBA(216, 100, 61); // [58, 134, 255, 1]
rgbaToHSV(58, 134, 255); // [216, 77, 100, 1]
hsvToRGBA(216, 77, 100); // [58, 134, 255, 1]Modifying Alpha
setColorAlpha parses any color string, replaces its alpha channel, and returns an RGBA string:
import {
setColorAlpha,
} from '@ripl/web';
setColorAlpha('#3a86ff', 0.5); // 'rgba(58, 134, 255, 0.5)'
setColorAlpha('rgb(255, 0, 110)', 0.8); // 'rgba(255, 0, 110, 0.8)'Color Interpolation
When animating between colors via renderer.transition(), Ripl reaches for interpolateColor. It parses both colors to RGBA, interpolates each channel linearly, and serializes back:
import {
interpolateColor,
} from '@ripl/web';
const lerp = interpolateColor('#3a86ff', '#ff006e');
lerp(0); // 'rgba(58, 134, 255, 1)'
lerp(0.5); // 'rgba(157, 67, 162, 1)'
lerp(1); // 'rgba(255, 0, 110, 1)'This happens automatically when transitioning fill or stroke between color values.
Color Schemes
Ripl ships a set of perceptually-uniform palettes as arrays of color stops, each prefixed COLOR_SCHEME_: VIRIDIS, PLASMA, INFERNO, MAGMA, CIVIDIS, TURBO (sequential) and RDBU, BRBG (diverging). Being plain arrays, they compose directly with the interpolation and scale helpers below.
import {
COLOR_SCHEME_VIRIDIS,
interpolateColors,
} from '@ripl/web';
// Build a 0–1 → color interpolator from a scheme's stops.
const viridis = interpolateColors(COLOR_SCHEME_VIRIDIS);
viridis(0); // first stop
viridis(0.5); // midpoint color
viridis(1); // last stopinterpolateColors accepts any array of color stops, so you can pass your own palette just as easily.
Color Scales
scaleSequential maps a numeric domain through a color interpolator (or an array of stops, such as a COLOR_SCHEME_* palette). Values are clamped to the domain, and the returned scale exposes domain, ticks(), and the underlying interpolator (handy for rendering a legend gradient).
import {
COLOR_SCHEME_VIRIDIS,
scaleSequential,
} from '@ripl/web';
const color = scaleSequential(COLOR_SCHEME_VIRIDIS, [0, 100]);
color(0); // first stop
color(50); // midpoint color
color(100); // last stop
color.ticks(5); // [0, 25, 50, 75, 100]Passing a three-element domain [min, neutral, max] produces a diverging scale: neutral maps to the interpolator's midpoint, so signed data reads symmetrically around a reference value:
import {
COLOR_SCHEME_RDBU,
scaleSequential,
} from '@ripl/web';
const anomaly = scaleSequential(COLOR_SCHEME_RDBU, [-5, 0, 5]);
anomaly(-5); // deep red
anomaly(0); // neutral midpoint
anomaly(5); // deep blueThis is exactly how the heatmap chart and its continuous-color legend translate values into color. Tick generation defers to an underlying continuous scale; formatting is always left to the caller and is never bound to the scale.
Internal Representation
All colors are internally represented as RGBA tuples:
type ColorRGBA = [red: number, green: number, blue: number, alpha: number];red,green,blue: 0–255alpha: 0–1