Notes on Reading and Type

Good typography is invisible. You don’t notice it — you just keep reading. That is the whole goal of this little theme: get out of the way of the words.

Measure matters#

The single biggest lever for readability is the measure — the width of a line of text. Too wide and your eye loses the start of the next line; too narrow and the rhythm breaks. Somewhere around 60–75 characters is the sweet spot.

Here is roughly how a paragraph’s text flows within a constrained measure:

  1. The eye scans left to right.
  2. It returns on a short, predictable hop.
  3. Repeat, comfortably, for as long as you like.

A scale, not a guess#

Font sizes shouldn’t be picked at random. A modular scale builds every size from a single base and a fixed ratio \(r\), so the \(n\)-th step is just \(s_n = s_0 \cdot r^{\,n}\). Pick the golden ratio, \(r = \tfrac{1 + \sqrt{5}}{2} \approx 1.618\), and the sizes relate to one another the way the eye already expects:

\[ s_n = s_0 \cdot \left(\frac{1 + \sqrt{5}}{2}\right)^{n}, \qquad n \in \mathbb{Z}. \]

So from a 19px body \(s_0\), one step up lands near \(s_1 \approx 30.7\,\text{px}\) for a heading, and one step down gives \(s_{-1} \approx 11.7\,\text{px}\) for fine print — all in proportion, nothing arbitrary.

A little code#

Code should feel at home here too. Inline like const x = 42, and in blocks:

// Resolve the visitor's preferred theme without a flash of the wrong one.
function resolveTheme() {
  const stored = localStorage.getItem("theme");
  if (stored) return stored;
  return matchMedia("(prefers-color-scheme: dark)").matches
    ? "dark"
    : "light";
}
def measure(text: str) -> int:
    """Characters per line — keep it human."""
    return max(len(line) for line in text.splitlines())

What this is not#

This blog is deliberately small. There’s no sidebar of widgets, no related-posts carousel, no newsletter popup chasing you down the page.

Has Skips
Posts Profiles
Dark + light Trackers
An RSS feed Pop-ups

That’s the idea. Now, back to writing.