Skip to content

JetBrains Mono, and an editor that follows the page - #108

Merged
kisielewski merged 4 commits into
mainfrom
feat/jetbrains-mono-and-an-editor-that-follows
Sep 7, 2026
Merged

JetBrains Mono, and an editor that follows the page#108
kisielewski merged 4 commits into
mainfrom
feat/jetbrains-mono-and-an-editor-that-follows

Conversation

@kisielewski

Copy link
Copy Markdown
Member

Four things, and the first of them turned out to be already done.

Inter and Lato were already here

Six files in src/assets/fonts/: Lato 400 and 700 across latin and
latin-ext, which is the product's own face, and Inter 600 across both, which
exists to draw the wordmark and nothing else. Nothing to add; neither is touched.

JetBrains Mono

Two files, byte for byte the ones AlgoJudge-Docs ships, for the reason
Lato's four are Keycloak's: one typeface across the product rather than one per
repository. Variable, so one file per subset carries the whole weight range — a
bold token in a highlighted source comes out of the face rather than out of
synthetic bolding, and it is two files where per-weight slices would be four.
public/OFL-JetBrainsMono.txt beside the other two.

font-display: swap, like Lato and unlike Inter: Inter blocks because a fallback
overflows the drawing it paints, and there is nothing here to overflow.

typography.ts gains fontFamilyMonospace, and one key is the whole of it —
Mantine emits --mantine-font-family-monospace and every fixed-pitch surface
reads it: <Code>, <JsonInput>, the gutter beside a highlighted source, and
the editor, which takes the same constant rather than writing a stack of its own.

PRODUCT_STACK is untouched. verify-hero.mjs asserts /^Lato/ on the body,
and its face counts are family-filtered before they are counted, so a third
family is invisible to them.

The editor follows the page, and has an edge

theme="vs-dark" was hard-coded with a comment arguing that a code surface is
read differently from a page of prose. It takes vs or vs-dark from
useComputedColorScheme now, through the prop rather than a remount — a key=
would throw away the undo stack and the scroll position mid-solution.

Monaco painted its own ground and nothing else, so against a card of the same
colour there was no edge and where a solution may be typed was a guess. The
frame is on the wrapper, not on .monaco-editor — that class is Monaco's — and
in --mantine-color-default-border, which branding.ts writes an installation's
own border colour into.

monaco.editor.remeasureFonts() is new work the font made necessary. Monaco
measures a glyph once at start-up and lays every column out from that number; at
font-display: swap the first editor of a cold load mounts on the fallback, and
without the call the text is one width and the cursor another.

The check, and why it is not getComputedStyle

verify-editor.mjs asks the browser which face painted the glyphs, over the
DevTools protocol. getComputedStyle(el).fontFamily reports the stack that was
asked for, so a silent fall back to Consolas is invisible to it — the same
class of defect that shipped in AlgoJudge-Docs last week and was caught only by
eye. The harness gains one capability, paintedWith(selector), and
scripts/verify/README.md gains the two traps it carries: the answer covers a
node's own text runs, so .view-lines reports nothing and .view-line > span is
what has the glyphs; and an empty editor paints nothing at all, so a line has to
be typed before measuring.

Five sabotages, each red and each restored from a file copy: the fontFamily
option removed (24× Consolas), the theme pinned back to dark (light / vs-dark),
the .woff2 pointed at nothing, the border removed (0px), and the border made
transparent (1px rgba(0, 0, 0, 0)).

Verified

lint, lint:deps, typecheck, build, the ten file-reading checks, and the
whole check:ui: 52 passed — one more than before, the new script. Run twice
in full, the second time because adding a wrapper element could have moved a
width assertion elsewhere. It did not.

The suite was pointed at a dev server of this branch's own with APP=, and that
was checked rather than assumed: exactly two Vite processes on the machine
throughout, and Playwright started neither.

One variable file per subset covers the whole weight range, and they are the
bytes AlgoJudge-Docs ships. One theme token reaches every fixed-pitch surface.
vs in light, vs-dark in dark, through the prop rather than a remount. Monaco
measures a glyph once, so the face arriving late needs remeasureFonts.
getComputedStyle reports the stack that was asked for; only the protocol says
which face drew the glyphs, and a fall back to Consolas is invisible without it.
Monaco paints its own ground and nothing else, so against a card of the same
colour there was nothing saying where a solution may be typed. The border is on
the wrapper, in the semantic colour an installation can theme.
@kisielewski
kisielewski merged commit 7da88ab into main Sep 7, 2026
3 checks passed
@kisielewski
kisielewski deleted the feat/jetbrains-mono-and-an-editor-that-follows branch September 7, 2026 00:19
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