Skip to content

fix(ui): render the visual gate in the typefaces the tokens name (RIG-2154) - #1061

Open
rigel-mintaka wants to merge 1 commit into
mainfrom
compass-ux/2154-pin-gate-fonts
Open

fix(ui): render the visual gate in the typefaces the tokens name (RIG-2154)#1061
rigel-mintaka wants to merge 1 commit into
mainfrom
compass-ux/2154-pin-gate-fonts

Conversation

@rigel-mintaka

@rigel-mintaka rigel-mintaka commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

The design tokens ask for two faces that were never installed anywhere.
--rigel-mono is "Space Mono" and --rigel-display is "Departure Mono"
(apps/ui/src/design/tokens.css), but neither the CI runner nor a dev box has
either, so every screenshot ever captured fell through the CSS stack to
whatever fontconfig happened to pick.

The substitution was invisible because the substitute is a near-metric match.
From the font metrics: IBM Plex Mono is 600/1000em, i.e. 6.600px at 11px and
7.600px/glyph with the 1px letter-spacing .bridge-col-head uses. The
committed baselines measure exactly 7.600px/glyph, so they are IBM Plex Mono
— the runner's substitute, not the brand face. Space Mono is 612/1000em =
7.732px/glyph at the same spec, a 0.132px difference no reviewer could see.

Pinning the real faces is therefore a deliberate visual change: every
text-bearing baseline moves once, and this is the first time the UI
rasterizes in the typeface it was designed for.

Two determinism holes close with it, both of which made the baselines a
function of the machine rather than of the repo.

The host's font set was an undeclared input: whichever faces a box happened
to have decided the substitute, with nothing in the repo recording it. The

list now names format subdirectories rather than each package's whole share/fonts tree, so the woff/woff2 duplicates and Unifont's bdf/otb/pcf bitmap strikes never enter the scan — a strike outsorts the scalable face at some pixel sizes, which would make glyph choice depend on font size.

Rasterization was also unpinned, and the font set alone does not fix it.
hintstyle, antialias and rgba fell through to fontconfig's compiled-in
defaults, making them a property of the linked library rather than of this
repo: under the built-in hintfull, Space Mono renders 0.26px/glyph wider than
under hintslight, same browser and same font file (measured in the pinned
Chromium). A devenv.lock bump that moved fontconfig would then shift every
baseline with no declared cause. The config now pins them, with rgba=none
because subpixel order changes per-pixel colour and a diffed screenshot wants
grayscale AA.

Coverage needs one fallback, and which one is a brand decision rather than a
packaging detail. The UI draws 49 distinct non-ASCII glyphs; the branded
faces cover 28 (Space Mono 14, Departure Mono 27, overlapping). Unifont and
its upper-plane companion cover the remaining 21 exactly — verified all 49
resolve under the built config.

Deliberately NOT a general-purpose system font. DejaVu was the first choice
and was wrong twice over: DejaVu Sans is a proportional humanist sans, and
once present fontconfig also pulled in DejaVu Math TeX Gyre — a
variable-width TeX math face — for 14 glyphs including ✓ ○ ■ ▼ ⇒ ≡. That
is proportional metrics in a monospace grid and a stock sans in a brand whose
shape language is hard 1-bit dot-matrix.

Unifont is the better choice on brand grounds but is not free: it is
dual-width (fontconfig spacing=90), so 17 of the fallback glyphs sit at 0.5em
and 4 — including the sidebar gear — at 1.0em, against Space Mono's 0.612em
cell. Those glyphs do not land on the grid. It costs ~14MB more than DejaVu,
accepted for the brand reason. RIG-3603 retires the whole fallback by drawing
those 21 as dot-matrix SVG, the pattern BadgeGlyph.tsx already uses for six
status glyphs — on-brand and font-free.

Both lanes that touch pixels export it, and both fail closed. The regen lane
needs it as much as the gate: it captures the bytes the gate later replays
against. The guards matter because the two malformed values fail in opposite
directions and both stay green — an empty FONTCONFIG_FILE is read as a config
with no font dirs at all (every string measures zero width), while a
nonexistent path falls back to the full host set, which is the input this
change exists to remove.

Linux-only in the dev shell: the faces build everywhere, but chromium is
Linux-only in nixpkgs so a darwin shell cannot run this gate, and
FONTCONFIG_FILE is process-tree-wide — it would replace the font universe for
everything launched from the shell in exchange for nothing.

google-fonts is filtered to the one family — unfiltered it is 2.3GB.

Baselines are NOT regenerated here. That needs a CI capture under the pinned
env, which RIG-3550 blocks (Actions cannot open the regen lane's PR), so the
bytes are hand-carried as in #1024. The gate task itself is wired into ci
in the follow-on commit, so this PR's own green CI does not exercise the
change.

@linear-code

linear-code Bot commented Sep 10, 2026

Copy link
Copy Markdown

RIG-2154

@trunk-io

trunk-io Bot commented Sep 10, 2026

Copy link
Copy Markdown

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

@rigel-mintaka
rigel-mintaka force-pushed the compass-ux/2154-pin-gate-fonts branch from 3913546 to 8dacc14 Compare September 10, 2026 02:57
@github-actions

github-actions Bot commented Sep 10, 2026

Copy link
Copy Markdown

Compass engineering docs preview: https://compass-ux-2154-pin-gate-fon.compass-eng-docs.pages.dev

Deployed from compass-ux/2154-pin-gate-fonts at e846226.

…-2154)

The design tokens ask for two faces that were never installed anywhere.
`--rigel-mono` is "Space Mono" and `--rigel-display` is "Departure Mono"
(apps/ui/src/design/tokens.css), but neither the CI runner nor a dev box has
either, so every screenshot ever captured fell through the CSS stack to
whatever fontconfig happened to pick.

The substitution was invisible because the substitute is a near-metric match.
From the font metrics: IBM Plex Mono is 600/1000em, i.e. 6.600px at 11px and
7.600px/glyph with the 1px letter-spacing `.bridge-col-head` uses. The
committed baselines measure exactly 7.600px/glyph, so they are IBM Plex Mono
— the runner's substitute, not the brand face. Space Mono is 612/1000em =
7.732px/glyph at the same spec, a 0.132px difference no reviewer could see.

Pinning the real faces is therefore a deliberate visual change: every
text-bearing baseline moves once, and this is the first time the UI
rasterizes in the typeface it was designed for.

Two determinism holes close with it, both of which made the baselines a
function of the machine rather than of the repo.

The host's font set was an undeclared input: whichever faces a box happened
to have decided the substitute, with nothing in the repo recording it. The
<dir> list now names format subdirectories rather than each package's whole
share/fonts tree, so the woff/woff2 duplicates and Unifont's bdf/otb/pcf
bitmap strikes never enter the scan — a strike outsorts the scalable face at
some pixel sizes, which would make glyph choice depend on font size.

Rasterization was also unpinned, and the font set alone does not fix it.
hintstyle, antialias and rgba fell through to fontconfig's compiled-in
defaults, making them a property of the linked library rather than of this
repo: under the built-in hintfull, Space Mono renders 0.26px/glyph wider than
under hintslight, same browser and same font file (measured in the pinned
Chromium). A devenv.lock bump that moved fontconfig would then shift every
baseline with no declared cause. The config now pins them, with rgba=none
because subpixel order changes per-pixel colour and a diffed screenshot wants
grayscale AA.

Coverage needs one fallback, and which one is a brand decision rather than a
packaging detail. The UI draws 49 distinct non-ASCII glyphs; the branded
faces cover 28 (Space Mono 14, Departure Mono 27, overlapping). Unifont and
its upper-plane companion cover the remaining 21 exactly — verified all 49
resolve under the built config.

Deliberately NOT a general-purpose system font. DejaVu was the first choice
and was wrong twice over: DejaVu Sans is a proportional humanist sans, and
once present fontconfig also pulled in DejaVu Math TeX Gyre — a
variable-width TeX math face — for 14 glyphs including `✓ ○ ■ ▼ ⇒ ≡`. That
is proportional metrics in a monospace grid and a stock sans in a brand whose
shape language is hard 1-bit dot-matrix.

Unifont is the better choice on brand grounds but is not free: it is
dual-width (fontconfig spacing=90), so 17 of the fallback glyphs sit at 0.5em
and 4 — including the sidebar gear — at 1.0em, against Space Mono's 0.612em
cell. Those glyphs do not land on the grid. It costs ~14MB more than DejaVu,
accepted for the brand reason. RIG-3603 retires the whole fallback by drawing
those 21 as dot-matrix SVG, the pattern BadgeGlyph.tsx already uses for six
status glyphs — on-brand and font-free.

Both lanes that touch pixels export it, and both fail closed. The regen lane
needs it as much as the gate: it captures the bytes the gate later replays
against. The guards matter because the two malformed values fail in opposite
directions and both stay green — an empty FONTCONFIG_FILE is read as a config
with no font dirs at all (every string measures zero width), while a
nonexistent path falls back to the full host set, which is the input this
change exists to remove.

Linux-only in the dev shell: the faces build everywhere, but chromium is
Linux-only in nixpkgs so a darwin shell cannot run this gate, and
FONTCONFIG_FILE is process-tree-wide — it would replace the font universe for
everything launched from the shell in exchange for nothing.

google-fonts is filtered to the one family — unfiltered it is 2.3GB.

Baselines are NOT regenerated here. That needs a CI capture under the pinned
env, which RIG-3550 blocks (Actions cannot open the regen lane's PR), so the
bytes are hand-carried as in #1024. The gate task itself is wired into `ci`
in the follow-on commit, so this PR's own green CI does not exercise the
change.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
@rigel-mintaka
rigel-mintaka force-pushed the compass-ux/2154-pin-gate-fonts branch from 8dacc14 to e846226 Compare September 10, 2026 03:49
@rigel-mintaka
rigel-mintaka marked this pull request as ready for review September 10, 2026 04:03
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