← all games

action-roguelite-gpt-5-unknown — GAME.md

# NULL//VECTOR game manifest

`RunScene` owns one complete run. Room changes rebuild room-owned entities inside that scene, so the player, camera, HUD, inventory, floor graph, and run counters survive every door transition.

## Scenes

| Scene | Responsibility | Exit |
|---|---|---|
| `TitleScene` | Controls, persistent records, and start action | replace with `RunScene` |
| `ArchiveScene` | Persistent data-shard balance and upgrade-pool unlocks | purchase an unlock or return to title |
| `RunScene` | Floor, rooms, combat, HUD, minimap, audio, and Inspector extension | push pause or upgrade; replace with result |
| `PauseScene` | Build, inventory, active combinations, and run controls | pop to run or replace with title |
| `UpgradeScene` | Three upgrade cards and an optional credit cost | apply one choice and pop; black market can cancel |
| `ResultScene` | Success or failure summary and persistent records | retry or return to title |

Pause and upgrade scenes set `pauseBelow` and `transparentBelow`. All menu scenes support pointer clicks, keyboard actions, D-pad actions, and left-stick edge navigation.

## Ownership

| Owner | State and entities | Lifetime |
|---|---|---|
| Boot | renderer, input, physics, particles, audio, debug, save, progression record | application |
| `RunScene` | `RunSession`, camera, player, reticle, HUD, `RoomDirector`, Inspector extension | run |
| `RunSession` | seed, floor graph, build, inventory, counters, boss state, input-device label | run |
| `RoomDirector` | backdrop, walls, doors, encounter, projectiles, fields, combat audio | room |
| Overlay scene | DOM overlay and focus controller | overlay |

The game uses a feature-first directory structure. `scenes/` contains lifecycle boundaries. `features/` contains floor, combat, room, inventory, upgrade, run, and UI code. `app/` contains boot-wide constants, audio declarations, and persistent progression.

## Rapier lifecycle

The player and enemies use dynamic, fixed-rotation Rapier bodies. Walls use static bodies. Doors and damage fields use kinematic sensor bodies. Projectiles use dynamic sensor bodies with continuous collision detection. Projectile transforms follow their velocity, including after ricochets.

`PhysicsSteeringAgent` drives enemies with impulses. Ability hits add knockback through the same bodies. The player controller uses velocity for direct movement and yields control during dash and stagger windows.

Dash fields use a 48px damage radius and pulse every 0.58 seconds. Breach Amplifier expands active fields to 84px and shortens their pulse interval to 0.28 seconds. Field damage selects live enemies by distance so the damage radius matches the visible radius.

Projectile drawings encode their active modifiers. Burn adds orange trails, viral adds a violet diamond, bounce adds an orbit ring, fork adds prongs, pierce adds an acid outline, and heat adds a red outer ring. Burned and infected enemies receive a tint plus separate status badges above their body.

Enemy body drawings live on child entities so their rotation does not turn the physics root or the status badges. Sentries, drones, and the boss face the player. Rippers and enforcers face their movement direction, falling back to the player when stopped.

`RoomDirector.retire()` moves a body outside the arena and places its entity in a retirement queue. The director destroys one queued entity per frame. Room transitions wait for the queue to empty and for two more frames before creating the next room. Run completion removes room bodies and the player body through the same queue before replacing the scene.

Room transitions resolve the destination room's door that points back to the origin room and place the player 76px inside that edge. The arrival door stays disabled until the player moves at least 120px inside that edge. All destination doors remain disabled until movement returns to neutral once. Door sensors also require outward player velocity, so standing in a sensor or holding one direction across a room change does not cause another transition.

## Communication

The composition root passes a narrow `CombatRuntime` interface to combat entities. The interface owns projectile creation, hit feedback, enemy rewards, room queries, entity retirement, camera shake, audio cues, and run completion.

YAGE entity events handle `HealthDied`. Ability hit delivery handles damage, i-frames, stagger, and death. Scene callbacks handle upgrade offers and result transitions. The game does not add a global gameplay event bus.

## Input actions

| Action | Keyboard and mouse | Gamepad |
|---|---|---|
| movement | WASD and arrow actions | left stick |
| primary | left mouse | RT |
| dash | Space | A |
| active | E or right mouse | LB |
| repair | Q | X |
| pause | Escape | Start |
| build | Tab | Y |
| confirm and cancel | Enter/Space/E and Escape/Backspace | A and B |
| menu direction | arrows or WASD | D-pad or left-stick edge |

The stick dead zone is 0.2. The trigger dead zone is 0.08, with a 0.45 press threshold. The right stick keeps the last non-zero aim. The run switches HUD hints after keyboard, pointer, or gamepad activity. A gamepad disconnect switches the hints back to keyboard and mouse.

## Assets

Gameplay art, room geometry, icons, telegraphs, the minimap, and the HUD are drawn in code.

The repository contains six original generated WAV files under `public/assets/audio/`: pulse, hit, dash, breach, alarm, and boss loop. `scripts/generate-audio.mjs` recreates them. The game uses no downloaded images, audio, or video.

## State boundaries

Every `RunScene` creates a new floor, health pool, build, inventory, ability state, room population, and run counters.

The saved `Progression` record contains successful and failed run counts, the fastest extraction time, a data-shard balance, firmware and upgrade unlock IDs, and achievements.

Each completed or failed run awards data shards. Rooms, defeated enemies, data fragments, access keys, and a successful extraction contribute to the award. The Black Ice Archive spends shards to add Forkbomb Rounds, Breach Amplifier, Rail Kernel, and Redline Firmware to future upgrade pools. Archive purchases add build choices and do not grant permanent combat stats.

## Inspector extension

`RunScene` registers `window.__yage__.inspector.getExtension("nullVector")`. The extension exposes:

- `state()`, `physicsState()`, `projectiles()`, `fields()`, `floor()`, and `validateFloor()`
- `gotoRoom(id)`, `clearRoom()`, `teleportPlayer(x, y)`, and `spawnDashFieldAt(x, y)`
- `damagePlayer(amount)`, `damageEnemy(id, amount)`, and `damageBoss(amount)`
- `grantUpgrade(id)`, `grantItem(id, quantity)`, `defeatBoss()`, and `extract()`
- `cleanupCounts()`

The scene removes the extension on exit. Inspectable game components implement `serialize()` for their owned state.