This is now an 11ty blog

February 20, 2026 at 2:57 AM (UTC)

I mean, sort of. It's running 11ty. And I'll probably talk about 11ty a bit.

Starting now.

As threatened, I have converted my site to 11ty. I looked at eleventy-base-blog. I learned a bunch, but eventually decided I just wanted this site to be my own.

The editing process is marvelous, I say as I write this post. I just hit command+S and viola! My live preview updates.

I started this post just by creating a new file and dropping a tiny bit of front-matter—a tag and a title. (I will have to check on the date. It seems to be stuck at the time I created the file. Oh! Maybe I wanted date: Last Modified.)

Speaking of the date!

The date

The way the date on this page works is pretty cool, and a prime example of something I wanted to do myself.

Remember graceful degradation? Well, maybe not exactly as Mozilla describes it—I blatantly used all the hottest CSS—but that date line at the beginning of the post practices that old thing.

If you look at the source of the page you downloaded, the text there actually starts out with the UTC version. But then, an inline script immediately runs:

const date = new Date("2026-01-01T12:00:00Z");
const formatter = new Intl.DateTimeFormat(undefined, {
    dateStyle: "long",
    timeStyle: "short"
});
const postDateElement = document.getElementById('some-random-uuid');
postDateElement.textContent = formatter.format(date);

The date that comes with the HTML is tagged with a random UUID. That same UUID is injected into the little bit of script above, along with an ISO 8601 representation of the post date.

The script then completely localizes the date, both to your locale and your timezone, and replaces that "UTC" version of the time with one that makes sense to you.

See, I care about my readers. 💙

The CSS nightmare

But the truth is, I am… not much of a front-end type. I can do it. But then CSS and I just want to sit in a corner and cry.

I had previously used Kev Quirk's Simple.css for gbfs-web, but I wanted to try something else. I landed on Pico CSS—specifically, the classless version.

Pico comes with a lot of useful stuff. I don't have to sweat most of what I think people expect from a website. I did tweak a few things, particularly as I imported posts.

Getting syntax highlighting was murder, though. PrismJS, right? Sorta. It was opinionated. I had to really push stuff around to get it like I wanted it, re-applying some Pico styles after it was done, and wiring it up with some media-selection arts because I could not find Prism themes that auto-selected light or dark mode depending on user preference.

I like respectful software, dammit! I made it work. I hope it works well for y'all.

The import

I wanted to be present for importing content, rather than run a one-and-done. I started off by actually hand-writing the post front-matter and pasting Markdown from Standard Notes.

This worked for awhile, but ended up kinda slow. So I ended up writing a Python script that wrote front-matter for me, using feedparser to grab my old RSS feed and turn it into a bunch of empty Markdown files ready-loaded with titles and dates. Then I pasted content from Standard Notes. Much faster, and I still got to take a trip down memory lane.

I had a ridiculous idea after that. Why not bring in my really old Blogger… um… journal? The content is ridiculous, but I made it happen from an old, crusty HTML backup and a truly evil script leveraging Beautiful Soup and html-to-markdown. It wasn't perfect, but I have manually fixed up the small variances.

The content, however, remains ridiculous. Oh, how I've grown. Into a snarky old enby.

Adding features

To get everything I expected from this new website, I needed several plugins and setups for 11ty.

I was a little surprised some of this wasn't in a standard config. But it's fine. I like getting my hands a little dirty.

Hosting

Hosting myself is actually not a huge deal—I am just moving everything to my existing OpenBSD server that I have with the wonderful OpenBSD Amsterdam.

The biggest thing I needed to do was some httpd.conf finagling to make sure all the crusty old links worked. The relevant bits look like this:

location not found match "/%d%d%d%d%d/(.+)" {
    block return 301 "https://mattiebee.io/%1"
}

for mattiebee.io, and for zigg.com:

location not found match "/journal/%d%d%d%d/%d%d/(.+).html" {
    block return 301 "https://mattiebee.io/%1"
}

Since I pulled in slugs for all the old posts, things should just work. This in addition to the huge list of existing 301s I already had for posts from the old Felix Felicis blog should keep things working. 🤞🏻

Staging

I got great news as I worked on this: OpenBSD gained a few fixes that enabled me to run it in a VM on macOS, using my Apple Silicon Macs. It works great in VirtualBuddy.

I was able to (extensively) refactor my Ansible setup that I've used up till now to provision just my regular OpenBSD server. But I had some changes I needed to make, so I really wanted to test-apply it to a staging environment.

Most of that was relatively easy, but HTTPS and acme-client for Let's Encrypt, all wonderful things, were not gonna work in a staging environment. There's only one "mattiebee.io" (and one "zigg.com") and my VM could not pretend to be them without jumping through a whole bunch of hoops.

So I invested some time reworking that Ansible configuration so that it could apply both places. Relevant rules would be present for normal HTTP mode in staging, where I could at least explore the idea that they would work correctly.

I discovered at least one problem here! Like UTF-8 troubles, as all my unicode characters sprinkled everywhere were suddenly little bits of garbage. (Fixed that up with a meta charset element.)

Beyond that, though, worth it. I like having a staging setup I can check things on before breaking the main server.

And it's… done?

I'm sure I'll find things that need fixing in the near-to-far future. But for now… I think it's in good shape, and (obviously, since you're reading this) ready to share with the world.

…maybe.