<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Subterrans devlog</title><description>Progress, decisions, and AI-agent notes from the making of Subterrans.</description><link>https://subterrans.com/</link><language>en-us</language><item><title>Phase 3 shipped: it&apos;s a round now</title><link>https://subterrans.com/devlog/phase-3-shipped/</link><guid isPermaLink="true">https://subterrans.com/devlog/phase-3-shipped/</guid><description>Phase 3 is done. Seven mechanics, eight implementation stages, seven sim-version bumps. Here is what shipped and what it actually felt like to land.</description><pubDate>Wed, 27 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Phase 3 is done. Two colonies, a neutral predator, a deterministic AI that invades on its own, real combat math, a reproduction lever, difficulty tiers, and a polish pass that makes the events legible. The &lt;a href=&quot;/devlog/phase-3-designing-the-first-real-round&quot;&gt;design post from ten days ago&lt;/a&gt; described what it was supposed to be. This is what it actually turned out to be.&lt;/p&gt;
&lt;p&gt;The short version: it is all there. Seven mechanics, eight implementation stages, seven sim-version bumps (V16 through V22). The game is now something that has a beginning, a middle, and an end. A round has shape. That is a different thing than what existed before.&lt;/p&gt;
&lt;h2&gt;What changed in combat&lt;/h2&gt;
&lt;p&gt;Before Phase 3, two ants meeting on the same tile resolved combat by coin flip: one died, one lived, repeat. Numbers barely mattered. Position did not matter. The home colony had no meaningful advantage.&lt;/p&gt;
&lt;p&gt;Phase 3 replaced this with a deterministic multi-tick model. Each ant has HP and a damage-per-strike, and home-ground ants get a 25% buff to both. A home defender at a tunnel entrance wins reliably against a single invader — not sometimes, always. Two invaders at the same chokepoint still beat one defender, because replacement depth means the second attacker inherits a wounded opponent. Three invaders beat the defender and barely lose anyone. The math is exact enough to plan around.&lt;/p&gt;
&lt;p&gt;The practical effect is that tunnel geometry matters now. A narrow underground passage is defensible in a way it was not before. The decision about where to put the queen chamber relative to your entrances is a real decision. Widening a tunnel to speed supply trades directly against its defensibility. This was theoretically true before; now the numbers support it.&lt;/p&gt;
&lt;p&gt;One thing that was not in the original plan: after combat shipped, a follow-on pass added sight-based fighter aggression. Fighters who see an enemy within range now initiate without being directed. The behavior ratio still governs how many fighters you have, but they are no longer passive — they engage what they find. This made the surface feel alive in a way the original plan underspecified.&lt;/p&gt;
&lt;h2&gt;What changed with the AI&lt;/h2&gt;
&lt;p&gt;The AI in Phase 2 foraged. It built its colony, occasionally its fighters ended up in the same space as your fighters, and things happened. It was never planning anything. The game outcome was whoever got unlucky on coin flips while running roughly parallel processes.&lt;/p&gt;
&lt;p&gt;Phase 3 gave the AI a named state machine: Peacetime, War Footing, Probing, Invading, Recovery. The transitions are driven by conditions in the sim — fighter count, food storage, round age, your colony size relative to theirs. The AI enters War Footing when it is ready and starts sending small probe raids — three fighters toward a surface food pile, not toward your queen. If the probe succeeds, it comes back at scale. If it fails, it recovers and tries again.&lt;/p&gt;
&lt;p&gt;The first time I saw a probe raid while the AI was in War Footing was the first time the game felt genuinely hostile. Not randomly hostile — intentionally hostile. There is now a reason to watch what the enemy colony is doing, not just your own.&lt;/p&gt;
&lt;p&gt;The loss-cause ledger was spec’d as a low-key requirement in the design plan. It ended up shipping as its own PR and becoming more central than expected. The game-over screen now tells you specifically how you lost — the enemy fighters broke through, the spider rampaged your nursery, your queen starved — using actual sim event data, not placeholder text. That one detail made losing feel informative instead of opaque. Players need to know what went wrong. Generic “you lost” is a dead end.&lt;/p&gt;
&lt;h2&gt;What changed with the spider&lt;/h2&gt;
&lt;p&gt;The spider is a neutral predator with a hunger clock. It wanders the surface on a ~60-second hunt cadence and places a red reticle on its target tile 6–8 seconds before striking. Workers self-scatter away from the reticle. If enough fighters arrive within engagement range, the spider retreats. If not enough arrive, they die.&lt;/p&gt;
&lt;p&gt;The design intent was that ignoring the spider is viable but costly: it picks off workers slowly, which compounds over a long round. Engaging it costs fighters and attention. The actual dynamic in play is that the reticle creates a recurring decision — every hunt cycle, you choose whether to respond. Most rounds you do not respond directly; you just route around it or accept the occasional worker loss. But at higher hunger levels the spider rampages into the nest, and that is immediately and visibly catastrophic. The hunger ring on the spider sprite (a color gradient that intensifies as hunger builds) is the only cue. If you are not watching it, you get surprised.&lt;/p&gt;
&lt;p&gt;The right-click command to designate the spider as a priority target shipped last, in its own cleanup stage. It was deferred from the spider’s initial implementation to keep that PR focused on the sim foundation. By the time it shipped the mechanic was solid enough that adding the input felt like filling in a blank rather than making a design decision.&lt;/p&gt;
&lt;h2&gt;Reproduction and difficulty&lt;/h2&gt;
&lt;p&gt;The reproduction lever ties food surplus to egg-laying speed. When your food storage is high relative to colony size, the queen lays faster. Nurses in nursery chambers accelerate larval maturation. Nursery capacity caps the throughput. The three levers interact: more surplus → more eggs → more demand for nurses → fewer foragers → slower surplus accumulation. The cycle regulates itself if you let it.&lt;/p&gt;
&lt;p&gt;This was the mechanic I was most uncertain about before Phase 3. In isolation, “food surplus accelerates growth” sounds like “just stockpile food and win.” In practice, the food-to-workers pipeline has enough latency and enough competing demands that it reads as a real trade-off, not a stat to maximize.&lt;/p&gt;
&lt;p&gt;Difficulty tiers shipped as Easy/Normal/Hard and apply two independent axes: asymmetric modifiers on both colonies’ economics and combat (AI gets buffed, player gets nerfed, or vice versa) and symmetric world-pressure changes (spider hunger interval, food pile respawn rate). Normal is balanced for a player who has played two or three rounds. Easy gives enough margin to learn the systems without constant punishment. Hard is hard.&lt;/p&gt;
&lt;h2&gt;What this unlocks&lt;/h2&gt;
&lt;p&gt;Phase 2 was a proof that the simulation worked. Phase 3 is a proof that the game loop has the right shape. A round now has pressure that escalates, decisions that compound, and outcomes you can explain after the fact.&lt;/p&gt;
&lt;p&gt;The honest next question is whether the game is fun in the hands of someone who did not build it. That is what the demo is for. &lt;a href=&quot;/demo/play&quot;&gt;Play it&lt;/a&gt; and use the feedback form at the end. The sim produces a playtrace for every session — loss reasons, decision points, where the round broke. That data is going to drive Phase 4 tuning.&lt;/p&gt;</content:encoded></item><item><title>A new roadmap</title><link>https://subterrans.com/devlog/a-new-roadmap/</link><guid isPermaLink="true">https://subterrans.com/devlog/a-new-roadmap/</guid><description>The roadmap has been reorganized into phases. Where we are, where v1.0 is, and what changed from the old structure.</description><pubDate>Sun, 17 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We have reorganized the roadmap. Versions are out; phases are in. Phases describe what we are building. Versions describe where we are. Those are different questions, and the old roadmap was trying to answer both with the same label.&lt;/p&gt;
&lt;h2&gt;Where we are&lt;/h2&gt;
&lt;p&gt;Subterrans is around v0.2. The simulation runs. Two colonies, pheromone trails, foraging, combat, a rule-based AI opponent. You can play a round end-to-end and lose to the enemy queen.&lt;/p&gt;
&lt;p&gt;What rounds do not yet have is shape. There is no middle. You dig, forage, and fight until one queen dies. That is a loop, but it is not yet a game — there is nothing that builds pressure, no moment where the match turns, no point at which the right decision earlier becomes visible as the right decision in retrospect.&lt;/p&gt;
&lt;p&gt;That is what Phase 3 is for. More on that in a &lt;a href=&quot;/devlog/phase-3-designing-the-first-real-round&quot;&gt;companion post&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Where v1.0 is&lt;/h2&gt;
&lt;p&gt;Version 1.0 is feature-complete and genuinely fun. Not a date. A destination. The phases between here and there are the things we have to build to know whether the game is actually fun, and to fix it if it is not.&lt;/p&gt;
&lt;p&gt;That framing matters. The old roadmap listed v1.0 as a milestone we had already shipped — the PRD and architecture phase. That was wrong in a way that mattered: it implied more progress than there was, and it made “v2.0” the new thing instead of acknowledging we are early in a long arc. The new numbering is honest. We are around v0.2. We know what we are building. The destination is clear.&lt;/p&gt;
&lt;h2&gt;The phases&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;/roadmap&quot;&gt;roadmap page&lt;/a&gt; has the full detail. Short version:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 1 — PRDs &amp;amp; Architecture.&lt;/strong&gt; Shipped 2026-04-14. Requirements and architecture for the seven essential systems.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 2 — Playable POC.&lt;/strong&gt; Shipped 2026-04-28. The simulation runs in a browser with two colonies and a functional game loop.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 3 — First Real Round.&lt;/strong&gt; In implementation now. Seven mechanics that give a match a beginning, middle, and end.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 4 — Yard Scale.&lt;/strong&gt; The world grows from one patch to a yard of connected territories with biome diversity.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 5a — Sensory Pass.&lt;/strong&gt; Audio and pixel art. The game starts to feel like a finished product.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 5b — Variety Pass.&lt;/strong&gt; Additional predator types, multiple map seeds, expanded round configurations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 6 — Mobile.&lt;/strong&gt; Touch input and a performance budget for mid-range phones.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 7 — World &amp;amp; Social.&lt;/strong&gt; Castes, weather, day/night. Multiplayer is also here, framed as exploring — see below.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Version 1.0.&lt;/strong&gt; Feature-complete, genuinely fun.&lt;/p&gt;
&lt;h2&gt;What changed from the old roadmap&lt;/h2&gt;
&lt;p&gt;Three things came off the list or moved.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Yellow Ant is removed.&lt;/strong&gt; Direct control of a single ant, SimAnt-style, was on the old roadmap as a planned depth feature. It is not in any current design. The game’s interesting design space is in colony management, not individual control. Removing it is not a concession — it is an honest accounting of what the game is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Castes, weather, and day/night have moved.&lt;/strong&gt; They were filed under “Beyond v2.0” with no home. They now belong to Phase 7 — World &amp;amp; Social — which gives them a place in the sequence without implying a timeline.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Multiplayer stays, framed correctly.&lt;/strong&gt; It is in Phase 7, labeled as “exploring.” The architecture preserves the option — deterministic simulation, replay logging, the whole foundation — but no design work has started, and a commitment to ship multiplayer before we know whether the single-player game is fun would be the wrong commitment to make. It is on the roadmap to anchor future architectural decisions. It is not a promise.&lt;/p&gt;
&lt;h2&gt;The point&lt;/h2&gt;
&lt;p&gt;Working in phases keeps us honest about scope. Each phase has a question it is answering. Phase 3 asks whether a round can have shape. Phase 4 asks whether the world can have scale. Phase 5 asks whether the game can be felt as well as played. Each question has a real answer, and if the answer is no, the phases after it are wrong.&lt;/p&gt;
&lt;p&gt;The roadmap is subject to change. Phases may be reordered, split, or dropped as we learn what makes the game fun.&lt;/p&gt;</content:encoded></item><item><title>Phase 3: designing the first real round</title><link>https://subterrans.com/devlog/phase-3-designing-the-first-real-round/</link><guid isPermaLink="true">https://subterrans.com/devlog/phase-3-designing-the-first-real-round/</guid><description>Phase 3 is the first version of Subterrans where a match has a beginning, middle, and end. Here is what it introduces and why.</description><pubDate>Sun, 17 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Phase 3 is the first version of Subterrans where a match has a beginning, middle, and end.&lt;/p&gt;
&lt;p&gt;Right now the simulation runs. Two colonies start on opposite sides of a patch, dig chambers, forage for food, grow workers, fight. One queen dies. The simulation is correct — deterministic, headlessly testable, well-specified. But a round does not have shape. There is no pressure that builds, no moment where the match turns. You play until one side wins, and the outcome feels roughly proportional to the decisions you made, but the decisions were not made &lt;em&gt;in response to anything&lt;/em&gt;. That is a loop. It is not yet a round.&lt;/p&gt;
&lt;p&gt;Phase 3 adds the mechanics that give it shape. Seven of them, in the order they layer in:&lt;/p&gt;
&lt;h2&gt;The spider&lt;/h2&gt;
&lt;p&gt;A neutral predator, not allied with either colony. The spider operates on a hunger clock independent of both players: it wanders, it attacks anything it finds, and when it is hungry enough it will engage ants it would otherwise avoid. It cannot be defeated by one colony alone at early-game population levels. Both colonies have to deal with it.&lt;/p&gt;
&lt;p&gt;This introduces the first thing that happens to you that you did not cause — and that your opponent did not cause either. The early game is no longer just a race to grow. It is a race to grow while something is reducing your workers.&lt;/p&gt;
&lt;h2&gt;The threat reticle&lt;/h2&gt;
&lt;p&gt;Six to eight seconds before a spider attack lands, a reticle appears over the target area. The warning is long enough to react to — pull workers back, adjust the behavior ratio, send fighters — but short enough that the reaction has to be fast and costs something. You cannot pre-position perfectly for a threat you have not seen yet.&lt;/p&gt;
&lt;p&gt;The reticle is a design principle as much as a mechanic. Danger that is invisible until it lands does not create decisions; it creates complaints. Telegraphed danger creates decisions. The question is whether you saw it, how fast you reacted, and whether the cost of reacting was worth paying.&lt;/p&gt;
&lt;h2&gt;The mark-priority command&lt;/h2&gt;
&lt;p&gt;A player command that designates a high-priority target — spider, enemy fighter, enemy entrance. Workers and fighters route toward it before taking other actions.&lt;/p&gt;
&lt;p&gt;This is the player’s most direct lever over the colony’s response to a threat. Before Phase 3, the behavior ratio (forage / defend / dig) was the only coarse-grained control over what the colony was doing. Mark-priority adds a fine-grained one: not “send more fighters” in general, but “send fighters &lt;em&gt;there&lt;/em&gt;, &lt;em&gt;now&lt;/em&gt;.” The distinction between the two is most visible under threat, which is exactly when the difference matters.&lt;/p&gt;
&lt;h2&gt;Worker self-scatter&lt;/h2&gt;
&lt;p&gt;When danger is close, workers in the affected area move away from it without a player command. They do not fight. They do not freeze. They scatter, and return when the threat passes.&lt;/p&gt;
&lt;p&gt;Self-scatter sounds passive, but it is the mechanic that makes the spider feel like a disruption rather than a damage event. A spider does not just remove workers — it scatters them, and scattering takes time to recover from. If workers were foraging a food pile near a spider patrol path, you lose not just the workers that got hit but the next twenty seconds of foraging efficiency while the rest return and re-establish trails. That is the middle of a round: a sequence of disruptions you manage better or worse than your opponent.&lt;/p&gt;
&lt;h2&gt;Danger pheromones&lt;/h2&gt;
&lt;p&gt;When ants encounter a threat — spider, enemy fighter, proximity to an enemy entrance — they emit danger pheromones. These propagate across the grid and decay over time, following the same two-grid pheromone system already used for food trails.&lt;/p&gt;
&lt;p&gt;The effect: the colony remembers where things went wrong, and ants route around those areas until the pheromone fades. A spider that killed workers in a corner of the map leaves a danger signature there. Workers will forage around it. Fighters will approach more cautiously.&lt;/p&gt;
&lt;p&gt;Danger pheromones do not require player input. They are emergent colony-level memory. But they are also visible — the pheromone overlay shows them — which means a player who reads them has information about where pressure has been and where it might return.&lt;/p&gt;
&lt;h2&gt;The reproduction lever&lt;/h2&gt;
&lt;p&gt;Food surplus above a threshold accelerates egg-laying rate and larva maturation speed. When the colony is well-fed, it grows faster. When food is contested or restricted, growth slows.&lt;/p&gt;
&lt;p&gt;This creates a mid-game dynamic that was absent before: food is not just a resource, it is the colony’s growth rate. A player who controls more food patches earlier builds population faster, which enables defending more food patches, which compounds. The reproduction lever is the mechanism that makes early-game foraging decisions visible as late-game population differences — the thing that makes a middle exist.&lt;/p&gt;
&lt;p&gt;It also makes the spider more interesting. A spider that disrupts foraging near a food-rich area does not just kill workers; it reduces the food flow that drives reproduction. Two disruptions, one event.&lt;/p&gt;
&lt;h2&gt;Difficulty tiers&lt;/h2&gt;
&lt;p&gt;Three settings that change how the AI opponent plays and how the world generates pressure. The differences are asymmetric: easier tiers reduce the AI’s resource efficiency and combat aggression, not just its health or numbers. Harder tiers give the AI better foraging routes, faster reaction to threat, and a world with more spider activity.&lt;/p&gt;
&lt;p&gt;Difficulty tiers exist because Phase 3 adds enough mechanistic depth that the same settings that make the game learnable for a new player make it trivial for an experienced one. The tiers are a tuning surface. What matters for Phase 3 is that they exist and that the hardest tier is genuinely hard — that requires the spider system and the reproduction lever to be working, which is why it gets built last.&lt;/p&gt;
&lt;h2&gt;The design weekend&lt;/h2&gt;
&lt;p&gt;Phase 3 was designed over one weekend, using a three-pass Codex review process and a dual-reviewer structure: each proposal was reviewed independently by two agents before being folded into the decision journal. The seven mechanics above came out of that process.&lt;/p&gt;
&lt;p&gt;The methodology matters only insofar as it produced a coherent phase. The seven mechanics reinforce each other — the spider creates disruption, the reticle makes disruption legible, scatter makes it expensive, danger pheromones make it persistent, the reproduction lever makes it consequential, mark-priority gives the player agency over it, and difficulty tiers calibrate how much of it there is. Designing them separately would have produced seven features. Designing them together produced a round.&lt;/p&gt;
&lt;h2&gt;What this unlocks&lt;/h2&gt;
&lt;p&gt;Once Phase 3 lands, the question shifts from “does the simulation run?” to “is the round fun?”&lt;/p&gt;
&lt;p&gt;That is the question Phase 1 — the original PRD, written in April — said we would answer first. We are finally there. The simulation is correct. The architecture is sound. The feedback tooling is in place. Phase 3 is the first version of Subterrans that can be evaluated as a game.&lt;/p&gt;
&lt;h2&gt;What comes next&lt;/h2&gt;
&lt;p&gt;Implementation starts now, stage by stage. The spider comes first; then the reticle and scatter; then pheromones and reproduction; then mark-priority; then difficulty tiers and tuning. Each stage ships as a PR, visible in the &lt;a href=&quot;https://github.com/LightAxe/subterrans&quot;&gt;game repo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The devlog will be quieter while builds are happening. When Phase 3 is done, you will hear about it. In the meantime, the demo at &lt;a href=&quot;/demo/play&quot;&gt;/demo/play&lt;/a&gt; is the current state of the game, and the &lt;a href=&quot;/roadmap&quot;&gt;roadmap&lt;/a&gt; tracks where each phase sits. If you play it and something is confusing, broken, or just wrong — say so. That feedback matters more now than it will at any later point.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;This post is a companion to &lt;a href=&quot;/devlog/a-new-roadmap&quot;&gt;A New Roadmap&lt;/a&gt;, which covers the updated phase structure and what changed from the old roadmap.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title>The week the ants got better</title><link>https://subterrans.com/devlog/the-week-the-ants-got-better/</link><guid isPermaLink="true">https://subterrans.com/devlog/the-week-the-ants-got-better/</guid><description>Visible brood carry, diagonal motion, real pixel-art terrain — plus a structured codebase review that found twenty latent bugs you&apos;ll never see fire.</description><pubDate>Mon, 04 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Five days since &lt;a href=&quot;/devlog/first-players-first-bugs&quot;&gt;the last post&lt;/a&gt;. Nineteen merged PRs in the game repo, somewhere north of fifty individual commits. A few of the changes are immediately visible the next time you load the demo. Most of them aren’t, and that’s a story too.&lt;/p&gt;
&lt;h2&gt;Things you can see&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Nurses now carry brood.&lt;/strong&gt; Eggs and larvae used to teleport from the Queen’s chamber into the Nursery — the simulation faked transport and the renderer faked the rest. As of this week, a nurse picks up a brood entity, walks it visibly across the colony, and deposits it in an Open tile inside a Nursery. It’s a real pickup-and-deposit state machine: pickup field seeded from claimable brood, deposit field seeded from Nursery tiles, the brood’s position syncs to the carrier each tick, and the renderer nudges the brood sprite a quarter-tile up so it sits in the carrier’s arms instead of stacked on her thorax. Dead carriers drop their brood in place; a maturing larva drops the carry mid-flight; another nurse can claim an orphaned brood from the death tile. All of that sounds obvious until you write it; six rounds of internal + Codex review caught about ten edge cases I’d missed on the first pass.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ants move diagonally now.&lt;/strong&gt; Movement was 4-connected (N/E/S/W only) since the first prototype. This week the simulation switched to 8-connected with a scurry-stop-scurry cadence: forager workers take a few steps, pause to “search,” then resume. The change is subtle in a screenshot and dramatic in motion — the colony reads as alive in a way it didn’t before. Fighters keep their direct line, because fighters chasing a target shouldn’t look hesitant.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The dirt is dirt.&lt;/strong&gt; Until last week, the underground was solid brown. It now uses a procedurally-generated pixel-art terrain atlas, with quarter-tile autotiling on the walls so chamber edges, tunnel turns, and chamber corners all join correctly. The surface got ant-scale motifs — boulders, twigs, leaves the size of a worker — that block movement and give the world a sense of scale. After all that, I went back and fixed the rim-clip artifacts at the chamfered corners. The art will still get redrawn entirely in a later phase; the point of this pass was to make programmer-art look intentional rather than pre-final.&lt;/p&gt;
&lt;h2&gt;The AI got harder to push around&lt;/h2&gt;
&lt;p&gt;Two changes worth calling out:&lt;/p&gt;
&lt;p&gt;The enemy AI was concentrating its colony into a tight pocket near the entrance — easy to invade, predictable to fight. New depth gate + spread bias + frontier-dig logic means the enemy now expands their colony over a wider area, with chambers placed reachable-but-not-adjacent and digging continued past initial chamber satisfaction. They feel like a colony making decisions instead of a script unrolling.&lt;/p&gt;
&lt;p&gt;The AI’s chamber-placement BFS was running every tick — a ~4096-tile search per AI colony, sixty times a second. Strategic chamber decisions don’t need 60 Hz responsiveness; they’re bounded by how fast diggers can reach the marked tiles. Cadence is now once every eight seconds. That’s a 99% cost reduction on the BFS for no observable downside, and it matches how the rest of the simulation budgets work — fast loops on the cheap stuff, slow loops on the strategic stuff.&lt;/p&gt;
&lt;h2&gt;Things you can’t see&lt;/h2&gt;
&lt;p&gt;Now the bigger story: I did a structured review pass over the entire codebase and shipped roughly twenty fixes for things nobody had reported yet.&lt;/p&gt;
&lt;p&gt;A few of the worse ones:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Entity ID overflow.&lt;/strong&gt; &lt;code&gt;allocateEntityId&lt;/code&gt; would let the counter walk past &lt;code&gt;MAX_ENTITIES = 8192&lt;/code&gt; and the next caller would write to TypedArray index 8192 — silent corruption. Fixed: counter freezes at the cap, callers receive a &lt;code&gt;-1&lt;/code&gt; sentinel and gracefully bail. Egg-laying becomes a soft population cap instead of a crash.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NaN command coordinates.&lt;/strong&gt; Every existing range check rejected &lt;code&gt;Infinity&lt;/code&gt; (&lt;code&gt;Infinity &amp;gt;= max&lt;/code&gt; is true) but not &lt;code&gt;NaN&lt;/code&gt; (&lt;code&gt;NaN &amp;gt;= max&lt;/code&gt; is false). A &lt;code&gt;NaN&lt;/code&gt; coord slipped through every guard, persisted into colony state, and broke save replay determinism via &lt;code&gt;JSON.stringify(NaN) === &apos;null&apos;&lt;/code&gt;. New shared &lt;code&gt;isTileCoord&lt;/code&gt; predicate enforces integer-in-range at handler entry.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Save validation against tampering.&lt;/strong&gt; &lt;code&gt;s.ants.count: 1e9&lt;/code&gt; used to allocate ~88 GB of TypedArrays before any sanity check. Now clamped. &lt;code&gt;s.simVersion&lt;/code&gt; outside the supported range used to silently flip every gate. Now throws.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Forward-compatible saves.&lt;/strong&gt; A new &lt;code&gt;FutureSimVersionError&lt;/code&gt; distinguishes “save written by a newer build” from “save corrupted.” Future-build saves are now preserved across &lt;code&gt;bootFresh&lt;/code&gt; + autosave (the autosave gets suspended explicitly), so a player who downgrades the build can recover their world by reloading on a newer build. Definitively-corrupt saves get deleted normally.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Camera-pan freeze on HUD crossing.&lt;/strong&gt; Drag-pan would jump every time the cursor crossed a HUD widget mid-drag. Combined with a related fix where keyboard pan no longer stacks on top of an active drag-pan, the camera input is finally consistent across every gesture I can think of.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pheromone leakage between zones.&lt;/strong&gt; Underground carriers were writing phantom trails on the surface food-trail grid, corrupting surface forager behavior. Behind a sim-version gate so existing saves replay byte-identically.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The pattern across all of these is the same: each one was a real bug hiding behind an acceptable-looking range check or an unexamined invariant. None of them produced obvious symptoms in normal play. All of them would have produced very confusing symptoms eventually.&lt;/p&gt;
&lt;h2&gt;Why the simVersion gates matter&lt;/h2&gt;
&lt;p&gt;Every correctness fix in the simulation is gated behind a sim-version sentinel. New games run at the latest version. Saves written before the fix replay at their original version, byte-for-byte identical to what they would have produced before the fix existed. There are now twelve sim versions, each with a documented contract.&lt;/p&gt;
&lt;p&gt;The cost is ugly conditionals at hot paths. The benefit is that a player’s seed-3201734851 mid-game save still replays today exactly as it would have in week one — and that I can fix sim correctness without breaking a single existing player’s save. That property is non-negotiable for a deterministic simulation that wants a multiplayer future.&lt;/p&gt;
&lt;h2&gt;Going forward&lt;/h2&gt;
&lt;p&gt;The rest of the week was infrastructure: command-coordinate validation, save-boundary hardening, code hygiene, defensive guards. None of it ships a feature. All of it makes the next feature safer to ship.&lt;/p&gt;
&lt;p&gt;Next up: another pass at the player-facing UI, especially the underground view’s information density, and probably the start of a tutorial layer. Plus more art, because the procedural terrain atlas opened up the path to actually-good-looking tiles and I want to follow it.&lt;/p&gt;
&lt;p&gt;If you find something, &lt;a href=&quot;https://github.com/LightAxe/subterrans/issues&quot;&gt;issue tracker&lt;/a&gt;. The bug-report template walks you through the F9 debug log, which gives me a reproducible replay instead of guesswork.&lt;/p&gt;
&lt;p&gt;More soon.&lt;/p&gt;</content:encoded></item><item><title>First players, first bugs</title><link>https://subterrans.com/devlog/first-players-first-bugs/</link><guid isPermaLink="true">https://subterrans.com/devlog/first-players-first-bugs/</guid><description>What changed in two weeks of going from private repo to embedded demo: real issue reports, the last Phase 1 gameplay seams, and one system that got smaller instead of bigger.</description><pubDate>Wed, 29 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Two weeks ago the game lived in a private repo on my laptop. Today it’s embedded at &lt;a href=&quot;/demo/play&quot;&gt;/demo/play&lt;/a&gt;, the source code is on &lt;a href=&quot;https://github.com/LightAxe/subterrans&quot;&gt;GitHub&lt;/a&gt;, and the issues page has real bug reports from people who aren’t me. That shift — from building in isolation to building under observation — changed what I worked on this week.&lt;/p&gt;
&lt;p&gt;Here’s what landed.&lt;/p&gt;
&lt;h2&gt;Phase 1 is now actually playable end-to-end&lt;/h2&gt;
&lt;p&gt;The simulation has supported invading the enemy hive since Phase 09.1: a fighting ant standing on the enemy’s entrance descends into their grid, hunts the nearest hostile, and resolving combat against their queen triggers victory. That’s the win condition for Phase 1. But none of it was reachable from the UI — clicking on an enemy entrance did nothing visible, the keybind to swap underground views was undiscoverable, and there was no visual cue distinguishing “enemy entrance” from “any other surface tile.”&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/LightAxe/subterrans/pull/29&quot;&gt;PR #29&lt;/a&gt; wired up the four UI seams. Left-click on an enemy entrance now sets your rally point there. The X-keybind got a clickable button labeled “Your Colony / Enemy Colony.” Underground clicks on the spectator view became no-ops (instead of silently dispatching dig-marks against your own grid at the matching coordinates). And enemy entrances got a single-pixel red perimeter ring so they read as “rally here to invade” without any tutorial text.&lt;/p&gt;
&lt;p&gt;The simulation work was already done. The lesson was that “feature ships when sim supports it” is wrong; the feature ships when a player can find it without reading the source.&lt;/p&gt;
&lt;h2&gt;One system got smaller&lt;/h2&gt;
&lt;p&gt;Phase 10 was originally going to add a dig-priority slider to the existing forage/dig/fight ratio that players control. After playtest, the slider got cut entirely. The behavior ratio is now two fields — &lt;code&gt;forage&lt;/code&gt; and &lt;code&gt;fight&lt;/code&gt; — and digging is auto-assigned based on outstanding marked tiles. Less UI, less to explain, and the simulation does the bookkeeping that a human would have done badly anyway.&lt;/p&gt;
&lt;p&gt;This is the second time I’ve removed a control from the player surface in this project. The pattern: if a system has a single right answer most of the time, exposing it as a knob just lets the player make it worse. Auto-assign isn’t a smarter system; it’s a refusal to let the player accidentally starve the dig queue while staring at a UI element.&lt;/p&gt;
&lt;h2&gt;The first round of real issues&lt;/h2&gt;
&lt;p&gt;The issues page collected reports faster than I expected. The interesting ones, in rough order:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/LightAxe/subterrans/issues/16&quot;&gt;&lt;strong&gt;#16 — queen wanders into the corner of her chamber and stays there.&lt;/strong&gt;&lt;/a&gt; Visually unsettling; functionally fine. Fix was a wander policy that keeps her inside the chamber bounds rather than against an arbitrary wall.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/LightAxe/subterrans/issues/15&quot;&gt;&lt;strong&gt;#15 — chamber food storage was render-authoritative.&lt;/strong&gt;&lt;/a&gt; Storage capacity was being computed by the rendering layer reading sprite occupancy, which is exactly the inversion the &lt;a href=&quot;/devlog/the-seven-principles&quot;&gt;seven principles&lt;/a&gt; say to never do. Made the chamber the authoritative source.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/LightAxe/subterrans/issues/27&quot;&gt;&lt;strong&gt;#27 — carriers oscillating between food piles when colony storage was full.&lt;/strong&gt;&lt;/a&gt; A worker would pick up food, walk halfway home, drop it because storage was saturated, walk back, repeat. Fix: bail out at pickup time, not at delivery.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/LightAxe/subterrans/issues/30&quot;&gt;&lt;strong&gt;#30 / #31 — invisible ceiling-row dig marks.&lt;/strong&gt;&lt;/a&gt; Clicking on the grass strip at the top of the underground view dispatched a real dig command against the tile underneath, but the renderer kept painting grass on top — zero feedback that anything happened, and the orphan marks were dragging idle workers into infinite loops. Fixed in three layers: input rejection, sim-handler rejection, and AI-controller pre-filter. Defense in depth, because the AI was creating ceiling-row marks too.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A pattern in this list: most of the bugs were &lt;em&gt;input-layer or rendering-layer&lt;/em&gt; bugs surfacing &lt;em&gt;simulation-layer&lt;/em&gt; symptoms. The sim itself, the part the seven principles protect, has been mostly fine. The friction is in the seams — the places where player intent translates into commands, or where world state translates into pixels.&lt;/p&gt;
&lt;h2&gt;How the game gets to the page&lt;/h2&gt;
&lt;p&gt;The library bundle work was the biggest mechanical chunk. The game builds itself as a single ESM module with a &lt;code&gt;mount()&lt;/code&gt; entry point that the website’s Astro page imports dynamically. Cache-busted hashed filenames + a manifest.json so the website’s deploy can reference the right URL. A &lt;code&gt;ready&lt;/code&gt; promise so the loading state knows when to clear. Source maps. A &lt;code&gt;.d.ts&lt;/code&gt; file generated directly from the source so the public API can’t drift from its declared types.&lt;/p&gt;
&lt;p&gt;It now takes a single push to game &lt;code&gt;main&lt;/code&gt; to redeploy the live demo. The game’s CI bumps the website’s submodule pointer, the website’s deploy picks that up, the bundle builds with a fresh hash, and CloudFront serves it. None of that is interesting in isolation. What’s interesting is that the friction-to-ship is now low enough that I’ll fix bugs in the morning instead of batching.&lt;/p&gt;
&lt;h2&gt;The dual-AI review pipeline went live&lt;/h2&gt;
&lt;p&gt;Every PR on the public repo now gets reviewed by Codex automatically (skipped on owner-authored PRs, since I’m reviewing my own work via Claude already). The bug-report template emphasizes the F9 debug log, which produces the input-log + seed needed to reproduce a deterministic replay. The branch-and-PR workflow is now the rule, not the convention.&lt;/p&gt;
&lt;p&gt;If you find something broken in the demo, I’d rather hear about it than not. The &lt;a href=&quot;https://github.com/LightAxe/subterrans/issues&quot;&gt;issue tracker&lt;/a&gt; is the place — the bug-report template walks you through the F9 debug log, which gives me a reproducible replay instead of guesswork.&lt;/p&gt;
&lt;p&gt;More soon.&lt;/p&gt;</content:encoded></item><item><title>The seven principles</title><link>https://subterrans.com/devlog/the-seven-principles/</link><guid isPermaLink="true">https://subterrans.com/devlog/the-seven-principles/</guid><description>Seven non-negotiable architectural rules for Subterrans, why each one matters, and what breaks if you skip it.</description><pubDate>Thu, 23 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;(Editor’s note, 2026-05-17: Phase numbering has been updated since this post was published. See the &lt;a href=&quot;/roadmap&quot;&gt;current roadmap&lt;/a&gt; for the active phase structure.)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Subterrans has seven architectural principles I won’t compromise on. They sound austere written down. They are. The reason they’re non-negotiable is that every one of them protects something I want — replay, future multiplayer, deterministic debugging, AI agents that can actually reason about the code — and the cost of relaxing any of them shows up later, when fixing it requires rewriting half the simulation.&lt;/p&gt;
&lt;p&gt;This post is the long version of &lt;a href=&quot;https://github.com/LightAxe/subterrans/blob/main/AGENTS.md&quot;&gt;AGENTS.md&lt;/a&gt;, with the reasoning expanded.&lt;/p&gt;
&lt;aside&gt; &lt;p&gt;If you&apos;re skimming&lt;/p&gt; &lt;div&gt;&lt;p&gt;Each principle has the same shape: a hard rule, what it protects, what breaks if you ignore it. The rules are boring. The consequences of ignoring them are not.&lt;/p&gt;&lt;/div&gt; &lt;/aside&gt;
&lt;h2&gt;1. Strict separation of simulation from rendering&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;src/sim/&lt;/code&gt; is pure TypeScript. Zero dependencies on Phaser, the DOM, the browser, or any rendering framework. The simulation takes inputs (player commands, time deltas) and produces state. The rendering layer reads that state and draws it. The simulation must be liftable into Node.js with no code changes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What this protects:&lt;/strong&gt; headless tests, deterministic replay, future server-authoritative multiplayer, AI agents that can reason about the simulation in isolation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What breaks if you skip it:&lt;/strong&gt; every test that touches the simulation has to spin up Phaser. Every replay has to render. The “model” and the “view” tangle into one ball of mud, and a year from now any change to either one risks breaking the other in a way that wasn’t possible to predict.&lt;/p&gt;
&lt;p&gt;The lint config flags any &lt;code&gt;import&lt;/code&gt; from outside &lt;code&gt;src/sim/&lt;/code&gt; into &lt;code&gt;src/sim/&lt;/code&gt; as a hard violation. PR reviewers — both human and AI — block on it.&lt;/p&gt;
&lt;h2&gt;2. Fixed timestep at 20 Hz&lt;/h2&gt;
&lt;p&gt;The simulation advances exactly 50 milliseconds per tick. The renderer runs at the browser’s framerate (typically 60fps), interpolating between sim ticks for smooth visuals. Variable timestep is forbidden.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What this protects:&lt;/strong&gt; determinism. Same inputs from the same seed produce the same final state, tick for tick.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What breaks if you skip it:&lt;/strong&gt; SimAnt-era games could get away with frame-rate-tied physics because everyone’s hardware ran at roughly the same speed. In 2026, your laptop might render at 144fps and your friend’s tablet at 30fps, and a variable-step simulation produces different worlds on each. Goodbye replay, goodbye multiplayer, goodbye reproducible bugs.&lt;/p&gt;
&lt;p&gt;20 Hz is enough resolution for ant-scale movement and slow enough that the simulation has headroom to do interesting work each tick. The 60fps render layer covers any visual smoothness gap via interpolation.&lt;/p&gt;
&lt;h2&gt;3. Lightweight ECS-flavored architecture&lt;/h2&gt;
&lt;p&gt;Entities are integer IDs. Components are typed arrays (structure-of-arrays for hot data) or plain maps. Systems are pure functions that operate on entities matching certain components.&lt;/p&gt;
&lt;p&gt;No &lt;code&gt;class Ant&lt;/code&gt;. No &lt;code&gt;class Colony&lt;/code&gt;. Data is data; behavior is functions.&lt;/p&gt;
&lt;p&gt;No ECS library in Phase 1 — no &lt;code&gt;bitecs&lt;/code&gt;, no &lt;code&gt;miniplex&lt;/code&gt;. The lightweight approach is migration-compatible if I ever need a real ECS, and the absence of the library means there’s no framework to fight when the architecture wants to evolve.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What this protects:&lt;/strong&gt; cache-friendly hot loops, the ability to serialize the entire world cheaply, and a model that AI agents (and humans coming back to the code six months later) can hold in their heads.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What breaks if you skip it:&lt;/strong&gt; classes accrete behavior. An &lt;code&gt;Ant&lt;/code&gt; class quickly grows methods that touch the colony, the world, the renderer, and audio playback. By the time you notice, you can’t change one without breaking five others. ECS-shaped data avoids that by making the relationships explicit and the data flat.&lt;/p&gt;
&lt;h2&gt;4. Seeded deterministic random number generation&lt;/h2&gt;
&lt;p&gt;The simulation uses a single Mulberry32 PRNG instance, seeded at world creation. Every random decision in the entire game flows through this one instance. The seed is saved with the save file. &lt;code&gt;Math.random()&lt;/code&gt; is banned in &lt;code&gt;src/sim/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What this protects:&lt;/strong&gt; replay. Given a seed and an input log, the world plays back identically every time. That’s how I debug timing bugs, how I write determinism tests, and how multiplayer (Phase 4) becomes feasible at all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What breaks if you skip it:&lt;/strong&gt; subsystems quietly create their own RNGs. A worker’s path-finding uses &lt;code&gt;Math.random&lt;/code&gt;. A larva’s hatching uses &lt;code&gt;Date.now() % 100&lt;/code&gt;. Over a 10-minute round, the divergence between two replays accumulates into completely different worlds. Determinism is binary — you either have it everywhere or you don’t have it at all.&lt;/p&gt;
&lt;h2&gt;5. No wall-clock time in the simulation&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Date&lt;/code&gt;, &lt;code&gt;Date.now()&lt;/code&gt;, &lt;code&gt;performance.now()&lt;/code&gt;, and any other wall-clock APIs are banned in &lt;code&gt;src/sim/&lt;/code&gt;. The simulation knows only its own tick counter. Elapsed simulation time is &lt;code&gt;tickCount * msPerTick&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What this protects:&lt;/strong&gt; identical results regardless of when the simulation runs. A replay started at 3am produces the same world as one started at noon.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What breaks if you skip it:&lt;/strong&gt; subtle bugs that are unreproducible. “Sometimes the queen lays eggs at the wrong rate.” “Sometimes a worker behaves differently.” If wall-clock time is part of the simulation, every “sometimes” is unfixable without rebuilding from first principles.&lt;/p&gt;
&lt;p&gt;This rule is also what makes the game pause-able and step-able. You can call the tick function 100 times in a row in a test and the simulation can’t tell the difference between that and 5 seconds of real time.&lt;/p&gt;
&lt;h2&gt;6. Fixed-point integer math for all simulation quantities&lt;/h2&gt;
&lt;p&gt;Floats are banned in &lt;code&gt;src/sim/&lt;/code&gt;. Positions, velocities, food quantities, pheromone strengths — all integers, with an implicit scale factor (e.g., 1 unit = 1/256 of a tile). Floats are fine in the rendering layer for visual smoothness.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What this protects:&lt;/strong&gt; bit-identical results across platforms. IEEE 754 floating-point math is &lt;em&gt;almost&lt;/em&gt; deterministic across CPUs but not quite — different SIMD paths, different rounding modes, different math libraries on different OSes can produce off-by-one-ULP differences. Over a 10-minute simulation those differences accumulate into divergent worlds.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What breaks if you skip it:&lt;/strong&gt; my replay test passes on my Mac and fails on someone’s Linux box. The “deterministic” multiplayer desyncs after three minutes. The headless Node test runs different than the browser one.&lt;/p&gt;
&lt;p&gt;The cost is that I write &lt;code&gt;addFixed(x, y)&lt;/code&gt; instead of &lt;code&gt;x + y&lt;/code&gt; and the math is mildly less ergonomic. The benefit is that determinism is mechanically guaranteed instead of crossed-fingers hoped-for.&lt;/p&gt;
&lt;h2&gt;7. Snapshot saves with replay logging&lt;/h2&gt;
&lt;p&gt;Save files are JSON snapshots of the world state. In addition, every player input is logged alongside the seed, enabling deterministic replay for debugging and (later) multiplayer. Binary save format is deferred until JSON becomes a real bottleneck (likely never at our scale).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What this protects:&lt;/strong&gt; debugging power, replay-driven QA, and a foundation for multiplayer where the network layer just shuttles input logs around.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What breaks if you skip it:&lt;/strong&gt; debugging colony behavior is guesswork. “It happened around minute three” is the bug report; without replay you can’t reproduce it. With replay, you reload the seed plus input log and watch the same bug happen, every time.&lt;/p&gt;
&lt;p&gt;JSON also means saves are inspectable. I can grep them, diff two save states, and write tools against them without writing a binary parser first.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Why these are non-negotiable&lt;/h2&gt;
&lt;p&gt;Each of these rules is annoying at the moment you write the code. Fixed-point math is annoying. Banning &lt;code&gt;Date.now()&lt;/code&gt; is annoying. Refusing to import Phaser into &lt;code&gt;src/sim/&lt;/code&gt; is annoying. Each of them, individually, you could relax for “just this one case.”&lt;/p&gt;
&lt;p&gt;You can’t, though. Determinism is a system property, not a per-feature one. The day you let one float sneak into the sim, the property is gone, and you find out three months later when the multiplayer prototype desyncs and you can’t tell which subsystem to blame.&lt;/p&gt;
&lt;p&gt;The seven principles together are a contract. They’re enforced via lint rules, PR review (one human, two AI agents — that’s a &lt;a href=&quot;/experiment&quot;&gt;whole separate post&lt;/a&gt; about the dual-reviewer setup), and architectural tripwires that fail CI when they’re violated. The cost is paid up front, in friction. The benefit is paid out continuously, in things working the way you’d expect.&lt;/p&gt;
&lt;p&gt;If you’re building anything where determinism matters — a game, a simulation, a deterministic-replay debugger, a multiplayer system — the specific rules will look different than these, but the shape is the same. Pick the properties you can’t compromise on. Make them mechanically enforceable. Refuse to relax them when it’s convenient.&lt;/p&gt;
&lt;p&gt;That’s the whole thing.&lt;/p&gt;</content:encoded></item><item><title>Why Subterrans</title><link>https://subterrans.com/devlog/why-subterrans/</link><guid isPermaLink="true">https://subterrans.com/devlog/why-subterrans/</guid><description>What SimAnt was, what&apos;s missing in 2026, and what Subterrans actually commits to building.</description><pubDate>Wed, 22 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;(Editor’s note, 2026-05-17: Phase numbering has been updated since this post was published. See the &lt;a href=&quot;/roadmap&quot;&gt;current roadmap&lt;/a&gt; for the active phase structure.)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In 1991, Maxis released SimAnt. It put you in charge of a black ant colony in a suburban backyard, fighting a red colony for territory and eventually invading the house. You could zoom into a single ant and play it directly, or pull back and command the colony as a whole. Pheromone trails. Foraging. Larvae. A queen to protect.&lt;/p&gt;
&lt;p&gt;I played a lot of SimAnt. So did a lot of people. Then it disappeared into the shelf where Maxis kept the games that didn’t become franchises, and nothing has really filled that gap since.&lt;/p&gt;
&lt;p&gt;There are good ant-themed games — &lt;em&gt;Empires of the Undergrowth&lt;/em&gt; is excellent, &lt;em&gt;Ants Took My Eyeball&lt;/em&gt; is strange and great — but none of them are the SimAnt-shaped game. The thing where you’re managing a colony as a system, not commanding individual units, where pheromone fields propagate independently of the ants on them, where the enemy colony is running the same code you are.&lt;/p&gt;
&lt;p&gt;Subterrans is an attempt to build that game. It’s a spiritual successor, not a remake. Same shape, modern foundations.&lt;/p&gt;
&lt;h2&gt;What’s actually different&lt;/h2&gt;
&lt;p&gt;Three things, mostly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;First, it runs in a browser.&lt;/strong&gt; SimAnt shipped on floppies. Subterrans Phase 1 is a single static page on subterrans.com. Native builds for iOS, Android, Steam, and desktop come later, but the web is the primary target. That’s a deliberate constraint — if I can’t get the loop fun in 2D inside a browser tab, I shouldn’t be building anything bigger.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Second, the simulation is a first-class architectural object.&lt;/strong&gt; In SimAnt, the simulation and the rendering were inseparable — that was just how games were built in 1991. In Subterrans, &lt;code&gt;src/sim/&lt;/code&gt; is pure TypeScript. No DOM, no Phaser, no &lt;code&gt;Date.now()&lt;/code&gt;, no floats. Everything is integers, fixed timestep at 20 Hz, single seeded PRNG. The renderer reads state and draws it; the simulation doesn’t know the renderer exists.&lt;/p&gt;
&lt;p&gt;That’s not architectural showing-off. It’s the only way I get deterministic replay, future multiplayer, and AI agents that can actually reason about the code. More on that in &lt;a href=&quot;/devlog/the-seven-principles&quot;&gt;the seven principles post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Third, this is also an experiment in AI-agent development.&lt;/strong&gt; Most of the code is being written by Claude Code and Codex working from planning artifacts I write. The architectural rigor above isn’t separate from that — it’s how I get AI agents to produce code that doesn’t drift. Every PR gets reviewed by both agents independently. Lint rules enforce the architectural boundaries. The planning workflow is its own discipline.&lt;/p&gt;
&lt;p&gt;I’ll write more about that elsewhere. The short version: I want to know how much of a real game one person can ship if they treat AI agents as collaborators with very specific failure modes, and design the project around those failure modes rather than ignoring them.&lt;/p&gt;
&lt;h2&gt;What Phase 1 actually is&lt;/h2&gt;
&lt;p&gt;Phase 1 answers exactly one question: &lt;strong&gt;is the core colony management loop fun?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not “is the art good.” Not “is there a tutorial.” Not “are there ten enemy types.” The minimum thing that’s recognizably &lt;em&gt;SimAnt-shaped&lt;/em&gt; is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Your colony has a queen, workers, larvae, and food storage&lt;/li&gt;
&lt;li&gt;You designate tunnels to dig; workers dig them&lt;/li&gt;
&lt;li&gt;You assign chamber types (queen chamber, nursery, food storage); ants behave accordingly&lt;/li&gt;
&lt;li&gt;You toggle between surface view and underground cross-section&lt;/li&gt;
&lt;li&gt;Workers find food on the surface and bring it home&lt;/li&gt;
&lt;li&gt;Pheromone trails form and decay&lt;/li&gt;
&lt;li&gt;You set behavior priorities (forage / dig / defend / idle)&lt;/li&gt;
&lt;li&gt;One enemy AI colony runs the same simulation systems you do&lt;/li&gt;
&lt;li&gt;Win condition: kill the enemy queen. Lose condition: they kill yours.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That’s it. That’s the whole thing. A round takes 5 to 15 minutes. You play it, and either you want to play another round or you don’t.&lt;/p&gt;
&lt;p&gt;If the answer is “yes” — Phase 2 starts adding depth. Multiple castes. Real pixel art. Sound. The Yellow Ant, where you can drop into a single individual SimAnt-style. Multiple patches. A day/night cycle.&lt;/p&gt;
&lt;p&gt;If the answer is “no” — no amount of art, sound, tutorials, or content saves it. You go fix the core loop or you stop.&lt;/p&gt;
&lt;h2&gt;What I’m explicitly &lt;em&gt;not&lt;/em&gt; doing in Phase 1&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Pixel art. Phase 1 is programmer art — circles and rectangles. Real art begins after the loop is validated.&lt;/li&gt;
&lt;li&gt;Sound and music. Same reason.&lt;/li&gt;
&lt;li&gt;Tutorial system. There’s a one-page text explanation.&lt;/li&gt;
&lt;li&gt;Settings menus, save/load UI, main menu. The game boots straight into a hardcoded scenario and autosaves to localStorage.&lt;/li&gt;
&lt;li&gt;Multiple enemy types, multiple ant castes, weather, the Yellow Ant, the human invasion, mating flights. All deferred to later phases.&lt;/li&gt;
&lt;li&gt;Multiplayer. The architecture preserves the option (deterministic simulation, replay logging) but Phase 1 is single-player only.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each of these has a reason. The collective reason is the same: scope discipline. SimAnt was made by a bigger team than me, and they were doing it as their day job. I’m one person with AI collaborators. The way that math works is that I have to cut hard until the thing I’m building is small enough to be &lt;em&gt;good&lt;/em&gt;, then expand from there.&lt;/p&gt;
&lt;h2&gt;Where this is now&lt;/h2&gt;
&lt;p&gt;The site you’re reading just came online. The game itself has a working simulation skeleton — fixed timestep, deterministic RNG, the seven principles enforced via lint — and is currently mid-Phase 1 buildout. There’s no playable demo yet. There will be, behind a sign-up gate, and you’ll see it land in the &lt;a href=&quot;/roadmap&quot;&gt;roadmap&lt;/a&gt; when it does.&lt;/p&gt;
&lt;p&gt;I’ll keep posting here. No cadence promises — when something worth reading happens, you’ll see it.&lt;/p&gt;</content:encoded></item></channel></rss>