Developers
Architecture
How the Arborwake alpha is put together, the save and reward boundaries, and the older engine of the original opening.
Content checked 2 November 2026
The Arborwake alpha#
Layers#
| Layer | Where | What it does |
|---|---|---|
| Integrated game state | src/main-game/game/ β state.js, controller.js, campaign.js, home.js, encounters.js | Pure state for session.game version 1: roster, side quests, observations, journal, home duties, pending rewards and the shared Threadway position. |
| World and travel | src/main-game/game/world.js, maps.js, residents.js; shared src/main-game/navigation.js | The six 2D places, polygon floors (CR-NAV-01), resident routes and physical gates. |
| Threadway | src/main-game/threadway3d/, src/main-game/game/threadway-host.js, threadway-assets.mjs, transport-package.mjs | The 3D street. It borrows the host ledger and checkpoint, streams nearby sections, and saves its position. |
| Encounters | src/main-game/alpha/ (host, rules, pinned presenter in public/encounter/) | Opens a turn room in a child presenter with host-owned setup, then verifies the result. |
| Services and shops | src/main-game/services.js, src/main-game/game/shops.js, vendored kit in src/main-game/vendor/ and game/vendor/ | Claude Bβs pinned services v3, kit and roster rules behind lead adapters. |
| Presentation | src/main-game/game/presentation.js, ui.js, effects.js, world.css, src/hud/ | Drawing, menus, the HUD and transaction-driven effects. |
| Saves | src/main-game/game/migration.js, src/main-game/progress-store.js | Key arborwake.game.progress.v1. Earlier alpha saves keep their resources; their records are archived, not accepted as story evidence. |
Provenance files sit beside the code: game/INTEGRATION.json, game/UPDATED-PINS.json, game/art/SOURCES.json and game/RELEASE-FILES.json (1,149 inspected inputs with hashes).
Trust boundaries#
- The renderer never grants anything.
beginRoomreserves endurance and fixes the launch facts.checkpointRoomchecks the append-only command log with the pinned turn engine before saving it.finishRoomreplays the log. A completion pays once, even after a reload. - Shops recompute. A town menu sends only IDs; the host recomputes the transaction against the current ledger, commits it, and only then shows feedback.
- No farming. A trip that stays in town cannot advance a return cycle, refill deliveries or give recovery.
- Recruitment needs a quest receipt. The podium cannot recruit. Early story steps need physical observations and verified encounters. The story stops on purpose at the unwritten II2 scene.
- Threadway transport. Files over 20 MiB travel in exact-byte parts that are joined before decoding. Blender sources and review GLBs are not shipped.
Commands and tests#
Command (in the Placeholder checkout) | What it does | Last lead result (2 Nov) |
|---|---|---|
npm run build | Release build; dist/index.html opens the game | passed |
npm run test:systems | Node tests for tests/main-game/*.test.js | 135 passed |
npm test | The original Placeholder world rules | 11 passed |
npm run build:prototype | Keeps the older preview files | passed (49 files) |
npm run test:browser | Edge through local Wrangler: podium, observation, building, lesson, Workshop purchase, return, reload, touch, the full journey | 7 passed |
npm run deploy:check | Wrangler dry run only | passed; nothing uploaded |
These results are the leadβs own. On 3 November the wiki reran npm run test:systems (135/135) and npm test (11/11) on a clean extract of b89f778; it did not rerun the builds or browser suites.
The original opening on main (history)#
This is the engine of the three-minute Circuit Ranger opening. It still builds and runs on main, and parts of it (navigation, saves) were reused.
Stack#
JavaScript, HTML and CSS; Phaser 4.2.1 for drawing; Vite 8.3.5 for building; Playwright 1.64.1 with installed Edge for browser tests; Prettier 3.6.2; Node β₯ 22.12. Logical viewport 512Γ288, pixel-art scaling.
Principles#
- Plain-JavaScript state is the truth. Phaser only draws; renderers never complete work or grant anything.
- Deterministic fixed steps of 1/30 s. Paused or hidden time is discarded, so nothing changes while you are away.
- One world, one player, one home, one clock. Regions are data; there is one reusable scene.
- Every command goes through one dispatcher and returns
{ok, reason?}. A rejected command changes nothing.
Modules#
| File | Responsibility | Key exports |
|---|---|---|
| src/app.js | Owns the state reference, the fixed-step accumulator, input and boot | β |
| src/core/state.js | World factory and constants; bounded event ring (100) | createWorld, STEP, REACH, emit |
| src/core/runtime.js | Opening setup, command dispatcher, step order, opening director | newGame, targets, dispatch, step |
| src/world/maps.js / src/world/navigation.js | Region records; walking, path-finding (16 px grid) and doorways | REGIONS, movePlayer, setDestination, transition, isWalkable, findPath |
| src/simulation/cells.js | Tend, Call, care, material, response, neuron strain, residents | tend, call, cancelWork, updateCells, addMaterial, getCellTargets |
| src/home/progression.js | Building, banking on return, recruiting Mote, assignment | startBuild, updateHome, onReturn, assignResident |
| src/persistence/save.js | Snapshot validation and IndexedDB saves | validateSnapshot, createSnapshot, saveWorld, loadWorld |
| src/render/scene.js | The single Phaser scene | createScene |
src/render/manifest.js, art-format.js, art-layer.js | Optional approved sprite/layer loading (catalogue empty) | ART_CATALOG |
| src/ui/panel.js | DOM interface, drawers and ending dialog | mountUI |
One step#
step(state, dt) advances in this order:
time += dt β movePlayer β updateCells β updateHome β updateDiscovery β updateDirectorstep throws if dt is not in (0, 0.05]. The director runs the opening phases: welcome β forecast β defence β recovery β ending β commons (after Continue), or practice in Gate A mode.
Commands#
pause, continue, move {x,y}, destination {x,y}, select {id}, cycle, cancel, call, build, assign {residentId, sectorId}, ready, tend. There are no skill or expedition commands; their future shapes are agreed in Integration.
Trace one action: select β tend β dispatcher checks pause, target, region and range β cells latch the action β each step advances material progress β completion writes cleared = true before one event β the renderer simply stops drawing it.
Saves#
IndexedDB database arborwake-save-v1, keys current and previous. A save writes both in one transaction (the old current becomes previous) with a revision check that rejects stale tabs. Schema version 1 validates the fixed regions, six sectors, 1β3 residents and Supply limits. Snapshots drop input, path and action, and load paused. Extra unknown data is not a supported extension mechanism.
Since the 31 October rename, the first run at a browser origin copies saves from the database used under the project's former name into the new one, keeping their revisions. It never overwrites an existing Arborwake record and never deletes the old database, which stays as a recovery source. Close tabs running an older build first: the old database is not kept in sync. Old identifiers are recognised only by src/persistence/legacy-brand.js.
Tests#
| Command | What it covers | Last lead result (27 Oct) |
|---|---|---|
npm test | Node unit/integration rules (world, cells, home, saves, runtime review, art) | 60/60 |
npm run build | Static production build | passed (bundle-size advisory) |
npm run test:browser | 7 Edge smoke routes: Gate A, both branches, saves, restart, pointer/keyboard, W/A | 7/7 |
npm run test:art | Art loader on Canvas and WebGL with synthetic sheets | 4/4 |
npm run test:realtime | One unaccelerated three-minute run | 1/1, 180,878 ms, held 37/45 |
Browser suites refuse to reuse an existing server; set ARBORWAKE_TEST_PORT (or ARBORWAKE_SYSTEMS_TEST_PORT for the systems preview) for an isolated port. ?qa=1 exposes disclosed fixed-step acceleration for tests only; the browser QA hooks are window.arborwake and window.arborwakeSystems.
After the rename (main 54cc7cc), the lead reported on 31 October: npm test 101/101, npm run build and npm run build:systems passed, npm run test:browser 10/10 (including save migration), and npm run test:systems:browser 3/3. test:art and test:realtime were not rerun; the table above shows their last results.
Run it#
npm ci
npm run dev # http://127.0.0.1:5173
npm test
npm run build
npm run test:browserOr play the built snapshot without any setup.