↓ Skip to main content
Migrating from Jekyll Chirpy to Hugo Blowfish with Claude Code
  1. Posts/

Migrating from Jekyll Chirpy to Hugo Blowfish with Claude Code

·704 words·4 mins
 Author
Author
Lin Bing HOE
Curiosity Driven. Security Focused.
 Author
Author
Claude Code
Keep thinking.

This blog has moved from Jekyll with the Chirpy theme to Hugo with the Blowfish theme. I did the migration with Claude Code, and built two new features along the way: an animated threat map on the landing page and a design inspired by Apple that follows its Human Interface Guidelines (HIG).

Why I migrated
#

  • Ruby gem dependencies. Jekyll needs Ruby, Bundler and a set of gems, and keeping their versions working together in my dev container and on Cloudflare Pages was a recurring chore. Hugo is a single binary, pinned to one version (0.167.0) in both places, and the theme is a Git submodule pinned to Blowfish v3.9.0.
  • Shorter build times. Hugo builds the whole site, thumbnails included, in about five seconds in my dev container, and the live server refreshes almost instantly as I edit.
  • Testing Claude Code. I wanted to see how well Claude Code handles a real migration: reading an unfamiliar theme, changing content, configuration and styling together, and checking its own work.

The migration
#

Each post became a Hugo page bundle: a folder under content/posts/ holding index.md with its images and attachments, in place of Chirpy’s split between _posts/ and assets/img/. The slugs stayed the same, so existing URLs still work.

The front matter changed slightly. Dates moved to ISO 8601 (2024-10-28T03:00:00+08:00), the image: banner became a featured.png inside the bundle, and each post gained a summary. I also replaced Chirpy’s nested categories with exactly one of Writeup, Tutorial, Project or Misc, and up to three tags. Chirpy’s {: .prompt-tip } callouts became GitHub-style > [!TIP] alerts, and its YouTube includes became Hugo’s youtube shortcode.

On Cloudflare Pages, the build switched to the Hugo preset with the environment variable HUGO_VERSION set to 0.167.0, the same version as my dev container. Blowfish v3.9.0 needs Hugo 0.164.0 or later. Without the variable, Cloudflare uses its older default Hugo and the build fails.

Feature 1: the threat map
#

The landing page opens with a dotted world map and coloured arcs flying between 32 internet hubs, from Singapore and Tokyo to London and San Francisco. It is decorative rather than real attack data, and it is a single script with no libraries, drawn on an HTML <canvas>.

  • The land is a 200 by 79 grid of dots made from the public-domain Natural Earth land outline. Each row is stored as a hexadecimal string, so the whole map fits in a few kilobytes inside the script.
  • The arcs are quadratic Bézier curves that rise higher for longer routes. Each one draws a fading trail with a glowing head, and leaves a ripple where it lands.
  • The details: the colours switch with light and dark mode, the animation pauses when it is off screen or the tab is hidden, and with Reduce motion turned on it shows a single still frame.

Feature 2: an Apple-inspired design
#

I wanted the site to feel like Apple’s own pages: calm, spacious and focused on the content. Blowfish allows a custom colour scheme and overrides of individual templates, so the theme itself stays untouched. The design applies the HIG in a few ways:

  • Colour. Apple’s system greys and system blue, with matching light and dark values. The site follows the reader’s system appearance.
  • Typography. The system font, which is San Francisco on Apple devices, with 17-point body text, the HIG’s default.
  • Materials. A translucent navigation bar that blurs the content scrolling beneath it.
  • Shape and depth. Capsule buttons, rounded cards and soft shadows in place of hard borders.
  • Accessibility. Hit targets of at least 44 by 44 points, support for Reduce motion and Increase contrast, visible focus rings and safe-area padding on devices with a notch.

What I learnt
#

Claude Code handled most of the editing well. It read the theme’s templates before changing anything, rebuilt the site after each change and inspected the output to confirm the result. It worked best when I gave it a concrete reference, such as a specific button on apple.com, rather than a vague description. Judging how the design looked was still my job. To keep future posts consistent, the repository now has a CLAUDE.md setting out how posts are structured and written, and this post follows it.