Building My Own Static Site Generator: A 9-Year Journey Home

The Wandering Years

Nine years ago, I made a decision that would haunt me for nearly a decade: I left Jekyll.

Don't get me wrong—Jekyll served me well. It was simple, it worked, and GitHub Pages made deployment trivial. But I wanted more. I wanted speed. I wanted modern tooling. I wanted that shiny new thing everyone was talking about.

So I moved to Hugo. Then Nuxt. Then Next.js. Each time, I told myself this was the one. Each time, I found myself fighting the framework more than writing content. Configuration files grew. Build times increased. Dependencies multiplied. And somewhere along the way, I lost sight of what I actually needed: a simple way to publish my thoughts.

The Spark

One day, while procrastinating on actual work, I stumbled upon jakewharton.com. Jake Wharton—the legend of Android development—had a website that was... simple. Brutally, beautifully simple. No fancy animations. No JavaScript frameworks. Just content, presented cleanly.

I loved it.

Digging deeper, I found that the syntax highlighting CSS traced back to mojombo/tpw—Tom Preston-Werner's personal website. The co-founder of GitHub. Built with Jekyll.

The irony wasn't lost on me. After years of framework-hopping, the answer had been there all along: simplicity.

But I didn't want to go back to Jekyll. I wanted something that was mine. Something I understood completely. Something I could mold to my exact needs.

The Challenge

Here's the thing: I'm a Kotlin developer. Android is my world. JVM is my comfort zone. JavaScript? I know just enough to be dangerous—and by dangerous, I mean dangerous to myself.

But I knew exactly what I wanted:

Could I build this? With my limited JavaScript knowledge?

I decided to try. And I had a secret weapon: Claude.

The Journey

What started as a simple build script evolved into something I'm genuinely proud of. Let me walk you through the key phases.

The Foundation

The first step was humble: a basic static site generator that could parse markdown and generate HTML. Nothing fancy. But it worked.

Within the first few iterations, I had:

The Great Migration

Deployment is where things got interesting. I started with GitHub Pages, moved to Netlify, and finally settled on Cloudflare Pages.

Each migration taught me something. Netlify was easy but limited. Cloudflare gave me the edge performance and configuration I needed.

The Build System Revolution

The build script was getting unwieldy. At 1,704 lines, it was a monster. So I did what any sane developer would do: I split it up.

Now the largest file is 328 lines. Each module has a single responsibility:

The TUI Adventure

This is where things got fun. I didn't want a boring terminal output during development. I wanted something beautiful.

Enter Ink—React for the command line. Building a TUI (Text User Interface) for the dev server became an obsession.

The result? A development experience that includes:

But it wasn't smooth sailing. Ink v6 broke everything. Older Ink helper packages used require() which doesn't work with Ink v6's top-level await. I had to implement custom components—a Link component using ANSI OSC 8 escape codes, a custom dimension hook, everything.

Was it necessary? Probably not. Was it worth it? Absolutely.

The PWA Journey

I wanted my site to work offline. Not just "show a cached page" offline, but properly offline with smart caching strategies.

The service worker uses:

And when there's an update? A dismissible notification with a 24-hour cooldown, following Google's PWA patterns.

The Polish Phase

The final stretch was all about polish. Accessibility fixes. Typography improvements. OG image generation with CTA badges.

I even built a GitHub contribution graph as a footer widget. Then removed it. Some experiments don't make the cut, and that's okay.

What I Built

Here's what exists today:

Core Features:

Developer Experience:

Production:

What I Learned

1. You Don't Need a Framework

For a personal blog, a custom static site generator is not only viable—it's liberating. No fighting configuration. No mysterious build errors. Just code you wrote and understand.

2. Claude is a Game-Changer

As a Kotlin developer with limited JavaScript experience, Claude was invaluable. Not for writing code blindly, but for understanding patterns, debugging issues, and learning best practices. Every feature was a collaboration.

3. Developer Experience Matters

I spent way too much time on the TUI. Fixing spinner flickering. Implementing custom Ink components. Adding keyboard shortcuts. But every time I run npm run dev and see that beautiful terminal interface, I smile. That matters.

4. Simplicity is Hard

The hardest part wasn't adding features—it was knowing when to stop. The GitHub contribution graph was cool. But it didn't serve the purpose of the site. Removing it was the right call.

5. The Journey is the Destination

This project isn't "done." It never will be. And that's the point. It's a living thing that grows with me, that I can shape and improve forever.

The End (For Now)

Nine years. Jekyll to Hugo to Nuxt to Next.js to... this. A static site generator I built myself, with help from an AI, using a language I barely know.

Sometimes the longest journeys bring you right back home. But you're not the same person who left.


This site is built with love, frustration, and determination. If you're interested in how something specific works, feel free to reach out.