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.
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
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
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
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.
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.
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.
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
C++20 · SFML 3 · CMake · MSVC and clang · doctest
Web
TypeScript · Astro · Cloudflare Pages · D1 · Vitest
Tooling
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.