← all games

arena-shooter-fable — GAME.md

# Neon Break — top-down arena shooter

Survive 3 waves of enemies in a walled neon arena. WASD to move, mouse to aim
and shoot, Space/Shift to dash, R to restart after a win or loss.

## Scenes

- `ArenaScene` (`src/scenes/ArenaScene.ts`) — the only scene. Registers layers
  `floor` (-10), `world` (0), `fx` (10), `hud` (100, screen space); the UI
  plugin adds its own screen-space `ui` layer. Builds the floor graphics, four
  static walls, the player, camera (follows player, clamped to the arena),
  HUD, banner, reticle, particle emitter pool, and a `director` entity running
  `WaveDirector`. Restart replaces the scene with a fresh `ArenaScene`.

## Entity types

- `Player` (`src/entities/Player.ts`) — dynamic body, circle collider r12.
  `PlayerController` handles movement (285 px/s), pointer aim, fire
  (9 shots/s), dash (780 px/s for 0.16 s, 1.3 s cooldown, i-frames while
  dashing), 5 HP with 1 s invulnerability + sprite flicker after a hit.
  Contact damage is polled via `collider.getOverlapping()` when vulnerable.
- `Enemy` (`src/entities/Enemy.ts`) — kinds `grunt` / `sprinter` / `brute`
  (stats in `src/config.ts`). `PhysicsSteeringAgent` (impulse drive): grunts
  and brutes `seek` the player, sprinters `pursue` with prediction; all use
  `separation` against other enemies. `EnemyBrain` owns HP, hit flash,
  bullet knockback, and death (particles, shake, `EnemyDiedEvent`).
- `Bullet` (`src/entities/Bullet.ts`) — sensor circle collider, ccd, 0.9 s
  lifetime; `onTrigger` damages enemies / dies on walls.
- `Hud` (`src/entities/Hud.ts`) — three UI corner panels: HP cells (top-left),
  wave + hostiles remaining (top-right), dash cooldown bar (bottom-left).
- `Banner` (`src/entities/Banner.ts`) — center-screen announcements on the
  `hud` layer ("WAVE 2", "YOU DIED", "ARENA CLEARED").
- `Reticle` (`src/entities/Reticle.ts`) — world-space crosshair at the pointer
  (the CSS cursor is hidden over the canvas).
- `fx-*` emitter entities — one `ParticleEmitterComponent` per effect flavor,
  managed by `FxPool` (`src/fx.ts`).

## Game flow

`WaveDirector` (`src/WaveDirector.ts`) on the `director` entity: schedules the
3 waves from `WAVES` in `src/config.ts` (counts, speed multiplier, spawn
interval), telegraphs each spawn with a tinted shrinking ring (0.75 s), tracks
remaining enemies via `EnemyDiedEvent`, and owns win/lose banners and the R
restart. Spawn points sit on the arena edge at least 260 px from the player.

## Input actions (`src/main.ts`)

`up/down/left/right` (WASD + arrows), `fire` (MouseLeft), `dash`
(Space, ShiftLeft), `restart` (KeyR).

## Assets

None on disk. All sprites are runtime textures baked in `src/textures.ts`
(`tex.player`, `tex.grunt`, `tex.sprinter`, `tex.brute`, `tex.bullet`,
`tex.dot`, `tex.ring`). SFX are synthesized in `src/sfx.ts` via WebAudio.

## Effects

Bloom on `world` and `fx` layers; scene-scope shockwave (brute kills, player
death); screen-scope vignette + chromatic-aberration damage pulse installed
once at boot (`src/screenFx.ts`); `hitFlash` per sprite on player and enemies.

## Save payload

Not used. `PlayerController`, `EnemyBrain`, and `WaveDirector` implement
`serialize()` so `Inspector.getComponentData` can read hp / wave / phase for
verification.