inverse design

Adversarial Illuminant Synthesis

Finds a physically realizable light that makes a safe palette confusable.

figure generated by the instrument itself. hover to let the light in.

The problem

A palette validated under one illuminant is only safe under that illuminant. Metamerism means a set of materials that separate cleanly under D65 can become confusable when the light changes, and nobody checks the worst case. Published adversarial color work attacks CNNs in pixel space; this tool asks the harder question of what the worst realizable light is for a human observer looking at your actual palette.

The method

The candidate illuminant is parametrized as shifted Chebyshev coefficients synthesized onto the canonical 380 to 750 nm grid, clamped to non-negative power, and normalized to 100 at 560 nm so results compare directly to CIE illuminants. A seeded (1+1) evolution strategy with 1/5-success-rule step adaptation then minimizes the palette's smallest pairwise Oklab delta E as perceived under the candidate light, optionally routed through the engine's Machado (2009) CVD simulation for protan, deutan, or tritan observers. The objective rejects degenerate near-dark lights with a total-power floor, since darkness trivially collapses everything and is not a meaningful attack. This builds on the framing that existing adversarial color work targets CNNs in pixel space, while this attacks a human-observer colorimetric system with a realizable light source.

What it promises

  • The attack SPD is physically realizable: non-negative power at every wavelength on the canonical 38-sample grid, normalized to 100 at 560 nm for direct comparison with CIE illuminants.
  • Degenerate near-dark lights are rejected by a total-power floor, so the reported collapse comes from spectral shape, not from turning the lights off.
  • The response reports baseline and attacked minimum delta E (Oklab), the degradation factor between them, and exactly which pair of palette entries collapsed.
  • Fully deterministic given a seed, and it fails loudly: tristimulus palette input is refused with INVALID_ARG because a color has no unique spectrum to attack.

Calling it

{
  "tool": "synthesize_adversarial_spectrum",
  "arguments": {
    "palette": [
      {
        "space": "spd",
        "values": [
          0.85,
          0.6,
          0.25,
          0.1
        ],
        "wavelengths_nm": [
          380,
          500,
          620,
          750
        ]
      },
      {
        "space": "spd",
        "values": [
          0.12,
          0.35,
          0.7,
          0.88
        ],
        "wavelengths_nm": [
          380,
          500,
          620,
          750
        ]
      },
      {
        "space": "spd",
        "values": [
          0.4,
          0.75,
          0.5,
          0.2
        ],
        "wavelengths_nm": [
          380,
          500,
          620,
          750
        ]
      }
    ],
    "baseline_illuminant": "D65",
    "observer": {
      "type": "deutan",
      "severity": 1
    },
    "order": 8,
    "iterations": 2000,
    "seed": 42
  }
}

Clone the repo, build with cd mcp && npm install && npm run build, then register: claude mcp add maryslab -- node <repo>/mcp/dist/server.js

Known limits

  • The optimizer is a seeded stochastic search, so the returned light is a found attack, an existence witness rather than a proven worst case. For guaranteed bounds, use the companion certificate tool.
  • Realizable here means non-negative spectral power on the canonical grid. The tool does not check whether a lamp emitting this exact SPD is manufacturable or commercially available.
  • Separation is measured as minimum pairwise delta E in Oklab under one viewing condition per run: one baseline illuminant (D65, D50, A, or E) and at most one optional CVD observer profile.