Hub Illumination Map

The illuminationMap is a per-hub Map<hubId, boolean> (semantically a set of lit hub IDs) that records which hubs the player has illuminated this run. It is the core progression signal a run produces.

Lifetime

  • Per-run. The map is owned by LevelData and lives for the duration of one run.
  • Permanent within the run. Once a hub is set to true via lantern activation, it never reverts. There is no “darken” path during play — setIllumination exists only for playground/debug.
  • Initialized from level data. When the illumination system is constructed (createIlluminationSystem), each hub’s lantern is marked activated if the level data’s illuminationMap already has that hub set to true — allowing pre-lit hubs to be seeded by generation.

Writers

Exactly one gameplay writer: tickIllumination in engine/world/illumination.ts. When a lantern’s fill reaches 1 (player standing inside the activation circle for the fill duration), it:

  1. Marks the LanternState as activated.
  2. Sets illuminationMap.set(hub.id, true).
  3. Increments hubsIlluminated.
  4. Fires all registered onActivate callbacks (including onHubIlluminated in engine/bridge-hub-illumination.ts).

Debug/manual writes go through setIllumination, which also recounts hubsIlluminated.

Readers

Two main consumers consult the map every frame:

  • Spawner / zone resolution. Spawn pools and event eligibility branch on whether a hub is dark vs lit. getIlluminatedHubIds returns the lit set; isHubLit answers point queries. The cascade handler onHubIlluminated immediately culls dark_only events in the just-lit hub (idle/failed events spliced out, active events flipped to failed).
  • Renderer. Palette swap is driven off the same map — lit hubs and lit spokes render in the illuminated palette, dark hubs in the dark palette.

Spoke illumination

Spokes are not stored in the map directly. isSpokeLit(system, spoke, hubs) returns true if either endpoint hub is in the map — a single lit endpoint is enough to light the whole spoke. This means lighting a hub immediately illuminates every spoke touching it, even if the far endpoint is still dark.

  • Lantern activation mechanic — see engine/world/illumination.ts constants: ACTIVATION_RADIUS_FRAC = 0.35, DEFAULT_FILL_SECONDS = 4, DRAIN_RATE = 0.5. Fill duration scales with config.illuminationSpeed (0 = instant, higher = slower).
  • Cascade side-effects on activation — onHubIlluminated also pushes nearby enemies away from the hub (force 300 * (1 - dist / (hub.r * 2)) within hub.r * 2) and bumps world._hubsIlluminated for the director.