Files
Metal AgentandClaude Opus 5 401760d670 Generate the theme catalog from real themes instead of a hand table
The derivation landed in decision 0018 with the catalog and the terminal ANSI
palette still fixed tables written by hand. tools/theme-gen reads the
TextMate themes under assets/themes/ and emits the catalog and the reference
vectors, so the anchors a palette is derived from are the ones the theme
actually ships rather than the ones somebody transcribed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SPYebLiN2w4TqnHUYGdECq
2026-09-01 12:51:25 -07:00

2.8 KiB

theme-gen

Turns the theme files vendored in assets/themes/ into crates/lumbridge-theme/src/generated/catalog.rs and assets/themes/NOTICE-THEMES.md.

cargo run -p theme-gen             # rewrite both files
cargo run -p theme-gen -- --check  # fail if either is out of date

Dev-only. Nothing in the workspace depends on it at build time, and --check is the hook a future CI step would use.

Why it is a binary and not a build.rs

Two reasons, in order of weight.

The colours a user sees should be reviewable as text in a pull request. If an upstream theme changes a hex digit, that should arrive as a diff someone reads, not as a silently different build. Everything this tool produces is checked in for exactly that reason, and --check is what keeps the checked-in copy honest.

And a build that reads assets/themes/ makes the asset tree a build input. Trimming assets in a packaging step would then break compilation rather than breaking a theme picker, which is the wrong failure.

What it decides, and what it only measures

The tool makes no aesthetic choices. It applies rules and records what they produced:

  • Anchors. editor.background, editor.foreground, the comment token's foreground, and the git-decoration colours, by the rules in src/extract.rs.
  • Terminal palette. The theme's terminal.ansi* keys where it has them, a syntax token that stands for the same role where it does not, and a documented hue derived from the theme's own foreground where it has neither.
  • Contrast gate. A theme whose body text measures below 4.5:1 against the surface Lumbridge derives for it is held back, and the measurement is written into the generated file's header. Three themes currently fail.
  • Distinctness. Two escape codes that would paint the same colour, and two role colours that would make decision 0012's provenance shades identical, are forced apart — and every such substitution is written down twice: as a comment above the theme, and in a machine-readable constant the tests read back.

Licence exclusion happens before this tool, at the vendoring step, so a GPL theme is never in the tree at all. See assets/themes/SOURCE.md.

reference/

reference/emit-reference-vectors.mjs regenerates crates/lumbridge-theme/src/generated/reference_vectors.rs by running Buzz's original TypeScript under Node over the same vendored theme files. It needs the Buzz checkout, which lives outside this repository and is pinned in docs/RESEARCH_SNAPSHOTS.md, so it is not a step CI can run — which is why its output is checked in and the test that reads it runs everywhere.

Run it only when the derivation itself changes. Decision 0018 explains at some length why these vectors must come from running the original and never from re-deriving them.