@pindoba/fonts
v0.0.0-alpha-20260829223243
Published
Self-hosted typefaces for the pindoba design system (Geist + Geist Mono).
Readme
@pindoba/fonts
The typefaces the pindoba design system is designed around: Geist and Geist Mono, self-hosted.
Why this package exists
The preset's fonts.sans and fonts.mono tokens name Geist and Geist Mono first. Without this package those names resolve to nothing and the stacks fall through to the system fonts (ui-sans-serif / ui-monospace). Nothing breaks — but the design system then renders in whatever font the OS happens to supply, which is SF on macOS, Segoe UI on Windows and Arial on Linux. Small mono text like the eyebrow kicker suffers most, because those three faces differ in width, x-height and stroke weight.
Usage
Import once, as early as possible — a root layout or app entry:
import "@pindoba/fonts/index.css";Use the explicit .css extension. A bare import "@pindoba/fonts" resolves at build time but trips TypeScript's ts(2882), which wants a type declaration for a side-effect import; the extension lets it use the ambient *.css module declaration instead.
Single families, if you only need one:
import "@pindoba/fonts/geist.css";
import "@pindoba/fonts/geist-mono.css";What you get
Both are variable fonts, so one file per family covers the whole 100–900 weight range. That matters because the preset sets font-synthesis: none: a weight that isn't loaded renders at the nearest one that is, rather than being faked by the browser. The previous setup requested Geist at weights 400/500/600 only, so every bold (700) heading, label and numeric in the docs was a browser-synthesized fake bold.
Why Geist and Geist Mono specifically
They're a designed superfamily — same foundry, same skeleton, same terminals. Mono text in this system isn't only for code: it also carries the eyebrow kicker and kbd keycaps, which sit directly beside body copy. A mono from an unrelated family reads as a third font in those places; Geist Mono reads as a deliberate counterpart.
Known gap
There's no metric-matched fallback face yet, so there's a small reflow when the real font swaps in. Closing it means a @font-face with size-adjust and ascent-override over a local() source, registered through the preset's globalFontface, with percentages derived from the actual woff2 metrics. Those numbers have to be measured, not guessed — a wrong size-adjust shifts text more than having no fallback at all.
Licence
Both families are OFL-1.1. See the upstream @fontsource-variable/* packages for full attribution.
