Skip to content

Keep source alpha and tolerate round-trip error when extrapolating a single colour [patch] - #127

Merged
matt-edmondson merged 1 commit into
mainfrom
fix/111-single-colour-alpha-and-gamut
Oct 5, 2026
Merged

matt-edmondson merged 1 commit into
mainfrom
fix/111-single-colour-alpha-and-gamut

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #111

What changed

Both defects are in SemanticColorMapper.ExtrapolateColorToLightness, which handles single-colour meanings.

  • Alpha. Every Color.FromOklab call there now passes baseColor.A. Before this, accents always came out opaque, while interpolated neutral ramps kept their alpha.
  • Gamut tolerance. The two exact [0, 1] channel checks are replaced by one IsInGamut helper that allows ±1e-6 (GamutTolerance). Both return paths now finish with Color.Clamp(), so a colour accepted inside that tolerance still comes out in [0, 1]. As a result, #ff0000 comes back as #ff0000 instead of #ff0201.
  • ExtrapolateColorToLightness is now internal so it can be tested directly. The test project already has InternalsVisibleTo.

Tests

These are added to SemanticColorMapperEdgeCaseTests:

  • MapColors_WithSingleTranslucentSourceColor_KeepsItsAlpha uses the issue's repro: Neutral #10101080/#f0f0f080 and Primary #3366cc80. It asserts that every Primary priority keeps alpha 0.502.
  • ExtrapolateColorToLightness_AtItsOwnLightness_ReturnsTheSameColor checks that each of these comes back with exactly the same hex: the six sRGB primaries and secondaries, white, black, and a translucent colour.

With the fix reverted, 5 tests fail: the alpha test and #FF0000, #00FF00, #FFFF00, #3366CC80. With it applied, all 77 tests pass on net10.0. ThemeSnapshotTests is unchanged, so none of the built-in theme palettes shift.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SerwFWrikSrdorQJydu9st


Generated by Claude Code

…single colour [patch]

ExtrapolateColorToLightness rebuilt colours with Color.FromOklab and no
alpha, so every single-colour meaning (every accent) came out opaque while
interpolated neutral ramps kept theirs. Pass baseColor.A through.

Its gamut test also bounded linear channels exactly at [0, 1]. An Oklab
round trip leaves ~1e-7 of error, so colours on the gamut boundary such as
#ff0000 were treated as out of gamut and had their chroma shaved
(#ff0000 -> #ff0201). Move the check into IsInGamut with a 1e-6 tolerance
and clamp the result, at both call sites.

Fixes #111

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01SerwFWrikSrdorQJydu9st
@sonarqubecloud

sonarqubecloud Bot commented Oct 5, 2026

Copy link
Copy Markdown

@matt-edmondson
matt-edmondson merged commit e2edc91 into main Oct 5, 2026
14 checks passed
@matt-edmondson
matt-edmondson deleted the fix/111-single-colour-alpha-and-gamut branch October 5, 2026 14:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Single-colour semantic meanings drop the source alpha (always opaque), and the strict gamut check shifts in-gamut colours like #ff0000 → #ff0201

2 participants