-
We Are Now On Homebrew
Every public Jorvik app, game and screen saver is now installable from the terminal in one line. Which matters less for the one line than for what it lets you do: put your whole machine in a text file, and rebuild it from scratch without clicking anything.
-
Announcing Citadel: My Latest Native Mac Game
My second native game is out. Six weeks, forty-eight floors, one flamethrower, and a rule that quietly reorganises everything else: killing the thing that holds a floor is only half the job. Here's what Citadel is, what makes it strange, and every promise I broke to finish it.
-
Changelog: MenuTidy and ActiveSpace
A clutch of small, careful updates to two of my menu-bar tools. MenuTidy learned to tidy itself and made its peace with macOS Tahoe; ActiveSpace's space-aware app switcher finally makes it obvious which app you're about to land on.
-
When a Broken Link Is Not a Broken Link
I built a small dashboard to keep an eye on this website, and one morning it told me one of my own posts had a dead link — to Shadertoy, in the very post where I’d gushed about Shadertoy. Except the link works perfectly. Shadertoy just won’t talk to robots, and my robot took it personally. Here’s the small, careful feature I built so a tool can tell the difference between ‘broken’ and ‘I’ve checked, and it’s fine.’
-
The Volume Knob Was Winning
I’ve spent thirty years building a music library — pub bands, street buskers, support-act CDs that never reached a single streaming service, an almost-complete collection of a band who deleted themselves from history. All of it recorded at wildly different volumes, all of it a chore to actually listen to, because one hand was forever on the dial. So I built a small app that learns how loud each track really is and quietly evens them out — no audio driver, nothing to install. This is also the project the dancer was hiding in.
-
Nobody Dances Like That
A little app I’ve been building sprouted a music visualiser, and I decided it needed a dancer in the spotlight. So I drew one — head, arms, a swirling skirt — and she looked wrong in a way I couldn’t explain. Here’s how a black blob, a smoke machine, and a hard lesson about the human form taught me to make something feel alive by refusing to say what it is.
-
The Furniture Was a Lie
I filled my next game's rooms with bunks, lockers, oil drums and dead terminals to make the place feel lived-in. It looked wonderful. There was just one problem: you could walk straight through all of it. Here's how I made the set-dressing solid — without costing a single frame.
-
Every Level Is Winnable, and I Can Prove It
My next game builds its levels fresh every time you play — rooms, corridors, locked doors, hidden keys. Which raises a terrifying question: what if it builds one you physically can't finish? Here's how I stopped blindly trusting the generator and started proving it wrong.
-
I Tore Out the Renderer. Again.
When I built my first game I ripped out a renderer I loved and rebuilt the world from scratch. For the second one I did it again — only this time there are no models, no meshes, no geometry in the usual sense at all. Every wall and every enemy is an equation. Here's why I keep doing this to myself.
-
The Sound I Could Not Fake
I wrote a whole post bragging that my games ship no asset files — every pixel and every note generated in code, the lot small enough to fit on a floppy. Then I started the second one, and a monster in the dark made me break my own rule. Here's why sound was the one thing I couldn't synthesise, and how I broke the rule without betraying it.
-
One Television, One Kilobyte
Something set me thinking about the Sinclair ZX81 today — the first computer I ever touched, when I was twelve. The sublime manual, the housework I did to earn telly time, the tape that never loaded, the RAM pack that lost everything, and the unbridled joy of the first program that was properly mine.
-
Better Late Than Never
An afternoon with no business case whatsoever: I opened the dead issue tracker of a PHP library I’d kept frozen since 2014 — eighty-five issues, the newest a decade old — and cleared the lot. Not by mass-closing, but by reading every one, fixing the two that were genuinely still broken, and replying by hand to all eighty-five people who’d once filed into a void. This is the whole story: the humane method, the gnarliest bug (a one-character CSS mistake that survived ten years), and what a dead repo taught me about the actual shape of software maintenance.
-
My AI Had Amnesia, So I Built It a Memory
Claude can refactor a Metal renderer at 2am and forget the entire estate by morning. Here is how I gave it a permanent, self-maintaining memory of all of Jorvik Software — three layers, one local LLM running on my own machine, zero cloud, and a fistful of bugs that lied to my face along the way.
-
The Shortcut I Never Meant to Press
There is a key combination on every Mac that toggles display mirroring, it sits one slip away from shortcuts you use all day, and I kept hitting it by accident at exactly the wrong moment. So I built a tiny app to swallow it. The build had a twist: the key I was trying to block turned out not to be the key I thought it was.
-
Strataris: The Screensaver That Became a Game
Five months, a lot of swearing, the occasional actual tear, and a stubborn rule that the whole thing had to fit on a floppy disk. My first native game is finished. Here's the messy story of how it got here.
-
The Details Are the Software
Tugboat is an internal-only tool, used by exactly one person, and almost nobody will ever see its menu-bar icon. I reworked that icon anyway, so it shows — in real time — which edge of the screen the Dock is actually living on. This is a post about the smallest of details: why they matter, why they're the line between hand-crafted code and AI slop, and the other invisible little things scattered across the Jorvik suite.
-
The OS Upgrade Tax
Two apps, three Tahoe regressions, one afternoon — the price of shipping a macOS suite through an OS upgrade.
-
The Column I Couldn't Copy
Last week I needed to copy a single column out of an HTML table in an email, and discovered that the boring solution — copy the whole table, paste it somewhere, trim it back — is a fifteen-second tax on a one-second intention. So I built CopyLens. Draw a rectangle anywhere on screen; if there's text inside, it lands on the clipboard as text. If not, the cropped image does. Same gesture, two outcomes. Plus a full-disclosure note about how the OCR engine actually got built, which wasn't by me.
-
Rainy Day Isn't a Screensaver
Rainy Day shipped this past weekend. The product page calls it a screensaver. The bundle on disk is a regular .app — no .saver in sight. This is the story of why. A run-down of the macOS frictions that ended my attempt to build it the orthodox way: WebContent suspended within seconds of activation, an Apple SPI that no longer works in macOS 26, a CARenderer that returns blank frames, ScreenCaptureKit edge cases when the saver occludes the screen it's trying to read, multi-instance lifecycle thrash from System Settings previews, and the way ad-hoc signing burns TCC grants on every rebuild. And then the architecture I ended up with — LSUIElement app, SMAppService login item, idle-driven fullscreen NSWindow at screenSaver level — which side-stepped every one of those frictions in an afternoon.
-
Putting The House In Order
Two weeks of housekeeping on the Jorvik estate. It started with Spotlight launching the wrong version of an app, ended with a 1,100-line refactor of Release Manager, and surfaced about ten gigabytes of accumulated nonsense in between. This is the diary of the fortnight: what the audit found, what `ps` told me about my own apps, and why a clean filesystem is a clean countertop.
Notes
Development notes, technical write-ups, and things I've learned along the way.