← All posts

How this site was built

· #nextjs #tailwind #github-pages

Every portfolio site is a chance to eat your own cooking, so this one is built with the same tools I like using on real projects — with one constraint that shaped everything: no backend, ever. And since machine learning and security are what I do, the design leans into both: a living neural network in the hero, ciphertext that decrypts as you scroll, and deterministic hash art everywhere else.

The stack

  • Next.js (App Router) with output: "export" — the whole site compiles to plain HTML, CSS and JavaScript
  • Tailwind CSS v4 for styling, with light/dark themes defined as design tokens in globals.css
  • An interactive neural-network canvas on the hero — plain Canvas API, zero libraries. Signals run forward passes, the pointer excites nearby neurons, and adversarial (red) pulses get killed mid-network
  • Markdown posts parsed at build time with gray-matter and marked
  • GitHub Actions builds and deploys to GitHub Pages on every push

Why static export

A personal site doesn't need a server, and not running one means there's nothing to patch, nothing to pay for, and nothing that can fall over. The blog is just markdown files rendered at build time — writing a new post means adding a file, not maintaining a CMS.

The one wrinkle with GitHub Pages is that project sites live under a sub-path (/<repo-name>/). The build handles that with a BASE_PATH environment variable, so the same code runs at the root locally and under the sub-path in production.

Editing content

All the site content lives in the content/ directory:

File What it controls
content/site.ts Name, bio, email, social links
content/projects.ts The project cards grid
content/experience.ts The work-history timeline
content/blog/*.md Blog posts

Change a file, push to main, and GitHub Actions ships it a minute later.