Giving each theme a font, including a script I can't read
Each theme's signs now have a face picked for that place, the eldritch theme has a generated script, and the interface is set in one narrower face.
I said the game’s font was very basic and standard, and that I wanted a font for each theme that fits the theme. There are now 16 font files, about 0.8 MB, and a table that says which one a sign uses by theme and by what the sign is. The eldritch theme’s plates use a script I generated that looks like writing and can’t be read.
Which font goes with which theme?
A sign has one of four roles: a plate (door plates and labels, which is most signs), a name (a big name on a fascia or a tank), a stencil (sprayed through a stencil on steel) and a readout (codes and printed notices). The table is a constant dictionary in ThemeFonts: theme, then role, then a file name. The plant is the theme with the empty name, and it’s what an unknown theme falls back to. An unknown role falls back to the plate face.
| theme | plate | name | stencil | readout |
|---|---|---|---|---|
| plant | Barlow Condensed SemiBold | Barlow Condensed | Saira Stencil SemiBold | Share Tech Mono |
| steampunk | League Gothic | Holtwood One SC | Stardos Stencil Bold | Special Elite |
| fantasy | Cinzel Bold | UnifrakturMaguntia | Cinzel | IM Fell English |
| meat | Barlow Condensed | Butcherman | Saira Stencil | Share Tech Mono |
| eldritch | Blobber Eldritch | Metamorphous | Blobber Eldritch | Blobber Eldritch |
| cyberpunk | Oxanium SemiBold | Oxanium | Saira Stencil | Share Tech Mono |
The sign kit’s font function now takes the theme and the role and reads this table. If a file is missing it falls back to the face the interface uses for plates.

Contact sheet of the film, each frame captioned with the face in use.
Where do the fonts come from?
Everything bought in is SIL OFL 1.1 except Special Elite, which is Apache 2.0. I said I could ship it as long as I don’t pay royalties, and then allowed Apache 2.0 fonts too. A script, fetch_fonts.py, has a row per face with its family, weight and licence file. It downloads each face’s static TTF (Latin subset, one weight) from google-webfonts-helper, and copies it into the project as F_<name>.ttf with its licence text beside it and a row in the credits file. I used static single-weight files because their outlines don’t overlap, and Godot’s MSDF rendering needs that.
Saira Stencil One is no longer on Google Fonts, so the table uses its successor, Saira Stencil.
Why is MSDF on for some fonts and not others?
Signs are drawn into a texture at a large size and then scaled, so the 13 sign faces are imported with multi-channel signed distance field rendering on. That keeps the edges sharp at any size. The 3 interface faces have it off, since small HUD text looks better hinted at its own size.
How do you make a script nobody can read?
It looks like writing and says nothing. The generator is build_eldritch.py, with seed 1108, using fontTools, PIL and numpy. It makes 74 glyphs. Every glyph hangs from a head bar, 70 units thick with its top at 700 in a 1000 unit em, and each bar runs into the next, so a word reads as one written line. Under the bar, a seeded generator picks strokes from a small set: stem, hook, loop, notch, tail, ring and dot. A to Z are the first forms. a to z are second forms of the same letters, with one stroke moved, so the sign kit can swap in a different look. 0 to 9 are counting marks.

The script. Every glyph hangs from a bar that joins the next one.
Making the outlines is the interesting part. Each glyph’s strokes are drawn thick with PIL on a raster of 4 font units per pixel. Then I trace the outline of the union of the strokes along the pixel edges, keeping the filled side always on the right, so outer contours run clockwise and holes run counter-clockwise, which is what TrueType wants. The points are smoothed by taking the midpoints of the edges, thinned with Ramer-Douglas-Peucker, and written with fontTools’ TTGlyphPen and FontBuilder. Because it traces a union, the contours never overlap or cross, which is the same thing MSDF needs from the bought-in fonts. The face is CC0, and none of it is another font’s outlines.
When I saw it on the plates in the film I said to keep it.
What does the interface use?
Everything that names no font, the HUD, the inventory, the stats sheet and the rack plates, now gets Barlow Semi Condensed, set in project.godot under [gui] as theme/custom_font, with Share Tech Mono for readouts. A 14 px sample line is 270 px wide in Bahnschrift and 232 px in Barlow Semi Condensed, about 14 percent narrower, so panels that were tight have room.

The HUD and party panel in the new interface face.
What’s left?
The test for fonts, tests/theme_fonts, passes 15 checks. It covers the table, the licences and credits rows, the letters each face has, whether a door plate’s words fit in every face, and whether the party panel and inventory lay out at the default window size. The sign, rack, ui, hud and font tests together are 18 tests with none failing. The whole suite on main hadn’t finished when I wrote this.