About

Systems developer


I write systems software — emulators, engines, simulation. Not as projects that compile and are never checked again, but as work that gets held against an external standard and published either way, which is rarer in this corner of software than it ought to be.

What I do

Low-level code. Not web apps or glue between APIs — the layer underneath, where you own the memory, the timing and the correctness.

Fluid simulation
Has to stay stable across thousands of ticks.
Light propagation
Runs every frame, without dropping one.
CPU emulation
One cycle out and the game boots to a black screen, telling you nothing.

Why this kind of work

It is unforgiving in a useful way. There is no arguing with a failing test ROM — either the timing is right or it is not, and the distance between "looks fine" and "is correct" is measurable rather than a matter of opinion.

That is rarer in software than it should be.

Why native code, specifically

Two numbers explain the whole project.

499/500 CPU instructions, 1,000 tests each
155/165 public test ROMs passing
10 still failing, each with its evidence

Those are public test suites, not my own. Getting the last few percent is where the work actually is, and it is hard for three specific reasons.

Hostile output
A template instantiation error runs to hundreds of lines, almost all noise, and the one line that matters is somewhere in the middle of it.
Broken loop
Change a file in web work and see the result instantly. Here it compiles for minutes, and the bug is a frame that is seven dots early — invisible unless something is checking every pixel.
Nothing to copy
Cycle-accurate behaviour is not in a tutorial. It is in hardware documentation, in test ROMs written by people who measured a real console, and in the disagreements between them.

Most of what is written about building software covers the layer where a mistake is visible immediately. Down here it is not, so the only honest answer is to measure it and publish the number.

How I work

Spec first

Every feature starts as a written spec — what it does, what it does not do, how we would know it failed. Then a plan, broken into tasks small enough that a reviewer could reject one without rejecting the rest.

The implementation answers to that document, not to a vague idea of it. Specs and plans get committed next to the code, so six months later the reasoning is still there.

Tests are the contract

Write the failing test. Run it. Watch it fail for the reason you expect. Then implement, watch it pass, and commit.

That middle step is the one people skip and the one that matters most. Code that looks right and does not work is the normal case down here, and reading it will not reliably tell you which is which. A test you have watched fail for the correct reason is the only evidence worth anything.

Review everything

Every task gets read again with fresh eyes, and the review has to point at file and line. Findings are treated as claims to verify, not as facts.

Reviews find real defects, and they also raise false alarms with total confidence. Both happen often enough that checking the finding against the actual artefact is not optional.

In public, failures included

Every claim ships with its artefact: the spec, the diff, the commit, the test output. If a number goes down, it gets published going down.

The failures are the useful part. Anyone can write a post about the feature that worked first time. Far fewer will show you the three hours spent confidently fixing the wrong file.

What I'm building

FourShades

Game Boy emulator · C++20 · 2026 – present

A yardstick, not a product. The Game Boy is a solved problem — hundreds of emulators exist and several are far better than mine will be. That is exactly why it works.

Known answers
165 test ROMs in gbdev's Emulator Shootout already say what correct looks like.
Respected difficulty
Cycle-accurate timing is hard, and C++ developers know it.
A real number
The pass count is not an opinion. It goes up or it does not.

Litharia

2D engine · C++20 · SFML 3 · 290 commits

Written from scratch, with no framework handling the hard parts. The structural decision I am most pleased with is a dull one.

Simulation
Cellular fluid with surface tracking, propagating light on a day/night cycle, physics and collision.
World
Sparse chunked tile storage, procedural terrain, machines, inventory, enemy behaviour.
Headless core
The simulation links no graphics code at all, so the whole world steps inside a test in about a second.

Almost every hard bug I have fixed there was found by a test that only exists because of that split.

How I got here

2019

Scratch

Rebuilt games like Cookie Clicker and Idle Eleven, piece by piece, to work out how they were put together. Reverse-engineering something that already works turns out to be one of the fastest ways to learn.

2023

Lua and Roblox

Founded a studio and shipped multiplayer games to real players. Different discipline entirely: a game with players has bug reports, edge cases, and people doing things you never anticipated.

2025

C++ and systems work

Started Litharia, a 2D engine written from scratch. No framework handling the hard parts — my own fluid simulation, my own lighting, my own spatial data structures, and my own bugs.

2026

Measured in public

Began FourShades, a Game Boy emulator published against the public test ROMs, every result in the open. Including the ones that go backwards.

Stack

Systems

where most of the work happens

C++20 · SFML 3 · CMake · MSVC and clang · doctest

Web

this site, and anything that needs a browser

TypeScript · Astro · Cloudflare Pages · D1 · Vitest

Tooling

the loop everything runs through

Git · GitHub Actions · CMake · Lua

Elsewhere

Everything I build is on GitHub, including the specs and plans behind it. If you are working on native code at this layer and hitting the same walls, I would genuinely like to hear about it.