Skip to main content

max / alloy

Retire IosevkaTerm: the image cuts its own faces now Alloy's half of the typography standard (wiki `typography-standard`, GO alloy 9ff4653f). The image installed a 60 MB IosevkaTerm Nerd Font zip and an upstream Atkinson Hyperlegible tarball; it now cuts `Quasi Mono` and `Quasi Body` in the rust stage with `quasi-type` and installs those. Both are Atkinson Hyperlegible, one superfamily on one axis, with the house glyph set drawn into them. WHY CUT RATHER THAN DOWNLOAD. There is nothing to download: a built face is not committed anywhere, so the pipeline is the only source of truth for what a face contains. The two reasons the old pair existed are both gone - the Nerd Font Private Use Area was carrying seven characters that are drawn into the face now, and upstream Atkinson is the base Quasi Body is cut from. THE PUA IS GONE FROM THE IMAGE ENTIRELY. yazi was the one live consumer, falling through to its built-in Nerd Font filetype icons for want of an `[icon]` section, and that section now exists and is empty - all five rule lists named, since yazi merges what a theme does not mention. A file's kind is carried by the [filetype] colours, which the theme owns and can state consistently; a private-use glyph is a distinction one font happens to draw. Everything that named a family moves with it: the fontconfig aliases, both GTK settings, and the pango consumers (sway bar and title, mako, swaylock, mpv, imv, satty). The plain-versus-Mono family split went with the PUA it existed to constrain, so there is one family now rather than two. The build assertions move too, and gained one: `fc-match monospace` has to answer Regular as well as Quasi Mono. Both faces are variable and a cut keeps its base's default instance, which for the mono is ExtraLight - fontconfig enumerates named instances so an unweighted query resolves to Regular, and this asserts that rather than assuming it. TWO THINGS FOUND BY BUILDING IT, both fixed here. `cargo install shop` lost `--locked`. shop now takes an in-house git dependency and every machine in the tree redirects those to working copies through `~/Code/.cargo/config.toml`'s [patch] block, which writes a lock entry with no source line - so `cargo metadata --locked` on a clean clone of shop fails outright. Measured. What replaces the guarantee for the part that matters: shop pins quasi-type by revision in its own manifest, so the face it bundles is the same cut this image installs. The theme staging globbed `makeover-*` in the registry and got two directories: shop's lock has moved to makeover 2.6.0 while alloy is deliberately held at 2.5.1 (GO makeover 85ad7547). It reads the version out of alloy's own lock now, which is the more correct claim regardless - the console needs the themes of the makeover it was compiled against. The face COPY sits with the other staged copies rather than where the old font layer was. It depends on the rust stage, so up there it would rebuild 7 GB of package installs every time a console edit changed the stage it comes from. Verified with `build/check-rust-stage.sh`, which now covers the faces since the cut happens in the stage it builds: shop installs and its build.rs cuts the bundled face in-container, and the stage cuts Quasi Mono (176 marks) and Quasi Body (16), each asserting its own coverage, each with its licence beside it. WHAT IS NOT VERIFIED HERE and needs a booted image: `fc-match` under HOME=/etc/skel, yazi painting no missing glyphs, and box drawing rendering from the primary face in a real TUI. FONTS.md says which of its numbers were re-measured off the built faces and which still want a mounted rootfs.
Author: Max Johnson <me@maxj.phd> · 2026-08-17 15:37 UTC
Signed with PGP, not checked
Commit: b672e77bebc5f64b4295ac5d197856c12f352e2c
Parent: a387350
20 files changed, +329 insertions, -143 deletions
M Containerfile +114 -48
@@ -131,15 +131,14 @@
131 131 #
132 132 # `cargo install` rather than a second COPY-and-build stage: shop is a separate
133 133 # repo with its own workspace, so there is no local tree to copy and no
134 - # existing pin to imitate. `--locked` builds the dependency graph shop
135 - # committed rather than whatever resolves that day, matching the console's
136 - # `--locked` below.
134 + # existing pin to imitate. It used to carry `--locked` as the console's build
135 + # below does; see the comment on the install itself for why it cannot any more.
137 136 #
138 137 # Above the console's source on purpose. This layer is keyed on the revision
139 138 # alone, so console edits — the thing that changes most often — reuse it
140 139 # instead of rebuilding a terminal that did not change. Moving it below the
141 140 # `COPY crates/` would defeat the dependency-cache split that follows.
142 - ARG SHOP_REV=24e722fbc13f0b13a023d77d1cad72d9e0a27930
141 + ARG SHOP_REV=584d11946047e9363569d34bb9fdb0d77feda293
143 142
144 143 # Does the remote have anything to build from, before anything expensive runs.
145 144 #
@@ -176,10 +175,24 @@
176 175 echo "SHOP_REV ${SHOP_REV} is not a ref tip; it may still be reachable, leaving it to cargo"; \
177 176 fi
178 177
178 + # `--locked` came off on 2026-08-17, and the reason is a property of the tree
179 + # rather than of shop. shop now takes an in-house git dependency (`quasi-type`,
180 + # which cuts its bundled face), and every machine in that tree redirects in-house
181 + # git URLs to working copies through `~/Code/.cargo/config.toml`'s `[patch]`
182 + # block. Cargo writes a patched package into the lock with no `source` line, so
183 + # the committed lock names a package a fresh clone cannot resolve and `--locked`
184 + # refuses to update it: measured, `cargo metadata --locked` on a clean clone of
185 + # shop fails outright. The tree's own note says as much — `--locked` is off the
186 + # table for as long as that block exists.
187 + #
188 + # What replaces the guarantee, for the part that matters here: shop pins
189 + # `quasi-type` by revision in its own manifest, so the face it bundles is a
190 + # pinned cut rather than whatever resolved that day, and it is the same cut this
191 + # image installs. Everything else in shop's graph is a crates.io semver
192 + # requirement, which is the same latitude every other build in the tree takes.
179 193 RUN cargo install \
180 194 --git https://makenot.work/git/max/shop.git \
181 195 --rev "${SHOP_REV}" \
182 - --locked \
183 196 --root /shop \
184 197 shop
185 198
@@ -191,6 +204,44 @@
191 204 RUN test -x /shop/bin/shop \
192 205 || { echo "shop did not install; the session would have no terminal" >&2; exit 1; }
193 206
207 + # =====================================================================
208 + # The house faces, cut rather than downloaded.
209 + #
210 + # Quasi Mono and Quasi Body are a pinned base plus the house glyph set, run
211 + # through `quasi-type` (wiki `typography-standard`). They replaced a 60 MB
212 + # IosevkaTerm Nerd Font download and an upstream Atkinson tarball, and the
213 + # marks in them are the same drawings every other Alloy surface uses instead
214 + # of whatever each renderer's fallback ordered first.
215 + #
216 + # Cut here rather than fetched because there is nothing to fetch: built faces
217 + # are deliberately not committed anywhere, since a font in a repo is a second
218 + # source of truth that nothing rebuilds. The pipeline pins its own bases by
219 + # sha256, so this layer is reproducible for the same reason the download it
220 + # replaced was.
221 + #
222 + # A clone and `cargo run` rather than `cargo install`: the tool reads its pins
223 + # and its cache out of the checkout it is run from, so an installed binary has
224 + # nowhere to put a downloaded base.
225 + #
226 + # Above the console's source for the same reason shop is: keyed on a revision
227 + # that changes rarely, so a console edit does not recut two fonts.
228 + ARG QUASI_TYPE_REV=6d076b7f85268381f6cd34dd0d28e84c574929cc
229 + RUN git clone --no-checkout https://makenot.work/git/max/quasi-type.git /quasi-type && \
230 + git -C /quasi-type checkout --detach "${QUASI_TYPE_REV}" && \
231 + cargo build --release --locked --manifest-path /quasi-type/Cargo.toml && \
232 + /quasi-type/target/release/quasi-type build quasi-mono --out /faces && \
233 + /quasi-type/target/release/quasi-type build quasi-body --out /faces && \
234 + rm -rf /quasi-type/target
235 +
236 + # Both faces, and the licence beside them. The cut asserts its own coverage —
237 + # every codepoint an Alloy surface emits, checked against the built `cmap` —
238 + # so what is left here is that the files arrived.
239 + RUN test -f "/faces/QuasiMono[wght].ttf" && test -f "/faces/QuasiBody[wght].ttf" \
240 + || { echo "the house faces were not cut; every TUI would draw borders from a fallback" >&2; exit 1; }; \
241 + test -f /faces/OFL-QuasiMono.txt && test -f /faces/OFL-QuasiBody.txt \
242 + || { echo "the OFL text is missing; the licence has to travel with a modified face" >&2; exit 1; }; \
243 + rm -f /faces/*.woff2
244 +
194 245 WORKDIR /src
195 246
196 247 # The dependency graph first, against a stub main. Without this split
@@ -266,9 +317,24 @@
266 317 #
267 318 # The glob is asserted rather than trusted: silently copying nothing here
268 319 # would rebuild exactly the failure this fixes.
320 + #
321 + # **The version comes from Alloy's own lock**, and `makeover-*` used to stand in
322 + # for it. That worked only while exactly one makeover was ever unpacked into the
323 + # registry, and it stopped on 2026-08-17: `cargo install shop` resolves shop's
324 + # graph, shop takes `makeover = "2.5.0"` and its lock has moved to 2.6.0, while
325 + # Alloy is deliberately held at 2.5.1 (GO makeover `85ad7547`, an unresolved
326 + # regression in derived emphasis). Two directories, and the glob asserted its way
327 + # to a failed build rather than staging the wrong themes — which is the assertion
328 + # working, and the reason it is here.
329 + #
330 + # Naming the version is also the more correct claim on its own terms: what the
331 + # console needs staged is the themes of the makeover *it* was compiled against,
332 + # not whichever one happens to be on disk.
269 333 RUN set -eux; \
270 - set -- /root/.cargo/registry/src/*/makeover-*/themes; \
271 - [ "$#" -eq 1 ] && [ -d "$1" ] || { echo "expected one makeover themes dir, got: $*" >&2; exit 1; }; \
334 + ver=$(awk '/^name = "makeover"$/{f=1;next} f&&/^version = /{gsub(/[";]/,"",$3); print $3; exit}' /src/Cargo.lock); \
335 + [ -n "$ver" ] || { echo "alloy's own lock names no makeover, so there is no version to stage" >&2; exit 1; }; \
336 + set -- /root/.cargo/registry/src/*/makeover-$ver/themes; \
337 + [ "$#" -eq 1 ] && [ -d "$1" ] || { echo "expected one makeover-$ver themes dir, got: $*" >&2; exit 1; }; \
272 338 mkdir -p /staged-themes; \
273 339 cp -a "$1/akari-dawn.toml" "$1/akari-night.toml" /staged-themes/
274 340
@@ -654,38 +720,19 @@
654 720 # until someone drops the one that was actually carrying the package.
655 721
656 722 # =====================================================================
657 - # Fonts pulled from upstream releases (not cleanly packaged in Fedora):
658 - # - IosevkaTerm Nerd Font (mono, TUI-safe: no ligatures, has NF glyphs)
659 - # - Atkinson Hyperlegible (sans, high-legibility)
723 + # fontconfig, for the faces staged much further down.
660 724 #
661 - # These sit ahead of the package list on purpose. They are the largest
662 - # downloads in the build, and the package list is the line that changes
663 - # most often; behind it, every package edit re-fetched both archives.
664 - # The unzip/fontconfig they need comes from its own small layer rather
665 - # than from the main install, which is what lets the split work.
725 + # The two house faces used to be two large downloads here, and this block
726 + # sat ahead of the package list because of it: they were the biggest
727 + # fetches in the build and the package list is the line that changes most
728 + # often. Neither half of that is true any more. The faces are cut in the
729 + # rust stage (wiki `typography-standard`), so there is nothing to
730 + # download, and copying them in *here* would put a layer that changes
731 + # whenever any Rust source does above the 7 GB of package installs below.
732 + # So the copy moved to the other `--from=rust-build` staging near the end
733 + # of the file, and what is left here is the one package `fc-cache` needs.
666 734 # =====================================================================
667 - # Both sources are pinned. Unpinned (`releases/latest`, branch `main`)
668 - # these layers change content without the Containerfile changing, so a
669 - # cache hit stops meaning "same bytes" and two builds of the same commit
670 - # can ship different fonts. Bump deliberately.
671 - #
672 - # Atkinson Hyperlegible publishes no tags, so it pins to a commit.
673 - ARG NERD_FONTS_VERSION=v3.4.0
674 - ARG ATKINSON_COMMIT=1cb311624b2ddf88e9e37873999d165a8cd28b46
675 -
676 - RUN dnf install -y unzip fontconfig && dnf clean all
677 - RUN mkdir -p /usr/share/fonts/iosevkaterm-nerd \
678 - /usr/share/fonts/atkinson-hyperlegible && \
679 - curl -fsSL -o /tmp/iosevkaterm-nf.zip \
680 - "https://github.com/ryanoasis/nerd-fonts/releases/download/${NERD_FONTS_VERSION}/IosevkaTerm.zip" && \
681 - unzip -o /tmp/iosevkaterm-nf.zip -d /usr/share/fonts/iosevkaterm-nerd && \
682 - rm /tmp/iosevkaterm-nf.zip && \
683 - curl -fsSL -o /tmp/atkinson-hyperlegible.tar.gz \
684 - "https://github.com/googlefonts/atkinson-hyperlegible/archive/${ATKINSON_COMMIT}.tar.gz" && \
685 - tar -xzf /tmp/atkinson-hyperlegible.tar.gz -C /tmp && \
686 - find /tmp/atkinson-hyperlegible-* -name '*.ttf' -exec cp {} /usr/share/fonts/atkinson-hyperlegible/ \; && \
687 - rm -rf /tmp/atkinson-hyperlegible.tar.gz /tmp/atkinson-hyperlegible-* && \
688 - fc-cache -fv
735 + RUN dnf install -y fontconfig && dnf clean all
689 736
690 737 # =====================================================================
691 738 # Package additions — full Alloy stack per docs/STACK.md
@@ -996,7 +1043,7 @@
996 1043 # No fontconfig change goes with this. The aliases in
997 1044 # etc/skel/.config/fontconfig/fonts.conf use <prefer>, which leaves
998 1045 # fontconfig free to fall through to a font that has the glyph, so
999 - # Atkinson stays the sans for Latin text and Noto covers what it
1046 + # Quasi Body stays the sans for Latin text and Noto covers what it
1000 1047 # cannot.
1001 1048 #
1002 1049 # Emoji is untouched and still deliberately absent (docs/STACK.md):
@@ -2457,6 +2504,23 @@
2457 2504 # and the policy already agree.
2458 2505 COPY --from=rust-build /staged-themes /usr/share/alloy/themes
2459 2506
2507 + # The house faces: Quasi Mono for everything monospaced, Quasi Body for UI text.
2508 + #
2509 + # Cut in the rust stage rather than downloaded, because there is nothing to
2510 + # download: a built face is not committed anywhere, so the pipeline is the only
2511 + # source of truth for what a face contains (wiki `typography-standard`). What it
2512 + # replaced was a 60 MB IosevkaTerm Nerd Font zip and an upstream Atkinson
2513 + # tarball, and it retired the Private Use Area from the image entirely.
2514 + #
2515 + # Down here with the other staged copies rather than up in the old font layer:
2516 + # this depends on the rust stage, so above the package installs it would rebuild
2517 + # 7 GB of them every time a console edit changed the stage it comes from.
2518 + #
2519 + # The OFL text travels with the faces, in the same directory, because OFL 1.1
2520 + # requires it to travel with a modified build and both of these are one.
2521 + COPY --from=rust-build /faces/ /usr/share/fonts/quasi/
2522 + RUN fc-cache -fv
2523 +
2460 2524 # The schemas the settings view's Applications tab is built from. Straight
2461 2525 # from the build context: they are hand-authored TOML that nothing compiles,
2462 2526 # so there is no staged copy to take them from.
@@ -2545,8 +2609,8 @@
2545 2609 # `HOME=/etc/skel` is load-bearing and not decoration. Alloy's aliases live in
2546 2610 # etc/skel/.config/fontconfig/fonts.conf, which is per-user, so the build's root
2547 2611 # context does not see them: measured on this image, a plain `fc-match sans-serif`
2548 - # answers "Noto Sans" while the same query under the skeleton answers "Atkinson
2549 - # Hyperlegible". A guard written without it would have asserted the base's opinion
2612 + # answers "Noto Sans" while the same query under the skeleton answers Alloy's own
2613 + # sans. A guard written without it would have asserted the base's opinion
2550 2614 # and passed while claiming to check Alloy's.
2551 2615 #
2552 2616 # Conditional since 2026-08-03, for the reason the skel-night guard above it
@@ -2569,17 +2633,19 @@
2569 2633 [ "$(fc-list ":lang=$lang" family | wc -l)" -ge 1 ] \
2570 2634 || { echo "no font covers '$lang'; every page in that script renders as missing glyphs" >&2; exit 1; }; \
2571 2635 done; \
2572 - HOME=/etc/skel fc-match sans-serif | grep -q 'Atkinson Hyperlegible' \
2573 - || { echo "sans-serif is no longer Atkinson; the added coverage outranked Alloy's own pick" >&2; exit 1; }; \
2574 - HOME=/etc/skel fc-match monospace | grep -q 'IosevkaTerm Nerd Font Mono' \
2575 - || { echo "monospace is no longer IosevkaTerm; a cell grid would get mismeasured icons" >&2; exit 1; }; \
2636 + HOME=/etc/skel fc-match sans-serif | grep -q 'Quasi Body' \
2637 + || { echo "sans-serif is no longer Quasi Body; the added coverage outranked Alloy's own pick" >&2; exit 1; }; \
2638 + HOME=/etc/skel fc-match monospace | grep -q 'Quasi Mono' \
2639 + || { echo "monospace is no longer Quasi Mono; every cell grid would draw its borders from a fallback face on its own baseline" >&2; exit 1; }; \
2640 + HOME=/etc/skel fc-match monospace | grep -q 'Regular' \
2641 + || { echo "monospace resolves to a weight other than Regular; the face is variable and its own default instance is ExtraLight, so this is what an unnamed weight gets" >&2; exit 1; }; \
2576 2642 else \
2577 2643 [ "$(fc-list ':lang=ja' family | wc -l)" -eq 0 ] \
2578 2644 || { echo "profile=server carries the browser's script coverage; it ships no browser" >&2; exit 1; }; \
2579 - [ "$(fc-list ':family=IosevkaTerm Nerd Font Mono' family | wc -l)" -ge 1 ] \
2580 - || { echo "IosevkaTerm is missing; the font layers are unconditional and this profile has a console" >&2; exit 1; }; \
2581 - [ "$(fc-list ':family=Atkinson Hyperlegible' family | wc -l)" -ge 1 ] \
2582 - || { echo "Atkinson is missing; the font layers are unconditional" >&2; exit 1; }; \
2645 + [ "$(fc-list ':family=Quasi Mono' family | wc -l)" -ge 1 ] \
2646 + || { echo "Quasi Mono is missing; the font layers are unconditional and this profile has a console" >&2; exit 1; }; \
2647 + [ "$(fc-list ':family=Quasi Body' family | wc -l)" -ge 1 ] \
2648 + || { echo "Quasi Body is missing; the font layers are unconditional" >&2; exit 1; }; \
2583 2649 echo "fonts: Alloy's own faces present, the browser's coverage correctly absent"; \
2584 2650 fi; \
2585 2651 [ "$(fc-list ':charset=1F600' family | wc -l)" -eq 0 ] \
@@ -24,8 +24,15 @@
24 24 # break, rather than the one way it broke last.
25 25 #
26 26 # Only the builder. `--target rust-build` stops before the bootc stage, so this
27 - # skips the 7 GB runtime, the fonts, the browser and the profile split. What is
28 - # left is the toolchain layer, shop, and the console.
27 + # skips the 7 GB runtime, the browser and the profile split. What is left is the
28 + # toolchain layer, shop, the house faces and the console.
29 + #
30 + # The faces are in scope as of 2026-08-17, and this is now the cheapest check on
31 + # them: the image stopped installing fonts and started cutting them, so
32 + # `quasi-type` is cloned and run in this stage. A `QUASI_TYPE_REV` that does not
33 + # exist, a base whose upstream moved under its sha256, or a glyph recipe that
34 + # stopped drawing all of Alloy's own codepoints each fail here rather than in a
35 + # 7 GB build.
29 36 #
30 37 # Usage:
31 38 # build/check-rust-stage.sh # build it; say what happened
@@ -37,7 +37,7 @@
37 37
38 38 ## Typography
39 39
40 - Mono, by nature: a terminal renders one fixed-width font (IosevkaTerm Nerd Font). The former two-font working/display split does not apply; hierarchy comes from the levers a terminal has: **weight** (`Modifier::BOLD` for emphasis and section headers), **case** (`UPPERCASE` letter-labels above readouts, in the mil-spec placard tradition), and **Nerd Font glyphs**. Column alignment is free: the terminal font is already tabular, so numeric columns align without a special display font. The exact tokens live in [TOKENS.md](TOKENS.md#typography).
40 + Mono, by nature: a terminal renders one fixed-width font (`Quasi Mono`, the house face). The former two-font working/display split does not apply; hierarchy comes from the levers a terminal has: **weight** (`Modifier::BOLD` for emphasis and section headers), **case** (`UPPERCASE` letter-labels above readouts, in the mil-spec placard tradition), and **the house marks** (ICONOGRAPHY.md's functional tier: triangles, arrows, box drawing, block elements). Column alignment is free: the terminal font is already tabular, so numeric columns align without a special display font. The exact tokens live in [TOKENS.md](TOKENS.md#typography).
41 41
42 42 ## Geometry
43 43
@@ -73,7 +73,7 @@
73 73
74 74 ## Iconography
75 75
76 - Two tiers with non-overlapping roles. Functional icons are Nerd Font glyphs from the terminal font, used inline at cell size, and are the primary tier for TUIs. Hero illustrations survive only on the few graphical surfaces that remain (splash, swaylock background). Full rules in [ICONOGRAPHY.md](ICONOGRAPHY.md).
76 + Two tiers with non-overlapping roles. Functional icons are the house glyph set drawn into the face itself — triangles, arrows, box drawing, block elements — used inline at cell size, and are the primary tier for TUIs. There is no Private Use Area in the image as of 2026-08-17. Hero illustrations survive only on the few graphical surfaces that remain (splash, swaylock background). Full rules in [ICONOGRAPHY.md](ICONOGRAPHY.md).
77 77
78 78 ## Scope
79 79
M docs/FONTS.md +78 -23
@@ -5,10 +5,26 @@
5 5 measurement: which codepoints Alloy's own surfaces put on a screen, which of them the
6 6 shipped fonts cover, and what the fallback chain does with the rest.
7 7
8 - Measured 2026-08-06 against the image built from `Containerfile` at `eeeb768`, read out
9 - of `podman image mount localhost/alloy:local` rather than out of the package list. A
8 + First measured 2026-08-06 against the image built from `Containerfile` at `eeeb768`, read
9 + out of `podman image mount localhost/alloy:local` rather than out of the package list. A
10 10 package list says what was requested; the mounted rootfs says what is there.
11 11
12 + **Re-measured 2026-08-17, when the image stopped installing fonts and started cutting
13 + them.** IosevkaTerm Nerd Font and upstream Atkinson Hyperlegible are gone; the image
14 + carries `Quasi Mono` and `Quasi Body`, cut in the build by `quasi-type` at
15 + `6d076b7` from Atkinson Hyperlegible Mono and Atkinson Hyperlegible Next 2.001
16 + (STACK.md#fonts, wiki `typography-standard`). Every number below that names a font is
17 + from that run, reading `cmap` off the two built faces. What the widget stack can reach was
18 + not re-derived: it is a scan of `alloy_tui`, `ratatui-*` and `makeover`, and the lock has
19 + since moved to `alloy_tui 7.1.0` and `makeover 2.5.1`, so treat the 723 as the last
20 + measured ceiling rather than today's.
21 +
22 + Reading the built faces rather than a mounted rootfs is the stronger reading for this
23 + question and the weaker one for "what is installed": a cut face is fully determined by the
24 + pipeline's own pins, so the `cmap` of the file the build produces is the `cmap` the image
25 + gets. What still wants a booted image is the fallback-chain table and the `fc-match`
26 + answers, and both say where they have not been re-taken.
27 +
12 28 ## Method, so the numbers can be re-derived
13 29
14 30 Two enumerations and a set difference.
@@ -47,7 +63,8 @@
47 63 | U+2718 | `✘` | starship, error state |
48 64
49 65 Latin-1 punctuation, arrows, four block-element characters and one dingbat. No Private
50 - Use Area: **Alloy itself emits no Nerd Font icons.** The PUA reasoning in
66 + Use Area: **Alloy itself emits no Nerd Font icons**, and as of 2026-08-17 there is no
67 + Private Use Area in the image to emit. The PUA reasoning in
51 68 `etc/skel/.config/fontconfig/fonts.conf` and in STACK.md is entirely about third-party
52 69 consumers (starship, yazi, bottom, helix), which is worth knowing before anyone treats
53 70 the `Mono` family constraint as an Alloy-internal requirement.
@@ -78,22 +95,45 @@
78 95
79 96 | Font | Codepoints | Missing from Alloy's set | Missing from the widget ceiling |
80 97 |---|---|---|---|
81 - | IosevkaTerm Nerd Font Mono | 17,827 | **0** | **0** |
82 - | Atkinson Hyperlegible | 342 | 13 | 722 |
98 + | Quasi Mono (shipped) | 535 | **0** | 562 |
99 + | Quasi Body (shipped) | 378 | 4 | 719 |
100 + | Atkinson Hyperlegible Mono (the base, not shipped) | 359 | 13 | 730 |
101 + | IosevkaTerm Nerd Font Mono (retired 2026-08-17) | 17,827 | 0 | 0 |
83 102 | Departure Mono NF Mono (not in the image) | 11,468 | 5 | 557 |
84 103
85 - **The monospace answer is that there is no gap.** IosevkaTerm Nerd Font Mono covers
86 - every codepoint Alloy emits and every codepoint the widget stack could emit, sextants and
87 - octants included. Nothing in a terminal, the console, the installer or the greeter falls
88 - back to anything, so the chain below is insurance rather than a working part.
104 + **The monospace answer is still that there is no gap in what Alloy emits**, and it is now
105 + a built guarantee rather than a lucky one: `quasi-type` asserts the whole of Alloy's
106 + eighteen plus the two sort carets against the `cmap` of every face it cuts, so a face that
107 + lost one fails the font build instead of the image. The base underneath covers 5 of the
108 + 18 by itself; the other 13 are drawn.
89 109
90 - **Atkinson's gaps are not gaps**, because nothing routes box drawing to a sans font.
91 - Atkinson serves the `sans-serif` alias and `gtk-font-name`, which is proportional UI text
92 - in GTK dialogs and the portal file chooser. The 722 it lacks are box drawing, blocks,
93 - braille and legacy-computing, none of which any Pango surface asks for. The rule worth
94 - writing down: **cell-grid surfaces get the mono family and the symbol sets with it;
95 - proportional surfaces get Atkinson and never emit a symbol set.** A future surface that
96 - breaks that rule is where this becomes a real gap.
110 + **562 of the widget ceiling is missing, and it is exactly braille and legacy computing.**
111 + 256 braille, 230 at U+1CD00-U+1CDE5, 12 at U+1CEA0, 64 in the supplement. Those are
112 + ratatui's `Canvas` and sparkline marker sets, and there is no `Canvas` and no `Sparkline`
113 + anywhere in `alloy/crates/`, so this is a ceiling and not a use.
114 +
115 + **Five more were missing when this was first re-measured, and they were closed rather
116 + than recorded.** `←` and `▶ ◀ ► ▾`: the set drew three of the four scrollbar arrows and
117 + two of the six triangles, and the old base drew the rest so nothing showed. They went
118 + into the house glyph set (v2) the same day, because one arrow in a row of four arriving
119 + from a fallback face — at another weight, on another baseline — is visible in a way a
120 + missing sextant is not.
121 +
122 + **The rule that replaces "IosevkaTerm covers everything":** what a cell-grid surface can
123 + emit is a set the house glyph set has to carry, and adding to it is an edit to
124 + `quasi-type`'s manifest plus a rebuild. Braille is the live example — the day a TUI draws
125 + a sparkline, the answer is a generated recipe in the set, not a fallback face on its own
126 + baseline.
127 +
128 + **Quasi Body's four gaps are not gaps**, because nothing routes box drawing to a sans
129 + font — they are `│ █ ▏ ░`, the four codepoints that exist to tile, and the slot
130 + deliberately does not carry them. Quasi Body serves the `sans-serif` alias and
131 + `gtk-font-name`, which is proportional UI text in GTK dialogs and the portal file
132 + chooser. The rule worth writing down: **cell-grid surfaces get the mono face and the cell
133 + tier with it; proportional surfaces get the body face and never emit one.** A future
134 + surface that breaks that rule is where this becomes a real gap. The pipeline enforces the
135 + same split from its own side: the body slot's coverage floor is Alloy's eighteen minus
136 + those four.
97 137
98 138 **Departure's gaps only matter outside the running system.** It is not in the image
99 139 (STACK.md records the 2026-08-05 audit), so it can only appear in a mockup, the README,
@@ -102,7 +142,7 @@
102 142 are starship and helix prompt furniture, which is exactly what a terminal mockup renders,
103 143 so a mockup set in Departure loses its prompt separators silently. It also has no
104 144 braille, no sextants and no octants, so no Departure render can show a `Canvas` or a
105 - sparkline. Use Iosevka for any mockup of a running surface, and keep Departure for
145 + sparkline. Use the house mono for any mockup of a running surface, and keep Departure for
106 146 headers and brand plates, which is what STACK.md already asks for on other grounds.
107 147
108 148 ## The fallback chain, in order, and which links exist
@@ -112,12 +152,18 @@
112 152
113 153 | Alias | Order | In the image? |
114 154 |---|---|---|
115 - | `monospace` | IosevkaTerm Nerd Font Mono | yes, 81 faces under `iosevkaterm-nerd` |
116 - | `sans-serif` | Atkinson Hyperlegible | yes |
155 + | `monospace` | Quasi Mono | yes, one variable face under `/usr/share/fonts/quasi` |
156 + | `sans-serif` | Quasi Body | yes, the same directory |
117 157 | | Cantarell | yes, `abattis-cantarell-vf-fonts` |
118 158 | `serif` | Liberation Serif | yes |
119 159 | `emoji` | (deliberately absent) | no emoji font is installed |
120 160
161 + **Both house faces are variable, and fontconfig enumerates their named instances**, so
162 + `fc-match monospace` answers `Quasi Mono Regular` rather than the file's own default
163 + instance — which is ExtraLight, because a cut keeps its base's default. Measured
164 + 2026-08-17 by installing the built faces and querying fontconfig directly, not on a
165 + booted image; the build asserts the same thing so the trap cannot reach one.
166 +
121 167 **Every family named is installed.** That is new as of 2026-08-16: nine of the thirteen
122 168 names this list used to carry were not in the image, and they were deleted (GO task
123 169 `6aeeb122`, settled by Max as "delete"; the edit is `29390a99`). Gone from `monospace`:
@@ -130,7 +176,7 @@
130 176 not there.
131 177
132 178 **What the shortened `monospace` list makes visible is that the chain has one link.** If
133 - IosevkaTerm ever failed to install, resolution does not reach a second Alloy pick. It
179 + the house face ever failed to install, resolution does not reach a second Alloy pick. It
134 180 drops straight into Fedora's generic rules (`45-latin.conf`, `60-latin.conf`) and lands
135 181 on whatever those order first, which is the layer described below. The four dead Iosevka
136 182 spellings obscured exactly that.
@@ -160,6 +206,15 @@
160 206
161 207 The scripts are not in the repo: the measurement is a one-off against a built image, and
162 208 a checked-in tool that nobody runs drifts into a lie. Re-derive it by mounting the image
163 - and reading `cmap` tables directly. The three numbers worth re-checking after a font bump
164 - are the IosevkaTerm coverage count (17,827 at Nerd Fonts v3.4.0), the size of Alloy's own
165 - emitted set (18), and whether either "missing from the widget ceiling" cell is still 0.
209 + and reading `cmap` tables directly.
210 +
211 + Half of it no longer needs an image. The faces are cut rather than installed, so
212 + `cargo run -- build quasi-mono` in `quasi-type` produces the exact file the image gets,
213 + and `cargo run -- proof quasi-mono` rasterises it to a PNG — which is the check that
214 + catches a wrong shape, since a `cmap` count cannot. What still needs the image is
215 + everything about what else is on disk: the Noto set, the substitutes, and the `fc-match`
216 + answers under `HOME=/etc/skel`.
217 +
218 + The numbers worth re-checking after a font change are the size of Alloy's own emitted set
219 + (18), whether "missing from Alloy's set" is still 0 for the mono face, and whether the
220 + widget-ceiling miss is still only braille and legacy computing.
@@ -4,19 +4,21 @@
4 4
5 5 The application tier is the newest and is the one with a visual language of its own: Mac OS 8, chunky and dithered, where the hero tier is a mid-century relay station rendered as service-manual plates. Two languages in one system is deliberate rather than drift. They never appear at the same size, in the same place, or for the same purpose: an app icon says which program this is, at 32 pixels, in a launcher or a dialog; a hero plate says which system you are looking at, full-bleed, on a lock screen or a splash. Write any new icon into whichever tier its job belongs to rather than reconciling the two.
6 6
7 - ## Functional tier: Nerd Font glyphs (primary)
7 + ## Functional tier: the house glyph set (primary)
8 8
9 9 For small, identifying icons in chrome: list-item markers, pane/status indicators, file-type glyphs, severity glyphs paired with accent text, footer keymap hints.
10 10
11 - - **Source:** the nerd-patched glyph range in the terminal font (`IosevkaTermNerdFont`). No separate icon font.
11 + - **Source:** the marks drawn into the house face itself — the triangles, the arrows, the box drawing and block elements, the ballot X and the whitespace renders. `quasi-type`'s `glyphs/manifest.toml` is the set, and it is the same drawing in a terminal, a webview and an egui panel. No separate icon font, and as of 2026-08-17 no Private Use Area anywhere in the image.
12 12 - **Rendering:** treated as text, a cell wide. Inherits the surrounding text's ramp position and weight. Never accent-colored unless paired with information (an error glyph beside an error message uses `accent-error`).
13 13 - **Size:** the cell. There is no standalone sizing scale in a terminal.
14 14
15 15 This tier does the overwhelming majority of Alloy's iconography now. It is uncomplicated, and in a terminal it is the only icon form that renders inline.
16 16
17 - **As written, though, this tier is aspirational rather than shipped.** Measured 2026-08-06 ([FONTS.md](FONTS.md)): nothing in Alloy's own source or in `alloy_tui 5.0.0` emits a single Private Use Area codepoint, and the `severity_glyph(Urgency)` / `pane_marker` accessors this paragraph used to describe as the centralizing mechanism do not exist. What the widgets actually draw is the geometric-shapes block: `▶` and `▸` for selection, `▾` for disclosure, the block elements for gauges. The Nerd Font glyphs in the terminal font are reached only by third-party tools Alloy configures (starship, yazi, bottom, helix), never by Alloy itself.
17 + **The two readings this section used to leave open are settled, and the font change settled them.** It said either the semantic-name accessor was work not yet done, or the geometric-shapes set was the real functional tier and the Nerd Font framing should be retired. It is the second: measured 2026-08-06 ([FONTS.md](FONTS.md)), nothing in Alloy's own source or in `alloy_tui` emits a single Private Use Area codepoint, and what the widgets draw is the geometric-shapes block — `▶` and `▸` for selection, `▾` for disclosure, the block elements for gauges.
18 18
19 - Two readings are open and this file does not settle them: either the semantic-name accessor is work not yet done, or the geometric-shapes set is the real functional tier and the Nerd Font framing above should be retired. Deciding that belongs with the icon-set work, not here.
19 + As of 2026-08-17 there is no PUA left to reach for. The image ships `Quasi Mono` and `Quasi Body`, cut faces carrying the house glyph set, and yazi's built-in Nerd Font filetype icons — the one live PUA consumer on the machine — are off (STACK.md#fonts). So the functional tier is the house set by construction: a mark is in it because it carries meaning the UI depends on, and every renderer draws the same outline.
20 +
21 + What is still work rather than fact is the semantic-name accessor (`severity_glyph(Urgency)`, `pane_marker`), which does not exist. Widgets reach for the codepoint directly. That is a centralizing mechanism worth having and it belongs with the icon-set work, not here.
20 22
21 23 ## Application tier: a generic set Alloy owns (decided, not yet drawn)
22 24
M docs/STACK.md +29 -19
@@ -549,44 +549,54 @@
549 549
550 550 Optimized for readability. A single fontconfig at `~/.config/fontconfig/fonts.conf` routes every app that asks for a generic family to Alloy's picks. Config at [`etc/skel/.config/fontconfig/`](../etc/skel/.config/fontconfig/).
551 551
552 - This section holds the reasoning behind each pick. The measurement lives in [FONTS.md](FONTS.md): which codepoints Alloy's surfaces actually emit, what the shipped fonts cover, and which links in the fallback chain exist. The headline from the 2026-08-06 audit is that there is no coverage gap in any cell-grid surface, and that six of the fourteen families named in the chain are not in the image.
552 + This section holds the reasoning behind each pick. The measurement lives in [FONTS.md](FONTS.md): which codepoints Alloy's surfaces actually emit, what the shipped fonts cover, and which links in the fallback chain exist. The headline is that there is no coverage gap in any cell-grid surface, and that every family the chain names is installed: the nine that were not were deleted on 2026-08-16.
553 553
554 554 **Departure Mono, Alloy's brand mark, is not in the fontconfig chain.** It stays reserved for headers and brand elements and is invoked by name where wanted. Nobody reads code or long text in Departure.
555 555
556 - **It is also not in the image, which is the more useful fact.** Audited 2026-08-05. The font layer installs IosevkaTerm Nerd and Atkinson Hyperlegible and nothing else, and the only copy in the repo is `docs/mockups/fonts/DepartureMonoNerdFontMono-Regular.otf`, a design-time asset. So Departure is a font for things rendered *outside* the running system: mockups, the README and social card, a swaylock background plate, a first-boot splash image. Anything that names the family at runtime gets a silent fontconfig substitution, which is the same defect class as the emoji alias that named a font the image never installed. Naming it in a theme is therefore not a way to get it.
556 + **It is also not in the image, which is the more useful fact.** Audited 2026-08-05, and still true after the 2026-08-17 font change: the font layer installs the two cut faces and nothing else, and the only copy in the repo is `docs/mockups/fonts/DepartureMonoNerdFontMono-Regular.otf`, a design-time asset. So Departure is a font for things rendered *outside* the running system: mockups, the README and social card, a swaylock background plate, a first-boot splash image. Anything that names the family at runtime gets a silent fontconfig substitution, which is the same defect class as the emoji alias that named a font the image never installed. Naming it in a theme is therefore not a way to get it.
557 557
558 558 **Measured coverage, for whoever reaches for it in a mockup:** 11,468 glyphs across 169 declared languages. Latin, Cyrillic and Greek, the box-drawing range, and the Nerd Font private-use icons. It does not cover CJK, Arabic, Hebrew, Devanagari, Thai, Bengali or Tamil, and it does not cover Vietnamese, which is the one worth knowing: Vietnamese is Latin-script and looks like it should work, so a string with stacked diacritics falls back mid-word rather than failing visibly. For a brand mark set in English that is an acceptable limit rather than a gap, and it is the reason the font stays out of the generic-family chain where a page of arbitrary text would hit it.
559 559
560 - **One limit does bite where Departure is legitimately used.** Of the eighteen non-ASCII codepoints Alloy's own surfaces emit, Departure lacks five: `⏎` `␣` `▸` `◂` `✘`. Four are starship and helix prompt furniture, which is exactly what a terminal mockup renders, so a mockup set in Departure drops its prompt separators without saying so. It also carries no braille, sextants or octants, so no Departure render can show a `Canvas` or a sparkline. Mock a running surface in Iosevka; keep Departure for headers and plates. Detail in [FONTS.md](FONTS.md).
560 + **One limit does bite where Departure is legitimately used.** Of the eighteen non-ASCII codepoints Alloy's own surfaces emit, Departure lacks five: `⏎` `␣` `▸` `◂` `✘`. Four are starship and helix prompt furniture, which is exactly what a terminal mockup renders, so a mockup set in Departure drops its prompt separators without saying so. It also carries no braille, sextants or octants, so no Departure render can show a `Canvas` or a sparkline. Mock a running surface in the house mono; keep Departure for headers and plates. Detail in [FONTS.md](FONTS.md).
561 561
562 - ### Monospace: **IosevkaTerm Nerd Font Mono**
562 + ### The house faces, and why the image cuts its own
563 563
564 - The Term variant of Iosevka drops ligatures, which is safe for TUIs (yazi, bottom, helix status columns) that count characters. The Nerd Font bundle carries the glyphs starship, yazi, and bottom need for prompt icons and file-type indicators. Iosevka's narrow proportions give more columns per line than JetBrains Mono or Fira Code, real screen-real-estate value in a tiling stack.
564 + Settled 2026-08-16 (wiki `typography-standard`), landed here 2026-08-17. Alloy ships **two faces from one superfamily, both cut in the build**: `Quasi Mono` for everything monospaced and `Quasi Body` for UI text. Neither is downloaded, because neither exists as a download: `quasi-type` takes a pinned base, draws the house glyph set into it, and emits the face. Built faces are deliberately not committed anywhere, so the pipeline is the only source of truth for what a face contains.
565 565
566 - **The `Mono` family, in cell grids only.** The Nerd Fonts release ships three families from one typeface: `IosevkaTerm Nerd Font`, `… Nerd Font Mono`, and `… Nerd Font Propo`. They differ in how wide the icon glyphs are allowed to be. Icons live in the Private Use Area, which a terminal measures as one cell, while the plain family draws them at about two, so the glyph paints over whatever follows it. The `Mono` family constrains them to the single cell the terminal allocated.
566 + What that replaced was a 60 MB IosevkaTerm Nerd Font zip plus an upstream Atkinson Hyperlegible tarball, and it retired the Private Use Area from the image entirely.
567 567
568 - In practice the overflow is usually hidden, because yazi and starship both pad icons with a trailing space. The `Mono` family is still what the terminal and the fontconfig `monospace` alias use, because "usually hidden" depends on every TUI author choosing to pad, and the failure is silent when one does not. The cost is real and worth stating: single-cell icons are smaller and fainter than the plain family's, most noticeably at small point sizes.
568 + **The argument for cutting rather than picking.** A face chosen for the quality of its text comes from a designer who declined to ship UI symbols, so the two requirements pull apart: pick for legibility and you get no box drawing, pick for symbol coverage and you get a nerd-patched font carrying seventeen thousand codepoints to supply seven. Measured (FONTS.md), Alloy's own source and every config template it ships emit **zero** PUA codepoints; the one live PUA consumer was yazi's built-in filetype icon set, which is now off (`templates/etc/skel/.config/yazi/theme.toml.in`, an empty `[icon]` section). So the whole of what Iosevka was carrying is the box-drawing and block ranges plus a handful of marks, and those are drawings we can own.
569 569
570 - Pango consumers are not a cell grid and keep the plain family, where the fuller icons are free.
570 + **There is no separate terminal font.** One face answers the mono need everywhere: the terminal, the console, the installer, the pango surfaces. The Term-versus-Mono-versus-Propo family split went with the PUA it existed to constrain.
571 +
572 + #### Monospace: **Quasi Mono**, cut from Atkinson Hyperlegible Mono
573 +
574 + Atkinson Hyperlegible is designed by the Braille Institute to maximize letter distinguishability (Il1, O0, cCG all made unambiguous), which is the same thesis as the rest of this section, taken literally. The Mono and Next families are one superfamily by one pair of designers, both variable on `wght` 200-800, both with matching italics, and OFL 1.1 with no Reserved Font Name declared.
575 +
576 + Its cost is that it ships no box drawing and no block elements at all, so the house set grows to 176 glyphs, of which 160 are generated rather than drawn: box drawing is the most regular block in Unicode and both blocks must be cell-exact to tile, which is what hand-drawing gets wrong.
577 +
578 + **Fallback cannot cover the gap, which is what makes the cut necessary rather than nice.** `shop/crates/shop-render/src/shaper.rs` takes the baseline from the primary face only, on purpose, so a fallback face with its own ascent would sit its glyphs on a different line. Box drawing arriving that way is every table border in every TUI drawn off-baseline: broken borders, not tofu.
579 +
580 + **The ExtraLight trap.** The mono base's own default instance is `wght` 200 and its name record reads `Atkinson Hyperlegible Mono ExtraLight`, so a cut inherits that default. fontconfig enumerates a variable font's named instances and resolves an unweighted query to Regular, but a consumer that loads the file directly has to name a weight. The build asserts the resolved weight for exactly this reason.
571 581
572 582 Applied at:
573 - - shop: nothing to apply. It bundles `IosevkaTerm Nerd Font Mono` into the binary and has no font setting, so the terminal cannot be pointed at a font the image does not carry. This is also why it renders nerd-font glyphs with no system font install.
574 - - fontconfig `monospace` alias: `IosevkaTerm Nerd Font Mono`, for everything else that asks for mono.
575 - - `templates/etc/skel/.config/mpv/mpv.conf.in`, `templates/etc/skel/.config/imv/config.in`, the sway bar and title font, mako, swaylock, satty: the plain `IosevkaTerm Nerd Font`, all pango.
583 + - shop: it bundles `Quasi Mono`, cut at build time from the same pipeline (`shop@584d119`, which deleted the 13 MB Iosevka), so the terminal draws the house marks with no font install at all.
584 + - fontconfig `monospace` alias: `Quasi Mono`, for everything else that asks for mono.
585 + - `templates/etc/skel/.config/mpv/mpv.conf.in`, `templates/etc/skel/.config/imv/config.in`, the sway bar and title font, mako, swaylock, satty: `Quasi Mono`, all pango. They used to name a second Iosevka family; there is one family now.
576 586
577 - Rejected: JetBrains Mono (wider characters cost columns per line), Fira Code (older, ligatures on by default), Cascadia Code (Microsoft-shaped, fine but less Alloy-neutral), Berkeley Mono (paid, can't ship).
587 + Rejected: IosevkaTerm Nerd Font (60 MB and a Private Use Area to carry seven characters, and it is somebody else's design decision in the most-read font on the machine), IBM Plex Mono (the first base this pipeline cut, and it ships box drawing complete; lost to Atkinson on legibility and on licence), JetBrains Mono (wider characters cost columns per line), Fira Code (older, ligatures on by default), Cascadia Code (Microsoft-shaped, fine but less Alloy-neutral), Berkeley Mono (paid, can't ship).
578 588
579 - ### Sans: **Atkinson Hyperlegible**
589 + #### Sans: **Quasi Body**, cut from Atkinson Hyperlegible Next
580 590
581 - Designed by the Braille Institute specifically to maximize letter distinguishability (Il1, O0, cCG all made unambiguous). Optimized-for-readability by institutional charter, the honest answer to "make UI text as readable as possible." Fedora repos ship it.
591 + The sans half of the same superfamily, on the same axis, by the same designers, carrying the same drawn marks. It replaced upstream Atkinson Hyperlegible, which the image used to install directly from a pinned commit and which is now the base this is cut from.
592 +
593 + **It takes the marks and not the cell grid**: 16 glyphs rather than 176. Box drawing and block elements are sized against the cell and must be cell-exact to tile, and a proportional face has no cell, so a `┌` set in one draws a corner that joins nothing. Its coverage floor is Alloy's eighteen minus the four that exist to tile (`│ █ ▏ ░`), because a slot answers to the floor of the role it fills.
582 594
583 595 Applied at:
584 - - `etc/skel/.config/gtk-{3.0,4.0}/settings.ini`: `gtk-font-name = Atkinson Hyperlegible 11`.
585 - - fontconfig `sans-serif` alias: everything else that asks for sans.
596 + - `etc/skel/.config/gtk-{3.0,4.0}/settings.ini`: `gtk-font-name = Quasi Body 11`.
597 + - fontconfig `sans-serif` alias: everything else that asks for sans, then Cantarell.
586 598
587 - **One-line swap to Inter** if a more conventional interface font is preferred: Inter is tighter at UI sizes, more common in mainstream design, still highly legible. Replace the first `<family>` in the sans-serif alias and the `gtk-font-name` value. Alloy's shipped default is Atkinson because it matches the "optimize readability" thesis more literally.
588 -
589 - Rejected: Inter (excellent but less legibility-maximized; kept as documented alternate), IBM Plex Sans (corporate-shaped), Roboto/Cantarell (default-neutral, no advantage over Atkinson), Iosevka Aile (family coherence appealing but Aile isn't as readable at small sizes as dedicated UI fonts).
599 + Rejected: upstream Atkinson Hyperlegible (the base, and the thing this supersedes: same letters, none of the marks), Inter (excellent but less legibility-maximized; it also used to sit at position 2 of the alias, so anyone installing it for an unrelated app silently repointed Alloy's whole UI font), IBM Plex Sans (corporate-shaped), Roboto/Cantarell (default-neutral, no advantage), Iosevka Aile (family coherence appealing, less readable at small sizes than a dedicated UI face).
590 600
591 601 ### Serif: **Liberation Serif, by inventory rather than by choice**
592 602
M docs/TOKENS.md +1 -1
@@ -130,7 +130,7 @@
130 130
131 131 - **Calibrated-display verification** on real hardware in real terminals (truecolor and 256-color). Pre-1.0 gate.
132 132 - **256-color downgrade table** for terminals that report no truecolor.
133 - - **Figlet / Nerd-Font recipes** for the large numeric readouts a display font would otherwise carry.
133 + - **Figlet / block-element recipes** for the large numeric readouts a display font would otherwise carry.
134 134 - **Swapping the desktop's mode without a re-login.** `alloy theme apply` ships and the settings row writes the mode file, but the configs it lays down are read once by programs already running, so the switch lands at the next login. The console itself re-themes immediately.
135 135
136 136 ## How this file is consumed
@@ -372,16 +372,16 @@
372 372 title = "the fonts"
373 373
374 374 [[section.project]]
375 - name = "Iosevka"
375 + name = "Atkinson Hyperlegible Mono"
376 376 license = "OFL-1.1"
377 - url = "https://typeof.net/Iosevka"
378 - note = "shipped as IosevkaTerm Nerd Font; the patcher is Nerd Fonts, MIT"
377 + url = "https://github.com/googlefonts/atkinson-hyperlegible-next-mono"
378 + note = "the base Quasi Mono is cut from; Applied Design Works and Letters from Sweden, for the Braille Institute of America"
379 379
380 380 [[section.project]]
381 - name = "Atkinson Hyperlegible"
381 + name = "Atkinson Hyperlegible Next"
382 382 license = "OFL-1.1"
383 - url = "https://brailleinstitute.org/freefont"
384 - note = "Braille Institute of America"
383 + url = "https://github.com/googlefonts/atkinson-hyperlegible-next"
384 + note = "the base Quasi Body is cut from; the sans half of the same superfamily"
385 385
386 386 [[section.project]]
387 387 name = "Noto"
@@ -76,15 +76,24 @@
76 76
77 77 | Role | Font |
78 78 |---|---|
79 - | Monospace | IosevkaTerm Nerd Font Mono |
80 - | Sans | Atkinson Hyperlegible |
79 + | Monospace | Quasi Mono |
80 + | Sans | Quasi Body |
81 81 | Serif | Not shipped; falls through to Fedora's default |
82 82 | Emoji | Not shipped |
83 83
84 - Atkinson Hyperlegible is designed by the Braille Institute to make letters as
85 - distinguishable from each other as possible, which is the most literal answer
86 - to "make UI text readable". If you want something more conventional, Inter is a
87 - one-line swap in `~/.config/fontconfig/fonts.conf` and the GTK settings.
84 + Both are Atkinson Hyperlegible, which is designed by the Braille Institute to
85 + make letters as distinguishable from each other as possible — the most literal
86 + answer to "make UI text readable" — with one difference: Alloy builds its own
87 + copies rather than installing the upstream files, and draws the symbols a
88 + terminal needs into them. Box drawing, block elements, arrows and a handful of
89 + marks, all missing from the upstream faces, which is why a table border in a
90 + TUI used to need a second font on the machine.
91 +
92 + They are variable fonts, so any weight from 200 to 800 is available to anything
93 + that asks for one; unweighted requests get Regular.
94 +
95 + If you want something more conventional, Inter is a one-line swap in
96 + `~/.config/fontconfig/fonts.conf` and the GTK settings.
88 97
89 98 CJK, Arabic, Hebrew, Indic and Thai coverage comes from Fedora's font
90 99 metapackages, so web pages in those scripts render. **Emoji do not.** No emoji