Fresh Start
I’m back online. Same blog, new domain. Shortly before going to China over the summer I set myself a goal; relaunch my blog before I travel. I had a week to get it done and I failed spectacularly. More frustratingly than that, I half completed the job essentially blocking any new posts until the job was complete.
Throughout 2026, I’ve been publishing more than in previous years. Most of these have been journal entries liberally supported by an ever growing collection of images. I was starting to reminisce about the fun I used to have with technology, first photos, starting blogging, discovering how things worked, and starting to reply to other blogposts. It was fun again. The old stuff was still here and I still enjoyed it. I started to experiment with new ideas like learning Chinese in public. I have more I want to explore.
But at every turn, I felt like I was fighting my blog. It last got a refresh at a time when I felt that my online identity should be tightly coupled with my role at work. I tried to shift things to publishing more about the tools and products I used at work. I introduced /notes for those short lessons or aha moments that didn’t quite make for a full blog post. I stopped sharing anything that was unrelated to work. Except I didn’t stop. Many of the things I was publishing remained hidden in unlinked sections of the site. I started to share /music and /links. The /photos section was visible but was neglected in favour of including photos in blogposts directly.
Alongside growing friction with the way my blog was structured, I was starting to have issues with the infrastructure that allowed me to publish. Other things hosted on the same server were starting to struggle under the near constant barrage of bots crawling the internet looking for training material. I was rebooting the host to clear memory issues near daily. My pipeline for publishing was starting to fail with all the image processing it was doing on every build. I suspect I’d have lived with the structural frustrations if it hadn’t been for these infrastructure issues forcing me into a rethink.
Goals
I typically associate a blog relaunch with a new theme or a change in tooling. I use Hugo to publish this site and am very happy with it. I started with a new theme but quickly realised that my main goal wasn’t a visual refresh.
Photos needed to stand on their own, be included in galleries, and be embedded in posts. I wanted the ability to share a link to a photo or collection of photos. I also wanted the ability to include some of these photos in a journal style post about the same trip. I needed the ability to publish an image once and use it in multiple contexts on the site.
Publishing needed to be fast and dependable. The old blog relied on a Forgejo Actions pipeline to build and publish the site. It wasn’t taking advantage of asset caching and depended on the machine hosting the pipeline to be available. I wanted to go back to basics; build the site locally and copy HTML to the web server.
Structure needed simplification. I wanted to write a post and publish without having to think about whether it was a /blog post, a /note, a /reply, some /music, etc. I wanted everything in date prefixed folders not scattered about on the filesystem. I wanted to reduce the choices that needed to be made in order to publish a post but without restricting creative flexibility.
Approach
I started off by working on a new theme. I find choosing fonts and colours two of the hardest things about working and so I used default fonts, and resorted to picking colours from album covers for the them. Let me know if you recognise the albums.
But, whilst fun, a visual refresh didn’t address any of the goals that I had. Trying to move content around after building out a new theme was an exercise in frustration. And so I threw the new theme away and decided to go HTML only until the foundations of the site were in a place where I felt they were working for me. The visual refresh could come later (see backlog).
I chose to do as much of the work as possible offline. I have no doubt that this made the work slower. The significant upside was that I spent more time getting to know Hugo. I discovered hidden tricks and quirks of working with Hugo. I feel like I’m more familiar with the tools I use.
I migrated every post by hand. No automated scripts, no AI. Any mistakes are all mine, and mine alone. It was incredibly tempting to reach for automation but manual migrations gave me the opportunity to go through each post and evaluate how it fit into the new structure.
Throughout all of this, I’ve done my best to ensure old links remain valid unless they were for sections or content that has been deliberately retired.
I learned some things along the way.
- My spelling and grammar is atrocious. At least I can’t be accused of generating these posts with an LLM. One of my more frequent habits is repeating words. I can only assume that these represent points where I got distracted. Most posts were written in a code editor without spell checking enabled.
- I keep forgetting that Hugo doesn’t clean up old output. My local folder, and previous live version of the site were littered with files that were no longer linked from anywhere. I spent many hours debugging issues when I should have been doing clean builds.
- It is possible to give two posts the same URL in Hugo and have the site silently clobber older posts with new ones.
- When referencing other posts, it is best to use relative file paths on your local system for links. Hugo will then resolve these to the correct URLs on build. You can also then warn on invalid links.
- Speaking of warnings, you can include
warnforerrorfin your templates to log warnings or errors on build. One good example is logging errors for missing alt text. If you want to suppress specific categories of warnings or error then you can use thewarnidforerroridfalternatives. - You can do some creative things with post hierarchy using the
.Ancestorsand.Descendantsproperties on posts. I got carried away trying to map posts and photos to hierarchical locations; e.g. Daxing > Beijing > China. - Hugo allows you to control the build properties of a post in front matter. This includes setting whether a post or section gets included in various lists. This can be applied to all descendants of a post with the
cascadeproperty. I use this to avoid individual photos showing up in the main feed. - Setting
publishResources: falsein the build options means I’m no longer copying full size versions of every image to the server unless they are referenced in a template. This has saved me from a spiralling disk space issue.
Distractions
Gemini the protocol, not the statistical slop generator, is something that I’ve been tinkering with on the side. I couldn’t resist the opportunity to publish a Gemini pod alongside my main blog. If you have a Gemini browser installed, you can visit this site at gemini://bill.dev. If you don’t, then give Lagrange a try. More on this later.
Location has always been an interest. Many of my photos are geo-tagged and I still log GPS coordinates for most of my movements. But I’ve never found a way to work location into this site. With the work I’d done on embedding photos within galleries and posts, I realised I could take the same approach to location.
Post front matter can include a location:
---
title:
date: 2026-08-07T13:51:27Z
location: /england/london/chiswick/chiswick-house
This path can then be used to map the post at the appropriate hierarchy in /locations. This is still early days when it comes to location and I have more that I want to do with this. The foundations are in place though.
Success
Photos now exists as first class posts. The majority of the work is done by front matter and I generate much of this from the image file. It is possible to include a post body if I want to provide more detail on an image. The duplicate title field is a hangover from the way photos work historically and isn’t needed.
---
title: The Great Wall
date: 2024-10-11T20:48:00+0100
location: /china/beijing/great-wall
tags:
- Film
- Pentax17
- KodakGold
resources:
- title: The Great Wall
src: 20241008-0073-e921e.jpeg
params:
alt: "A view looking over the Great Wall of China."
caption: "The Great Wall"
license: CC BY-NC-ND 4.0
To include this photo in a blog post, I reference it by path in a short code.
{{< photo "photos/2026-07-16T162900" >}}
The short code is flexible in that I can override the caption if needed because sometimes the caption is specific to the context. Where photos don’t have a title I resort to using the date. Where displayed in a text only context, for example Gemini, I use the caption and provide a link to the image. I now throw warnings on missing alt text.
Change detected, rebuilding site (#3).
2026-10-27 18:54:53.738 +0000
Source changed /posts/2026-10-27-fresh-start/index.md
WARN photo: missing alt text for img/2026-08-13-light.png in posts/2026-10-27-fresh-start/index.md
WARN photo: missing alt text for img/2026-08-13-dark.png in posts/2026-10-27-fresh-start/index.md
Web Server is available at http://localhost:1313/ (bind address 127.0.0.1)
Total in 710 ms
Galleries work in a similar way by essentially including photos within a dedicated post. The gallery can then be referenced using another short code. This has given me the flexibility I need to continue to share photography without needing to publish images in multiple places.
Backlog
I still have more to do, bit I’ve reached the point where it was time to cut over to the new site and give myself the freedom to iterate in public again. I’m not sure I’ll get to all of these, but my backlog includes the following:
- Add latest photos to the homepage.
- Restore the missing and unfinished.
- Address the awkward looking Chinese fonts.
- Iterate on the theme with colour and dark mode.
- Revive
/music. It was invisible on the previous version of the site. - Restore blogrolls and web rings.
- Iterate on the ladybird. I’ve had to hide a few of them.
- More…
I’m pleased to have got this out. The theme may be basic work on the foundations has meant that I’m having fun with it again. Now to start publishing the backlog of posts that I wrote while ‘offline’.