Dimension Choice Popup — Design (replaces the portal system)
Dimension Choice Popup — Design (replaces the portal system)
Section titled “Dimension Choice Popup — Design (replaces the portal system)”Status: open questions resolved (2026-07-10, Toby — draft answers, not set in stone). Not yet planned into executable tasks, not implemented. Batch D of the 2026-07-09 playtest feedback list.
Problem
Section titled “Problem”The current portal system spawns one physical wormhole per Dimension (Sim._spawn_area_wormhole,
sim.wormholes) in a ring around the boss’s death point, which the player must physically fly
into. Toby has hit “many bugs” with portal placement (ring math near arena walls, spacing, which
portal ends up reachable) and wants the mechanic replaced outright: a UI popup after the boss
fight (and after any post-boss upgrade cards are resolved) offering 3 randomly-chosen Dimensions
to warp to next, excluding the one just completed. Removing the physical entities removes the
whole bug class at the root, rather than patching placement math again.
Current architecture (what’s being replaced)
Section titled “Current architecture (what’s being replaced)”Sim.wormholes: Array— up toAreaDefs.DIMENSION_IDS.size()(currently 7) portal dicts{pos, dest, element, name}, spawned by_spawn_area_wormhole(pos)in a ring around the boss’s death spot (PORTAL_SPREAD_RADIUS, arena-edge clamping viaPORTAL_ARENA_MARGIN).Sim.portals_open: bool+Sim._portal_timer— while true, several other systems gate on it: spawn-suppression (_spawn_waveearly-return),_update_dimension_hazard,dimension_hazards.update(both already changed in Batch A to stop pausing on boss-alive, but still pause onportals_open), and_check_pilot_hit’s “not portals_open” gate on_move_enemies-adjacent updates.Sim._update_wormholes()— per-tick: check player overlap with any portal (→ emit a"warp"area_event + clear), else count down_portal_timerand auto-close if ignored.render/wormhole_renderer.gd(WormholeRenderer) — draws the physical portal ring.main.gd’s_begin_warp(dest)/_finish_warp()— the actual area-transition (freeze + fade +_apply_area_change) is already fully decoupled from wormholes — it just takes a dest id. This is the one piece we keep and reuse as-is.- A separate, independent “teaser wormhole” system (
_spawn_teaser_wormhole,teaser_wormhole,TEASER_*) exists purely as a v0.1 “coming soon” hint on the first FunZo kill — unrelated to real navigation, out of scope, do not touch.
Proposed architecture
Section titled “Proposed architecture”Replace the physical-wormhole flow with a pause-and-choose popup, matching the existing
level-up panel’s own pattern (_paused_for_levelup / LevelUpPanel / CrystalsLevelUpPanel)
rather than inventing a new one:
- Sim side: a new
pending_dimension_choice: Array[String](empty = none pending), populated once boss death handling AND every resultingpending_levelupshave been fully drained (see sequencing below). Drawn viaupgrade_rng, notrng— this is a player-facing choice offer, not a spawn decision, and must not desync the spawn stream (same rule the crystal-grant rolls already follow). Pick logic (per Q1 answer below): trackvisited_dimensions: Array[String]for the run (appendcurrent_areaon every warp); candidate pool isAreaDefs.DIMENSION_IDSminusvisited_dimensions. Failsafe: if the candidate pool has fewer than 3 entries, pop the earliest entry offvisited_dimensions(oldest-visited, not most-recent) and add it back into the pool — repeat until ≥3 candidates, then shuffle and take the first 3.HOMEis never added tovisited_dimensions/never a candidate (Q3 — Home is one-way, never re-offered). - main.gd side: a new
_paused_for_dimension_choice: bool(added to every existing freeze condition alongside_paused_for_levelup) and a new UI panel (e.g.ui/dimension_choice_panel.gd) that shows the 3 offered Dimension names in a plain vertical list inside a bordered box, centered on screen (Q2 — deliberately minimal for this draft: reuseLevelUpPanel’s existing card-list/box visuals as-is, no bespoke “star-map” treatment). On pick: hide the panel, unpause, call the existing_begin_warp(dest)— no changes needed to the warp-transition/fade code at all. - Deleted:
Sim.wormholes,portals_open,_portal_timer,_spawn_area_wormhole,_update_wormholes,PORTAL_SPREAD_RADIUS/PORTAL_ARENA_MARGIN,render/wormhole_renderer.gdand itsmain.gdwiring, and everynot portals_opengate this removes the need for (since a hard pause — like the level-up screen already does — makes those gates redundant: nothing ticks during the popup, so there’s nothing to suppress).
Sequencing: boss death → upgrades → dimension choice
Section titled “Sequencing: boss death → upgrades → dimension choice”A boss kill already can produce pending_levelups (XP crosses a threshold same tick), and the
existing level-up flow already handles the “possibly more than one queued” case
(_on_upgrade_chosen re-opens _open_levelup() if pending_levelups > 0 after a pick). The
dimension-choice popup must only open after that whole chain is empty — i.e. hook its open
condition where _on_upgrade_chosen’s “no more pending levelups” branch already resumes normal
play, checking sim.pending_dimension_choice there instead of (or in addition to) resuming. If
the boss death produced zero level-ups, the popup should still open on the same tick/frame the
boss death is detected, same as _open_levelup()’s own pending_levelups > 0 check today.
Determinism
Section titled “Determinism”Boss deaths only happen well past BOSS_FIRST_TIME (210s) — nowhere near the pinned 600-tick/10s
baseline window — so this is expected to need no re-pin, same reasoning as every other
boss/late-game feature. Confirm, don’t assume (per the project’s own standing rule) once built.
Resolved answers (Toby, 2026-07-10)
Section titled “Resolved answers (Toby, 2026-07-10)”Draft answers, not set in stone — revisit at plan time if something doesn’t fit once built.
- Exclusion scope: exclude all already-visited Dimensions this run (Toby changed his mind from the original brief, which only excluded the immediately-previous one). Failsafe: if fewer than 3 unvisited Dimensions remain, drop the earliest entry off the visited list and re-include it as an offerable option — just enough to keep 3-of-N satisfiable when the run has cycled through most/all Dimensions, not a real gameplay mechanic.
- Panel visuals: just the 3 Dimension options in a plain list (like the upgrade cards) inside a box, centered on screen. Reuse existing visuals — no bespoke treatment needed, this is a draft.
- Home/Generic: confirmed — no going back to Home. It’s a one-time tutorial/warm-up Dimension, never re-offered once left.
- First-boss-at-Home: yes, Warden’s death at
HOMEtriggers the popup too (otherwise there’d be no way to leave Home) — unchanged from the current wormhole system. Mid-dimension bosses (i.e. bosses that aren’t the last thing standing) do not trigger it — the player only changes Dimension once every wave and boss in the current one is cleared, so “boss death” here specifically means “the Dimension is now fully cleared,” not any individual boss kill.
Suggested next step
Section titled “Suggested next step”Once the open questions above are answered, turn this into an executable task-by-task plan (same
format as docs/superpowers/plans/2026-07-06-centurion-enemy.md) via
superpowers:writing-plans / subagent-driven-development, sized similarly (content/UI/sim
wiring + removal tasks, each with its own failing-test-first step).