feat(udg): canonical bg.surface-card token and a no-fallback theme marker (#233) #236

Merged
peterswimm merged 1 commit from feat/233-bg-surface-card into main 2026-10-28 23:19:00 +00:00
Member

Refs #233. Does not close it: the Rituals counterpart is a separate PR in toilville_rituals.

Scope

Makes the card surface a canonical token and adds a guard so other themes cannot inherit it by fallback. Implements the decision in the #233 comment (issuecomment-38127).

  • Brand/UDG/products/rituals/dtcg/color.json: new color.bg.surface-card. Light #E2AC96, dark #5F2E1C, vanillanight #333333. udg.dart-key stays bgSurfaceCard.
  • New optional token marker udg.theme-fallback: none. A marked token has a value only in the themes its $value lists. It must still define light. Any other value of the marker fails the build.
    • udg/generators/extract.py: omits the token for the other themes in tokens.dtcg.json, and resets its CSS var to initial in their skin.css blocks.
    • udg/generators/native.py: no entry for those themes in the native manifests.
    • udg/generators/wcag.py: skips the token's pairs there. New pair text.primary on bg.surface-card, checked in the three themes that define it.
    • udg/generators/artifact.py: the swatch has no baked fallback colour.
    • udg/mcp_server.py: get_color_token reports "no value" instead of the light value.
  • bg.surface-card is the only marked token. The six other themes (Accessible Alt, Cosmic Crisp, Pardner, Sundered, Truancy, Vanilla Day) get no card surface value. Their palettes are work in progress and this PR makes no decision for them.
  • README.md, Brand/UDG/README.md: the marker is documented.
  • generator/tests/unit/test_theme_fallback.py: 11 tests.
  • dist/: regenerated, 18 files.

Testing

  • All justfile check commands pass. Each command was run directly because just is not installed on this machine.
  • python3 -m pytest generator/tests/: 411 passed, 20 skipped. With the marker removed from the source, the new tests fail.
  • Old and new extract.py give byte-identical output for all 13 products when the marker is stripped. The marker changes nothing for unmarked tokens.
  • text.primary on bg.surface-card: light 8.52:1, dark 9.17:1, vanillanight 12.63:1.
  • Chrome, skin.css: in Cosmic Crisp, Pardner and Vanilla Day the var is invalid. background: var(--udg-color-bg-surface-card) resolves to transparent, and a consumer fallback is used when one is given. Child elements inherit the invalid value. Other tokens in those themes are unaffected.
  • Chrome, dist/rituals/artifact.html: the card swatch is transparent in those three themes. It showed a stray pale peach before the artifact fix.
  • apps/rituals-macos/tool/dtcg_to_udg_tokens.py --check in toilville_rituals passes against this output.

Impact Statement

  • Existing features: none change. No existing token value changes in any theme. A test pins this.
  • Public APIs / contracts: new CSS var --udg-color-bg-surface-card, new Dart key already used by the Flutter app. New optional token key udg.theme-fallback. In the six themes above the var is initial. A consumer that needs a colour there must pass a var() fallback.
  • Schemas: tokens.dtcg.json entries may now list fewer themes than the product has, when the marker is set. Readers that look up a missing theme must not assume light.
  • Data / artifacts: dist/rituals and dist/blocks are regenerated. blocks borrows the Rituals palette (color_from: rituals). Its skin.css and tokens.dtcg.json changes match the Rituals ones. dist/rituals/udg_tokens.{dart,swift,json} gain the card entries.
  • Integrations: toilville_rituals takes udg_tokens.dart through udg_colors.dart (separate PR). macOS Swift has no consumer and gains none. The macOS udg_tokens.json is unchanged.
  • Mappings: wcag.py gains one pair.
  • Backward compatibility: additive. The old and new generators match for every unmarked token.
  • Known limit: a reader that names a specific token, such as forgejo.py, still falls back to light. A test fails if any reader outside the allowlist names this token.
Refs #233. Does not close it: the Rituals counterpart is a separate PR in `toilville_rituals`. ## Scope Makes the card surface a canonical token and adds a guard so other themes cannot inherit it by fallback. Implements the decision in the #233 comment (issuecomment-38127). - `Brand/UDG/products/rituals/dtcg/color.json`: new `color.bg.surface-card`. Light `#E2AC96`, dark `#5F2E1C`, vanillanight `#333333`. `udg.dart-key` stays `bgSurfaceCard`. - New optional token marker `udg.theme-fallback: none`. A marked token has a value only in the themes its `$value` lists. It must still define `light`. Any other value of the marker fails the build. - `udg/generators/extract.py`: omits the token for the other themes in `tokens.dtcg.json`, and resets its CSS var to `initial` in their `skin.css` blocks. - `udg/generators/native.py`: no entry for those themes in the native manifests. - `udg/generators/wcag.py`: skips the token's pairs there. New pair `text.primary` on `bg.surface-card`, checked in the three themes that define it. - `udg/generators/artifact.py`: the swatch has no baked fallback colour. - `udg/mcp_server.py`: `get_color_token` reports "no value" instead of the light value. - `bg.surface-card` is the only marked token. The six other themes (Accessible Alt, Cosmic Crisp, Pardner, Sundered, Truancy, Vanilla Day) get no card surface value. Their palettes are work in progress and this PR makes no decision for them. - `README.md`, `Brand/UDG/README.md`: the marker is documented. - `generator/tests/unit/test_theme_fallback.py`: 11 tests. - `dist/`: regenerated, 18 files. ## Testing - All `justfile` check commands pass. Each command was run directly because `just` is not installed on this machine. - `python3 -m pytest generator/tests/`: 411 passed, 20 skipped. With the marker removed from the source, the new tests fail. - Old and new `extract.py` give byte-identical output for all 13 products when the marker is stripped. The marker changes nothing for unmarked tokens. - `text.primary` on `bg.surface-card`: light 8.52:1, dark 9.17:1, vanillanight 12.63:1. - Chrome, `skin.css`: in Cosmic Crisp, Pardner and Vanilla Day the var is invalid. `background: var(--udg-color-bg-surface-card)` resolves to transparent, and a consumer fallback is used when one is given. Child elements inherit the invalid value. Other tokens in those themes are unaffected. - Chrome, `dist/rituals/artifact.html`: the card swatch is transparent in those three themes. It showed a stray pale peach before the artifact fix. - `apps/rituals-macos/tool/dtcg_to_udg_tokens.py --check` in `toilville_rituals` passes against this output. ## Impact Statement - Existing features: none change. No existing token value changes in any theme. A test pins this. - Public APIs / contracts: new CSS var `--udg-color-bg-surface-card`, new Dart key already used by the Flutter app. New optional token key `udg.theme-fallback`. In the six themes above the var is `initial`. A consumer that needs a colour there must pass a `var()` fallback. - Schemas: `tokens.dtcg.json` entries may now list fewer themes than the product has, when the marker is set. Readers that look up a missing theme must not assume `light`. - Data / artifacts: `dist/rituals` and `dist/blocks` are regenerated. `blocks` borrows the Rituals palette (`color_from: rituals`). Its `skin.css` and `tokens.dtcg.json` changes match the Rituals ones. `dist/rituals/udg_tokens.{dart,swift,json}` gain the card entries. - Integrations: `toilville_rituals` takes `udg_tokens.dart` through `udg_colors.dart` (separate PR). macOS Swift has no consumer and gains none. The macOS `udg_tokens.json` is unchanged. - Mappings: `wcag.py` gains one pair. - Backward compatibility: additive. The old and new generators match for every unmarked token. - Known limit: a reader that names a specific token, such as `forgejo.py`, still falls back to `light`. A test fails if any reader outside the allowlist names this token.
feat(udg): canonical bg.surface-card token and a no-fallback theme marker (#233)
All checks were successful
PR policy check / policy-gate (pull_request) Successful in 1s
UDG dist drift gate / dist/ matches dtcg + udg sources (pull_request) Successful in 29s
Test Generator / lint-workflows (pull_request) Successful in 39s
Security Scans / Gitleaks secret scan (pull_request) Successful in 40s
Security Scans / Trivy filesystem scan (pull_request) Successful in 40s
Test Generator / lint-prose (pull_request) Successful in 48s
Copy coverage / Design copy reaching rendered HTML (pull_request) Successful in 59s
Block Validation / validate (pull_request) Successful in 1m36s
Test Generator / test (pull_request) Successful in 4m7s
f373034737
Adds color.bg.surface-card to the Rituals palette: light #E2AC96, dark
#5F2E1C, vanillanight #333333. The Dart key stays bgSurfaceCard.

Adds the optional token marker udg.theme-fallback: none. A marked token has
a value only in the themes its $value lists. Every other theme has none, so
the light value no longer reaches a theme by fallback. The generators omit the
token for those themes (tokens.dtcg.json, native manifests, WCAG pairs), reset
its CSS var to initial in their skin.css blocks, and draw its artifact swatch
without a baked fallback. bg.surface-card is the first marked token.

Adds a text.primary on bg.surface-card contrast pair for the themes that
define it, 11 generator tests, and README notes. dist/ regenerated.

Refs #233
peterswimm deleted branch feat/233-bg-surface-card 2026-10-28 23:19:01 +00:00
Sign in to join this conversation.
No description provided.