<span class="mw-page-title-namespace">Blog</span><span class="mw-page-title-separator">:</span><span class="mw-page-title-main">Hacks/Mills 8A in LaTeX</span>
Fabrice P. Lauss𝕪’s ℤebuine Web

Mills 8A in LaTeX

Mills 8A is a digital revival of Monotype Modern No. 8A, the typeface of the Bulletin of the American Mathematical Society in the 1940s, packaged for $\mathrm{\LaTeX}$. It is not a redrawing: every glyph is traced from the printed type itself, averaged over about 900,000 letter impressions on 461 scanned pages of the Bulletin and the Transactions (1940–1948). It is also the face Knuth modelled Computer Modern on.

I installed it for my own notes; this post archives what it is, how to install it and how to use it.

What it is

The name comes from W. H. Mills, A prime-representing function, Bull. Amer. Math. Soc. 53, 604 (1947), the page the project started from. The repository resets that page from its $\mathrm{\LaTeX}$ source next to the 1947 scan (mills-compare.pdf), and six other first pages the same way: Erdős (1947), Doob (1947), Kac (1947), Post (1944), Wright (1942) and von Kármán (1940).

Monotype Modern 8A is Lanston Monotype's series 8, roman with italic: a Scotch-style "modern" face with strong contrast and ball terminals, cast in hot metal and printed by letterpress. It was a standard face of American mathematical printing from the 1920s to the 1960s.

font contents
Mills8A-Regular roman, small caps, f-ligatures, lining and old-style figures, accents (Latin-1, Latin Extended-A)
Mills8A-Italic italic, Greek, f-ligatures
Mills8A-Bold, -BoldItalic bold (from the 1947 titles); bold italic (synthesized)
Mills8A-Regular9, -Italic9 the 9pt cut, for footnotes and references
Mills8A-Math the 1947 letters, Greek, operators, relations, Fraktur, display ∑ ∏ ∫, and the real script sorts for indices

What is real and what is filled in:

  • Traced from the 1940s scans: every roman and italic letter and figure at 11pt, old-style figures (from the years in the running heads of the Bulletin), punctuation with the 1947 quotes, 23 small capitals, bold (from title lines and run-in heads), Greek, most math operators and relations, display ∑ ∏ ∫, some Fraktur and script capitals, the 9pt cut (80 roman and 54 italic sorts), and 43 script sorts for indices (40 first-order, 3 second-order), among them the short 1947 index arrow.
  • Filled in: a few small caps and $ from the 1922 Lanston Specimen Book (public domain); some ligatures, the em dash, ellipsis, \cdot, \cdots and bold italic built from 1947 sorts; accents other than the dieresis, rarer symbols (# % @ † ‡ ¶ « » ß Æ Œ Ø Ł…) and the math symbols the scans lack from Latin Modern, thickened to the type's weight.
  • Spacing is measured too: side bearings fitted from about 440,000 letter pairs in the text (they land on Monotype's 18-unit grid), the thin space set before : and ;, and the script positions of the Mills page.

The pdfLaTeX package adds a few 1947 touches of its own: \neq, \leqq, \geqq and \cong come from the 1947 sorts, \cdots has its dots 0.65em apart as on the Mills page, § † ‡ ¶ are taken from the text font, and the math script sizes are the measured ones (58.9% and 50.1% of the 11pt body).

Installing

The built fonts are committed in the repository, so nothing needs building. I keep a clone inside my personal TeX tree and symlink it into place, so that a git pull is all an update takes:

T=$(kpsewhich -var-value TEXMFHOME)          # ~/texmf
git clone https://github.com/heiner/mills8a.git $T/source/mills8a
S=$T/source/mills8a
mkdir -p $T/tex/latex $T/tex/luatex/mills8a $T/fonts/{tfm,vf,type1,enc,map,opentype}
ln -s $S/revival/pdftex/tex $T/tex/latex/mills8a
ln -s $S/tex/mills8a-jitter.lua $T/tex/luatex/mills8a/mills8a-jitter.lua
for d in tfm vf type1 enc map; do ln -s $S/revival/pdftex/fonts $T/fonts/$d/mills8a; done
ln -s $S/revival/fonts $T/fonts/opentype/mills8a
kpsewhich mills8a.sty Mills8A-Math.otf mills8a.map   # all three must be found

No environment variables and no updmap are needed: the package loads its own map file (\pdfmapfile{+mills8a.map}), and ~/texmf is searched without a file database.

Upstream's own way copies the files instead of linking them (updating then means re-running it):

git clone https://github.com/heiner/mills8a && cd mills8a
./make-tds.sh        # assemble the TeX tree (build/tds) and mills8a.tds.zip
./install.sh         # copy it into TEXMFHOME

For latex + dvips, use ./install.sh --dvips, which also enables the map with updmap-user. On MiKTeX, unzip mills8a.tds.zip into a new directory, add it as a root directory and refresh the file name database.

Using it

With pdfLaTeX, one line in the preamble:

\usepackage{amsmath}
\usepackage{mills8a}        % or [osf] for old-style figures in text

It replaces both the text and the math fonts, so any other font package (lmodern, newtx, mathpazo…) must go. Below 10pt the 9pt cut is picked automatically.

With LuaLaTeX, through the OpenType fonts. Here each letter can be set as one of up to 8 real 1947 impressions at random (feature rand), and an optional Lua filter adds the letterpress baseline wobble (0.04pt standard deviation, fixed seed so the output is reproducible):

\usepackage{unicode-math}
\directlua{require("mills8a-jitter").enable(0.04, 1947)}   % optional wobble
\setmainfont{Mills8A-Regular.otf}[RawFeature=+rand,
  SizeFeatures={{Size=-10, Font=Mills8A-Regular9.otf}, {Size=10-}},
  SmallCapsFont=Mills8A-Regular.otf, SmallCapsFeatures={RawFeature=+smcp},
  ItalicFont=Mills8A-Italic.otf,
  ItalicFeatures={SizeFeatures={{Size=-10, Font=Mills8A-Italic9.otf}, {Size=10-}}},
  BoldFont=Mills8A-Bold.otf, BoldItalicFont=Mills8A-BoldItalic.otf]
\setmathfont{Mills8A-Math.otf}

The difference from the pdfLaTeX output is slight. For the full Bulletin look (11pt on 12pt leading, 317pt measure, 1947 script positions, fixed leading, footnotes following the text), the model is tex/mills.tex in the repository (here: ~/texmf/source/mills8a/tex/mills.tex), which typesets with either engine. To see the type at its true size, print mills-specimen-a4.pdf at 100%, not "fit to page".

Things to know

  • It is young and moving fast. Version 0.1.0; the repository started on 3 October (2026) and had 78 commits six days later, eleven of them on the 8th alone (two changing how second-order indices are set). Until 1.0.0, glyph shapes and spacing may still change in a minor release, so a git pull can change the line breaks of a note already written. To freeze a document, check out the commit it was written with.
  • Script sizes are tuned for 11pt (\DeclareMathSizes{11}{11}{6.48}{5.51}). At 10pt or 12pt $\mathrm{\LaTeX}$'s default math sizes apply; both compile cleanly.
  • The 9pt cut is visibly heavier than the 11pt. That's the metal type, not a bug.
  • With pdfLaTeX, the big delimiters still come from cmex10 (a virtual font slots the 1947 big operators into it), so CMEX10 shows up among the embedded fonts.
  • Licence: the font files are a modified Latin Modern / Latin Modern Math and are under the GUST Font License (LPPL 1.3c or later); everything else is MIT. The 1940s scans are not redistributed; they are free from the AMS back-issue archive.
  • Rebuilding from the scans (not needed to use it) takes about 1.5–2 hours on 4 cores and needs TeX Live with lcdf-typetools, Tesseract, potrace, and Python 3 with numpy, scipy, Pillow and fontTools.

How it was made

  1. Segment each 600dpi page into glyph impressions, with Tesseract for a first reading and the page's lines.
  2. Normalize the scans: each paper's ink weight and type size are measured against the Erdős paper and corrected.
  3. Cluster identical sorts and label them. Rules do most of it; overrides.tsv holds the hand corrections, each naming one impression, so re-clustering does not invalidate them.
  4. Average each sort's impressions at 4× resolution, aligned to ¼ px. Old-style figures come from the years in the running heads.
  5. Trace and space the masters into OpenType fonts, fit the side bearings from the letter pairs, then build the accents, the math font on Latin Modern Math's tables, the bold and 9pt fonts, and the pdfLaTeX fonts.
  6. Check baselines, heights, side bearings and script sorts of every font (check_fonts.py), with proof sheets of everything the family sets in proof/.

Updating, removing

git -C ~/texmf/source/mills8a pull          # update (may reflow existing notes)
git -C ~/texmf/source/mills8a checkout e219cb0   # back to a given commit
rm -rf ~/texmf/source/mills8a ~/texmf/tex/latex/mills8a ~/texmf/tex/luatex/mills8a \
       ~/texmf/fonts/{tfm,vf,type1,enc,map,opentype}/mills8a   # uninstall

Installed here at commit e219cb0 (8 October 2026) and tested with TeX Live 2025: pdfLaTeX at 10, 11 and 12pt and LuaLaTeX, no missing characters, all fonts embedded. Set up with Claude.