Skip to content

feat(color): add ktsu.Semantics.Color (linear-RGB color science)#104

Merged
matt-edmondson merged 11 commits into
mainfrom
feat/semantics-color
Jun 29, 2026
Merged

feat(color): add ktsu.Semantics.Color (linear-RGB color science)#104
matt-edmondson merged 11 commits into
mainfrom
feat/semantics-color

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Summary

Adds ktsu.Semantics.Color — a new dependency-light color-science package (multi-target net10/9/8 + netstandard2.0/2.1), the first shippable unit of the color consolidation described in docs/roadmap-semantic-domains.md.

The canonical type is readonly partial record struct Color(double R, double G, double B, double A) storing linear RGB + straight alpha. Around it:

  • Spaces + conversions: Srgb, Hsl, Hsv, Oklab, Oklch; hex (#RGB/#RRGGBB/#RRGGBBAA) and 8-bit byte parsing (sRGB-interpreted).
  • WCAG: RelativeLuminance, ContrastRatio, AccessibilityLevel, AdjustForContrast.
  • Operations: DistanceTo (Oklab), MixOklab, Lerp, Gradient.
  • NamedColors (CSS/X11 subset) with case-insensitive lookup.

The correctness fix

The existing ThemeProvider/ImGuiStyler color code fed sRGB values straight into the Oklab matrix and WCAG luminance (the structs were labelled "linear" but never gamma-decoded). This package confines the gamma transfer to the single SrgbColor boundary, so perceptual math always runs on linear values and "feed sRGB into Oklab" is unrepresentable through the API.

  • Displayed colors are unchangedhex → linear → sRGB round-trips to identity (pinned by GammaRegressionTests).
  • Perceptual math is now correct — Oklab distance/gradients, WCAG contrast, accessibility matching.
  • ImGui interop is via the explicit ToSrgbVector4() (never a raw linear cast).

Scope

Core package only. The ktsu.ImGui.Color adapter (ToImColor/ToImGuiVector4/ImGuiVector4, ImGuiApp repo) and the ktsu.ThemeProvider / ktsu.ImGui.Styler migrations are intentionally separate follow-on PRs in their own repos, once this publishes. Spec: docs/superpowers/specs/2026-06-29-semantics-color-design.md; plan: docs/superpowers/plans/2026-06-29-semantics-color.md.

Verification

  • 39/39 Color tests pass (9 test classes).
  • Clean 5-TFM build (0 warnings; warnings-as-errors): net10.0, net9.0, net8.0, netstandard2.1, netstandard2.0.
  • netstandard2.0 needs a conditional System.Numerics.Vectors reference (for Vector3/4) and a sign-aware Cbrt (no Math.Cbrt).
  • Built TDD task-by-task with per-task spec+quality review and a final whole-branch review (verdict: ready to merge, no Critical/Important findings).

Notes

  • Oklab round-trip tolerance is 1e-6, not 1e-9: the published Ottosson forward/inverse matrices are independently-rounded and don't invert to exact identity (~1e-7). Non-Oklab conversions round-trip to ~1e-9.

Follow-ups (non-blocking)

  • Dark-background AdjustForContrast test (lighten branch); gradient out-of-gamut doc/clamp decision; cache NamedColors as static readonly; broaden a few R-only test asserts.
  • When ktsu.ImGui.Color lands: a cross-package smoke test that ToSrgbVector4 is what reaches ImGui.

🤖 Generated with Claude Code

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@matt-edmondson matt-edmondson merged commit 0fc7638 into main Jun 29, 2026
5 of 6 checks passed
@matt-edmondson matt-edmondson deleted the feat/semantics-color branch June 29, 2026 11:29
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.

1 participant