This is my personal website where I write and share my projects and thoughts. This is primarily a static site built with Next.js and is self-hosted on a VPS behind Docker.
The design was inspired by dithered and retro themed media out there - which is some of my favourite.
| Framework | Next.js (App Router, React 19) |
| Styling | Tailwind CSS v4 |
| Content | MDX files on disk, rendered with next-mdx-remote |
| Animation | Motion |
| Deploy | Docker Compose, output: "standalone" |
npm install
cp .env.example .env # fill in the values below
npm run dev| Variable | Required | Notes |
|---|---|---|
NEXT_PUBLIC_SITE_URL |
yes | Absolute site URL. Read at build time — baked into the image. |
DISCORD_WEBHOOK_URL |
yes | Where contact form submissions are delivered. |
GITHUB_TOKEN |
no | Classic PAT, no scopes needed. Used for the contribution graph on the GitHub social card and star counts on project cards. Without it, public (rate-limited) APIs are used instead. |
All content for the site is done using markdown or JSON - there is no database or CMS to keep the site as simple as possible.
content/
├── blogs/*.mdx posts — frontmatter + body
└── socials.yaml profile data for the social hover cards
Slugs are derived from filenames, not frontmatter. If you name a blog post
content/blogs/my-post.mdx then the path for the post will be /blog/my-post
Footnote-style references at the bottom of a post are parsed out of the body.
app/ routes, API handlers, feed/sitemap/robots
components/
├── article/ long-form rendering: MDX components, references, share
├── home/ home page sections
├── layout/ site chrome: preferences bar
├── providers/ theme context
├── socials/ per-platform hover cards
├── icons/ hand-rolled brand marks
└── ui/ primitives
lib/ content loading, palettes, validation
Themes (⌘B) swap a set of CSS custom properties registered with @property, so every colour on the page cross-fades rather than snapping. The choice is applied by an inline script before first paint to avoid a flash.
Social cards are per-platform widgets that mimicks each platforms UI. The GitHub widget has a contribution graph, Letterboxd has a poster row and LinkedIn has the LinkedIn colours and banner.
Sounds play on interactions and are always on.
docker compose up -d --buildServes on port 3001, expecting a reverse proxy in front for TLS.

