Skip to content

Fix muddy custom-theme surfaces on vivid backgrounds#85

Merged
mapgie merged 1 commit into
mainfrom
claude/custom-theme-colors-bug-pd7fek
Jul 11, 2026
Merged

Fix muddy custom-theme surfaces on vivid backgrounds#85
mapgie merged 1 commit into
mainfrom
claude/custom-theme-colors-bug-pd7fek

Conversation

@mapgie

@mapgie mapgie commented Jul 11, 2026

Copy link
Copy Markdown
Owner

Problem

A custom theme with a vivid background (e.g. the "cray" theme: pink #FA098E, green #00FF27, blue #001CE7, yellow background #F3FF00) rendered every card and surface as a dark muddy olive with dim, low-contrast text, while menus, bottom sheets, and the navigation bar fell back to a clashing default neutral. The theme read as "not applied" even though the seed colours were stored correctly.

Root cause

The defect was entirely in buildCustomColorScheme() (ui/theme/Color.kt). It derived every neutral/surface role from the background's own HSL, using saturation up to 0.20 and lightness offsets (bg[2] - 0.10, etc.) that assumed a near-white light-mode background. It decided light vs dark by luminance but did the offset math on HSL lightness — those two diverge badly for a vivid mid-lightness hue. For yellow #F3FF00 (luminance 0.93, HSL lightness 0.5) that produced surfaceVariant = hsl(63°, 0.20, 0.40), the olive seen on every card. The whole Material 3 surfaceContainer* / surfaceDim / surfaceBright family was never set, so those roles used the library default that clashes with the custom background.

Fix

Reworked only the neutral/surface derivation in buildCustomColorScheme(); seed colours (primary/secondary/tertiary) and the background override are unchanged.

  • Derive all neutral surface roles from the background hue only, at a near-zero fixed saturation (0.04), so a saturated background can never tint surfaces muddy.
  • Anchor surface lightness to an absolute per-mode ramp (0.99 down to 0.87 in light, 0.06 up to 0.24 in dark), independent of the background's own lightness.
  • Choose onBackground / onSurface by contrast, reusing the existing contrastingOn() helper, so text stays legible on any pick.
  • Set the full surfaceContainer* palette plus surfaceDim / surfaceBright in both the light and dark scheme constructors.

Result for "cray": yellow page background, clean near-neutral legible cards, and vivid pink/green/blue on buttons, chips, and the nav indicator.

Verification

  • python3 a11y_check.py → all clean (no .clickable changes).
  • Hand logic-check: #F3FF00bgIsLight true, surfaceVariant = hsl(63°, 0.04, 0.90) (light neutral tint, not olive), onBackground near-black. #000000 → near-black neutral surfaces with white on-text.
  • App build is validated by CI (no Android SDK in the dev environment).

Includes a patch changelog fragment and a LESSONS.md entry (#28).


Generated by Claude Code

buildCustomColorScheme derived every neutral/surface role from the
background's own HSL, using saturation up to 0.20 and lightness offsets
that assumed a near-white light-mode background. It decided light vs dark
by luminance but did the offset math on HSL lightness, so a vivid
mid-lightness background like yellow (#F3FF00: luminance 0.93, HSL
lightness 0.5) produced a dark olive surfaceVariant on every card with
dim, low-contrast text. The Material 3 surfaceContainer* / surfaceDim /
surfaceBright roles were never set, so menus, bottom sheets, and the nav
bar fell back to a clashing default neutral.

Derive all neutral surface roles from the background hue only at a
near-zero fixed saturation (0.04) and an absolute per-mode lightness
ramp, choose onBackground/onSurface by contrast, and set the full
surfaceContainer palette in both light and dark schemes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0154oNEvwJNtprknEQfFAyND
@mapgie mapgie marked this pull request as ready for review July 11, 2026 17:49
@mapgie mapgie merged commit 7633b45 into main Jul 11, 2026
4 checks passed
@mapgie mapgie deleted the claude/custom-theme-colors-bug-pd7fek branch July 11, 2026 17:49
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.

2 participants