Rebuilding this portfolio from scratch in the age of AI

My portfolio was handcrafted in 2019 with Jekyll and Bootstrap 4, and it aged. In 2026 I rebuilt it on Astro. Just like at my day job these days, I didn’t type a single line of code.

Before / after: home, projects, a project page and a post, each wiping from 2019 to 2026.

How

I used Claude Code with get-shit-done, a framework that drives the work in phases: discuss the goal, research, plan, execute, verify. Kinda V-model lifestyle.

With Opus 4.8, that structure is what kept a months-long migration on track: 6 phases, 30-odd plans, 50 requirements, all met, and 571 commits between April and October (I was busy elsewhere).

By the end of the adventure the method was already obsolete: Opus 5.5 holds large, long-running goals on its own. Not to mention get-shit-done pulling an exit scam in the middle of my migration.

It proposes, I pick

The handiest part. Instead of asking for a design, I asked for fifteen: the LLM built them side by side behind a little picker, and I cycled through with the arrow keys. Then I asked for fifteen variations of my favorites, and so on, until the final pick.

Reviewing the LLM’s first proposals for the blog list, one arrow key at a time.

Before / after, optimization <3

Infographic, 2019 to 2026: Jekyll, Bootstrap 4 and jQuery to Astro 6, TypeScript and CSS. Build size down 73%, about 400 MB to 110 MB. JavaScript on the homepage down 99%, 964 KB to 6 KB. Photos page, first visit, down 98%, 144 MB to 3 MB. Blog list down 95%, 3 MB to 156 KB. A post down 77%, 1.9 MB to 0.45 MB. Homepage down 64%, 1.9 MB to 0.7 MB and 20 to 9 requests. The server went from HTTP/1.1 with no cache and no gzip to HTTP/2 with a 1-year cache and gzip. The code went from about 1,000 lines and no tests to about 4,700 lines of code plus 3,300 lines of tests, and from 1.1 MB of vendored libraries to none.

What did it:

  • No JavaScript by default. The old site loaded 964 KB of scripts on every page, 777 KB of it MathJax for one post’s equations. Now one 6 KB script; KaTeX renders math at build time.
  • Images resized for the screen. WebP in several widths, and the browser picks one. Photos went from originals of up to 31 MB to 256 KB at most.
  • Lazy loading. Off-screen images wait until you scroll near them.
  • CSS written for the site. 13 KB, instead of Bootstrap (142 KB) and Font Awesome’s icon fonts (about 160 KB).
  • Videos instead of GIFs. 12 GIFs and 4 videos (220 MB) re-encoded as MP4: 49 MB for all the site’s videos today.
  • Only what’s used ships. The build drops any file no page uses. Jekyll even shipped 7 MB of Krita and Photoshop files.
  • gzip, HTTP/2 and a 1-year cache. Compressed text, one connection, and a second visit downloads next to nothing.

Visual gating

You ship fast, but are you sure of the impact?

  • 145 screenshots, 5 devices. Playwright compares every page on desktop, tablet, Android and two iPhones against references I approved.
  • No way around it. The deploy scripts run the gate first.
Playwright's report for the homepage screenshot test, on its Diff tab: the page in faded grey, with only the heading 'Hacker on various things.' marked in red and yellow where its pixels changed
Example of changing the heading's letter spacing. Hard to see by eye; 4,110 pixels diff to the gate.

Where this is going

Well, I’m left with the good part: writing content. And the place and the tooling have never been better for it.