This website
My personal website: who I am, what I’ve done and how I work. In three languages, cookie-free and with its infrastructure on show.
- React 19
- TypeScript
- Vite
- Tailwind CSS 4
- React Router
- Cloudflare Workers
- Playwright

Why I built it
I wanted a place of my own to explain who I am, what I’ve done and how I work, beyond a CV. And I wanted the site itself to be a real, published project with its decisions documented.
How it’s organised
- Content kept apart from design: every text, in three languages, lives in src/data.
- Reusable components (components/), home sections (sections/) and pages (pages/).
- Every page is prerendered to static HTML at build time and hydrated by React in the browser, so search engines and link previews see the real content.
Design decisions
- A “working notebook” concept: cream paper, ink and a single accent colour, red lead.
- Three typefaces with fixed roles: Newsreader for headings, IBM Plex Sans for text and IBM Plex Mono for dates and labels.
- A navigation index that highlights the section you’re in as you scroll.
- The “Show the infrastructure” mode, which overlays the grid and explains how the site is built.
Accessibility
- Contrast checked against WCAG 2.2 AA (at least 4.9:1 for text).
- Full keyboard navigation, a skip link and an always-visible focus ring.
- aria-current on the section index and the language switcher.
- Animations disabled under prefers-reduced-motion.
- Alt text on every informative image.
Security and performance
- No cookies, analytics or third-party requests.
- Security headers with a strict CSP: no inline scripts or styles.
- AVIF and WebP images with explicit dimensions, and self-hosted fonts.
Testing
- Playwright at 375, 768 and 1440 px: navigation, active index, links, keyboard and browser console.
- Lighthouse to measure performance, accessibility, best practices and SEO.
- Custom scripts that check for broken links and colour contrast.
Technical difficulties
- Hydrating prerendered pages without mismatches, especially the 404, which can be served at any URL.
- Keeping a strict CSP means avoiding style attributes and injected scripts.
- The first Cloudflare deploy failed: without a config, Wrangler altered the Vite build. An explicit wrangler.jsonc fixed it.
- Scroll-linked animations left off-screen sections invisible in screenshots and print. Content is now always visible.
What I learned
- How Cloudflare’s automatic deploys from GitHub work: every push triggers a new build and, if it passes, a new version of the site.
- The experience of representing myself: deciding what to say about me, how to say it and how I want it to look.