If you delete every pixel of Business Baron, the game still exists. What is left is a Rust library with no window, no sound and no input handling, which will take a seed and a list of decisions and play out a century of a company's life in less time than it takes to read this sentence.
That library is the game. The thing you look at is a way of talking to it.
For a while we planned five more games on top of it. We have stopped. What those games were going to cover now lives inside Business Baron as business types, some in the full game and some in add-on tracks, because a library that can run a café can run a hotel and a building firm in the same town.
The dependency list is the design document
The engine is a pure library crate. It compiles to something other programs call. It does not open a window, read a file, touch the network, ask the operating system for the time, or spawn a thread.
Its manifest lists three: serde, serde_json and libm. That is the whole of it. The first two turn the simulation's state into a stable serialised form and back again, with serde_json's float_roundtrip feature switched on, because a save that reads a number back a fraction out from the one it wrote is a save that replays into a different company.
The third arrived when the game started running in a browser as well as on a desktop. Functions such as exp and ln normally come from whatever maths library the machine provides, and those libraries are allowed to round the last digit differently. The engine uses exp to decide how many random draws to take in a month, so one digit's disagreement would send a browser career and a desktop career down different roads. libm is a maths library written in Rust and compiled into the engine itself, so both run exactly the same arithmetic.
That list is not asceticism for its own sake. It is what makes the rest of the properties possible. A dependency that reads the clock, or that iterates a hash map in a different order between runs, or that changes its floating point behaviour in a point release, is a dependency that can break determinism without anybody noticing for six months. Every library we do not include is a category of nondeterminism we do not have to audit.
Money in the engine is integer pence. Not a decimal type, not a float, an integer, with rounding written out explicitly at every point where a division occurs, because VAT on a £4.99 item and the apportionment of an overhead across four sites both have a correct answer in law and in accounting practice, and we would rather match it than approximate it.
Because the engine touches nothing outside itself, it runs anywhere: in a desktop build, headless in a test harness, thousands of instances in parallel on a build server, or compiled to WebAssembly in a browser. None of those are ports. They are the same library with a different caller.
A month happens in fifty-nine ordered steps
Time in the game moves a month at a time. Calling tick advances the simulation by one month, and inside that call fifty-nine steps run in a fixed order.
The order is the interesting part, because in an economic simulation almost every result depends on sequence. Does rent come out before or after the day's takings are banked. Does interest accrue before or after the overdraft moves. Is a wage rise applied before or after the National Insurance calculation that depends on it. Get those in the wrong order and the model still produces numbers; they are simply the wrong numbers, and nobody can tell by looking.
So the sequence is written down, in one place, as a list. Broadly it runs: resolve the economic environment for the month, then demand, then trading, then production and stock, then staff and payroll, then overheads and premises, then finance and interest, then tax accruals and payments, then investment and construction progress, then competitors, then events, then the accounting close, then the digest.
Each step is a function that takes the world and a scoped random stream and returns the world. There is no step that quietly reaches sideways into another. When we add a system, it becomes a numbered step in that list and we have to argue about where it belongs, which is a useful argument to be forced into.
The accounting close at the end is the one that keeps us honest. It posts every transaction the month generated through a double entry ledger, produces a profit and loss account, a balance sheet and a cash flow statement, and refuses to finish if they do not reconcile. A month that does not balance is not a month with a bug in the reporting. It is a month with a bug in the simulation, and the ledger finds it immediately rather than in year nineteen.
The front end holds no rules, and that is enforced
The interface can read the state and send decisions. It cannot compute anything that matters.
This sounds like ordinary layering, and the difference is in how strictly it is held. The front end does not know the rate of corporation tax. It does not know that a business under a certain rateable value gets small business rates relief. It does not decide whether a loan application succeeds. If a screen needs to show what a decision would cost, it asks the engine to evaluate that decision and tell it, rather than working it out with its own copy of the arithmetic.
Two copies of a rule is the classic way a simulation rots. The engine changes, the screen does not, and for eight months the game tells players a number that the simulation disagrees with. Players believe the screen, because the screen is the game.
The practical test we apply is this: could someone write a completely different interface, in a different language, against this engine, and get exactly the same game. If the answer is no, a rule has leaked out of the library.
It also means the engine has to expose its reasoning, not just its results. When profit falls by £30,000 in a quarter, the player has to be able to trace it through the profit and loss, into the cost line, into the transactions, back to the decision. The engine emits that trail as part of the state. A number that cannot be explained is treated as a defect, however sophisticated the model that produced it.
The digest is a single number that describes an entire game
At the end of every tick, the engine computes a digest over the whole simulation state. It is a hash, folded forward from the previous month, so the value at the end of a run depends on every value in every month that led to it.
Two runs from the same seed and the same decisions produce the same digest. If a single pence differs anywhere, in any account, in any month, the digest differs.
That gives us a cheap, exact answer to a question that is otherwise expensive: did this change alter the game. We keep recorded runs, replay them on every build, and compare digests. When a refactor is meant to change nothing, the digests prove it changed nothing. When a fix is meant to change one thing, the digests tell us how much else moved with it.
It also changes what a save file is. A save is a seed plus an ordered list of decisions, not a snapshot. The engine replays it from the beginning. So a player who thinks a figure is wrong can send us a short file, and we will see exactly what they saw, at our desks, on a different machine, months later.
Why we care about this
A business simulation is only worth playing if the numbers underneath it mean something, and the only way we know to keep them meaning something across more than two hundred business types and decades of simulated time is to make the core small, pure and checkable. The same core is why a hotel, a housebuilder and a dental practice can sit in one career: the tax, the ledger, the towns and the tick already exist, and each business type is a set of models and rules layered onto them. Business Baron is built and not yet released, and the engine is the reason we are comfortable calling it finished before anybody has paid for it.