Arriving anywhere set health to maximum, so a run cost nothing: walk in, take what you could, walk out, walk back in whole. Current health now lives on the character record for the same reason the inventory does -- SimWorld builds a blank player on every instance change, so anything that must survive a door has to be written down -- and it is banked at every transfer, every disconnect, and on every item transaction, since a potion moves an item and hit points in one action. The hub is where that damage is paid off, at 10% of maximum per second: about ten seconds from nothing, fast enough not to be a chore and slow enough to be a decision before walking back in. The dungeon rate is unchanged, so waiting one out is still not a plan. Regeneration is a property of the world now rather than a constant. adopt() no longer touches current health. It is called mid-session by on_choose_upgrade, and reading health from the record there would snap a player back to whatever was last written to disk; recompute_max_hp still clamps downwards so Glass Cannon takes the hit points above the new ceiling with it. ServerRuntime._adopt_character stays the one place a record becomes a live player. Experience is still undivided, but now only among players within XP_AWARD_RADIUS of the kill -- ten percent past what a player can see, so anyone who watched it die is inside and someone parked in the entrance room is not. The death events carry a position for this, and deliberately do not put it on the wire: encode_events still writes the id alone. diag_progression covers the whole chain end to end -- wounded in a dungeon, escaped to the hub with the wound intact, healing there, and walking back in still hurt -- because a unit test cannot transfer a peer. Both halves were mutation-tested against it; the unit suite alone missed the arrival heal entirely. The Proving Grounds is recorded in the roadmap as a debugging tool that does not ship: it pays full experience for a boss with 8% health. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Transcience
Top-down twin-stick bullet-hell with a dedicated, server-authoritative backend. Godot 4.7, GDScript, no external runtime dependencies.
Play
tools/server.sh # dedicated server on :27015
tools/client.sh --join --name ada # connect a client
Or run one client and press Host and play for a listen server.
Controls — WASD move, mouse aim, LMB fire, E to pick up loot and to use the hub's portals and quartermaster, 1–4 use an inventory slot, shift+1–4 drop one, hold F for one second to escape a dungeon, Esc menu, F1 hitbox overlay. Every one of those is rebindable in Settings.
What is here
| Twin-stick bullet hell | Server-simulated bullet field, ~300 concurrent bullets at 0.28 ms/tick — around 60x headroom against the 60 Hz budget. |
| Authoritative multiplayer | Clients send input and nothing else. Hits, damage, death, loot, upgrades and instance transfers are all server decisions. Prediction and reconciliation for the local player. |
| Enemies | Five readable movements (static, drift, orbit, approach, strafe) composed with bullet emitters. Nothing deals contact damage; every threat is a bullet you can see. |
| Two bosses | The Warden of the Fold stands still through four phases. The Cantor of the Vault walks a circuit, chases, orbits, and marks the floor before it strikes. Both are pure data. |
| Three dungeons | Two real runs, one per boss, plus a Proving Grounds: the same content at a fraction of the health and ten times the drop rate, for testing by hand. |
| Characters | Up to five living per account, permadeath, levels 1–15, experience shared across the party undivided. |
| Inventory and loot | Four slots, always on screen. Loot is either world-shared or instanced per player, and the instanced kind is filtered on the wire rather than hidden in the client. |
| Upgrades | Seven, drawn three at a time and spent at a hub NPC. Damage, fire rate, extra projectiles, splitting, poison, and a legendary that deletes enemy bullets. |
| Emergency escape | A one-second channel back to the hub that damage does not interrupt — because if it did, quitting the process would be the better escape. Dropping your connection runs the same channel. |
| Settings | Rebindable controls and volumes, and an in-game credits screen. |
Develop
tools/check.sh # parse-check every script ~5s
tools/test.sh # 468 GUT tests, headless ~4s
tools/smoke.sh # server + 4 bot clients over ENet ~40s
Read CLAUDE.md first — it is short, and the Godot CLI gotchas in it will otherwise cost an afternoon.
Docs
- docs/ROADMAP.md — what is built, what is next, where each feature lives
- docs/DECISIONS.md — settled design decisions and their reasoning
- docs/ARCHITECTURE.md — code map and the node-free simulation
- docs/NETCODE.md — replication model, hit validation, known gaps
- docs/WORKFLOW.md — agent-assisted Godot development, and the verification traps this project has actually hit
- docs/ASSETS.md — asset packs and their licence findings
- CREDITS.md — third-party attribution
- CLAUDE.md — commands, invariants, Godot CLI gotchas
Not ready for the internet
LocalAuthProvider lets any client claim any account id. It exists to have the
same shape as Steamworks so swapping is one class, and it must be replaced
before this is reachable from anywhere untrusted. There is no transport
encryption either. See docs/ROADMAP.md.