/colophon

Colophon

How this site is built and measured. Every figure on this page is read at build time from the same configuration CI enforces — the table cannot say one thing while the pipeline asserts another.

§ 01 — stack

Stack

Versions below are read from package.json at build; they are the versions this page was built with.

LayerComponentNotes
FrameworkAstro 7.1.1Fully static output. Zero client JavaScript by default; HTML is rendered once, at build.
InteractivitySvelte 5.56.6 · @astrojs/svelte 9.0.1Interactive elements ship only as islands, hydrated when the browser is idle or the element is visible — never eagerly.
StylingTailwind CSS 4.3.3CSS-first configuration. Every color, size, and spacing value resolves to a single design-token file.
Content@astrojs/mdx 7.0.3 · astro-expressive-code 0.44.0Articles and guides are MDX in typed content collections; code blocks are rendered at build.
SearchPagefindStatic index generated after the build. Queries run in the browser against local index chunks; there is no search server.
OG imagessatori 0.28.0 · @resvg/resvg-js 2.6.2Social cards are rendered to PNG at build time. Scrapers fetch them; pages never do.
Feeds@astrojs/rss 4.0.19 · @astrojs/sitemap 3.7.3Full-text RSS and sitemap, generated at build.
HostingCloudflare Workers static assets · wrangler 4.112.0The site is static files on a CDN. Nothing server-side sits in the page path.

§ 02 — zero third parties

Zero third-party requests, enforced

The claim in the footer — 0 cookies, 0 third-party requests — is not a policy. It is a CI gate: a Playwright suite that fails the build if any page reaches any origin other than this site. Per route, the guard:

  • discovers routes dynamically — every HTML file in the build output becomes a test, and the discovered set is cross-checked against the sitemap so a published route can never silently drop out of coverage;
  • loads each route in a real browser with every network request intercepted — documents, scripts, styles, fonts, images, fetch/XHR, frames, websockets. One request to a foreign origin fails the build;
  • scrolls each page end to end, so lazily hydrated islands and lazy-loaded images fire the requests they would fire for a real visitor;
  • fails on preconnect and dns-prefetch hints to foreign origins — those never surface as observable requests, but they leak the visitor’s IP address at the DNS/TCP layer;
  • parses every stylesheet actually served — linked files, inline blocks, and style attributes — for url() and @import references resolving off-origin. This catches the classic CDN-font regression statically, in both color themes at once;
  • exercises the 404 page for real, via a probe URL that matches no route.

§ 03 — performance budget

Performance budget

The table below is generated from lighthouserc.json, the Lighthouse CI configuration that gates every merge. Every assertion is at level "error": a single miss blocks the merge. Collected 3× per route against the static build, on / · /writing/ · /guides/ · /about/.

MetricAssertion keyBudget
Lighthouse performancecategories:performance≥ 95 / 100
Lighthouse accessibilitycategories:accessibility≥ 95 / 100
Lighthouse SEOcategories:seo= 100 / 100
Cumulative Layout Shiftcumulative-layout-shift= 0
Largest Contentful Paintlargest-contentful-paint≤ 1500 ms
Total transfer, any routetotal-byte-weight≤ 350,000 bytes
JavaScriptresource-summary:script:size≤ 60 KB
Third-party requestsresource-summary:third-party:count= 0

§ 04 — typography

Self-hosted, subset fonts

All fonts are served from this origin — the CSS scan in § 02 turns a CDN font into a build failure. The Archivo variable font is subset at build into three small WOFF2 files: a 400 and a 700 text face (width pinned to 100%), and a 700–900 variable display face pinned to the 125% width axis and subset to capitals only, since display contexts here are always uppercase. Each file is small enough to fit a single TCP congestion window; rarely used accented characters live in a lazy unicode-range extension file that most pages never fetch.

Loading uses font-display: optional plus local fallback faces with size-adjust and ascent/descent/line-gap overrides computed from the real font metrics — layout is identical whether the webfonts arrive or not, which is how the budget’s layout-shift line holds at exactly 0. Monospace data contexts currently render in a system fallback pre-sized to JetBrains Mono metrics, so the planned mono face can arrive later with zero shift.

§ 05 — measurement

Measured locally

Measurement runs in the visitor’s browser first: the session HUD, the receipt, and the read-depth strip are computed locally and rendered back to the visitor. When a page is left, the browser sends one small beacon to aelmgren.com/api/collect — this site’s own worker, and the only network destination a page ever talks to. The payload is the page path, the referrer, web vitals, and a random session id that lives in sessionStorage and dies with the tab. No cookies, no fingerprinting, and zero third-party requests from the browser — the CI assertions on this page enforce that on every deploy.

Server-side, the worker keeps aggregates only — page path, referrer class (the full referrer URL is never stored), country, vitals — and forwards that same aggregate view to the analytics backends configured at the edge. Vendors are a server-to-server concern here; the visitor’s browser never loads their code.

A full narrative write-up of the measurement architecture is planned. Until then, this page is the reference, and it is rebuilt — numbers included — with every deploy.

dataLayer

0 events · 0 sent

    • home /
      writing /writing
      guides /guides
      work /#work
      about /about
      colophon /colophon
      toggle analyst mode ctrl+.
      print session receipt /#receipt