How beetread paces every word with an LLM
Most rapid readers have one knob: words per minute. You set it to 400, or 600, or some number you saw in a productivity blog, and every word gets the same slice of time. beetread gives each word its own duration, decided before you ever press play.
The work happens before you read
When a book enters the library, it's broken into overlapping windows of roughly seven hundred words, small enough to reason about carefully and wide enough to preserve context. A language model reads each window and produces a reading script: for every word, how long to hold it on screen, and where to insert a pause.
None of this runs while you read. By the time a book reaches you, the pacing is baked in. The reader plays the script. That keeps reading instant and private, with no model in the loop watching you turn pages, and it means the expensive analysis happens exactly once per book rather than once per reader.
Two things drive the hold time
The duration of each word comes from two signals that pull in the same direction but for different reasons.
- Cognitive density: how much thinking a passage demands. A sentence introducing a new abstract idea, or one that turns on a subtle logical pivot, earns more time even if its words are short and common. This part needs a model to read for meaning.
- Lexical complexity: how hard the individual words are. Here we use a deterministic measure based on age-of-acquisition norms: when people typically learn a word. "Cat" is learned early and reads fast; "susurration" is learned late (if ever) and gets room to breathe. Because this is a lookup rather than a judgment call, it's fast, cheap, and consistent across books.
Splitting the signal this way matters. The model spends its effort on the thing only a model can do, judging conceptual difficulty, while the mechanical question of "is this a hard word" gets answered the same way every time, with no tokens spent and no drift.
Breath-pauses give the stream structure
Holding hard words longer helps. Comprehension also needs boundaries. When someone reads aloud well, they pause at commas, breathe at full stops, and leave a beat of silence between paragraphs. beetread inserts the same breath-pauses at clause and sentence boundaries, so each idea has a moment to settle before the next word arrives. Without them, a fast stream turns into an undifferentiated blur, the failure mode of fixed-pace reading we wrote about in why fixed-pace speed reading fails your memory.
One contract, two planes
The reading script is the single source of truth shared between the analysis pipeline and the reader. The pipeline validates every script against a strict schema before it's ever stored, so malformed model output can't reach your screen. The reader trusts the script and plays it. That clean contract is what lets the slow, careful work of pacing happen offline while your reading stays fast and lightweight.
If you want to see the result rather than read about it, the library is open. Pick something dense, like Conrad or Dostoevsky, and watch where it decides to slow down.