Spectral Palette Designer
Design reflectance spectra whose separation survives changes in lighting and observer.
The problem
A palette designed in a color space is only safe under the illuminant it was designed for. Change the lighting and metamerism can collapse pairs that looked well separated, and a color vision deficiency can collapse them further. This tool designs the physical reflectance spectra instead of the colors, so separation can be constrained jointly across every lighting and observer condition you care about.
The method
Each spectrum is parametrized as shifted Chebyshev coefficients, synthesized onto the canonical 380 to 750 nm grid (38 samples) and clamped to [0,1]. Low order means smooth, and smooth is the tool's proxy for manufacturable. A seeded (1+1) evolution strategy with 1/5-success-rule step adaptation maximizes the worst-case minimum pairwise ΔE in Oklab over every listed illuminant times observer condition, with a small second-difference roughness penalty; deficient observers are modeled through the same Machado 2009 CVD simulation used everywhere else in the engine. The ES was chosen over gradient methods because the objective routes through clamping and CVD simulation, which are non-smooth, and because determinism given a seed matters more than the last few percent of convergence.
What it promises
- The reported separation is the measured worst case: minimum pairwise ΔE_OK re-evaluated per condition after optimization, returned alongside the per-condition breakdown, not the optimizer's internal score.
- Fully deterministic given a seed, so results are reproducible and every response carries engine_version and dataset_snapshot.
- Fails loudly instead of fudging: if the target minimum ΔE_OK is unreachable, the tool errors with NO_SOLUTION and reports the best achieved bound so you can relax the target, reduce classes, or raise iterations.
- The guarantee covers exactly the conditions you list (up to 8 illuminant times observer pairs). It is not a certificate over a continuous illuminant family; that stronger check is a separate tool, certify_illuminant_robustness.
Calling it
{
"tool": "design_spectral_palette",
"arguments": {
"n_classes": 5,
"conditions": [
{
"illuminant": "D65",
"cvd": null
},
{
"illuminant": "A",
"cvd": null
},
{
"illuminant": "D65",
"cvd": {
"type": "deutan",
"severity": 1
}
}
],
"target_min_delta_e_ok": 0.08,
"order": 6,
"iterations": 2000,
"seed": 42
}
} Clone the repo, run npm install and npm run build in mcp/, then: claude mcp add maryslab -- node <repo>/mcp/dist/server.js
Known limits
- The (1+1)-ES is a stochastic local search: the achieved bound is what it found under your seed and iteration budget, not a proven optimum.
- Separation is guaranteed only at the enumerated conditions, not over a continuous family of lights.
- Smoothness stands in for manufacturability: low-order Chebyshev spectra are smooth, but no pigment or fabrication model is checked.