level-progression.ts

Run-level sequence definitions, level-kind resolver, sealed-arena geometry constants, and boss kind-multipliers. Source of truth for “what kind of level is this?” and the physical size of sealed-arena fights.

Acheron (purpose)

Drives world-gen, AI director pinning, and end-conditions per level. Two sequences: normal mode (5 levels, one biome) and Challenge Mode (10 levels, same per-level curve, double payouts applied at run-assembly, not here). Also exports the sealed-arena half-extent / wall thickness and the boss “kind” HP/damage multipliers that scale mini-boss and boss tiers above their base enemy stats.

Lethe (key exports)

Types

  • LevelKind = 'normal' | 'mini_boss' | 'hard' | 'boss'

Sequences

  • RUN_LEVEL_SEQUENCE: readonly LevelKind[] — fixed normal-mode arc, index = level - 1:
    • 1: normal (4-min biome level, normal ramp)
    • 2: normal (same biome/palette, normal ramp)
    • 3: mini_boss (sealed square arena, mini-boss + roster, ends on boss death)
    • 4: hard (same biome/palette, ramp pinned at 1.0, basics-only window skipped)
    • 5: boss (sealed square arena, boss with 2× HP/damage at the tier level, ends on boss death → results screen)
  • CHALLENGE_LEVEL_SEQUENCE: readonly LevelKind[] — 10 levels for Challenge Mode (unlocked per-planet after clearing normal-mode final boss):
    • 1–2: normal, normal
    • 3: mini_boss
    • 4–5: normal, normal
    • 6: mini_boss
    • 7–8: hard, hard
    • 9: mini_boss
    • 10: boss

Resolvers

  • resolveLevelKind(currentLevel: number, isChallenge?: boolean): LevelKind — 1-indexed lookup. currentLevel < 1 returns seq[0]. Levels past the end clamp to the final boss kind (dev-mode safety — the engine never crashes; production runs terminate at the final level → results screen).
  • isFinalLevel(currentLevel: number, isChallenge?: boolean): booleancurrentLevel >= seq.length. Final level triggers post-clear → results screen.
  • _seqFor(isChallenge?: boolean) — internal switch between CHALLENGE_LEVEL_SEQUENCE and RUN_LEVEL_SEQUENCE.

Sealed-arena geometry

  • SEALED_ARENA_HALF_SIZE = 1400 — half-extent in world units. Arena footprint is a 2 * SEALED_ARENA_HALF_SIZE square (2800 units per side). Walls outside this footprint are unbreakable, enforced by per-frame ship clamp + Rapier static cuboid colliders + wall thickness rendered ≥ SEALED_ARENA_WALL_THICKNESS.
  • SEALED_ARENA_WALL_THICKNESS = 2000 — wall thickness for sealed arenas. Combined with the per-frame clamp this guarantees no entity (player, projectile, knockback push) escapes.

Boss kind multipliers

v5.162.2 across-the-board 4× buff so bosses feel like real walls. Boss tier doubles mini’s mult so the relative scale (boss = 2× mini) is preserved. Depth scaling on top is applied in encounter.ts (currentLevel / final level → ×1.0–×1.5 ramp).

  • BOSS_KIND_HP_MULT_MINI = 4.0
  • BOSS_KIND_HP_MULT_BOSS = 8.0
  • BOSS_KIND_DAMAGE_MULT_MINI = 4.0
  • BOSS_KIND_DAMAGE_MULT_BOSS = 8.0

Cocytus (consumers)

  • World-gen / encounter director consumes resolveLevelKind to decide spawn profile, arena vs open biome, ramp pin, and basics-only window behavior.
  • Sealed arena builders read SEALED_ARENA_HALF_SIZE / SEALED_ARENA_WALL_THICKNESS to place walls, set Rapier static colliders, and clamp the player each frame.
  • Boss/mini-boss stat code multiplies base enemy HP and damage by the BOSS_KIND_* constants; depth ramp (encounter.ts) multiplies on top.
  • Challenge Mode unlock pathway reads CHALLENGE_LEVEL_SEQUENCE after a planet’s normal final boss is cleared; payout doubling happens at run-assembly, not in this file.

Phlegethon (invariants)

  • Index is 1-based. currentLevel = 1 is the first level. resolveLevelKind(0) (or any value < 1) returns seq[0].
  • Sequences are readonly — never mutate at runtime. Add new kinds by extending LevelKind and authoring a new sequence.
  • Out-of-bounds currentLevel clamps to final boss rather than throwing. This is a dev-mode escape hatch; production must call isFinalLevel before advancing.
  • Sealed-arena walls are unbreakable by contract. Anything that bypasses the clamp + colliders + wall geometry is a bug.
  • Boss-tier multiplier ratio is locked: BOSS = 2 × MINI for both HP and damage. Changing this breaks the “bosses feel 2× mini” tuning intent.

EXTRACT-CANDIDATE

  • Boss kind multipliers (BOSS_KIND_HP_MULT_MINI/BOSS, BOSS_KIND_DAMAGE_MULT_MINI/BOSS) could move to a dedicated boss-tuning module alongside the encounter.ts depth-ramp constants — they’re tuning knobs, not progression structure. Keeping them here couples sequence definition with combat-stat tuning.
  • Sealed-arena geometry constants (SEALED_ARENA_HALF_SIZE, SEALED_ARENA_WALL_THICKNESS) could move to a sealed-arena.ts data file alongside other arena-only constants (wall material, render thickness floor). Currently they live here because mini-boss / boss levels are the only consumers, but the binding is conceptual not structural.