Skip to content

Demo's Lightness Mapping table shows the wrong "Target L" for every non-neutral meaning (it reimplements the mapper's target formula without the 20–82% band) #121

Open

Description

@matt-edmondson

What's wrong

ThemeProvider.Demo/Program.cs CalculateTargetLightnessForPriority (~lines 438–480) is a copy of the private SemanticColorMapper.CalculateTargetLightnessForSemantic (ThemeProvider/SemanticColorMapper.cs ~160–225). The copy predates the change that put non-neutral meanings into 20–82% of the global lightness range: it always spreads targets across the full global min–max and ignores the meaning.

So in the demo's "Lightness-Based Priority System" table, "Target L" disagrees with "Actual L" for Primary, Alternate, Success and every other non-neutral meaning, which makes the mapper look like it misses its targets. Only copy-paste keeps the two in sync, and it has already drifted.

Repro

Console app against the built library, Catppuccin Mocha, Primary. demoTarget = the demo's formula; actual = MakeCompletePalette(...) colour .ToOklab().L:

VeryLow    demoTarget=0.18 actual=0.32
Low        demoTarget=0.30 actual=0.39
MediumLow  demoTarget=0.41 actual=0.47
Medium     demoTarget=0.53 actual=0.54
MediumHigh demoTarget=0.65 actual=0.61
High       demoTarget=0.76 actual=0.68
VeryHigh   demoTarget=0.88 actual=0.75

For Neutral the columns agree, because Neutral really does use the full range.

Suggested fix

Stop duplicating the formula. Expose the target calculation from the library, e.g. a public SemanticColorMapper.GetTargetLightness(ISemanticTheme theme, SemanticColorRequest request) built on the existing private helpers; have the demo call it and delete CalculateTargetLightnessForPriority.

Acceptance criteria

  • The demo contains no lightness-range or target formula of its own.
  • A unit test asserts that, for every built-in theme, meaning and priority, GetTargetLightness is within 1e-3 of the Oklab L of the MakeCompletePalette colour wherever that colour is in gamut.

Related: #115 covers the demo's label text ("non-neutral uses 50–90%", Program.cs:252) and stale docs, not the computed values.

Activity

  1. matt-edmondson commented on Sep 30, 2026

    @matt-edmondson
    ContributorAuthor

    Triage

    • Category: Bug
    • Priority: Low. Only the demo app is affected. The library's actual palette output is correct. The demo's "Target L" column just misrepresents it, so the mapper appears to miss targets that it actually hits.
    • Area / suggested assignment: ThemeProvider.Demo/Program.cs (CalculateTargetLightnessForPriority) and SemanticColorMapper. The proposed fix adds a small public API (GetTargetLightness).
    • Duplicates / in progress: Not a duplicate. It is related to README's MapColors sample doesn't compile after the Semantics.Color migration (color.RgbValue), and the docs and demo still say non-neutral meanings use 50-90% of the range (code uses 20-82%) #115, which covers the demo's label text and stale docs rather than the computed values, and the two could land together. No open PR covers it; the only open PR in the repo, Bump the ktsu group with 1 update #120, is a dependency bump.
    • Notes: Exposing the target calculation is the right fix, and the proposed parity test (target within 1e-3 of the in-gamut Oklab L for every theme, meaning and priority) would also guard the library against future drift. Consider whether the new public method needs the same ISemanticTheme overloads as MakeCompletePalette.

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions