# A 4X that ends in one sitting: the constraint chose the scope

> A dice-free strategy core that resolves 480 hexes in 60 turns and runs offline in the browser; it shipped as Regnarium.

- What it does today: Runs a full 4X match on a 480-hex map in at most 60 turns; rules, map generation and the opponent AI live in one pure TypeScript core, and combat rolls no dice. Anyone with half an hour and an appetite for strategy can open it in a browser.
- Form: Web app
- State: Became a product
- Focus: Games & simulation
- Started: 2026-09-09
- Left Labs: 2026-09-13
- Technologies: TypeScript, Next.js, React, Vitest, MDX
- Tags: #games, #determinism, #offline, #typescript
- Website: https://regnarium.com
- This one became a product: Regnarium (https://www.muhammetsafak.com.tr/en/portfolio/regnarium/)
- Source: https://www.muhammetsafak.com.tr/en/labs/regnarium-lab/
- Language: en-US
- Author: Muhammet Şafak

---
Strategy is the one genre I have sunk tens of thousands of hours into. But a
usual session in that genre eats an entire evening, and nobody was building
anything for the player who does not have an evening.

## One sitting, a match that closes itself

The attempt was to fit the four verbs of 4X — explore, expand, exploit,
exterminate — into half an hour. The only honest way to do that is to let the
game end itself: a match closes after at most sixty turns, and if conquest is
incomplete the score decides. The clock is not a warning, it is part of the
rules.

Scope came out of the same constraint. A one-person project cannot match the
content volume of a large production, and trying to means finishing no system at
all. So the lists were deliberately kept short, and every entry has a job you
can tell apart on the board — adding a unit that does no distinct work lengthens
the list without enriching the game.

## No surprises, only regrets

The second decision is in combat. A system that rolls dice lets a player blame
the roll for every lost match instead of questioning their own call. Here the
preview you see before attacking *is* the calculation: same number, same
function. Writing a separate "estimate" function would have opened the one door
through which preview and outcome could drift apart; that door was never opened.

Randomness is not absent — the map comes from a seeded generator — but it does
not leak into play. The same seed and the same sequence of commands always
produce the same match, opponent decisions included.

## Having no server decided the save format

Running offline and without accounts also decided where a save could live. A
save is not a full copy of the state: it is the seed, the setup and the list of
commands issued so far. Loading replays that list to rebuild the state — and undo
uses the same machinery, trimming the log by one command and replaying the match.
No separate undo state is kept at all.

That carries a cost, and it was paid openly: when the rules change, replaying an
old save produces a different match, so no migration path can be written. The
save version goes up and the old file is quietly dropped. In a game that lasts
one sitting that is an acceptable loss; in a long campaign game it would not be.

## Letting the machine hold the constraint

I designed the mechanics and the architecture, and an AI wrote most of the code;
my job was keeping the architecture intact. But guarding a rule by eye does not
scale, so most of the constraints were handed to the machine: the rules core
cannot reach the browser, the clock or the network — those are banned at the lint
gate — and whether the gate actually holds is tested separately, by linting files
written to be wrong on purpose.

The game is live and playable; development continues and the open items sit in
their own records. The product side is detailed in the portfolio.
