A roach that gets tired: modelling race biology
The brief from my partners was simple: make roach races — a quick prototype to show investors. I suggested skipping the fake and building the game itself right away: we already had roach models, I could put them in, and people could actually come in and play. Why spend time on a mock-up?
And I didn’t want roaches that just run. I wanted races to look alive: a fast start that costs you later, a rival who fades in the last stretch, a final sprint that only works if there is something left in the tank. So I gave each roach a biological system inside, modelled on how a real runner’s body works. This is the part of the game I’m proudest of inventing.

Race model v2: from oxygen and ATP to power, force and speed.
The fuel is ATP. Running uses only ATP, and the store lasts about ten seconds at full power. After that the body has to make more, in one of two ways:
- Aerobic: fat plus oxygen gives ATP. It uses a lot of oxygen and gives little ATP per second.
- Anaerobic: glucose gives ATP plus lactate. It needs no oxygen, and in the model it kicks in when the load gets high.
Lactate is the price. It builds up in the muscles and brings fatigue, and force drops. Clearing it takes ATP from the aerobic system, so it only happens while there is enough oxygen. How well the oxygen system works depends on the heart rate.
On top of the body sits mechanics: power becomes force, which fights wind, mechanical resistance and mass. A roach running right behind another one meets less air — it rides in the leader’s slipstream.

One roach over a race: speed, ATP, oxygen, lactate, fatigue and the power switch. Lactate starts to build when the load goes up; at the final sprint the power switch goes to 100, and lactate and fatigue shoot up.
Where the numbers come from. Each roach’s stats are set by its genetics and by perks it picks up along the way:
- ATP system: the size of the ATP tank, and how efficiently ATP turns into running power — fatigue lowers it.
- Aerobic: the size of the oxygen tank, how fast oxygen recovers, how much oxygen per second can go into making ATP (it depends on blood saturation), and how much ATP one unit of oxygen gives.
- Anaerobic: the size of the lactate tank and how fast lactate makes ATP — closer to the maximum the less oxygen there is in the blood. Fatigue starts at 5% lactate and grows exponentially. Lactate is cleared only while the ATP tank is more than half full.
- Physical: mass; drag that grows exponentially with mass, so a heavier roach pays for it in the air; a fixed mechanical resistance; and wind speed and direction from a data feed.
Balancing it needed a tool. A model with this many parameters can’t be tuned by gut feeling, so I built an admin simulator: put roaches with different stats on the same track, run the race and watch the charts.

Ten variants of the same roach with different stats, raced against each other. The boxes at the top show each one’s result.

The roach editor in the admin: looks on top, the biological stats below — ATP and oxygen stores, lactate, heart rate, wind resistance, mass.
The second idea: roaches built from parts. Each roach was an NFT made of traits — body parts — and the parts came in tiers: the higher the tier, the better. In theory the traits were meant to shift those biological stats, so players would hunt for the good ones. That was turned down too, for fairness: all roaches have the same stats. But the colours stayed — every trait has its own hue, saturation and lightness. The backend assembles the model from the body parts, fits them onto a shared skeleton, applies the animations and paints each part in its colours. The plan was for colours to matter in a race as well — say, at 20 °C a more yellow roach would run better.
How players controlled it. In the first version you steered your roach with a slider: how much power to put in. Push too hard and it got tired, ran inefficiently and lost the race.
The best strategy turned out to be a real runner’s one. Cruise with the power switch at around 20–25%, then go to 100% before the finish — you can catch your breath after the line. The catch is knowing how far from the finish to start the sprint. And if you run in another roach’s slipstream, you can set slightly less power than it does — it runs at 20%, you at 19% — stay fresher, and break away at the end. In effect, the roaches formed a peloton.
What happened next. The team turned it down as too complicated for players. Together we arrived at a simpler control: you bet on the price of, say, Bitcoin, and a winning or losing trade pushes your roach’s motivation up or down. That is the game players race in today.
But the biology didn’t go away — it still runs under the hood. Each roach now has an AI that picks the power switch for it at every moment: it forecasts the next 10–20 seconds of the race and chooses the setting that keeps the roach from tiring, while near the finish it can afford to burn out. It makes the inside of the system a bit more complex, but for the player it is simple. And the races look the way we wanted: the lead keeps changing, one roach pulls ahead, then another.

A live race in April 2025: up to ten players, each roach tied to its own crypto pair.
Most importantly, there is no randomness under the hood. Everything is computed by the model. The only source of chance is the exchange rates, taken live from crypto exchanges.
Where the chance comes from. That part was my design too. We first thought of stocks, but stock prices don’t update often enough, and exchanges close at night — so crypto. Decentralised exchanges were out as well: a blockchain updates too rarely. That left centralised exchanges.
A coin like Bitcoin trades on ten or so exchanges at once. We could have taken prices from Binance alone, but trading happens everywhere, and for a game more movement means more volatility, which means more fun — the chart looks alive. On Binance alone a coin like XRP can sit still for 20 seconds, which is no good for a race. So we take a volume-weighted average across exchanges. On top of that, any exchange that hasn’t updated for more than 60 seconds stops counting — the weight of its last price lives in a 60-second sliding window.
It worked well enough, and some players really got good at it: one of them made a serious sum of money in the game.
What I took from it: keep the depth, but hide it. The model gives every parameter a meaning a person can reason about, and the simulator shows what a change does before any player sees it. The player, though, needs one clear lever — and the complexity can live inside, run by the roach’s own AI.