ORION

v0.27.1 · free · MIT

ORION

A StarCraft-style RTS built from scratch in Rust

  • deterministic lockstep sim
  • procedural pixel art and audio
  • two asymmetric races
  • ranked online multiplayer

No game engine — a purpose-built deterministic simulation with a wgpu isometric renderer. Three asymmetric races with heroes, skirmish AI, ranked online multiplayer, a map editor, and shareable replays. All art and audio are procedurally generated at startup: zero asset files.

Download

v0.27.1 · Aug 11, 2026 — precompiled, nothing to install. All releases · build from source

macOS (Apple Silicon + Intel)

Orion-macOS.zip

Unzip → double-click Orion.app. First launch only: right-click → Open (it isn't notarized)

Downloadv0.27.1 · 10.4 MB

Windows 10/11

orion-windows-x86_64.zip

Unzip → double-click orion.exe. If SmartScreen objects: More info → Run anyway

Downloadv0.27.1 · 4.9 MB

Linux (x86_64)

orion-linux-x86_64.tar.gz

tar xzf && ./orion (needs Vulkan drivers + ALSA libasound2)

Downloadv0.27.1 · 6.1 MB

Changelog

Read live from the project wiki.

v0.27.1The Caverns seat bugCaverns seat-bias patch: entombed-worker expel, bot builder watchdog, mirror-covariant tie-breaks — seat mirrors even again

A patch release for a real competitive bug: on Caverns, the player-1 seat was winning bot mirror matches about 8–0. Same race, same difficulty, same map — the seat decided the game. Found by pointing the mirror-covariance probe at Caverns (it now takes a map name), fixed by hunting the chain to its end.

What was actually happening

1. When a building finished (or started) it stamped its footprint into the blocked grid — sealing in any unit standing there. A worker walking the mining lane at the wrong moment ended up inside a depot, where no flow field could ever reach it. It never moved again. 2. The bot's macro has a gate: one construction at a time, and a busy builder blocks new orders. When the bot picked the entombed worker as its next builder, that gate froze the entire macro forever — no more depots, supply-capped at 36, thousands of minerals floating, army starved. The seat geometry of Caverns made this hit one seat far more often than the other. 3. Two smaller asymmetries stacked on top: perfectly coincident units were always pushed east (+x) to separate them, and the nearest-open-tile scan used a fixed raster order — both break the 180-degree symmetry the maps are built around.

The fixes

  • Units sealed under a new footprint are expelled to the nearest open tile — the root cure; an entombed unit can no longer exist.
  • The bot gained a stuck-builder watchdog (a builder still traveling after 15 s with nothing under construction gets stopped), a bad-site blacklist, and a reachability check before committing a builder to a site — so no single confused worker can deadlock a macro again, on any map.
  • The coincident-unit push and the nearest-open-tile scan are now mirror-covariant (away-from-center axis push; rotation-invariant ring ordering), removing the systematic eastward drift.

Measured result (Caverns, Hard, 8 seeds per matchup): mirror matches went from P1 winning 7–0 / 8–0 to even splits.

Full post-fix sweep (all Hard, 8 seeds): mirrors VC 3–3, Kyth 4–4, Ferron 3–5. The cross-race totals on Caverns now read VC 7 / Kyth 18 / Ferron 22 — the old numbers were seat-noise, and with the trooper trim in, VC looks weak on this map specifically (meridian reads VC 20 / 16 / 10). Map-by-map race spread goes on the watchlist; this patch is about seat fairness, and that box is ticked.

Sim behavior changed, so this is a protocol bump: 0.27.1 clients can't play 0.27.0 peers — update both sides.

Still open

The mirror probe still reports a residual ulp-level drift divergence at ~90 s on every map (present at least since v0.17.1 — fixed-point Mul truncation under mirrored normalization). It is chaotic, not directional: sweep mirrors stay even, so it doesn't bias games. Full covariance remains a long-term project; seat fairness is verified by sweep mirrors, which is the metric that matters.

v0.27.0The campaignThe mini-campaign: five scripted missions (play all three races, survive missions, a 2v2 finale with Marshal Kade) + trooper trim from the meridian taste pass

Five scripted missions, a story to play through, and a measured trim to the Vanguard's edge.

The campaign page — missions unlock in order

The mini-campaign

CAMPAIGN on the main menu. Five missions, unlocked in order, progress saved between sessions:

1. BROKEN DAWN — rebuild a broken mining line on Meridian and burn out a Kyth warren camp, under scripted skitter raids timed to hit while you're mustering. 2. HOLD THE LINE — the Ferron Compact comes for the Causeway with a war chest. Keep your headquarters standing for eight minutes; the objective panel counts down live. 3. THE ASSEMBLY — play as the Kyth for the first time. Swarm cheap, swarm fast. 4. IRON COMPACT — play as the Ferron on Thornwood: arclight lines, high ground, trees in the sightlines. 5. MERIDIAN'S END — the finale on Crossfire: a 2v2 with an allied commander at your side and Marshal Kade at the front.

Broken Dawn, objective 1 of 3

Missions are built on the tutorial's machinery: objectives are drawn in a gold mission panel, raids arrive through the same command channel as everything else, and the other seats are driven by real bots — the same brains you skirmish against, at mission-tuned difficulties. Mission replays are off (scripted events aren't part of a command stream).

For the beaten path there's a headless QA harness too: --mission-auto K plays mission K with a Hard bot standing in for you — missions 1–4 all resolve in victory; the finale's bot-vs-bot stand-in stalemates (three Normal bots counter-punch each other forever), which is exactly the hole Marshal Kade and a human plan are for.

Balance

Trooper cooldown 0.86s → 0.90s (−4.4% sustained damage).

The measured story (all Hard, 8 seeds per matchup, meridian): VC took the cross-race total 23–15–10, beating Kyth 13–3 and Ferron 10–6 — and the combat lab (new VC-vs-Kyth and Ferron-vs-Kyth fixtures in combat_lab) shows cost-matched Kyth ground cores getting wiped by trooper lines even with the lab's first-mover advantage. The trooper is the one unit in every VC composition, so it takes the trim; Kyth and Ferron numbers are untouched (Kyth already beats Ferron 12–4 there — a Kyth buff would have widened that).

After the change (same seeds): total 20–16–10, VC-vs-Kyth 12–4, VC-vs-Ferron 8–6. A modest shave, which is the intent — 8-seed sweeps are noisy and this number is the one in every VC composition. VC still leads against Kyth on meridian; that gap stays on the watchlist rather than getting a second speculative change stacked on top.

One-line revert if it plays badly: trooper cooldown_s: 0.90 → 0.86.

Also in this release

  • The mirror-covariance probe (examples/mirror.rs) now takes a map name. Pointed at Caverns it found a real seat bias (P1 wins mirror matches ~8-0): a non-mirror-covariant tie-break when two units land exactly coincident. Filed for the next patch — Caverns ladder games are affected today.
  • Room-host handshake code cleanup (no behavior change).
v0.26.0Observer modeObserver mode: watch live duels and 2v2 rooms through the relay — free camera, TAB fog perspectives, checksum-verified view

Watch live matches. Any lobby or 2v2 room can now be observed through the relay — silently, from the outside, with the full picture.

Observing a live 2v2 — revealed map, four corner bases on the minimap

Watching a match

Type a code on the multiplayer page and pick WATCH THIS CODE (shown under PRIVATE CODE). You'll drop into the match the moment it starts: map revealed, free camera, no seat of your own. TAB cycles the fog perspective — each player's own view, then ALL. Works for duels and 2v2 rooms alike, custom maps included; up to eight observers per match.

Observers are invisible to the players: they receive the game but send nothing, and joining or leaving mid-match disturbs no one.

How it works

  • The relay gained a third role: obs connections tap the room's broadcast without taking a seat. The match tears them down when it ends.
  • The observer client never handshakes — it watches the players' handshake fly by (Start/Start2, then Go) and builds the same deterministic sim from their tagged command streams, stepping each tick as soon as every seat's commands have arrived.
  • Trust, but verify: the players exchange periodic state checksums; the observer checks its own sim against them, so a diverged view is flagged (OBSERVER DESYNC) instead of silently lying.
  • Replay fog cycling is now sized to the player count, so 4-player room replays (new in v0.25.0) cycle all four perspectives too.
  • E2E-verified live: a duel and a bot-filled Crossfire room were both observed past tick 190 with checksums matching (--mp-auto obs:CODE, plus ORION_OBS_SHOT for visual proof).

Observing is desktop-only for now — the browser client doesn't speak the passive handshake yet.

Balance

No unit numbers changed.

v0.25.02v2 everywhere2v2 everywhere: bots fill empty seats, public rooms with live fill counts, room replays (teams + embedded maps), browser room joins

The polish pass on team games: everything v0.24.0 said "not yet" about 2v2, except ranked. Rooms are now listed publicly, start on demand with bot fill, record replays, and can be joined from the browser.

A public 2v2 room in the lobby browser

Bots fill empty seats

The room waiting page has a new row: START NOW — BOTS FILL EMPTY SEATS. Two friends no longer need two more friends — start with any number of humans and Hard bots take the remaining seats.

Under the hood the host drives the bot brains and feeds their commands through the exact same lockstep channel as its own input, so joiners need zero new code — a bot seat looks like any other player's tagged command stream. Which seats are bots rides in the start handshake, and bot races are dealt from the match seed.

Public rooms in the lobby browser

CREATE 2V2 ROOM now lists your room publicly (same as duel lobbies — private rooms by code still work). Rooms appear as JOIN 2V2 <name> 1/4 with a live fill count: the relay re-announces the room as seats fill and delists it when it's full or anyone leaves. One click seats you.

Browser room joins

A 2v2 room played from the browser — Kyth main on Crossfire

The web build speaks the room handshake. Type a room code (or click a listed room) in the browser and you're seated — the join path auto-detects duel vs room from the relay's seat frame, identically on desktop and web. Custom 4-start maps work too: the map itself travels inside the handshake, so the browser needs no file.

Hosting rooms stays desktop-only for now (the host runs the fill bots).

Room replays

Replays now record teams, and games on custom maps embed the map itself in the replay file — so a 2v2 on an editor-made map plays back anywhere, shared with anyone. Room games record automatically, like every other match. Old replay files load unchanged.

Under the hood

  • The wasm relay pump gained the room phases (seat frame → Hello2 → Start2 → Go), sharing the native handshake's shape; the duel path is untouched.
  • The relay directory upserts a room's entry on every join until it fills, keeping filled/slots live in /lobbies.
  • A new sim test replays a 2v2 on an embedded custom map and asserts the resimulated checksum matches the live game bit-for-bit.
  • Verified end to end: a native host + headless-Chrome joiner played Crossfire in lockstep past tick 240 with two host-driven bots, no desync — and the protocol version gate correctly refused a stale 0.24.0 web build during testing.

Balance

No unit numbers changed.

v0.24.02v22v2: four-seat relay rooms, team vision/victory/colors, N-player lockstep, and Crossfire — the four-corner team map

Team games. The biggest multiplayer feature since ranked, built in three verified layers.

Crossfire — the 2v2 map

Playing it

CREATE 2V2 ROOM on the multiplayer page gives you a 5-letter code for a four-seat room; the match auto-starts the moment it fills. Teams are seat pairs: the host and the first joiner against the other two. Joining needs nothing new — type any code into PRIVATE CODE and the game detects whether it's a duel or a room.

Crossfire is the 2v2 map: four corner mains where allies share a side of the map, mirrored contested expansions on the flanks, and ambush groves shaping the open center. The two teams occupy exactly mirrored ground (the symmetry checker now validates team maps). Editor-made 4-start maps work in rooms too — the map still travels inside the handshake.

Teammates share vision, can't be hit by your auto-attacks, benefit from your shield auras and heals, and share your team's color. Victory is by team: the game ends when one side has no standing players.

Under the hood

  • The relay's lobby became a slotted room (host + up to three seats, broadcast forwarding, seat assignment by control frame). 1v1 lobbies are byte-identical to before.
  • The lockstep driver now runs N tagged command streams and steps only when every seat's tick has arrived; the host sizes the shared input delay to the WORST seat's measured RTT.
  • Verified end to end: four processes through the live relay on crossfire — 240 lockstep ticks, matched checksums on every seat. Plus a four-peer in-process lockstep test and three team-mechanics tests in the sim suite.

Not yet: public room listing, ranked 2v2, browser-side room joins, bots filling empty seats, room replays.

Balance

No unit numbers changed.

v0.23.0Sudden death + a measured balance passBot sudden death (thornwood stalls fixed, games end) + measured balance pass: Breaker siege 40->36, Mauler 100->110

A gameplay batch: bot games now end, and the two most lopsided numbers in the game moved — with before/after measurements for all of it.

Bots: sudden death at 15 minutes

Two turtling bots on a multi-base map could rebuild faster than they killed — thornwood Hard mirrors mostly ran out the 20-minute clock. Past 15 minutes a bot now closes the macro tap: no new construction, no replacement workers. Armies decide the game instead of economies.

Thornwood Hard went from "mostly stalls" to two-thirds of games resolving — and with games actually ending, the map turned out to be nearly balanced (VC 9 / Kyth 11 / Ferron 9 in the round-robin).

Balance: two numbers, measured

Hard-bot round-robins, 8 seeds per matchup, before → after:

  • Breaker siege damage 40 → 36. The deployed tank's splash is the single biggest fight-winner in the game (the combat lab shows massed fights swinging entirely on it). Trimmed 10%.
  • Mauler hp 100 → 110. Ferron's mineral-only front line dies first in every open-field trade; one more volley of survival.

Results: meridian VC-vs-Ferron narrowed 12-4 → 10-6; causeway was already close (VC 16 / Kyth 10 / Ferron 12) and thornwood stayed even. Meridian still leans VC — especially against Kyth — and that's flagged for a taste pass with a human in the loop rather than deeper solo tuning. Soak: 24 games, zero invariant violations, all determinism shadows clean.

Also in this release

  • --menu-shot tutorial3: / tutorial4: step-jump captures for verifying tutorial hint rendering.
v0.22.0The tutorialThe tutorial: a guided first game — seven objectives over a normal botless match, browser build included; v0.22.1: build grid puts HQ last, hints derive from live keybinds

With the repo public and the game playable in a browser tab, strangers now land in Orion with zero context. The new TUTORIAL (top of the main menu, browser build included) turns that first five minutes into a guided game.

Tutorial opening

How it plays

Seven objectives, one at a time, in a gold-framed panel that stays out of the way:

1. Look around — pan the camera 2. Select your Fabricators — box-select the workers 3. Put them to work — right-click the crystals 4. Build a Supply Pylon — the build grid (B, then Q) 5. Build a Muster Hall — army production 6. Train 4 Troopers — queueing 7. Destroy the outpost — attack-move into a small Kyth camp mid-map

Completions chime and flash; razing the outpost triggers the normal victory screen. There is no fail state — no bot thinks during the tutorial, and the two Skitters guarding the camp only fight back.

Why it's built this way

The tutorial is a thin objectives layer over a completely normal single-player game — same sim, same commands, same HUD. Nothing is simulated differently, so every habit learned transfers 1:1 to skirmish and multiplayer. Practice runs don't record replays.

Objective predicates are unit-tested against the real sim (including the subtlety that mineral patches have limited mining slots).

Balance

No gameplay changes.

v0.22.1 — tutorial hotfix (thanks, first playtester)

The very first real tutorial run found it: "B then Q" placed a 400-mineral HQ, because the build grid was raw data order and the headquarters happened to be first. The pylon objective never advanced.

  • The build grid now puts the HQ last for every race — the first key a new player reaches raises supply, not an expansion.
  • Tutorial build hints are generated from the live build grid and your actual keybinds, so they can never drift from reality again.
  • The keybind screen's per-building "PLACE ..." labels (wrong per race and per order) became honest BUILD SLOT 1–7.
v0.21.0Custom maps online + map sharing by codeCustom maps in multiplayer (the map travels in the handshake — browser peers too) + map sharing by 5-letter code

The map editor stops being a single-player toy. Two changes, one theme: maps made in the editor now travel.

Custom maps in multiplayer

Host a lobby on any editor-made map — the joiner needs nothing. The map itself rides inside the match handshake, so the other player (desktop or browser) receives it in-band and both sides simulate the exact same terrain. No downloads, no version drift: verified end-to-end on the live relay with a native host and a headless-browser joiner playing 240 lockstep ticks on a custom map with matching checksums.

Share maps with a 5-letter code

Map code row on the difficulty page

  • In the editor, press U to upload your map — you get a code like PNKLJ in the status line.
  • On the PLAY VS AI page, type a code into the MAP CODE row — the map lands in ~/.orion-maps, appears in the picker (with its terrain preview), and is selected for the next game. From there it hosts online like any other map.

Shared maps live in the same relay locker as shared replays: 120 KB cap, 300 entries, 30-day shelf life.

Under the hood

The relay's per-message cap rose from 16 KB to 160 KB so the handshake frame can carry a map; abuse is still bounded by the per-connection byte budget and rate limits. A new dumpmap example serializes builtin maps as fixtures for testing the pipeline.

Balance

No gameplay changes.

v0.20.0Replay links: watch shared games in the browserReplay links: ?replay=CODE plays a shared game from a URL; v0.20.1: browser brightness/sound/disconnect fixes from the first real web playtest

v0.18.0 made replays shareable by code; now the code is all anyone needs. The web build's FETCH CODE row downloads a shared replay from the relay vault and plays it on the spot — no files, no install. Even better, replays are now linkable:

https://<demo-host>/index.html?replay=KRCAP

opens the demo and plays that shared game directly.

A shared replay playing in the browser

This capture is a fully headless Chrome given only a ?replay= URL: it fetched the replay from the live vault and rendered playback, controls and all.

What changed

  • start_replay split into a file loader (desktop) and an in-memory starter — the browser feeds fetched RON straight into playback.
  • The FETCH CODE row now appears in the web build's REPLAYS page; SHARE stays desktop-only (uploading needs local files).
  • ?replay=CODE boots straight into playback of a shared replay.
  • The vault's GET responses carry CORS headers so browser pages can read them.

Balance

No gameplay changes.

v0.20.1 — browser playtest fixes

Five reports from the first real two-player browser session, all fixed:

Correct browser brightness

  • It was far too dark: WebGPU canvases only accept non-sRGB surface formats, so the renderer's linear output was displayed raw. Frames now render through an sRGB view format — the browser finally matches the desktop look (screenshot above is the fixed web build).
  • "It crashed when my opponent left": it actually froze — the wasm transport's leaked pump closure kept channel ends alive, so the lockstep never learned the peer was gone and waited forever. Session shutdown now drops the channels; you get the OPPONENT DISCONNECTED banner and can leave to the menu. Reproduced and verified with a headless-Chrome match whose opponent quits at tick 240.
  • No sound: the web build never had an audio backend. It does now (WebAudio), initialized on your first click — browsers refuse audio before a user gesture.
  • FIND MATCH did nothing: ranked needs the desktop build; the web build now says so instead of dangling a dead button.
  • QUIT froze the tab: there is no process to quit in a browser — the button is hidden on the web.

Also new: ?host=CODE / ?join=CODE URL hooks, so a headless browser can play real relay matches — that's the harness that caught the disconnect bug.

v0.19.0The browser build joins the lobby listBrowser build lists and joins public lobbies (CORS + wasm fetch); headless-Chrome page hooks for web UI verification

The web demo can now see and join public lobbies — the same live list desktop players use. Until now a browser player could only join by private code; now the MULTIPLAYER page fills with click-to-join rows, polled from the relay every 3 seconds.

Browser lobby list

That screenshot is a fully headless Chrome running the game on WebGPU — the JOIN row is a real lobby hosted by a desktop client at capture time.

What changed

  • relay_wasm grew a real lobby-list fetch (browser fetch → JSON → the same channel shape the native thread version uses), and the relay's JSON endpoints now answer with CORS allow-origin: * so browser pages may read them.
  • Joining a listed lobby reuses the proven WebSocket session path from v0.16.0's code lobbies.
  • A backgrounded multiplayer page keeps its list fresh through the hidden-tab keep-alive, so it isn't stale the moment you tab back.
  • Testability: ?page=mp (also replays, difficulty) boots the web build straight into that menu page. Combined with headless Chrome's WebGPU support this gives one-command screenshot verification of web UI — it's how the CORS gap was found and confirmed against the live relay.

Ranked queue and replay sharing remain desktop-only.

Balance

No gameplay changes.

v0.18.0Replay sharing by codeReplay sharing by code: upload a replay to the relay, hand out a 5-letter code, it lands in the other player's list

Replays could already be saved and rewatched (since v0.3.0) — now they travel. Share one and you get a 5-letter code; anyone can type that code into their REPLAYS page and the game lands in their list, ready to watch.

Replay sharing

How it works

  • SHARE A REPLAY — GET A CODE arms share mode: click any replay in the list and it uploads to the relay, which answers with a code shown at the top of the page.
  • FETCH CODE: type a code (Enter or click) and the shared replay downloads straight into your list as shared-<CODE>.
  • Codes use an unambiguous alphabet (no I or O). Shared replays live on the relay for 30 days, capped at 120 KB per replay and 300 replays total (oldest evicted) — a courtesy locker, not an archive.
  • The transport is the same Cloudflare relay that runs lobbies and ranked play; a new Vault Durable Object stores the files, behind the same per-IP rate limits as the lobby list.
  • Desktop builds only for now — the web demo hides the rows.

Verification

Live end-to-end on the deployed relay: a 63 KB replay uploads, comes back bit-identical by code, bad codes 404, junk uploads are rejected, and oversized uploads are refused. Full test suite, smoke and scripted game stay green.

Balance

No gameplay changes.

v0.17.0Causeway + map previewsCauseway: 4th map around a contested land bridge with breachable rock ramps; live map-preview thumbnails in the SP/MP pickers; v0.17.1: demand-driven bot gas, bots research upgrades, summon spawn safety

A fourth built-in map, and you can finally see what you're picking.

Causeway (new map)

Causeway overview

88×88. A raised land bridge spans the middle of the map and carries two contested expansions — hold your half of the causeway and you hold the gas that pays for your third base. Mains sit on NW/SE cliff plateaus with a single ramp; naturals hug the low west/east walls.

The twist is in the ramps: each causeway third has an open flank ramp on one side and a rock-sealed breach ramp on the other. The side that's easy for the defender to reinforce is the side the attacker can't use — until they knock the rocks down and pour in from the blind side.

The breach

Wide low-ground flanks circle the whole bridge, dotted with ambush groves. Siege units parked on the causeway overlook both flanks; flyers ignore the whole geometry, as always.

Verification: 180°-rotation symmetric (symmetry example), 9-game soak slice clean — zero invariant violations, determinism shadows clean, and fewer bot stalls than caverns or thornwood. Hard-bot balance round on causeway shows no meaningful spawn-side bias in mirrors; the known VC-over-Ferron lean shows up here too and stays on the watch list as a race-balance item, not a map item.

Map previews in the pickers

Map preview

The MAP row in the single-player and multiplayer menus now shows a live terrain thumbnail beside the panel — minimap palette, mineral/geyser dots, start markers — for built-in and custom (editor-made) maps. No more picking blind.

Balance

No unit or economy numbers changed. Causeway's economy: mains 1250/patch, naturals and causeway thirds 1000/patch, all geysers 2500.

v0.17.1 — smarter bot macro, safer summons

  • Demand-driven gas: bots pull workers off gas when it banks with nothing spending it, and restaff when the bank drains. Found via the new probe_race timeline: Ferron was hoarding 1300+ gas at 50 minerals and fielding half of VC's army. Meridian Hard round-robin moved from VC 27 / Kyth 14 / Ferron 6 to 25 / 15 / 8; VC-vs-Ferron from 15-1 to 12-4 — better, still on the watch list.
  • Bots buy upgrades: Normal and Hard bots now build their research lab and purchase weapon/armor tiers from genuine surplus.
  • Summon safety: Spawn Brood lands its broodlings on open ground — one wedged inside a cliff for its whole lifetime (caught by soak QA). The spawn circle also dropped its f32 sin/cos for integer offsets, removing a latent cross-platform desync risk now that browser peers play against native ones.
  • New diagnosis tools shipped in-tree: combat_lab (equal-cost clump fights, seat-bias aware) and probe_race (30-second macro timeline).
v0.16.0Browser multiplayerBrowser multiplayer: code lobbies + cross-play with desktop through the live relay, localStorage settings, hidden-tab keep-alive

The web demo grew its missing half: online play now works from the browser. A browser player can host or join private code lobbies on the same live relay the desktop builds use — browser vs desktop cross-play included, since both sides speak the identical lockstep protocol.

Multiplayer menu

What's new

  • Browser code lobbies: CREATE PRIVATE LOBBY / PRIVATE CODE work in the web build. The wasm client carries a real WebSocket transport — the same newline-framed RON handshake (Hello → Start → Ping/Pong RTT probe → Go) the desktop client uses, driven by a 16 ms pump instead of blocking threads. The Lockstep engine is shared, untouched.
  • Settings persist in the browser via localStorage — name, race, hotkeys and HUD scale survive a reload.
  • Hidden-tab protection: Chrome fully stops requestAnimationFrame and clamps timers to ~1 Hz for pages you can't see. Without help, a browser player who tabs away would freeze the match for the opponent (their half of the lockstep just stops). A background keep-alive now nudges the game loop through the winit event-loop proxy while the page is hidden, so a backgrounded browser peer degrades to a slow game instead of a frozen one — the PING/PIPE/STALLS readout shows it.
  • Version gate works cross-play: a stale web bundle against a newer desktop build gets the same "both players must update" refusal as desktop mismatches (confirmed live, by accident).

Testing / infrastructure

  • --mp-auto test runs now open a small 480×300 corner window — never fullscreen, no audio, no settings writes. (A fullscreen test window popping over the desktop gets closed by whoever is at the machine, which read as a mystery disconnect in the logs for most of a morning.)
  • If an automated MP window is closed by hand, the run now says so (mp-auto: window closed by user) instead of exiting silently.
  • Heartbeat diagnostics on both sides: the browser logs pump/game-loop health to the console; --mp-auto runs print the same to stderr.

Still desktop-only

Ranked queue, the public lobby browser and replays stay desktop-only for now — the browser build's next milestones.

Balance

No balance or sim changes; determinism unaffected.

v0.15.0Feel polish + the experimental web portSmooth unit turning, idle-worker alert chip, per-ability cast sounds; v0.15.1: THE GAME RUNS IN THE BROWSER (WebGPU, ~70 FPS)
  • Smooth turning: units sweep toward their heading instead of snapping between the 8 facings — heavies turn slow, flyers bank, infantry stays snappy. Render-side only; the sim is untouched.
  • Idle-worker chip: a pulsing alert under the clock whenever harvesters stand around. Click it (or F1) to jump to one.
  • Ability voices: every hero cast now sounds like itself — barrage booms, corrosive/brood thwip, magnetic well twangs, overload cracks, Overcharge chimes.
  • Experimental WASM port (in-tree, not shipped): the whole game compiles for the browser and boots to full init on WebGPU — the deterministic sim needed zero changes. Frame presentation is the one remaining gap; web/README.md has the build steps and suspects.

v0.15.1 — the web demo works

Orion now runs in the browser: menus, single-player vs the bot, the map editor — ~70 FPS on WebGPU in Chrome. The orion-web-demo.zip release asset contains the bundle (unzip, python3 serve.py, open localhost:8765). Online play and persistence are desktop-only for now; web/README.md documents the port and the follow-ups.

v0.14.0The Map EditorVisual map editor with auto-mirrored painting, custom maps in the SP picker

A visual map editor, in the client, from the main menu.

  • Paint low/high ground, impassable rock, ramps, destructible trees and rock walls, mineral patches, geysers, expansion markers and the player starts, with a 1–4 tile brush.
  • Auto-mirroring: every stroke lands on both halves of the map (footprint-aware for geysers and expansion sites), so anything you build satisfies the same 180-degree symmetry fairness rule as the shipped maps. It is impossible to paint an unfair map.
  • S saves to ~/.orion-maps/ — saved maps appear in the map picker for single-player. P play-tests immediately against a Normal bot (after a quick validation: starts placed, minerals near them). ESC autosaves and returns to the menu; your work is restored next time.
  • The canvas renders through the real game renderer — what you paint is exactly what plays, glow, fog and all.
  • Custom maps are single-player for now: creating an online lobby on one is refused with a clear message (the joiner wouldn't have the file). Map sharing is a natural follow-up.

Map editor

v0.13.0HeroesHeroes: Marshal Kade, Broodmother Sszrak, Magnus Vex — two abilities each, bot support, deterministic zones/summons

One hero per faction: unique (one alive at a time), trained from your tier-0 hall behind the faction's tech building, 150/100 and 4 supply, with an energy pool and two abilities on F and G.

  • Marshal Kade (Vanguard) — caped banner-bearer with a heavy AA gun. Barrage (F): aimed artillery zone, heavy amber shelling. Overcharge (G): instant group heal around him.
  • Broodmother Sszrak (Kyth) — egg-swollen brood queen. Spawn Brood (F): four broodlings that fight for 15 seconds and dissolve. Corrosive Cloud (G): aimed lingering acid zone.
  • Magnus Vex (Ferron) — coil titan with a magnet hammer. Magnetic Well (F): aimed zone that physically drags ground units toward its center — feed it to Lodestone splash. Overload (G): instant burn around himself.

Zones are aimed with a click (same flow as Plasma Storm) and render tinted — amber shelling, green acid, violet well with debris spiraling in. Bots build their hero mid-game and use both ability slots. All of it is deterministic and checksummed: zone kinds, summon lifetimes, the well's pull. Five new sim tests pin every ability kind plus hero uniqueness.

Heroes in the field Broodlings

Balance starting point: heroes are strong mid-game spikes, not army replacements — watch the round-robin as always.

v0.12.0Smarter bots, heavier Ferron, honest netcode numbersAI ability micro + kiting + mop-up sweep (Thornwood stall fixed), Ferron mass rebuild, MP connection readout

AI depth pass

  • The bot uses its abilities now: Bulwarks deploy their shield dome when a fight lands within 8 tiles and pack up when the field clears; Burrowers holding near home dig in as an ambush screen and surface for the bite when something walks onto them (or when the army marches).
  • Kiting: reloading ranged units back off from melee that closes inside 1.8 tiles (Hard only).
  • The Thornwood "turtle" stall is dead — and it was never a turtle. Probing showed one side economically dead by minute 13 while its last unseen building kept the game alive forever. The bot now runs a mop-up sweep (enemy start → every expansion → map corners) when it has nothing left on its map. A seed that stalled 22 minutes ends in 10. Arena A/B: smart 16–10 over legacy (was parity).

Ferron mass rebuild

The faction read as stick figures and bobby cars. Every unit got rebuilt around a shared armored-leg kit — thigh quads, lit shin plates, piston highlights, stomper feet — plus tracked dozer skirts on the Scrapper, a hip-blocked chicken-walker Arclight, a crab-plated Mauler, a skirted Lodestone, a fat-shrouded Kestrel and a tiered Resonant.

Ferron base Ferron closeup

Multiplayer diagnostics

The MP HUD shows PING / PIPE / STALLS under the clock (orange when the connection is genuinely bad) — a live RTT probe and stall counter inside the lockstep. "Feels laggy" is now three numbers you can report.

v0.11.1MP responsiveness + UI fixesMP lag fix (adaptive input delay, stall-flush, nodelay), 3D shield dome, console/menu layout fixes

Multiplayer lag fix

Two-machine games were unresponsive and stuttery. Three fixes:

  • Adaptive input delay: the host measures real round-trip time through the session's actual transport (including the relay hop) during the handshake and sizes the lockstep pipeline to rtt + 2 ticks (4–12) instead of a fixed 4. A pipeline deeper than the network is slow means no per-tick stalls.
  • Stall-flush: your orders now go out immediately even while the sim is waiting on the opponent — they used to sit in a queue until the next successful step.
  • TCP_NODELAY on the relay socket: Nagle's algorithm was batching the 24 tiny lockstep frames per second into ~40ms clumps.

Both players must update (the version gate enforces it).

UI

  • The Bulwark shield is now a real translucent 3D dome — fresnel shell, hard rim, latitude bands, specular highlight, ground-contact ring.
  • The console's left block meets the deck with a clean vertical step; the old angled shoulder could collide with the info text on some display scales.
  • Menu dialog panels now size themselves around their intro copy (the multiplayer page cut through its own text), and plain button pages no longer reserve a dead headroom zone.

Shield dome

v0.11.0The Juice PassThe juice pass: additive glow lighting, per-weapon combat effects + sounds, material-true deaths, drifting fog of war, shadows, ambient emitters

No new mechanics — this release is entirely about feel. The goal: premium, not "sheep".

Real light

A second render pipeline draws an additive glow pass between the world and the console: light accumulates instead of blending. Mineral crystals shimmer, geysers breathe teal, pylons and capacitor masts stand as beacons, furnaces flicker, muzzle flashes and tracers cast actual light, and Plasma Storms charge the air over a glowing dome with rising light pillars.

Glow Storm

Every weapon is itself now

Combat effects and sounds key off the attacker: rifle tracers, sweeping energy-blade and claw slash fans, heavy cannon shells with impact rings, lobbed acid globs that burst into goo, jagged violet arclight lightning, streaking rail slugs, thin twin gunship bolts — with new synthesized fire sounds to match (acid thwip, electric crack, melee whoosh, rail twang). Workers mining no longer look like troopers shooting.

Staged brawl

Deaths that mean something

What a thing is made of decides how it dies: machines flash, throw plate debris, smoke and leave scorch marks; infantry bleed and leave bodies; Kyth burst into goo puddles. Buildings do all of it at scale.

Atmosphere

  • The fog of war is actual fog: two parallax layers of drifting haze over unseen ground, denser where unexplored.
  • Buildings cast drop shadows; all shadows now match the upper-left light.
  • The world breathes: geyser vapor, chimney smoke, drifting hive spores.

Fog March

Tooling

--stage arranges a deterministic three-faction brawl with no bot drivers, so any weapon or death effect can be captured at an exact tick. Used for every combat screenshot on this page.

(No camera shake. By request.)

v0.10.0The Ferron CompactThe Ferron Compact (third race), Bulwark + Burrower abilities, bust portraits, audio overhaul, deep forests, HUD/menu fixes

The headline: a third playable race, plus a new unit and ability for each existing race, bust portraits, an audio overhaul, deeper forests and a round of HUD/menu fixes from playtesting feedback.

The Ferron Compact (new race)

A salvager machine-cult of rusted iron, magnet-violet coils and amber furnace light — mechanically a full third faction, and the capability-driven bot plays it with zero engine changes.

  • Units: Scrapper (magnet-crane salvage cart, worker), Arclight (reverse-knee arc-caster walker, hits air), Mauler (quad wrecking walker, mineral-only melee), Lodestone (rail-coil artillery crawler — mobile long-range splash, no siege mode), Kestrel (ducted-fan gunship), Resonant (coil-priest caster).
  • Buildings: Bastion foundry-fortress, lattice Capacitor Mast, Fume Tap with a burning flare, open-bay Assembly Line, Refit Bay (vehicles
    • upgrades), truss-raised Skydock, Relay coil spire.
  • Full 3-race round-robin in the balance and soak harnesses; Elo ladder and matchmaking pick the race up automatically.

Ferron base Ferron vs Kyth

A new unit + ability per race

  • Vanguard Bulwark (Forge): deployable shield projector. While deployed it anchors and projects a field — allied units within 4 tiles take 35% less damage. Auras don't stack; the field dome is visible to both players.
  • Kyth Burrower (Incubator): heavy-bite ambusher that burrows: hidden from the enemy, untargetable by direct fire, other units walk over it — but it cannot move or attack, and area damage (siege splash, storms) still hits, so every race has counterplay.
  • Both share the transform hotkey with siege mode; the bot's perception honors burrow (no cheating wallhacks).

Presentation

  • Bust portraits: every unit gets a proper head-and-shoulders portrait in the console (per team), replacing scaled-down sprites.
  • Audio overhaul: layered, filtered synthesis — cracking shots, clanging cannons, sub-thump explosions; radio-squelch Vanguard acks, formant-warble Kyth voices, struck-metal Ferron rings; and a dark 64-second ambient bed (drones, wind, a distant knell) replacing the old melody loop.
  • Deeper forests: trees up to ~3 tiles of visual height in four variants with per-tree size jitter and canopy shadows — groves now layer and occlude like real woods.
  • Bolder font: the UI font is rebaked with thicker strokes, chamfered corners, a lit bevel and a dark outline.

Deep forest Portraits

HUD & menu fixes (from feedback)

  • Minimap now fills its console block edge-to-edge.
  • Info-panel text no longer clips under the console shoulder.
  • Top-bar mineral icon no longer overlaps the mineral count.
  • The redundant in-console MENU button is gone (ESC opens the menu).
  • Settings split into GENERAL and HOTKEYS tabs — no more off-screen options.

HUD Settings tabs

Balance notes

  • Arclight 6→7 damage, 50→55 hp, range matched to the Trooper (4.5).
  • Mauler loses its gas cost, +5 hp.
  • Kyth vs Ferron measures near-even after tuning; VC vs Ferron still leans VC — Ferron balance is young and being watched.
  • Known: Hard-bot mirrors on Thornwood often turtle past the balance harness budget; human games and Normal-difficulty games finish fine.
v0.9.0The Graphics OverhaulThe graphics overhaul: full 4x repaint — dystopian terrain, hard-edged angular units, industrial/organic bases, new forests, minerals and effects

Every sprite in the game was repainted from scratch. No mechanics changed in this release — same sim, same balance, same maps — but nothing looks the same.

What changed

Four times the resolution. The entire procedural atlas moved from 1x/2x painting to 4x supersampled sprites on a 4096 atlas, with a per-region scale so the renderer mixes densities freely. At the default zoom on a retina display, sprites are now texel-perfect instead of showing chunky 4x4 blocks per painted pixel.

A new art direction: futuristic, dystopian. The palette drops into dark ashen wasteland tones. Low ground is cracked ash with sparse debris and rust; high ground reads as scorched concrete slabs with plating seams; cliffs got noise-warped strata, rusted girder insets and a depth fade. Ground detail is deliberately low-contrast — units and buildings carry the light.

Overview

Hard-edged units. Soft ellipse blobs are gone. Vanguard units are built from angular armor plates: faceted carapaces, kill-spiked pauldrons, glow-cell rifles, energy blades with white-hot cores, treaded tanks with muzzle brakes, delta gunships with flaring engines. Kyth units are hard chitin: scalloped plate edges, jointed legs, scythe mandibles, acid-glow organs.

Workers at the mineral line

Buildings with presence. Vanguard structures use a new iso kit — panel-seamed walls, emissive team trim, glowing amber windows, hazard chevrons, furnace maws, landing pads with team light rings, antenna strobes. Kyth structures are mottled organic mounds with embedded forking veins, toothed maws, twisted vent spires and glowing spiracles.

Vanguard base Kyth colony

Sharper forests and resources. Trees became serrated alien conifers with bioluminescent specks; minerals hard-faceted crystal shards with internal glow; geysers lumpy slag mounds with glowing fissure veins.

Thornwood forest

Effects. Anti-aliased shadows and selection rings, glowing muzzle flashes, scorched-debris corpses, angular plate rubble.

Notes

  • The README GIF was re-recorded on the new art.
  • Minimap palette matches the new terrain.
  • HUD portraits, queue icons and command card icons render from the same repainted sprites at full resolution.
v0.8.0ThornwoodThornwood: destructible forests with line-of-sight occlusion, high-ground third bases, observer battle GIF

(v0.8.1: forest placement rewritten from rectangular bands to organic elliptical groves — dense ragged cores, doubled tree count, same squeeze-through guarantee. Screenshots show v0.8.1.): forests you can chop, sight you can deny

The third map, and the terrain system that makes it interesting.

Thornwood overview

Destructible forests

  • Thorn trees block their tile and line of sight. Fog runs a Bresenham occlusion pass: a tile is hidden when the ray from your unit crosses a standing tree — so a forest is a wall of shadows an army can physically squeeze through the gaps of, but never see through.
  • Flyers cross and see over everything — scouting the woods is what air is for.
  • Trees and rock walls are killable by an explicit attack order (units never waste shots on them automatically). Felling a tree opens the tile and the sightline; rock walls seal back-door corridors until someone commits to breaking them.
  • Locked by test: sight blocked behind a tree wall, the tree itself visible, chop it down, path and vision open.

The map

96x96, the busy one: high-ground mains, naturals, contested third bases sitting on defensible high-ground perches, rock-sealed back doors on the flanks, and three sparse forest bands (368 trees, spacing audited) shaping every approach. Exactly 180-degree symmetric — the symmetry audit now covers trees and rocks too.

Observer camera

The observer following a fight

--record-follow turns the frame recorder into an observer: the camera snaps to the mean of live attack events, lingers on the aftermath, and drifts to the densest army clump during lulls. The README's GIF is now real battle footage on Thornwood instead of a static overview.

v0.7.0Combat evaluation, the army ball, and match safetyCombat-sim AI (the army ball, measured via A/B arena), version-safe MP + update prompt, match-start countdown

The second half of the AI overhaul — where the first half's perception gets a decision engine that survives measurement — plus version-safe multiplayer and match-start polish.

The AI, measured honestly

Every iteration of this release was gated by an A/B arena: the new brain vs the old open-loop timer bot, both maps, both races, seats swapped across seeds. The journey matters:

IterationArena (smart - legacy)
v0.6.0 threat-response bot5 - 10
+ passivity fixes5 - 13
+ guard/strike squads3 - 16
+ unified combat-profile scales5 - 12
+ the army ball8 - 9

The squad split was a measured disaster — two clumps lose to one wave by defeat-in-detail, the oldest mistake in RTS AI. The fix is the classic one: one concentrated army ball with a state machine (hold at the ramp choke / push / retreat). Head-to-head it now trades evenly with the relentless timer bot — while also doing everything the timer bot cannot: intercepting harass with the right weapons, fleeing workers, counter-building, retreating lost fights, and using scouted information.

  • ai_combat.rs: engagement scores from real unit stats — DPS split vs ground/air, HP pools, splash and upgrade aware, time-to-kill ratios. A side that cannot shoot what the other fields loses.
  • Counter-push window: the enemy is weakest right after its wave dies on your choke; the ball punishes immediately.
  • Tech inference: an enemy air-tech structure counts as a flyer before the first one exists — anti-air starts building early.
  • Focus fire: three or more ranged units concentrate on the weakest target in range.
  • Difficulty is capability, never cheats — measured Hard 7 - 1 Easy: Easy keeps the old timer waves with no memory or micro, Normal runs the full stack tuned optimistic, Hard picks its fights.

Version-safe multiplayer

Two different builds in lockstep desync by definition. Three layers now prevent it: the lobby handshake carries the client version and rejects mismatches with a clear message; the matchmaker only pairs identical versions; and a found update interrupts startup with UPDATE AVAILABLE — download, or continue in singleplayer only.

Feel

  • Match-start countdown: five frozen seconds, pulsing gold 5..1, a tick each second and a GO chord — in single player and lockstep multiplayer both.
  • The README carries a full simulated VC-vs-Kyth game as a GIF.
v0.6.0The AI gets a brainAI overhaul: perception, memory, threat response, counter-production, strength-aware attack posture

The bot was open-loop: a build order and an attack timer, blind to everything you did. The canonical demonstration: park air units over its mineral line and it would ignore them forever. This release replaces the scripted reflexes with an actual decision architecture — no special cases, systems.

The architecture

Perception. Every think, visible enemies aggregate into 8-tile-cell sightings carrying a ground/air strength split and structure flags. Strictly fog-honest — the bot models only what its player could see.

Memory. Sightings persist after leaving vision and decay by difficulty (Hard remembers 30s, Normal 15s, Easy reacts only to what it literally sees). Seeing a spot empty clears its ghost. Scouting finally means something: what the 1:20 worker scout finds feeds every later decision.

Threat response. Enemy strength near any bot base triggers an interception force composed only of units that can actually hit that threat mix — air harass is answered by anti-air, not by melee staring upward — sized to outmatch the threat by 25%. If the threat still outguns the response, nearby workers flee the danger radius instead of dying at their patches.

Counter-production. Unit choices are scored against what the enemy has shown. If they fly and the bot owns no anti-air, anti-air becomes mandatory; heavy ground mass pulls splash weapons up the priority list.

Attack posture. Pushes launch when the bot's army outmatches the known enemy army by 20% (or nothing is known, or it's late game) — never while home is threatened. Attacks target the nearest remembered enemy structure rather than blindly marching at the spawn point, and a push that discovers it is badly outmatched retreats home instead of feeding.

Enforcement

tests/ai_defense.rs recreates the reported cheese: three enemy skywings parked over the bot's mineral line must take damage within 30 seconds. The old bot failed this test forever; it now passes at every difficulty above Easy. Full suite green, soak clean (0 invariant violations, shadow determinism intact).

Balance note

The smarter defense shifted Hard cross-race to 60/40 VC (ranged armies hold better) from 41/59 Kyth before — the races now trade the lead by map and difficulty with no runaway favorite. Defensive posture also makes bots more conservative, so evenly-matched games run longer.

v0.5.0The ladder, a balance pass, and a polish sweepIn-game ladder (top 25 by Elo), cross-race balance pass, professional polish sweep of every screen

The ranked loop gets its payoff, the races get re-tuned for the expansion era, and every screen got a professional once-over.

Ladder

The in-game ladder

  • LADDER on the multiplayer page: top 10 ranked players by Elo with game counts, your own row marked < YOU, fetched live from the relay.
  • The matchmaker now remembers display names, and GET /leaderboard serves the top 25 (ranked games only).

Balance

The v0.3.0 bot upgrades (expansions, siege micro, storms, multi-side approach pathing) had quietly swung cross-race winrates to 68% Kyth. Measured at Hard across both maps (8 seeds per matchup per map) and re-tuned:

ChangeWhy
Trooper damage 6 → 7VC's core ranged unit now kills a Skitter in 6 hits, not 7
Skitter cost 40 → 45The swarm's cost-efficiency curve was unmatched
Ravager HP 200 → 180The late-game splash wall was over-durable
Breaker sieged damage 35 → 40VC's anti-swarm answer hits like it should

After tuning: 41/59 VC/Kyth overall, with clear map personalities — VC favors Meridian's single-base brawls, Kyth thrives in Caverns' long two-base games. Further evening will come from bot micro (VC tank defense), not more stat hammering.

Polish sweep

  • Settings finally fits on one screen (compact rows; BACK was off the bottom edge at default HUD scale) and every label aligns with its row.
  • R: PLAY AGAIN no longer appears (or fires) in multiplayer and replays — it silently abandoned MP sessions into a bot game.
  • All Plasma Storm costs in the UI derive from the sim constant (two more stale "75 energy" strings were hiding in the card + tooltip).
  • Requirement hints shorten to the building's last word — no more "NEEDS MUSTE" mid-word truncation.
  • End-of-match stats spell out MINERALS / PLASMA; multiplayer copy sits inside its dialog panel; replay-load errors show on the Replays page; the main menu carries a version stamp.
  • Selection + command audio acknowledgments (from v0.4.3) round out the feel: every click answers.
v0.4.0The console reworkSC:R-style console + menu rework (gold/navy chrome), building box-select, update notice, overlap-free HUD

(v0.4.1 is the fixed build: the circuit-trace detailing on the first pass read as broken pixels at dialog scale and a long race label could overflow its plate — both patched, and the console got taller with a bigger portrait and larger type. Screenshots below show v0.4.1.)

The whole interface got the StarCraft: Remastered treatment: a proper command console instead of a flat bar, and menus that match it. Still 100% procedural — every panel texture, gold strip and beveled button is painted into the sprite atlas at startup; the game ships zero asset files.

The new command console

The console

  • Navy tech panels with brushed texture and animated-looking circuit traces, tiled at native scale across the deck.
  • Gold piping along every edge with rounded corners, riveted seams, and angled shoulders where the raised minimap and command-card blocks step down to the center deck.
  • Framed minimap and portrait — gold frames around dark insets.
  • Beveled command-card buttons with distinct hover states and gold hotkey badges.
  • MENU button in the console (opens the pause menu), SC-style.
  • The resource readout sits on its own framed plate top-right.

Menus

Main menu

Framed dialog pages

  • Gold-framed dialog panels behind every page, corner rivets included.
  • Winged title plates with gold underlines.
  • Rows are plated (gold end caps), glow gold on hover, and long labels auto-shrink to fit — no text ever overflows its plate.

Settings

Fixes & quality

  • Box select takes buildings: units win a mixed box (the SC2 rule), but a drag over buildings alone now selects all of them — they were previously filtered out of box selection entirely. Regression-tested through the scripted human-input path.
  • Overlap sweep: no HUD/menu text overlaps in any state — the queue label vs HP bar collision is gone, the subgroup hint clears the research bar, tooltips lift above the mode hint, and the multi-select strip caps its width before the MENU button on narrow windows.
  • Update notice: the main menu checks GitHub once at startup and shows UPDATE vX.Y.Z AVAILABLE — DOWNLOAD when a newer release exists; one click opens the download page. (True in-place self-update is deliberately not done: replacing an ad-hoc-signed binary makes macOS Gatekeeper re-prompt, so notify-and-open is the better UX until the project has a signing identity or a store build.)
  • The Plasma Storm cast hint reflects the v0.3.0 cost (100 energy).
  • v0.4.3: selection and command audio acknowledgments — Vanguard radio blips (softer for workers), Kyth organic warbles, building thunks; move/attack/gather/build order acks with alternating variations. All synthesized, zero asset files.
  • v0.4.2: the production queue panel shows the COMBINED queue across every selected building of the active type (per-building progress bars, separator gaps), so training into the least-queued building is visible — and click-cancel routes to the correct building's queue. Previously only the first building's queue was shown, which looked like a bug whenever several production buildings were selected or Tab-cycled.
v0.3.0Ranked matchmaking, replays, CavernsRanked matchmaking (MMR + latency), replays, second map "Caverns" with expansions, bot siege/storm/scout, spawn-fairness overhaul, storm nerf

The competitive release: press FIND MATCH and the matchmaker pairs you by skill and latency; every game becomes a rewatchable replay; and a second map brings expansions into the game.

FIND MATCH on the multiplayer page

Ranked matchmaking

  • One button: pick your race, FIND MATCH. The matchmaker (a Durable Object on the relay) pairs players whose Elo gap and combined latency both fit — and both windows widen the longer you wait, so close matches happen fast and a match always happens.
  • Latency is real, not guessed: the client probes its RTT to the relay edge, and cross-continent pairs get a penalty.
  • Ratings are Elo (K=32, start 1200) keyed to an anonymous ID generated on first launch — no accounts. Your MMR shows on the button and on the end-of-match screen.
  • Both players report the result; agreement updates ratings, a rage-quit resolves against the quitter on a timeout, and quitting a ranked game is a forfeit. No bots in the queue — every entry is a live human.
  • Ranked games are played on a random map from the pool.

Replays

Watching a replay with the observer strip

  • Every game (vs AI or online) auto-saves to ~/.orion-replays/ — a replay is just the seed + command stream, a few hundred KB at most, and reproduces the game bit-exactly.
  • The main menu gained REPLAYS: recent games listed by date, matchup and length. Watching gives pause (SPACE), speed (1/2/3 = 1×/2×/4×), fog perspective per player or reveal-all (TAB), free camera, and a neutral "NAME WINS" banner.
  • Determinism is enforced by test: a recorded game re-simulated from its file must land on the identical checksum.

New map: Caverns

Caverns overview — mains, naturals, cavern rocks

  • An homage to SC2's Xel'Naga Caverns: NE/SW high-ground mains, a natural expansion below each ramp with its own mineral line and geyser (first map with expansions), and cavern rock formations that split the center into a tight middle lane and two wide edge routes.
  • Bots understand expansions: they take their natural at ~13 workers.
  • Map select on both the vs-AI and multiplayer pages; the host's choice travels in the match handshake.

Bots got teeth

  • Siege micro: Breakers deploy inside working range and pack up when the field clears.
  • Storm micro: casters storm the biggest visible enemy clump (3+ units), avoid friendly fire, and never stack storms. Fog-honest — the bot only reacts to what its player can actually see.
  • Scouting: a worker pokes the enemy main around 1:20.
  • Decisive endgames: maps mine out around minute 15 and the bots go permanently aggressive at 13, all-in at 16 — turtle stalemates ended.

Balance & fairness

  • Plasma Storm nerfed: 100 energy (was 75), 48 total damage over 8 pulses (was 72 over 9), and overlapping storms no longer stack — the stacked version deleted whole armies with no counterplay.
  • Spawn fairness overhaul: a mirror-covariance probe proved the two spawns weren't playing the same game — fixed-point multiply rounded toward the northwest, flow-field tie-breaks preferred the northwest, the starting worker arc wasn't point-symmetric, and building-spiral mirroring was off by a footprint. All fixed; the Kyth mirror went from 0–7 for the SE spawn to even, verified by swapping spawns.
  • Gather traffic robustness: approach fields now seed from every open tile around a destination, so a walled-in base can't strand its workers (found by the soak harness as a full economy freeze).

Under the hood

  • Meridian mineral patches: 1500 → 1000 (mines out by ~15:00 by design).
  • The QA soak alternates both maps; map symmetry is audited by a dedicated example across terrain, elevation, resources, expansions and starts.
v0.2.0IP-free multiplayer & double-click installsIP-free multiplayer (lobby browser + private codes), double-click releases for all platforms, multi-worker build queueing, worker visual feedback

Multiplayer stopped feeling like 1998: no IP addresses anywhere, and the release artifacts became genuinely double-clickable on every platform.

The lobby browser — no IPs anywhere

New

  • Lobby browser — CREATE LOBBY lists your game publicly (player name
    • race); anyone clicks to join. A Directory Durable Object on the relay tracks open lobbies and unlists them the moment someone joins.
  • Private lobbies — CREATE PRIVATE LOBBY gives a 5-letter code that doubles as the password. The code is the only thing players ever see; the old direct-TCP/IP path was deleted outright.
  • Double-click releases — macOS gets a real Orion.app (universal arm64+x86_64 binary, app icon, ad-hoc signed so Apple Silicon launches it); Windows a zipped orion.exe; Linux a tarball. The install table in the README covers all three.

Improved

  • Multi-worker build queueing — placing several buildings with several workers selected spreads the jobs: 5 workers + 3 placements = 3 peel off, 2 keep mining. Previously one worker got the whole list.

Worker plan lines and weld arcs

  • Worker visual feedback — order-queue lines show each selected worker's plan (amber to build sites, blue to gather targets), mining shows chip sparks and a pick beam, construction shows weld arcs, carried cargo bobs visibly, and saturation labels over bases and extractors read workers/cap.
  • Rally on constructing buildings — worked in the sim, was never drawn; the rally line now shows immediately.
  • Relay hardening: rate limits, directory caps, per-connection frame budgets.
v0.1.0First playable releaseFirst playable release: two races, full macro loop, skirmish AI, online MP via relay codes

The foundation: a complete StarCraft-style 1v1 RTS in Rust with no game engine, no asset files, and a bit-deterministic simulation.

Vanguard Combine massing for a push

Features

  • Deterministic lockstep sim — Q16.16 fixed-point math, input-only mutation, FNV checksums every 24 ticks. Two peers stepping the same commands are bit-identical, which is what online play stands on.
  • Two asymmetric races, authored entirely in data (units.ron):
    • Vanguard Combine (industrial): Fabricator, Trooper, Vanguard, Breaker (siege tank with deploy mode + splash), Skywing (flyer), Stormcaller (Plasma Storm caster); HQ, Supply Pylon, Muster Hall, Plasma Condenser, Forge, Aerie, Archive (Weapons/Armor research).
    • Kyth Assembly (swarm): Drone, Skitter, Spitter, Ravager, Wisp, Weaver; Hive, Spire, Sap Well, Warren, Incubator, Roost, Cortex.
  • Full macro loop — minerals + plasma (gas), tech requirements, research, supply, production queues with cancel/refund.
  • One map ("Meridian") — two high-ground mains, ramps, chokepoints, fog of war with the high-ground vision rule (you can't see up cliffs).
  • Skirmish AI at three difficulties — no cheating, difficulty is macro tightness and aggression timing.
  • Online multiplayer through a Cloudflare Worker relay with 5-letter lobby codes; WebSocket lockstep with desync detection.
  • SC-style control: control groups, shift-queueing, ctrl+click type-select, rally points with auto-gather, attack-move, siege toggle, spellcasting, rebindable hotkeys, DPI-scaled HUD.
  • Procedural everything — every sprite (units at 8 facings × 2 walk frames × 2 teams), building, cliff face, effect, the 5×7 font, and all audio (music loop + SFX) are generated at startup. Zero asset files.

The Kyth Assembly swarm

Vanguard arsenal

Platforms

First release with CI-built binaries for macOS (universal), Windows and Linux, attached to the GitHub release.