Sandbox Mode
Sandbox mode is a run flag that suppresses the normal arcade-run subsystems so the mission becomes a tunable isolation chamber. It is the runtime backbone of the dev playground tabs (boss test, weapon test, artifact gauntlet, mods, feel) and is never used by player-facing arcade runs.
Activation
RunConfig.sandbox?: boolean on data/run-config.ts (defaults false). When runDef.sandbox === true the bridge takes the sandbox branch in engine/bridge.ts on every applicable subsystem. Telemetry records the flag at recordStart so any sample stream stays distinguishable from arcade runs.
What is disabled
When runDef.sandbox is set, bridge.ts skips:
- Mission timer.
game.missionElapsed += dtis gated behind!runDef.sandbox— elapsed time is frozen, so director / spawn ramps and any time-based level-end conditions never advance. - Overtime end condition. The overtime → game-over check is skipped, so the run cannot end on the wall clock.
- Director.
Director.update(game, ship, world, dt)(mood / pressure / personality) is suppressed. - GameMaster spawner. The trickle / waves / retreat / flank tick only runs if
game._sandboxSpawnerEnabledis explicitly toggled on via the right-panel control (setSpawnerEnabled). Default is off. - Leveling.
LevelingSystem.update(game)(XP threshold → level-up card popups) is skipped. - Event reward pipelines. Map events still trigger juice for layout walkthroughs, but
continueshort-circuits the artifact / hub-illumination reward flow so playground-controlled run state isn’t corrupted. - Disabled chest / artifact KPM schedulers. The legacy timed-drop blocks (currently
if (false)-gated) also include the sandbox guard for the day they’re revived. - Launch SFX + music.
MusicPlayer.start()andSampleSfx.playLaunch()are skipped onmission.start()because sandbox missions rebuild frequently.
What is enabled
- Frame scheduler swaps to
setTimeout(16). Sandbox usessetTimeoutinstead ofrequestAnimationFramebecause Claude Preview throttlesrAFto ~1fps even whendocument.hiddenis false.setTimeoutin a visible tab runs at the requested interval (~60fps). - Dev console API.
PERF_FLAGS.devScenario || runDef.sandboxexposeswindow.__dev(andwindow.__mission) for Playwright / Claude automation: spawn elite, clear enemies, set HP / shield / heat, god mode, freeze, screenshot, grant artifact, set speed, autopilot, weapon gauntlet, etc. - Sandbox mutators on the
MissionHandle. These mutate live engine state without a mission rebuild — the price of avoiding rebuilds is that some tunings stack against a baseline snapshot.
Sandbox API surface
Exposed on the MissionHandle (see “SANDBOX API” block in engine/bridge.ts):
| Method | Purpose |
|---|---|
setSpawnerEnabled(enabled) | Toggle GameMaster.tick (default off in sandbox). |
sandboxSpawnBoss(bossId, tier) | Spawn a boss into a fresh closing arena. Resets bossRoom / bossArena first so successive gauntlet runs always get a new shrinking-wall instance — otherwise stale spawnTime prevents the closing wall from reappearing. |
sandboxGrantArtifact(artifactId) | Each call grants +1 tier (level up if already owned). |
sandboxEquipMods(mods) | Re-equip mods against a one-time baseline snapshot of ship stats. Does not restart the mission. Caveat: a patchShipStats tweak made after the first equip is wiped on the next equip because the baseline is frozen. |
sandboxRespawn() | Restore ship HP / shield and return to playing phase after death. |
sandboxResetForTest() | Full reset for the artifact / weapon gauntlet — clock to t=0, frame-loop accumulator + lastFrameTime, ship HP / shield / heat, kills, damage stats, artifacts, enemies, speed. Does not rebuild the world or terrain. |
sandboxSetDebugOverlay(on) | Toggle collision-debug overlay. |
sandboxSetLighting(...) | Writes to game.vision for back-compat with the playground UI; no renderer consumes it. |
The dev console’s __dev.playground.resetForTest() and __dev.weaponGauntlet() both route through _missionHandle.sandboxResetForTest(). The weapon gauntlet additionally requires the page to be on /ship-playground because a live mission must exist for the reset to operate on.
Relationship to other modes
Sandbox mode is orthogonal to the arcade run pipeline — it is never produced by assemble-run for a player-facing run. It is set up explicitly by the dev playground entry points. PERF_FLAGS.devScenario (URL param ?dev=<scenario>) is a separate dev path that shares the same __dev console surface but does not flip the per-system gates above.
Why these gates exist
- Tuning a single enemy / boss / weapon needs steady-state damage / kills / time without the director feathering pressure based on imagined player skill.
- Re-running the same gauntlet slice repeatedly needs deterministic state (
Clock.reset()plus the reset of accumulators and run-stat counters). - The artifact reward pipeline assumes a normal run economy; firing it inside a playground-controlled run breaks subsequent artifact picks.
- Mission rebuilds are slow and visually noisy; sandbox prefers hot-swap mutators that mutate the live ship / artifact / mod state in place.
See also
data/run-config.ts—RunConfig.sandboxfield (line 435).engine/bridge.ts— sandbox gating atrunDef.sandboxsites and theSANDBOX APIblock.engine/bridge-sandbox-utils.ts—makeBlockerVertsand other sandbox geometry helpers.- Dev playground tabs in the metagame shell consume the
__dev.playgroundnamespace.