Conversions whitepoint
convert core/convert.js
Convert coordinates between any two color spaces.
coords number[] input coordinates (length 3)
from object|string source space (object or id)
to object|string destination space (object or id)
[out] number[] optional output array (zero-allocation hot loops)
convertBuffer core/convert.js
Convert an interleaved buffer of coordinates — [x0,y0,z0, x1,y1,z1, …] —
between two color spaces. The route is resolved once and the loop runs
allocation-free: a megapixel converts in one call at the cost of the
optimal hand-written zero-alloc loop (~46 ns/px for oklch→srgb), 1.75×
faster than the idiomatic fresh-array-per-pixel pattern. The point is
that you don't have to know how to write that loop.
src ArrayLike<number> length must be a multiple of 3
from object|string source space (object or id)
to object|string destination space (object or id)
[dst] number[]|Float32Array|Float64Array defaults to src (in place)
resolve core/convert.js
Resolve a space id string to its registry object. Throws on unknown ids.
registerRoute core/convert.js
Register a precomposed direct conversion for a space pair, bypassing the XYZ hub.
spaces core/convert.js
The space registry: every id convert() accepts, mapped to its space object.
makeYCbCr spaces/ycbcr.js
Build a YCbCr space. Both options are REQUIRED — there is no default
YCbCr, by design.
@param {{matrix: '601'|'709'|'2020', range: 'full'|'limited'}} opts
oklabToRgbDirect spaces/oklab.js
Build a direct OKLab → RGB-space converter with the LMS→linear-RGB matrix
precomposed at build time. This is the hot path for rendering work: one
3×3, three cubes, one 3×3, one transfer encode.
CSS strings whitepoint
parse parse/index.js
Parse a CSS Color 4 <color> string to registry coordinates.
Returns { space, coords, alpha } normalized to library conventions,
or null if the string doesn't parse — a bad string is data, not an
error. none components come back as NaN (they flow safely; see the
numerical policy). Accepts hex, the 148 named colors + transparent,
all Level 4 functional forms (modern and legacy comma syntax), and
color() with the predefined + CSS HDR draft space ids. Relative color
syntax (Level 5) and calc() are out of scope.
str string
returns {{space: string, coords: number[], alpha: number} | null}
parseTo parse/index.js
Parse a CSS color string straight to coordinates in to — the
one-liner: parseTo('#ff8800', 'oklch'). Alpha is dropped (use parse()
when you need it). Returns null if the string doesn't parse.
str string
to object|string destination space (object or id)
[out] number[]
NAMED_COLORS parse/named.js
The 148 CSS named colors (CSS Color 4 §6.1), name → #rrggbb.
serialize ops/serialize.js
Serialize coordinates in space to a CSS color string.
coords number[]
space object|string
@param {{alpha?: number, precision?: number}} [opts]
Illuminants & adaptation whitepoint
adapt lab/adapt.js
Adapt XYZ tristimulus values from one illuminant to another.
xyz number[] input XYZ
from string|number[] source white point (name, [x,y], or [X,Y,Z])
to string|number[] - destination white point
[out] number[] - optional output array
@param {{cat?: 'bradford'|'cat02'|'cat16'|'vonkries'|'xyz-scaling'}} [opts]
adaptMatrix lab/adapt.js
Resolve a white point argument to XYZ (Y = 1) plus a stable cache key.
Accepts: an illuminant name ('D65', 'A', …), an [x, y] chromaticity,
or a full [X, Y, Z] tristimulus.
/
const _namedWhites = new Map();
function resolveWhite(w) {
if (typeof w === 'string') {
let r = _namedWhites.get(w);
if (!r) {
const xy = illuminants[w];
if (!xy) throw new Error(whitepoint: unknown illuminant "${w}" (have: ${Object.keys(illuminants).join(', ')}));
_namedWhites.set(w, (r = { key: w, xyz: xyToXyz(xy) }));
}
return r;
}
if (w.length === 2) {
return { key: xy:${w[0]},${w[1]}, xyz: xyToXyz(w) };
}
return { key: xyz:${w[0]},${w[1]},${w[2]}, xyz: w };
}
const _matrixCache = new Map();
/**
The 3×3 adaptation matrix from one white point to another.
Cached per (cat, src, dst). Useful directly for precomposition.
illuminants constants/whitepoints.js
CIE illuminant chromaticities (CIE 15:2004): A, B, C, D50–D75, E, F2/F7/F11.
illuminantFromCCT lab/cct.js
XYZ (Y = 1) white point of CIE daylight at temperature T — usable directly
as a white point argument to adapt().
daylightXy lab/cct.js
xy chromaticity of CIE standard daylight at correlated color temperature T.
T number kelvin, 4000–25000
[out] number[]
cats constants/cats.js
Chromatic adaptation cone matrices: bradford, cat02, cat16, vonkries, xyz-scaling.
xyToXyz constants/whitepoints.js
xy chromaticity → XYZ tristimulus with Y = 1.
CSS_D50 constants/whitepoints.js
CSS Color 4 §10 D50 (4-digit).
CSS_D65 constants/whitepoints.js
CSS Color 4 §10 white points — the 4-digit chromaticities the CSS spec normalizes to.
CSS_D50_XYZ constants/whitepoints.js
CSS D50 as XYZ tristimulus (Y = 1).
CSS_D65_XYZ constants/whitepoints.js
CSS D65 as XYZ tristimulus (Y = 1).
Gamut whitepoint
toGamut gamut/index.js
Map a color into a bounded RGB gamut. Input and output are in space.
coords number[]
space object|string the space coords is expressed in
@param {{gamut?: object|string, method?: 'css'|'cusp'|'clip'}} [opts]
[out] number[]
inGamut gamut/index.js
Is a color inside the gamut of a bounded RGB space?
clip gamut/index.js
Per-channel clamp to [0, 1] (in gamut-space coordinates).
findCusp gamut/index.js
The OKLCH gamut cusp (L, C) at hue h — exact channel-zero cubic, centidegree-cached.
findCuspNumerical gamut/index.js
Ground-truth cusp by golden-section search over L with bisection on C,
using full library conversions. Slow; exists to verify findCusp.
maxChromaAt gamut/index.js
Exact maximum in-gamut chroma at a fixed OKLCH lightness and hue —
bracketed bisection on the channel cubics (checking both 0 and 1 bounds).
The exact counterpart of Ottosson's find_gamut_intersection along
constant L; used by OKHSL.
deltaEOK gamut/index.js
Euclidean distance in OKLab — the deltaE of CSS Color 4 gamut mapping.
Mixing & difference whitepoint
mix ops/mix.js
Mix two colors (both in space) at parameter t per CSS Color 4 §12.
a number[] coordinates in space
b number[] coordinates in space
t number 0 → a, 1 → b
space object|string
@param {{hue?: 'shorter'|'longer'|'increasing'|'decreasing'}} [opts]
[out] number[]
mixAlpha ops/mix.js
Premultiplied-alpha mix per CSS Color 4 §12.3. Inputs and output are
length-4: [c0, c1, c2, alpha]. Non-hue coordinates are weighted by alpha
before interpolation and unweighted after; hue is never premultiplied.
When the interpolated alpha is 0, coordinates interpolate unweighted
(the spec's 0/0 case — the color is fully transparent either way).
hueDelta ops/mix.js
Hue delta per CSS Color 4 §12.4, from normalized hues.
deltaE2000 ops/diff.js
lab1 number[] CIE Lab
lab2 number[] CIE Lab
@param {{kL?: number, kC?: number, kH?: number}} [weights] - parametric factors (default 1)
deltaECAM16 ops/diff.js
CAM16-UCS color difference ΔE′ (Li et al. 2017): Euclidean distance in
CAM16-UCS under the default viewing conditions.
a number[] coordinates in space
b number[] coordinates in space
[space] object|string the space a and b are expressed in
contrastWCAG2 ops/contrast.js
WCAG 2.x contrast ratio (1–21) between two colors in space.
WCAG is defined on sRGB; other spaces are converted (and clipped — WCAG
has no notion of out-of-gamut color).
wcagLuminance ops/contrast.js
WCAG 2.x relative luminance of gamma sRGB coordinates (0–1, clipped).
Compositing & blending whitepoint
composite ops/composite.js
Porter-Duff compositing of PREMULTIPLIED colors.
srcP number[] premultiplied [c0,c1,c2,a]
dstP number[] premultiplied [c0,c1,c2,a]
[op] string operator (default 'source-over')
[space] object|string rectangular space (default 'srgb-linear')
[out] number[]
overStack ops/composite.js
Source-over of an entire layer stack (layers[0] on top), PREMULTIPLIED,
via the closed form — one accumulation, no intermediate composites.
premultiply ops/composite.js
Straight [c0,c1,c2,a] → premultiplied.
unpremultiply ops/composite.js
Premultiplied → straight. The division amplifies relative error by 1/alpha;
at alpha = 0 the color is undefined and channels are passed through.
porterDuffOperators ops/composite.js
The 13 Porter–Duff operator names composite() accepts.
blend ops/composite.js
W3C blend-then-composite (source-over), on STRAIGHT-alpha colors, per the
spec's general formula: Cs′ = (1−αb)·Cs + αb·B(Cb, Cs).
The spec defines blending on gamma sRGB (the default here); other
rectangular spaces are accepted for deliberate off-label use.
src number[] straight [c0,c1,c2,a]
dst number[] straight backdrop [c0,c1,c2,a]
blendModes ops/composite.js
The 16 W3C blend mode names blend() accepts.
Direct space routes whitepoint
srgbToHsl spaces/hsl.js
gamma sRGB → [H, S, L]
hslToSrgb spaces/hsl.js
[H, S, L] → gamma sRGB, CSS Color 4 §7.1 algorithm.
srgbToHsv spaces/hsv.js
sRGB → HSV (hue degrees, s/v 0–1), the direct hexcone route.
hsvToSrgb spaces/hsv.js
HSV → sRGB, inverse of srgbToHsv.
srgbToHsi spaces/hsv.js
sRGB → HSI (intensity = mean of channels — the classic image-processing variant).
hsiToSrgb spaces/hsv.js
HSI → sRGB, inverse of srgbToHsi.
srgbToHwb spaces/hsl.js
gamma sRGB → [H, W, B]
hwbToSrgb spaces/hsl.js
[H, W, B] → gamma sRGB, CSS Color 4 §8.2
Math & internals whitepoint
mul core/mat3.js
3×3 matrix product a·b.
mulVec core/mat3.js
3×3 matrix × column vector.
invert core/mat3.js
Exact 3×3 inverse via adjugate over determinant — how every CAT inverse is computed.
deriveRgbMatrices core/derive.js
@param {{r:[number,number], g:[number,number], b:[number,number], white:[number,number]}} def
returns {{ toXyz: number[], fromXyz: number[], whiteXyz: number[] } }
polarToRect core/polar.js
[L, C, H] → [L, a, b]
rectToPolar core/polar.js
[L, a, b] → [L, C, H]
transfer constants/transfer.js
Transfer-function registry: named encode/decode pairs for every RGB space EOTF/OETF.
pqDecode constants/hdr.js
PQ signal (0–1) → absolute luminance (cd/m²). EOTF.
pqEncode constants/hdr.js
Absolute luminance (cd/m², ≥0) → PQ signal (0–1). Inverse EOTF.
DEG2RAD core/polar.js
Degrees → radians.
RAD2DEG core/polar.js
Radians → degrees.
YW constants/hdr.js
BT.2408 reference (graphics/diffuse) white, 203 cd/m² — the HDR signal anchor.
Shader emission whitepoint/codegen
glsl codegen/index.js
GLSL ES 3.00 source for a from→to conversion (declare precision highp float;).
glslBlend codegen/index.js
GLSL blend-then-composite (source-over) for a W3C blend mode, straight-alpha vec4.
glslComposite codegen/index.js
GLSL Porter-Duff compositor over premultiplied vec4.
glslGamutMap codegen/index.js
GLSL gamut mapper: OKLCH in, gamut-mapped RGB (in gamut coords) out.
glslMix codegen/index.js
GLSL mixer for a space with a CSS Color 4 hue interpolation method.
js codegen/index.js
JavaScript source for a standalone, dependency-free from→to function.
jsBlend codegen/index.js
Standalone JS blend (parity-tested against the library in CI).
jsComposite codegen/index.js
Standalone JS Porter-Duff compositor (parity-tested in CI).
jsGamutMap codegen/index.js
Standalone JS gamut mapper (used for parity testing the shader logic).
jsMix codegen/index.js
Standalone JS mixer (parity-tested against the library mix in CI).
specialPairs codegen/special.js
The hand-templated emitter pairs (solver spaces + CAM16) available beyond op-chains.
supported codegen/index.js
Space ids available to the codegen pipeline.
wgsl codegen/index.js
WGSL source for a from→to conversion.
wgslBlend codegen/index.js
WGSL blend.
wgslComposite codegen/index.js
WGSL Porter-Duff compositor.
wgslGamutMap codegen/index.js
WGSL gamut mapper.
wgslMix codegen/index.js
WGSL mixer.
Spectra & CMFs whitepoint/spectral
sampleSpd spectral/index.js
Sample a uniform-grid spectrum at wavelength λ (nm), linear interpolation.
emissionToXyz spectral/index.js
Unnormalized tristimulus of an emission spectrum: X = Σ S(λ)·x̄(λ)·Δλ.
Proportional values — normalize per your application (e.g. divide by Y
for relative colorimetry, or use spectrumXy for chromaticity).
spectrumXy spectral/index.js
xy chromaticity of a spectrum.
reflectanceToXyz spectral/index.js
Hub-ready XYZ (Y = 1 for the perfect reflector) of a reflectance spectrum
under an illuminant: the canonical CIE 015 object-color computation,
X = k·Σ R(λ)·S(λ)·x̄(λ)·Δλ, k = 1 / Σ S(λ)·ȳ(λ)·Δλ.
The result feeds convert()/adapt() directly.
resample spectral/index.js
Resample a uniform-grid spectrum onto a new grid by Sprague (1880)
quintic interpolation — the method CIE 167:2005 recommends for spectral
data tabulated at equal intervals. Exact at source nodes; interior
segments (two nodes in from each end) reproduce polynomials through
degree 4 to rounding and hit the analytic Planckian to ~4e-9 relative;
the two segments at each end use the CIE 167 boundary polynomials,
which are approximations tuned for spectra (~4e-4 on the Planckian) —
prefer sources that extend a little past the range you need. Never
extrapolates: the target grid must lie within the source range.
Verified against colour-science's SpragueInterpolator and Planck's law
in test/resample.test.js.
CMF_1931_2 spectral/data.js
CIE 1931 2° standard observer CMFs, 5 nm, 360–830 nm (CVRL).
CMF_1964_10 spectral/data.js
CIE 1964 10° standard observer CMFs, 5 nm (CVRL).
D65_SPD spectral/data.js
CIE standard illuminant D65 relative SPD, 1 nm, 300–830 nm (CVRL).
DAYLIGHT_S spectral/data.js
CIE daylight basis functions (CIE 015 Table 6), 5 nm.
Standard illuminant SPDs whitepoint/spectral
FL1_SPD spectral/data-fluorescent.js
CIE F1 fluorescent illuminant relative SPD — daylight, halophosphate (CIE 015), 5 nm.
FL2_SPD spectral/data-fluorescent.js
CIE F2 fluorescent illuminant relative SPD — cool white, halophosphate (CIE 015), 5 nm.
FL3_SPD spectral/data-fluorescent.js
CIE F3 fluorescent illuminant relative SPD — white, halophosphate (CIE 015), 5 nm.
FL4_SPD spectral/data-fluorescent.js
CIE F4 fluorescent illuminant relative SPD — warm white, halophosphate (CIE 015), 5 nm.
FL5_SPD spectral/data-fluorescent.js
CIE F5 fluorescent illuminant relative SPD — daylight, halophosphate (CIE 015), 5 nm.
FL6_SPD spectral/data-fluorescent.js
CIE F6 fluorescent illuminant relative SPD — light white, halophosphate (CIE 015), 5 nm.
FL7_SPD spectral/data-fluorescent.js
CIE F7 fluorescent illuminant relative SPD — D65 simulator, broadband (CIE 015), 5 nm.
FL8_SPD spectral/data-fluorescent.js
CIE F8 fluorescent illuminant relative SPD — D50 simulator, broadband (CIE 015), 5 nm.
FL9_SPD spectral/data-fluorescent.js
CIE F9 fluorescent illuminant relative SPD — cool white deluxe, broadband (CIE 015), 5 nm.
FL10_SPD spectral/data-fluorescent.js
CIE F10 fluorescent illuminant relative SPD — three-band (CIE 015), 5 nm.
FL11_SPD spectral/data-fluorescent.js
CIE F11 fluorescent illuminant relative SPD — three-band (CIE 015), 5 nm.
FL12_SPD spectral/data-fluorescent.js
CIE F12 fluorescent illuminant relative SPD — three-band (CIE 015), 5 nm.
HP1_SPD spectral/data-hp.js
CIE HP1 illuminant relative SPD — standard high pressure sodium lamp (CIE 015), 5 nm.
HP2_SPD spectral/data-hp.js
CIE HP2 illuminant relative SPD — colour-enhanced high pressure sodium lamp (CIE 015), 5 nm.
HP3_SPD spectral/data-hp.js
CIE HP3 illuminant relative SPD — high pressure metal halide lamp (CIE 015), 5 nm.
HP4_SPD spectral/data-hp.js
CIE HP4 illuminant relative SPD — high pressure metal halide lamp (CIE 015), 5 nm.
HP5_SPD spectral/data-hp.js
CIE HP5 illuminant relative SPD — high pressure metal halide lamp (CIE 015), 5 nm.
LED_B1_SPD spectral/data-led.js
CIE LED-B1 illuminant relative SPD — phosphor-converted (blue-pump) white LED, ~2700 K (CIE 015:2018), 5 nm.
LED_B2_SPD spectral/data-led.js
CIE LED-B2 illuminant relative SPD — phosphor-converted (blue-pump) white LED, ~3000 K (CIE 015:2018), 5 nm.
LED_B3_SPD spectral/data-led.js
CIE LED-B3 illuminant relative SPD — phosphor-converted (blue-pump) white LED, ~4000 K (CIE 015:2018), 5 nm.
LED_B4_SPD spectral/data-led.js
CIE LED-B4 illuminant relative SPD — phosphor-converted (blue-pump) white LED, ~5000 K (CIE 015:2018), 5 nm.
LED_B5_SPD spectral/data-led.js
CIE LED-B5 illuminant relative SPD — phosphor-converted (blue-pump) white LED, ~6500 K (CIE 015:2018), 5 nm.
LED_BH1_SPD spectral/data-led.js
CIE LED-BH1 illuminant relative SPD — hybrid (blue-pump + red) white LED, ~2700 K (CIE 015:2018), 5 nm.
LED_RGB1_SPD spectral/data-led.js
CIE LED-RGB1 illuminant relative SPD — RGB-mixed white LED, ~3000 K (CIE 015:2018), 5 nm.
LED_V1_SPD spectral/data-led.js
CIE LED-V1 illuminant relative SPD — violet-pump phosphor white LED, ~2700 K (CIE 015:2018), 5 nm.
LED_V2_SPD spectral/data-led.js
CIE LED-V2 illuminant relative SPD — violet-pump phosphor white LED, ~4000 K (CIE 015:2018), 5 nm.
Illuminants & emitters whitepoint/spectral
planckianSPD spectral/index.js
Relative SPD of a Planckian (blackbody) radiator at temperature T,
normalized to 1 at 560 nm per CIE convention. Pure physics, no fit.
planckianXy spectral/index.js
The TRUE Planckian locus: blackbody chromaticity by integration of
Planck's law against the CMFs. Replaces fitted approximations entirely.
Valid wherever Planck's law is (any positive T).
illuminantASPD spectral/index.js
CIE standard illuminant A: a Planckian radiator at 2856 K (CIE 015).
daylightSPD spectral/index.js
Relative SPD of CIE daylight at correlated color temperature T
(4000–25000 K), synthesized from the S0/S1/S2 basis functions with
weights M1/M2 from the daylight-locus chromaticity.
cctOf spectral/index.js
Correlated color temperature and Duv of a chromaticity — solved by
minimizing CIE 1960 uv distance to this library's EXACT Planckian locus
(Planck's law integrated against the CMFs), not a fitted approximation
like McCamy. Duv is signed: positive above the locus (greenish), negative
below (pinkish). CCT is conventionally meaningful for |duv| ≲ 0.05.
xy number[] chromaticity
returns {{cct: number, duv: number} }
lowPressureSodiumSPD spectral/index.js
Low-pressure sodium (SOX) lamp: the Na D doublet, D2 588.9950 nm and
D1 589.5924 nm (NIST ASD, air wavelengths) at the 2:1 statistical-weight
intensity ratio. The canonical near-monochromatic illuminant — under it,
color appearance collapses to a single hue.
Note this is NOT a CIE standard illuminant: the CIE standardizes only the
*high*-pressure sodium lamps (HP1_SPD, HP2_SPD). It's a modeled idealized
lamp, kept exact as two lines; for the full Na I line set under the
discharge model see emissionSPD('sodium').
emissionColor spectral/index.js
The render-ready color of an atomic emitter, in one call — the spectral
pipeline a web developer actually wants:
emissionColor('neon') // → [0.63, 0.26, 33] oklch, sRGB-safe
emissionColor('neon', { gamut: 'display-p3' }) // → a redder neon a wide screen can show
emissionColor('argon', { to: 'srgb' }) // → sRGB coords, ready for a hex
The hue *and saturation* are the physics: emissionSPD → XYZ against the
1 nm observer (so the spiky lines don't alias — the trap of the
lower-level path) → the emitter's chromaticity. The color is returned at
the chosen display's cusp *lightness* (as bright as that gamut allows for
the hue — right for a glowing light), carrying the emitter's own chroma
clamped to what the display can show. So saturated emitters land on the
cusp (vivid neon) while pale ones stay pale (argon's lavender, not a
cranked magenta) — never out of range. gamut picks the display (default
'srgb'); a wider gamut shows the same hue with more chroma (the
wide-gamut win, made literal). to is just the output coordinate space.
The physics is here, at load. For the GPU side, emit the matching color
math with whitepoint/codegen (glsl, glslGamutMap) — same constants,
parity-tested. This is a convenience over emissionSPD + emissionToXyz +
findCusp + convert; every step stays individually exported.
emissionSPD spectral/index.js
SPD of a named atomic emitter, or of your own transition data, derived —
not transcribed — from atomic physics: optically-thin emission with
Boltzmann-populated upper levels, line power ∝ (g_k·A_ki/λ)·exp(−E_k/kT).
emissionSPD('neon') // a name from EMISSION_LINES
emissionSPD(EMISSION_LINES.neon) // the same, data passed directly
emissionSPD(myLines) // your own [λ_nm, g·A s⁻¹, E_k eV] rows
There is no standard illuminant for a neon sign — this is how you compute
one. The same model fits any thermally-excited atomic emitter, a discharge
tube or a flame metal (sodium, lithium…). kT is the excitation temperature
in eV; the 0.5 eV default sits in the measured glow-discharge range, and
since level energies dominate the line ratios, each emitter lands in its
known color region across that whole range (neon red-orange x ≈ 0.67,
argon lavender, mercury blue-white — pinned in test/lines.test.js).
Honesty: sign plasmas are not in LTE; kT is an effective parameter, and
ASD's qualitative observed-intensity column is deliberately unused. The
lines are spiky — integrate against the 1 nm observer (see emissionColor,
or pass CMF_1931_2_1NM to spectrumXy/emissionToXyz).
lineSPD spectral/index.js
SPD of a set of emission lines, each [λ_center nm, power], as Gaussian
profiles whose integrals equal the line powers. Real discharge lines are
~0.1 nm wide; the default 2 nm FWHM is the narrowest a 1 nm grid sums
exactly (discrete-integral aliasing < 2e-6 by Poisson summation, vs ~5%
at 1 nm FWHM), and chromaticity is insensitive to width at this scale.
Integrate against the 1 nm CMFs (whitepoint/spectral-1nm) for spiky
spectra.
EMISSION_LINES spectral/data-lines.js
Emission-line transitions per element: arrays of [λ_air nm, g_k·A_ki s⁻¹, E_k eV].
Lamp quality whitepoint/spectral
cri spectral/quality.js
CIE 13.3-1995 color rendering index of a light-source SPD.
Reference is a Planckian radiator below 5000 K, CIE daylight at or
above. Ra is the mean of R1–R8; the specials R9–R14 (R9 = strong red,
the famous LED-killer) ride along in Ri. CRI is conventionally
meaningful only near the locus (|duv| < 0.0054 per the spec) — the duv
is returned so you can judge.
@param {{start:number, step:number, values:number[]}} spd
returns {{Ra:number, Ri:number[], cct:number, duv:number} }
tm30 spectral/quality.js
IES TM-30-20 / CIE 224:2017 color fidelity of a light-source SPD:
fidelity index Rf (0–100, CAM02-UCS distance over 99 spectrally
representative CES) and gamut index Rg (100 = reference gamut area;
below = desaturating, above = oversaturating). The modern, vastly more
robust successor to CRI.
@param {{start:number, step:number, values:number[]}} spd
returns {{Rf:number, Rg:number, cct:number, duv:number} }
cam02ViewingConditions spectral/quality.js
Precompute CIECAM02 viewing conditions. Surround is average
(F = 1, c = 0.69, Nc = 1); pass discountIlluminant for D = 1.
xyzToCam02Ucs spectral/quality.js
CIECAM02 → CAM02-UCS J′a′b′ for XYZ on the 0–100 scale. The forward
model only — exactly what CIE 224 / TM-30 needs.
Vision & media whitepoint/spectral
simulateCVD spectral/cvd.js
Simulate color vision deficiency. Input/output in space.
coords number[]
space object|string
@param {{type: 'protanopia'|'deuteranopia'|'tritanopia', severity?: number}} opts
[out] number[]
photopicLuminance spectral/index.js
Photopic luminance of a spectral radiance distribution:
Lp = Km·Σ S(λ)·V(λ)·Δλ, with V(λ) = the CMF ȳ. If S is in
W·m⁻²·sr⁻¹·nm⁻¹ the result is cd/m²; relative input gives relative output.
scotopicLuminance spectral/index.js
Scotopic (rod-vision) luminance: Ls = K′m·Σ S(λ)·V′(λ)·Δλ, with the
CIE 1951 scotopic efficiency V′(λ). Same units convention as
photopicLuminance. The two agree by construction on a 555 nm line —
that anchor is verified in the test suite, not assumed.
mesopic spectral/index.js
CIE 191:2010 recommended system for mesopic photometry (MES2): the rod/
cone blend weight m and mesopic luminance for given photopic and scotopic
luminances (cd/m²). m = 1 at and above 5 cd/m² (cones only), m = 0 at and
below 0.005 cd/m² (rods only); between, m solves the spec's implicit
equation by its published iteration. The constants 0.7670 and 0.3334 are
the spec's rounded solutions of those two endpoint conditions.
returns {{m: number, luminance: number} }
V_PRIME_1951 spectral/data-scotopic.js
CIE (1951) scotopic luminous efficiency function V′(λ), 1 nm,
380–780 nm (CVRL). Peak at 507 nm; the rod sensitivity
curve. Shaped like a CMF y-channel for use with the same samplers.
attenuate spectral/index.js
Attenuate a spectrum through an absorbing medium: Beer–Lambert
S(λ)·exp(−a(λ)·d). Pair with WATER_ABSORPTION (Pope & Fry 1997, 1/m)
and d in meters for underwater light; any absorption spectrum with
reciprocal-length units works the same way.
WATER_ABSORPTION spectral/data-water.js
Spectral absorption coefficient of pure water, 1/m, 2.5 nm,
380–727.5 nm. Pope & Fry (1997), Appl. Opt. 36, 8710,
integrating-cavity measurements (via OMLC). Beer–Lambert ready:
T(λ, d) = exp(−a(λ)·d) with d in meters.
Sky (Hosek–Wilkie) whitepoint/sky
SKY_WL sky/data.js
Band wavelengths, nm.
skyModel sky/index.js
Precompute a sky state for given conditions. The returned object feeds
skyRadiance/skySPD; reuse it across the whole dome.
opts object
opts.elevation number solar elevation above horizon, radians (0–π/2)
[opts.turbidity number =3] - Linke-style atmospheric turbidity (1–10)
[opts.albedo number =0.1] - ground albedo (0–1)
skyRadiance sky/index.js
Spectral sky radiance for a view direction, W·m⁻²·sr⁻¹·nm⁻¹.
Linear interpolation between the model's 40 nm bands, exactly as the
reference implementation does.
state object from skyModel()
theta number view zenith angle, radians (0 = zenith)
gamma number angular distance from the sun, radians
wavelength number nm (320–720; 0 outside)
skySPD sky/index.js
The sky's SPD for a view direction, on a uniform grid ready for
spectrumXy()/reflectanceToXyz()/cctOf(). Same units as skyRadiance.
sunRadiance sky/index.js
Direct radiance of the solar disc itself, W·m⁻²·sr⁻¹·nm⁻¹ — zero
outside the disc (angular radius 0.255°), limb-darkened within it
(the sun is visibly dimmer and warmer at its edge; the model carries
the astronomical 5th-order fit per band). The reference's
solar_radiance is this plus skyRadiance — add them for a view that
includes both the disc and the in-scattered sky.
state object from skyModel()
theta number view zenith angle, radians
gamma number angular distance from the sun's center, radians
wavelength number nm (320–720; 0 outside)
sunSPD sky/index.js
The direct sun's SPD for a view direction (disc only — add skySPD for
the total). Default gamma 0 looks at the disc's center: the color of
direct sunlight through this atmosphere.