Skip to main content
William Stoops

Behind the scenes

This site is part of my application as much as its content is. Its code, its tests and its decisions are public: here is how it is built, and what keeps it from getting worse.

See the code on GitHub (new tab)

Measured just now, in your browser

These figures do not come from a lab: your browser measured them as it loaded this site.

First contentful paint
Measuring
Largest contentful paint
Measuring
CI threshold: 2,000 ms
Layout shift
Measuring
CI threshold: 0.050
JavaScript downloaded, compressed
Measuring
Files requested
Measuring

What the CI turns down

Every change goes through a pull request, and the CI blocks it if any of these checks fails.

  • A loose type

    Strict TypeScript: no “any”, no “unknown”, no type assertion. Whatever comes from outside (address, storage, form) goes through a Zod schema.

  • A warning

    Oxlint then type-aware ESLint, without a single warning. The feature architecture and the direction of imports are enforced by the lint.

  • Dead code

    Knip on the whole repository, then on the shipped code alone: no unused file, export or dependency.

  • A regression

    Unit tests in Node, components in a real Chromium, Playwright journeys on 5 devices. At least 90% of lines and 85% of branches covered.

  • An accessibility barrier

    axe on every page, in both themes (WCAG 2.2 AA), and a Lighthouse accessibility score of 100.

  • Extra weight

    Initial JavaScript under 125 KB and CSS under 15 KB, compressed. Lighthouse: performance of at least 95, largest paint under 2 s, blocking under 150 ms.

The decisions

35 architecture decisions, each with its context, its choice and the alternatives it turned down. Among them:

  • prerender every page at build time, so the content shows without waiting for JavaScript;
  • animate in native CSS, on the compositor, without a library;
  • put the language in the address, one page per language;
  • race the two computing cycles to scale, rather than fake a computation.

Read the decisions on GitHub (in French) (new tab)