Method

How Percevra computes light-aware color

Last reviewed: September 25, 2026

Percevra claims that a palette behaves differently under different light, and that the difference can be measured. This page is the evidence for that claim: the illuminants and standards behind them, the color space the math runs in, the exact formula for the separation diagnostic, the blinded study that tested whether that diagnostic matches human perception (it does not — reported in full below), and the things the model cannot see.

Every threshold, band, and white point below is read directly from the running engine rather than transcribed into prose. If we retune the model, this page changes with it.

The pipeline

One engine, one clamp. The pipeline stays in unclamped linear light from the illuminant cast through chromatic adaptation, and only encodes to sRGB at the very end. That ordering is load-bearing rather than fussy: under a correct Illuminant A about 45% of colors leave the display range at the simulate stage, and clipping is irreversible, so encoding early would mean scoring data the display had already destroyed.

  1. Simulatescene-referred

    Your palette is re-lit by the illuminant — reflected = surface × light — as a von Kries scaling in CAT16 cone space rather than a multiply in RGB primaries. That choice is deliberate: adaptation happens in cone space, and casting the light in a different basis leaves a residue the two stages can never cancel. Nothing is clamped here, so a strong lamp can push bright swatches past 1.0 and those values carry forward rather than clip. Daylight is a true no-op, so D65 never quietly restyles your colors.

  2. Adaptstill unclamped

    The stimulus is chromatically adapted back toward D65 with CAT16 at a fixed degree of adaptation D = 0.6, modelling a viewer whose eyes have partly settled into the room. Because stage one casts in the same space, this is an exact partial inverse: at D = 1 it would recover your original color precisely, so what survives here is cleanly the 40% of the cast a partly-adapted viewer still sees.

  3. Measure and displayone clamp, at the end

    The adapted color is measured in OKLab for the score, and separately encoded to sRGB for the diagnostic swatch shown on this page. Both read the same stage, so this page's swatches and numbers can never tell different stories, and the score is taken before the display encoding throws anything away. (Product preview surfaces — palette cards, the Light Profile, studios — render a separate spectral pipeline at a gentler adaptation degree; see the illuminants section below.)

Which illuminants we simulate

The illuminant names are CIE standards—we did not invent the physics, and the tables below let you check our numbers against the published ones. What differs between our two engines is how much of each standard they reproduce: the tint model matches the illuminant's white point, and the spectral model matches its full spectrum.

Scoring — tint model

The stability diagnostic uses a three-channel linear-RGB multiply. The multipliers are not chosen by eye: each one is derived from its illuminant's published CIE chromaticity at constant luminance, so the white the engine adapts to is the standard's white by construction. The two right-hand columns below are the check — the left is computed live from the running engine, the right is transcribed from the standards. They should agree to four decimal places.

Product previews no longer use this model. Palette cards, the Light Profile, mood and decision previews, and Extract render the spectral pipeline (reflectance reconstructed from each hex, integrated against the lamp's SPD, then CAT16) at a display adaptation of D = 0.85 — a settled viewer — while the diagnostic keeps its harsher D = 0.6 stress test. One preview condition also differs from its diagnostic counterpart by design: the “Blue-sky shade” stop previews a daylight-locus 10000K proxy (shade lit only by clear sky — an estimate, not a measured spectrum), because the diagnostic's CIE D75 is chromatically so close to D65 that a preview of it is visually inert. The diagnostic below still measures CIE D75.

One row does not agree, and it is worth naming. Candlelight at 1900K falls outside the sRGB gamut: reproducing it exactly needs a negative blue multiplier. Its multipliers are clamped to the gamut boundary, which is why its white lands a few ten-thousandths off. Candle is preview-only and never enters a score.

IlluminantStandardUsed forAdapting white (x, y)CIE tabulated (x, y)
DaylightD65CIE D65Reference0.3127, 0.32900.3127, 0.3290
Warm2700KCIE Illuminant ADiagnostic0.4476, 0.40740.4476, 0.4074
Neutral LED4000KCIE LED-B3Diagnostic0.3756, 0.37230.3756, 0.3723
Shade7500KCIE D75Diagnostic0.2990, 0.31490.2990, 0.3149
FluorescentF11CIE F11 (TL84)Diagnostic0.3805, 0.37690.3805, 0.3769
Warm daylightD50CIE D50Preview only0.3457, 0.35850.3457, 0.3585
Candle1900KPlanckian 1900KPreview only0.5368, 0.41000.5381, 0.4112
NightmoonNon-standardPreview only0.2753, 0.2879—

Only 3 of these eight (A, LED-B3, Shade) feed the separation diagnostic below; D65 is the fixed reference it is measured against. A pass/warn/fail badge was formerly judged on A, F11, LED-B3 — it was retired after blinded perceptual testing (see “Does the diagnostic match what people see?” below). Candle, Night, and D50 are visualization only and never affect a number.

Light-Aware Lab — spectral model

The Light-Aware Palette Lab runs the real thing: tabulated CIE relative spectral power distributions for D65, D50, A, F11, and LED-B3, sampled from 380–780 nm at 5 nm intervals (81 samples), integrated against the CIE 1931 2° standard observer color-matching functions. Continuous color temperatures are generated from the Planckian locus or the CIE daylight locus as appropriate. The reference data is generated from colour-science 0.4.7 and committed to the repository rather than fetched at runtime, so results are reproducible.

This path can express spectral effects the tint model cannot, because it integrates a reflectance curve against a real lamp spectrum. It is still working from a reflectance recovered from your hex value, not one measured off your material.

What the math runs in, and why

OKLab / OKLCh

All perceptual distances are Euclidean in OKLab. Unlike HSL, equal numeric steps correspond to roughly equal perceived steps, and unlike CIELAB it stays well behaved for saturated blues, where CIELAB bends hue lines badly. OKLCh is the same space in polar form, so lightness, chroma, and hue readouts and the ΔE that scores them are the same measurement, not two that can disagree.

Distances are scaled ×100 so they land on the familiar ΔE range. On this scale roughly 4 units is a just-noticeable difference in context and 10 units is a comfortably distinct pair.

Linear RGB and CIE XYZ

Light mixes linearly; sRGB does not. Every simulation step is done after undoing the sRGB transfer function, then re-encoded for display. Adaptation runs in CIE XYZ, reached through the standard sRGB primaries matrix.

Whites are normalized to Y = 1, so adaptation only discounts the color of the light and never silently changes luminance.

CAT16 chromatic adaptation

The cone-response transform from CIECAM16 (Li et al., 2017), applied as a partial von Kries scaling from the illuminant's white toward D65. It is better behaved than Bradford in the blue region. The degree of adaptation is fixed at D = 0.6 — not adjustable, because it is the assumption the whole verdict rests on and a slider would let anyone tune their way to a nicer score.

The spectral appearance path in the Lab uses a full von Kries Bradford transform instead; the spectral surface path uses CAT16 at the same D.

Where other metrics are used

OKLab ΔE is the currency for lighting. Two places deliberately use something else: print-gamut and color-naming comparisons use CIEDE2000, which remains the industry reference for small-difference tolerancing, and contrast readouts use APCA alongside WCAG 2 ratios.

The emotional-character score (ECS) is a heuristic over palette statistics. It is not a CIE-defined quantity and should not be read as one.

How the separation diagnostic is computed

Every color shifts under a warm bulb. A uniform cast is physics, not a defect, so measuring absolute shift would mostly measure the lamp. What this diagnostic measures instead is whether the palette's internal structure survives: if two colors were clearly different in daylight, are they still clearly different under this light? It is a well-defined physical quantity — and, as the validation section below reports, one that turned out not to track what people perceive as a palette breaking, which is why it no longer grades anything in the product.

for each pair (i, j) in the palette:
    d_base = ‖ OKLab(cᵢ) − OKLab(cⱼ) ‖ × 100        // separation at D65
    skip the pair if d_base < 10                     // never distinct to begin with
    d_lit  = ‖ OKLab(lit(cᵢ)) − OKLab(lit(cⱼ)) ‖ × 100

retention(illuminant) = min over surviving pairs of ( d_lit / d_base )
collapsed             = any d_lit < 4

stability % = min( retention ) over A, LED-B3, Shade  × 100

where lit() is read at two points in the pipeline:
    settled      = adapt(simulate(c), D = 0.6)    // partly adapted viewer
    first glance = simulate(c)                     // D = 0, unadapted worst case

Why there are two numbers

The same formula is read at two points in the pipeline, and the honest reason is worth stating plainly: the settled number cannot fail. Once the illuminant is cast in cone space, adaptation is an exact partial inverse of it, so a viewer whose eyes have adjusted recovers almost all of the original separation. That is not a loophole in the model — it is colour constancy, and it is the correct result. But it means the settled score is a high, narrow quantity: we searched adversarially for the worst palette it can produce and could not drive it below 78%.

The first-glance figure — the unadapted stimulus, the moment you walk into the room before your eyes do any work — spans roughly 43–100 and was historically the graded number. Those grades are now retired (see the validation section below); both figures remain documented here as diagnostics. The gap between the two is still an honest reading: a palette whose numbers sit far apart is one that only holds together once the room has settled.

It is worst-case twice over: the weakest surviving pair within a light, and then the weakest light of the three. A palette fails at its weakest relationship under its worst condition, not on average, and reporting an average across lights would let a palette that collapses under a warm bulb be rescued by holding up under two others. Retention is a ratio of distances, so it is dimensionless and comparable across palettes of different overall contrast.

Inputs and thresholds

Distinct at base
ΔE ≥ 10 pairs closer than this are not measured
Collapse
ΔE < 4 roles have merged under the light
Retention pass
≥ 0.7 per-illuminant status ok
Retention warn
≥ 0.45 below this, or collapsed, is a fail
Adaptation degree
D = 0.6 settled view; first glance is D = 0
Minimum palette
2 colors fewer returns no score at all

What a number means

Either percentage is the share of the palette's weakest color relationship that survives under its worst light. A first glance of 90% means the pair most at risk still holds about nine tenths of the separation it had in daylight.

Neither percentage carries a grade any more. The five stability bands (Excellent → Sensitive) that used to grade the first-glance figure were retired in September 2026 after blinded perceptual testing found the metric does not predict what people judge as a palette breaking — the section below reports that study in full. The numbers remain published here as physical diagnostics.

A worked example

This palette is run through the live engine every time the page loads, so you can reproduce the arithmetic below rather than take it on faith.

  • #0B3C49
  • #137A7F
  • #7FB8B0
  • #E4DFD0
  • #C46D5E
IlluminantMean shift (ΔE)Retention, settledRetention, first glanceStatusIn headline
A Incandescent3.893.1%87.6%okyes
LED-B32.197.7%93.9%okyes
Open Shade0.6100.0%100.0%okyes
F11 Fluorescent1.691.0%88.4%okno

Worst retention across A, LED-B3, Shade: 93% settled, 88% at first glance. Both are set by Illuminant A, the hardest of the three for this palette. The mean shift column describes how strong each cast is; it does not enter the retention figures.

The second score: MSS

The Material Stability Score answers a different question—absolute drift rather than preserved separation—and is used where a color has to hit a target rather than merely stay distinguishable. Per color it is 1 − max(ΔE across illuminants) / threshold, clamped to 0–1, where the threshold tightens by use case. A palette's MSS is 70% of the mean plus 30% of the worst swatch, so one fragile color cannot be averaged away.

  • 14Print
  • 15UI
  • 16Architecture
  • 17Textile
  • 20Interior
  • 18Default

Thresholds are in the same OKLab ΔE ×100 units. Print is tightest because a proof is judged against a target; interior is loosest because a wall is judged against its own room.

Does the diagnostic match what people see?

In September 2026 we tested it, blind. A reviewer judged palettes shown as-authored beside their simulations under real lamps — no scores, categories, or metric values visible — across two rounds (79 palettes, then a 30-palette confirmation with hidden repeats, near-miss controls, and anchors). The question each time: did the palette’s internal relationships materially change?

The result was decisive and negative: separation retention — settled or first-glance — predicts those judgments at chance level. Palettes with the lowest retention were mostly judged fine; palettes judged broken were scattered across the whole retention range. What people actually track is hue: the judged failures were overwhelmingly pale, low-chroma cool swatches flipping to warm (a pale cyan reading as peach under an incandescent lamp), a signal that per-palette retention averages are structurally blind to.

So we changed the product before changing this page’s math: the pass/warn/fail badge, the stability grades, and every public retention percentage were withdrawn, and surfaces now describe simulations (“previewed across lighting conditions”) rather than issue verdicts. A candidate replacement — a per-swatch pale-flip event defined in Cartesian opponent coordinates — is under pre-registered blinded testing now, and no verdict language returns until a metric passes it. The retention formulas above remain published because they are honest physics and useful diagnostics; they are simply not proof that a palette will look broken or fine to a person.

What the model does not capture

This is the most useful section on the page. A model is only trustworthy to the extent its edges are known, so these are stated as specifically as we can rather than hedged.

Surface finish and geometry

Every color is treated as an ideal flat matte patch. Gloss, sheen, metallic and pearlescent flake, weave, pile direction, texture, translucency, and the angle you stand at all change appearance, and none of them are inputs. A gloss and a matte mix of the same pigment score identically here and will not look identical on a wall.

Metamerism from real pigments

The product path scales three cone responses. A real lamp is a spectrum and a real pigment is a reflectance curve, so two colors that match under one light can separate under another at the same color temperature. No three-channel model can see that, however well chosen its basis. The Light-Aware Lab's spectral path narrows the gap, but it recovers a plausible reflectance from a hex value rather than measuring your actual material.

Display calibration

Results are computed and drawn in sRGB and assume a reasonably calibrated display. Panel technology, gamut, brightness, color profile, ambient light in your own room, night-shift filters, and browser color management all shift what reaches your eye before any of this math matters.

Observer variance

The spectral path uses the CIE 1931 2° standard observer — an average derived from a small mid-century panel, and not a stand-in for any individual. Color vision differs between people, with age, and across field sizes. The degree of adaptation is likewise fixed rather than fitted to a viewer or a room — one value for the diagnostic (D = 0.6) and one for product previews (D = 0.85).

Materials, scale, and surroundings

From a bare hex code the engine infers behavior; it does not know your paint's formulation, substrate, batch, or age. It also scores colors in isolation, so it cannot account for area, adjacency, shadow, inter-reflection between surfaces, or the way a color reads differently on a chip and across a whole room.

The adaptation degree is an assumption, and it decides the answer

D = 0.6 is a deliberate choice representing partial adaptation — mixed lighting, a screen in a lit room, a viewer who has adjusted but not fully. It is not a measurement, and it is the single most consequential number on this page. Sweeping D from 0 to 1 moves the median diagnostic for random palettes from roughly 69 to 99, so almost any stability claim could be manufactured by choosing a different D. We fix it and publish it precisely so the choice is visible rather than load-bearing and hidden.

A settled viewer will see less drift than the score implies

Chromatic adaptation is real and it is strong. Someone who has been in a room for a few minutes discounts most of the lamp's cast, and at D = 1 would recover your palette's separation almost exactly. The first-glance figure deliberately describes the harsher moment before that happens, so treat it as a worst case rather than a prediction of everyday experience.

Known limits of the score itself

Separately from what the physics misses, the stability metric has properties worth knowing before you quote it.

  • It does not predict human judgment. Blinded testing (see the validation section above) found both retention readouts perform at chance against what reviewers perceive as a palette materially breaking under a lamp. Quote either number as a measured property of the simulation, never as evidence a palette will look stable.
  • Scores are not comparable across palette sizes. More colors means more pairs, and the score reports the weakest one, so a seven-color palette is structurally harder to keep stable than a three-color palette. Median first-glance scores across random palettes fall from roughly 79 at three colors to 67 at five and 61 at seven. Compare a palette against alternatives of the same size, not against a number you remember from elsewhere in the app.
  • Low-contrast palettes score perfectly by construction. Pairs closer than ΔE 10 in daylight are excluded from the measurement, so a palette of five near-identical tints has nothing to lose and returns 100%. That is the metric declining to comment, not an endorsement.
  • It is silent about absolute appearance. A palette can keep all of its internal separation while every color shifts a long way from what you specified. Retention will not catch that; the mean shift figure and MSS will.
  • It scores three lights, not your light. Warm 2700K, cool 4000K, and shade are stand-ins for common conditions. A low-CRI lamp, a colored wall bouncing light, or a mixed-source room is not represented.
  • The settled score is close to a formality. It has a floor near 78% even for palettes built adversarially to break it, so a high settled number is weak evidence on its own. Read it as confirmation that adaptation is doing its job, and take the disagreement between it and the first-glance figure as the real signal.

Standards referenced

  • CIE 15:2018 — colorimetry, standard illuminants D65, D50, A, and the F and LED series
  • CIE 1931 2° standard observer color-matching functions
  • CIECAM16 / CAT16 chromatic adaptation transform (Li et al., 2017)
  • IEC 61966-2-1 — sRGB color space and transfer function
  • OKLab / OKLCh perceptual color space (Ottosson, 2020); CSS Color 4
  • CIEDE2000 color-difference formula, used for print gamut and color naming
  • WCAG 2.2 contrast ratios and APCA lightness contrast, used for accessibility readouts

This page describes how the model works. For what its output can and cannot be used to claim—and why physical samples still decide consequential specifications—see Color Accuracy & Real-World Verification.

Color accuracyGuide: how colors change under lightLight-Aware Palette LabTerms of Use