How this site works

/ Personal

This site is a folder of static files. Nothing renders on a server when you open a page: every page is built ahead of time, and the build runs on GitHub each time I push and once a day. Here is the whole path, from the files I edit to the page you are reading.

  1. PrivateResearch vaultObsidian notes, exported to works.json
  2. Libraryrunetsmy React components and WebGL 2 effects
  1. GitHubPrivate repositorypages, MDX articles, one branch: mainBuilds on Research vault and runets.
  1. GitHub ActionsDeploy workflowevery push, daily at 03:45 UTC, on demandBuilds on Private repository.
  1. pnpmInstallNode 25, pnpm 11, the lockfile as committedBuilds on Deploy workflow.
  1. Next.jsBuildfeeds and contributions, static export to out/, placeholder and size guardsBuilds on Install.
  1. Node and PythonTestunit tests of the rules the build relies onBuilds on Build.
  1. wranglerDeploydatabase migrations, then the uploadBuilds on Test.
  1. WorkersStatic assetsout/, headers, redirects, Web AnalyticsBuilds on Deploy.
  2. WorkersVisitor count/api/visit, one row in D1Builds on Deploy.
  • The build: everything passes through it
  • Feeds the next step
  • Where it ends up

Sources

Three things feed the site, and two of them live in the repository itself.

  • My research vault. An Obsidian folder where I plan papers and keep track of my work. It stays private. A script copies out only the works I mark public into works.json, and the repository keeps that file, never the vault. The research list, the lineage on the research page, Working on and llms.txt all read it.
  • Articles, like this one, are MDX files. A draft shows up in previews and never on the live site.
  • runets, my component library. Every component on this site comes from it, from the badges to the WebGL effects behind the hero. You can browse them in My Components.

The pipeline

The code lives in a private GitHub repository with a single branch, main. One GitHub Actions workflow runs on every push, once a day at 03:45 UTC (so the contributions graph on the home page is never more than a day old), and whenever I start it by hand.

  1. Install. Node 25 and pnpm 11 install exactly what the lockfile says. The workflow's own actions are pinned to exact commits, so a change upstream cannot slip into a run.
  2. Build. First a script writes the RSS feed, the sitemap and llms.txt from the same data the pages use, and another fetches my GitHub contributions. Then Next.js exports every page to plain HTML in out/. Two guards run last: one fails the build if placeholder or draft text reaches a production page, the other if the home page ships more than 200 KB of compressed JavaScript.
  3. Test. Unit tests in Node and Python check the rules the build depends on: what counts as a preview, the placeholder scanner, the article and works parsers, the fallback for computers without a GPU, the hero's data, the design tokens and the contributions parser.
  4. Deploy. On main, wrangler applies any new database migration and uploads the site. Any other branch gets a preview at its own address instead. The Cloudflare token reaches these two steps only. Install, build and test run third-party package code, so they never see it.

On Cloudflare

The site runs on Cloudflare Workers with static assets. Static files are served free and without limit, and the only code that runs for a request is one small Worker that answers /api/visit.

  • Pages come straight from out/, with security headers (HTTPS only, no framing, no content sniffing) and redirects for old addresses.
  • The visitor count, under Contact on the home page, is one row in a D1 database. The first time a browser visits, the Worker adds one and returns the new number. The browser keeps that number, so it counts once, ever, and a later visit sends nothing. Bots, requests from other sites, more than three a minute from one address and preview copies don't count.
  • Analytics is Cloudflare Web Analytics. It sets no cookies, so there is no consent banner. Google Search Console and Bing read the sitemap.

Stack

Built with

Front end

  • Next.js (static export)
  • React
  • TypeScript
  • Tailwind CSS v4
  • Motion
  • MDX

My components

  • runets
  • WebGL 2
  • GLSL

Pipeline

  • GitHub Actions
  • Node.js
  • pnpm
  • Python
  • wrangler

Cloudflare

  • Workers static assets
  • D1
  • Rate limiting
  • Web Analytics
  • DNS and Registrar

Data

  • Obsidian vault
  • JSON
  • GitHub contributions

What it costs

The domain, about $10 a year. Hosting, the database, the pipeline and the analytics all fit in free plans.

Why it is built this way

A folder of static files has very little to break or patch, and it loads fast from anywhere. The site also works with JavaScript turned off. The effects, the search palette and the visitor count sit on top, and the words and links never depend on them.