Colophon
Last updated: 27 Aug 2026This site is built and published with a small, readable stack and a bias for flexibility and performance.
Stack#
- Static site generator: Eleventy (11ty) v4
- Language & tooling: Node.js (Yarn scripts), Nunjucks templates, Markdown via Markdown‑It with
markdown-it-anchor - Styles: Sass compiled to a single CSS file; custom utility classes; normalize; type set in IBM Plex Sans and IBM Plex Mono
- Previously used the EMBL Visual Framework (VF) and Gulp; the migration to a simpler Eleventy v3 stack is documented here.
- Search: Two modes on the search page:
- Pagefind — static keyword search, indexes built HTML at deploy time, serves chunked index fragments on demand. Source: search page template
- Semantic search — build-time vector embeddings (MiniLM-L6-v2 via Transformers.js) + in-browser cosine similarity. Same model runs both sides; no API keys, no server. Read the post
- Hosting: Vercel (auto‑deploys from GitHub, automatic HTTPS, CDN)
- Domain: Cloudflare (DNS, security, performance)
- Fonts: IBM Plex Sans and IBM Plex Mono, self-hosted. The site previously used Recursive.
Build & source#
- Source code:
github.com/khawkins98/allaboutken-11ty - Images: Eleventy Image plugin (Sharp under the hood) configured to generate deterministic, token‑based filenames
- Social sharing images: Auto‑generated OpenGraph/Twitter cards using Eleventy's Screenshot Service — dynamically captures styled HTML pages as 1200×630px images
- Build command:
yarn build→ compiles Sass, runs the two-pass Eleventy build, processes images, derives corpus data and builds the search indexes
How closest-in-meaning works#
At the foot of most entries there is a short list of the closest entries by meaning. It is not driven by tags, and it is worth being precise about what it is and is not.
The site already computes vector embeddings for semantic search: each page is split into chunks and each chunk is turned into a 384-number vector by a small language model at build time. Those vectors place text that means similar things near each other, whether or not it shares any words.
The related list reuses that work rather than adding anything new:
- Average a page's chunk vectors into one vector for the whole entry, and normalise it to unit length.
- Compare every pair by cosine similarity, which for unit vectors is just the dot product. 1.0 is identical, 0 is unrelated.
- Keep the best three above a floor of 0.55.
Three details do most of the work:
- Index pages are excluded. A page like the blog index is "about" everything, so it sits near everything and crowds out real matches.
- The floor is measured, not chosen by feel. Across this corpus the median entry's best match scores 0.70. At 0.55, about a fifth of entries end up with no neighbour at all, which is the right answer for a genuinely singular piece: a padded suggestion is worse than none.
- The number shown is the raw similarity, rounded to two places. It is not a percentage or a confidence, and it is stated rather than drawn as a bar, because a bar would imply more precision than a soft signal has.
The trade-off worth naming: this reflects what the writing is about, not what it argues. Two entries taking opposite positions on the same subject will look very close together, because they are, semantically. It is a reading aid, not an endorsement that one follows from the other.
Neighbours are computed after each build and committed as data, so a brand new
entry has no neighbours until the next build. Code:
scripts/compute-related.mjs.
Privacy#
- Analytics: GoatCounter (cookie‑free, aggregate counts only). See their rationale on GDPR consent and legitimate interest: GDPR consent notices.
- No trackers: No ad tech, no cross‑site profiling.
Principles#
- Prefer simple, inspectable pages over heavy frameworks.
- Ship as little JS as practical; keep content readable without it.
- Optimize images and typography for legibility.
- Document decisions in public when it helps future me (and you).
Classic web badges
Badges sourced from Seirdy’s “Classic web badges” — licensed under CC BY‑SA 4.0. Animated Eleventy badge made by Chris Burnell, self-hosted here rather than hotlinked.
More things I've been digesting