There’s a font that anyone who touched a computer in the 90s recognizes immediately.
MS Sans Serif. That small, square, pixel-visible font that showed up everywhere in Windows 95: menus, buttons, dialog boxes, title bars.
React95 already had the components and the styles. The fonts, no. In the browser, you’d get the system fonts. I felt like something was missing. React95 was built to be pixel perfect, and using the wrong font broke that.
There are plenty of fonts out there that look like MS Sans Serif. W95FA is one of them, made to remember that era. And they work, from a distance. Up close, they’re not the same. They’re not pixel perfect.
I wanted exactly that one.
The problem
The original Windows 95 fonts live inside .FON files, a Microsoft binary
format from 1987, built for bitmap fonts in the DOS era. There’s no direct path
from a .FON to a modern @font-face. Nobody’s going to just “import” this in
CSS.
So the question became: can it be done?
The extraction
The answer was Python. Not the language I use day to day, but what I needed. With a little help from AI to get unstuck on the parts I didn’t know well, I was able to keep moving.
A library called monobit reads old .FON
files and extracts the glyph data. From there,
fontTools rebuilds each size as a proper
TTF, with correct metrics and the gasp table configured so browsers wouldn’t
apply antialiasing and ruin the pixels. Then
brotli compresses to WOFF2 and embeds the
result as base64 directly in the CSS.
Each font, each size, became a standalone CSS file with a ready-to-use
@font-face.
The strange thing about bitmap fonts
Vector fonts scale: you set font-size: 32px and the font adapts. Bitmap fonts
don’t work that way. Each size is a fixed grid of pixels — scale it up and the
pixels fall apart: blurred, misaligned, wrong. You either render at the right
resolution or you don’t.
This means R95 Sans Serif 14pt and R95 Sans Serif 18pt aren’t sizes of the
same family. They’re different families. Each has its own name, its own native
pixel height, and needs to be used at the right scale.
body { font-family: 'R95 Sans Serif 14pt'; font-size: 24px; /* native height of 14pt at 96 dpi */}It’s counterintuitive until it clicks: each size is a different font because every pixel was drawn by hand for that exact scale.
The package
The result was @react95/fonts: four variants, MS Sans Serif and MS Serif, at
96 dpi and 120 dpi, with six sizes each. Twenty-eight CSS files generated
automatically by the Python script, with base64 embedded, no extra network
requests.
npm install @react95/fontsPick how much you want:
// Everythingimport '@react95/fonts';
// One full variantimport '@react95/fonts/sans-serif';
// One specific sizeimport '@react95/fonts/sans-serif/14pt';The code is on GitHub. The package is on npm. And if you want to see the fonts before installing, there’s a demo built with React95 itself.
Try it here:
No market case
Nobody needs MS Sans Serif to ship a product. But there’s a difference between “close enough” and “correct,” and that difference bothered me.
React95 exists because I wanted to learn by building something fun.
@react95/fonts exists for the same reason: the right font, at the right pixel.
Sometimes that turns into a package other people install.