Personal portfolio. A minimal, dark, fast and privacy-friendly static site: no cookies, no trackers, no third-party scripts or fonts.
Live: https://leonkrix.dev
- Astro (static output), TypeScript (strict), Tailwind CSS v4, React islands where needed
- Content as typed YAML (projects, experience) validated with Zod at build time
- A small Playground of browser games (Tech Words, Root Cause, Link Up, Word Radar, Backbone), each with a write-up of how it is built under "Behind the scenes" (
/notes/): pure TypeScript logic with unit tests, generators that prove every puzzle has one solution, keyboard play, and nothing stored on the device - A command palette (Ctrl or Cmd + K) with a terminal mode (
>), also on the 404 page: fetched only when it is opened, so no page pays for it; plus a few easter eggs,/humans.txtand/.well-known/security.txt - Contact form without any third-party service: a Cloudflare Pages Function validates the message (shared rules, signed time token, honeypot, rate limit in KV) and sends it through the own IONOS mailbox
- Hosted on Cloudflare (Git integration), every change goes through a pull request
Nothing reaches main without a green CI passed check (enforced by a repository ruleset):
| Check | What it covers |
|---|---|
| Lint, format, types | ESLint (typescript-eslint strict), Prettier, astro check |
| Unit tests | Vitest |
| Build-output checks | Metadata, legal pages, links and anchors, security headers, CSP, contact data protection |
| End-to-end tests | Playwright (desktop and mobile), layout guard and privacy guard (own packages), axe |
| Lighthouse | Every category at least 95 on mobile, size budgets, no third-party requests |
| Security | CodeQL, dependency review, pnpm audit, OpenSSF Scorecard, Dependabot, secret scanning |
| Workflow lint | actionlint for the workflow files, actions pinned to commit SHAs |
After the deployment (not part of the gate), the published site is watched: a live check every six hours and after every production deployment (headers, redirects, legal pages, contact form API, certificate, domain registration, mail DNS) and a weekly link check.
Check the numbers yourself. The scores are not only claimed, they are enforced and you can measure them independently:
- Every pull request runs the Lighthouse gate; the scores of each run are in the summary of the Lighthouse job in the public CI runs.
- PageSpeed Insights runs Lighthouse against the live site, from Google's servers.
- Security Headers grades the HTTP security headers of the live site.
A pre-commit hook (Husky and lint-staged) formats and lints staged files and runs the type check and related unit tests when code is staged.
Requirements: Node (see .nvmrc) and pnpm (see packageManager in package.json).
pnpm install
pnpm dev # local dev server
pnpm check # the fast checks below, as in CI
pnpm test:e2e # browser tests (first time: pnpm exec playwright install chromium)
pnpm lighthouse # performance, accessibility, best practices and SEO budgets| Script | Purpose |
|---|---|
pnpm dev |
Start the dev server |
pnpm build |
Production build to dist/ |
pnpm preview |
Serve the production build |
pnpm lint |
ESLint (generates the Astro types first) |
pnpm format:check |
Prettier check |
pnpm typecheck |
astro check for the site and tsc for the Cloudflare Functions |
pnpm test |
Unit tests (Vitest) |
pnpm test:dist |
Checks against the production build in dist/ |
pnpm check |
Lint, format check, types, unit tests, build and build-output checks |
pnpm build:form |
Build with the contact form switched on (used by test:e2e and lighthouse) |
pnpm test:e2e |
Playwright end-to-end tests (builds first) |
pnpm lighthouse |
Lighthouse quality gate (builds first, needs Chrome) |
pnpm live-check |
Check the published site from the outside (--base for another address) |
pnpm check-links |
Check the external links on the published pages (--dir dist for a local build) |
pnpm levels |
Make the Root Cause level pool again (runs through Vitest, takes minutes, keeps existing levels) |
pnpm og |
Regenerate the link preview image public/og.png (needs the Playwright browser) |
pnpm dev:functions |
Build, then run site and Cloudflare Functions locally (Wrangler, port 8788), needs .dev.vars |
pnpm build:functions |
Check that the Cloudflare Functions bundle |
Copy .env.example to .env to try the address of the legal notice locally. Real values are never committed; in production they are Cloudflare build variables.
src/
components/ Astro components (header, hero, cards, icons, ...), games/ for the Playground tiles
content/ Projects and experience as YAML (validated by src/lib schemas)
games/ The Playground: registry, shared code and one folder per game (see src/games/README.md)
layouts/ Base and legal page layouts
lib/ Plain TypeScript: schemas, helpers, site configuration, with unit tests
pages/ Routes: home, legal notice, privacy policy (English and German), games, notes (Behind the scenes), 404, sitemap
styles/ Design tokens and global styles
functions/ Cloudflare Pages Functions (contact form API) with their own tsconfig
public/ robots.txt, favicon, security headers (_headers)
tests/ Build-output checks (Vitest) and end-to-end tests (Playwright)
scripts/ Lighthouse gate, live and link checks, build with the contact form, generators for the preview image, the Defuze picture and the Root Cause levels
.github/ CI, CodeQL, security workflows and Dependabot
See SECURITY.md for how to report a vulnerability.
All rights reserved. See LICENSE.