How this site is built
Every post here is a plain markdown file in the repo. No CMS, no database, no login screen standing between me and writing. This post is also the documentation.
Adding a post
Drop a .md file into content/posts/. The filename becomes the URL:
content/posts/my-new-post.md → lanka.lol/writing/my-new-post
The frontmatter carries everything the site needs:
---
title: "My new post"
description: "One or two sentences for lists, RSS, and social cards."
date: "2026-08-26"
tags: ["ai", "engineering"]
draft: false
---
draft: true keeps a post out of every list and feed; it only renders when opened directly in development.
The pipeline
At build time each file goes through gray-matter for frontmatter, then a unified/remark/rehype chain: GFM tables and task lists, heading slugs, anchored headings, and Shiki for syntax highlighting — compiled to static HTML with both light and dark themes baked in as CSS variables. No client-side highlighter, no layout shift, no flash.
Code blocks look like this:
export function readingMinutes(content: string): number {
const words = content.trim().split(/\s+/).length;
return Math.max(1, Math.round(words / 220));
}
The rest
- Next.js App Router — every page statically prerendered; dynamic routes come from
generateStaticParams. - Tailwind CSS v4 with the typography plugin for long-form reading.
- RSS at
/rss.xml, plussitemap.xmlandrobots.txtgenerated by the framework. - OG images rendered per post at build time from the title, so links shared anywhere get real cards.
The whole thing is fast because there's almost nothing to it: HTML and CSS, shipped. That was the design constraint, not an accident.