Srikanth Bandaru

Hunch

A font that guesses the rest of your word. No JavaScript.

Type in the box. The grey ending is the font’s guess. Copy your text and the guess stays behind.

Voice

Hunch is a font that guesses what you’ll type next. Type “I like choc” and a grey “olate” appears after it. Nothing is running: no JavaScript, no WebAssembly, no extension. A small n-gram model is compiled into ordinary OpenType substitution rules, and the text engine already in your browser runs them on every keystroke. The guess is drawn by the font, so it never enters your text: copy what you typed and only your words come out.

llama.ttf put a real language model in a font in 2024, but it runs only through HarfBuzz’s experimental WebAssembly shaper, which needs a custom build and which no browser enables. Hunch is what fits on the plain-OpenType side of that line. Its matcher follows fontlex’s techniques: word rules at the run’s last glyph, longest first; an inserted empty slot glyph; packed format-1 subtables. What’s new here is ink drawn past the end of the run, a two-digit output channel that carries thousands of distinct guesses, the curve of accuracy against font size, and per-engine results. It also owes ideas to token-space fonts, translate.ttf, the GlyphDrawing.Club syntax-highlighting font and Sans Bullshit Sans.

How a font can guess

A font can’t run code, but it can swap glyphs for other glyphs when the glyphs around them match a pattern. Hunch chains 5 of those passes.

  1. Every glyph that has another glyph after it becomes its “not last” form, so the last thing you typed is the only glyph left in its plain form.
  2. Every letter that follows a letter becomes its “inside a word” form, so a word’s first letter is the only one without it. That anchors every rule at a word start: “stra” can fire after “I like ”, never inside “xstra”.
  3. The last letter, or a final space, gets 2 empty, zero-width glyphs inserted after it.
  4. The rules: 20,000 patterns like “c-h-o-c at the end of the line”, longest first. A matching rule writes 2 digits, each from 0 to 255, into the 2 empty glyphs.
  5. A single ligature turns each pair of digits into a ghost glyph: zero width, its outline drawn to the right of where it sits, in a grey that lives in the font’s colour table.

Because the ghost has no width, the line, the caret and the selection all behave as if it isn’t there. It is just ink past the end of the text.

The 2 digits are the trick that makes it scale. The obvious design, one rule per context writing its guess straight into the slot, stops compiling at 20,000 contexts: OpenType’s 16-bit offsets overflow. Writing a number instead, through 512 shared lookups, keeps the whole font at 519 lookups whatever the model’s size.

Is the font really the model?

The model is a table of word counts from 13 novels: for each word start, one-word context and two-word context, the most common next thing. The compiler turns that table into rules, so the honest question is whether the compiled font does exactly what the table says.

It does. Every one of the 986,942 positions in Great Expectations, a novel the model never saw, was shaped through the compiled font in HarfBuzz and compared with the model’s own answer. All of them agree (measured), and so do the 2 voice fonts on their own held-out novels. The hard part is what has to hold for that to be true: matching ignores case, so each rule position is a class of 2 glyphs, and the font has to keep 20,000 such rules in longest-first order across 25 subtables.

How much model fits in a font

Bigger fonts guess better, but not by much:

Rules Font size Word right after 3 letters Next word right
2,000 27 KB 45.7% 8.4%
5,000 55 KB 48.2% 10.0%
20,000 166 KB 49.4% 13.2%
50,000 391 KB 49.5% 14.9%

All measured on Great Expectations; the font sizes are WOFF2, as the page downloads them. Finishing a word is the strong effect: after 3 letters the font is right about half the time. Next words are right 13.2% of the time at 20,000 rules, so most of what it suggests after a space is wrong, and some of it is funny: “the cat” becomes “the catherine”. The demo page has a switch to type in each size and watch the guesses change.

Where it works

In Chrome 153 and Firefox 159 every check passes, with JavaScript on and off. Each case is drawn beside the same text in a control font, so the check catches a guess in the wrong place, a guess in the wrong colour or width, and any damage to the letters you typed. Safari and macOS apps (Core Text) haven’t been tested on this build yet, so the page doesn’t claim them. The page’s “Where it works” table comes straight from the test harness’s results file.

What it can’t do

  • The guess hangs off the end of each line, not your cursor. A font never knows where the cursor is.
  • You can’t accept a guess with Tab. A font can’t, and adding JavaScript would break the point.
  • Punctuation breaks a context: after “said, ” there’s no guess. Two spaces in a row break it too.
  • It speaks ASCII only, in one monospace face, Geist Mono.