Pagination a crawler can follow
Page two of a blog should be a URL, not a state. On a static host that constraint turns out to simplify the code rather than complicate it.
A reading-time estimate is a guess presented as a fact. That is fine, as long as the guess is not wrong in a way the reader will notice.
1 min read
Written by
Seratlas Team
Engineering and delivery
1 min read
We build and operate assessment software. We write here about the parts that are harder than they look.
Every blog card carries a number that nobody verifies. "6 min read" is a word count divided by an assumed rate, rounded, and then rendered in the same typeface as the publication date — which is a fact.
It is worth getting close to right, because a reader who finishes in half the promised time stops trusting the next number on the page.
The first is counting code as prose. A forty-line snippet is not two hundred words of reading; it is either skipped entirely or studied for far longer than any words-per-minute figure predicts. Leaving it in the count makes engineering posts claim roughly double their real length.
The second is false precision. Nothing is gained by "5.8 min", and something is lost: it implies a measurement where there is an assumption.
Strip fences, strip inline code, strip link URLs while keeping the label, then divide by 225 and round — with a floor of one, so a short note never advertises "0 min read".
const words = prose.split(/\s+/).filter((t) => /[\p{L}\p{N}]/u.test(t));
return Math.max(1, Math.round(words.length / 225));
The filter matters more than it looks. Splitting on whitespace alone counts leftover punctuation as words, which inflates every post by a percent or two — consistently, and in the same direction.
View counts. We have no analytics backend on this site, so any figure would be a literal invention, and a card is a bad place to start making things up.
Where a number appears, it should be one we could defend.
Page two of a blog should be a URL, not a state. On a static host that constraint turns out to simplify the code rather than complicate it.
A decision that only exists in a conversation gets re-argued every few months. Writing it down is cheaper than remembering it.
What this site is for, what is still missing from it, and why we would rather publish it in that state than wait.
A consent checkbox that starts checked is not consent. A few small decisions separate a form that asks from one that assumes.
We would rather answer a direct question than write a follow-up post nobody asked for.