# datokey/rouge-like-godot architecture

> Architecture diagram of the GitHub repository datokey/rouge-like-godot, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-17). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/datokey/rouge-like-godot
- Repository: https://github.com/datokey/rouge-like-godot

## Overview

This repository is a Godot 4 top-down action roguelike prototype built around a clear split between **scene-based gameplay objects**, **data-driven `.tres` resources**, and a small set of **autoload singletons** that coordinate run state and events.

1. **High-level composition**
   - The main entry point is `scenes/Main.tscn`.
   - `Main` separates the game into two major branches:
     - `World`: arena, player, enemies, projectiles, pickups, spawner logic.
     - `UI`: HUD, level-up selection, win, and game-over screens.
   - This makes the architecture easy to diagram as “core simulation” plus “presentation/UI”.

2. **Runtime orchestration via autoloads**
   - `autoload/RunManager.gd` controls run lifecycle: start, timer progression, win/lose state.
   - `autoload/GameState.gd` holds shared state like player HP, XP, and run progress.
   - `autoload/EventBus.gd` is the decoupled messaging layer for gameplay/UI communication.
   - `autoload/Rng.gd` centralizes randomness, which is important for reproducible run behavior and weighted drops.
   - These are the primary cross-cutting boundaries; most systems talk through them rather than direct node-to-node references.

3. **Scene layer: active gameplay entities**
   - Core runtime actors live in `scenes/entities/`:
     - `Player.tscn`
     - `Enemy.tscn`, `EnemyRunner.tscn`, `EnemyTank.tscn`
     - `Projectile.tscn`
     - `PickupItem.tscn`
     - `Simpatisan.tscn` as an additional entity/minion-type scene
   - World infrastructure lives in `scenes/world/`, especially `EnemySpawner.tscn` and `TestArena.tscn`.
   - Visual-only feedback is separated into `scenes/vfx/ImpactVFX.tscn`.

4. **Gameplay logic lives in scripts, not scenes**
   - Most behavior is implemented in `scripts/gameplay/`.
   - Scene files are thin containers; scripts like `PlayerController.gd`, `EnemyController.gd`, `WeaponManager.gd`, `EnemySpawner.gd`, and `Main.gd` own the behavior.
   - This keeps the visual hierarchy and the simulation logic distinct, which is useful when drawing the architecture: scenes instantiate, scripts decide behavior.

5. **Data-driven balancing through resources**
   - Almost all balance values are stored in `resources/` as `.tres` files, not hardcoded.
   - Key resource families:
     - `resources/actors/`: player and enemy stats/config
     - `resources/weapons/`: weapon definitions and variants
     - `resources/difficulty/`: time-based difficulty phases
     - `resources/items/`: pickups and magnet tuning
     - `resources/projectiles/`: projectile tuning
     - `resources/run/`: survival target and next scene target
     - `resources/xp/`: XP curve progression
     - `resources/feedback/`: hit response tuning
   - This is a strongly data-driven architecture: code executes the rules, resources define the numbers and variants.

6. **Enemy and difficulty progression**
   - Enemies are configured by `EnemyConfig` resources and controlled by `EnemyController.gd`.
   - Spawning is handled by `EnemySpawner.gd`, which consults `SpawnerConfig` and `DifficultyManager.gd`.
   - Difficulty is time-based, not wave-based: progress is derived from `run_elapsed_time / run_target_time`.
   - Difficulty phases in `resources/difficulty/phase_*.tres` define multipliers, spawn cadence, max alive enemies, and which enemy scenes can appear.
   - In the diagram, this is a pipeline: run time -> difficulty phase -> spawn selection -> enemy stat scaling.

7. **Player combat and weapon system**
   - `WeaponManager.gd` owns the active weapon(s) for the player.
   - Weapons are scene-driven and defined by `WeaponDefinition` / `WeaponConfig` resources.
   - The repo already contains multiple weapon styles:
     - projectile-based (`BasicGun`)
     - beam-based (`BeamGun`)
     - additional prototype weapons like `KoalisiDadakan`
   - Weapons read runtime modifiers and compute stats like damage, cooldown, range, projectile count, and level scaling.
   - This is a key boundary: the player does not directly implement attack behavior; weapon scenes encapsulate combat logic.

8. **Ability/upgrade subsystem**
   - Level-up rewards are data-driven through `abilities/definitions/*`.
   - `AbilityDefinition` describes the upgrade offer, while `AbilityEffect` describes individual stat effects.
   - `AbilityPoolConfig.gd` and `AbilityManager.gd` manage offer rolling, stacking, and runtime modifiers.
   - `AbilitySelectionScreen.gd` renders the 3-choice upgrade UI and sends the selected upgrade back through events.
   - Abilities modify weapon/player stats indirectly via the manager, so the systems stay decoupled from UI and from individual weapon scripts.

9. **Pickups, XP, and magnet behavior**
   - Enemies drop `PickupItem` scenes on death.
   - XP pickups increase player XP; HP pickups heal; magnet pickups activate a temporary pull effect.
   - `MagnetConfig.gd` controls the pull behavior, but only for `hp` and `xp` pickup types.
   - The XP system is tied to `XPConfig.gd` for level thresholds and progression, and level-up triggers the ability-selection flow.

10. **Feedback, hit response, and VFX**
   - Enemy hit reactions are configured by `HitFeedbackConfig.gd`.
   - Damage feedback includes knockback, flash, impact VFX, and hit-stop style feedback.
   - `ImpactVFX.gd` / `ImpactVFX.tscn` separate purely visual feedback from combat logic.
   - This keeps “damage resolution” distinct from “presentation of impact,” which is useful for clean architecture diagrams.

11. **UI and state transitions**
   - `PlayerHud.gd` listens to gameplay state via `EventBus` and displays HP, XP, and survival progress.
   - `GameOverScreen.gd`, `WinScreen.gd`, and `StartingWeaponSelectionScreen.gd` are separate UI states.
   - Win/lose conditions are not handled by UI; they originate in `RunManager`, which then signals the appropriate screen to show.
   - This means UI is mostly reactive, not authoritative.

12. **Main data flow to show in a diagram**
   - `Main` starts a run through `RunManager`.
   - `RunManager` initializes `GameState` and the survival timer.
   - `PlayerController` seeds player stats from config resources.
   - `EnemySpawner` spawns enemies according to `DifficultyManager`.
   - Combat resolves through weapons/projectiles into enemy damage.
   - Enemy death generates pickups and feedback.
   - Pickups feed XP/HP back into the player.
   - Level-up emits an event that opens ability selection.
   - UI subscribes to state changes and displays progress, win, or loss.

13. **Architectural boundary summary**
   - **Scenes** = instantiated gameplay objects and UI views.
   - **Scripts** = behavior and control logic.
   - **Resources** = all tunable game data and content definitions.
   - **Autoloads** = global coordination for state, run lifecycle, RNG, and events.
   - That four-part separation is the most important thing to capture when drawing the architecture.

14. **What makes this repo distinct**
   - It is not a generic Godot project; it is structured like a reusable roguelike combat framework.
   - The design emphasizes extensibility:
     - add a weapon by creating a weapon scene + `WeaponDefinition`
     - add an ability by creating `AbilityDefinition` + `AbilityEffect`
     - add enemy variety by adding `EnemyConfig` and including it in phase resources
   - The codebase is intentionally organized so most gameplay tuning happens without changing scripts.

Main entry points: [`autoload/RunManager.gd`](https://github.com/datokey/rouge-like-godot/blob/main/autoload/RunManager.gd) (RunManager), [`autoload/EventBus.gd`](https://github.com/datokey/rouge-like-godot/blob/main/autoload/EventBus.gd) (EventBus), [`scenes/world/TestArena.tscn`](https://github.com/datokey/rouge-like-godot/blob/main/scenes/world/TestArena.tscn) (Arena), [`scenes/entities/Enemy.tscn`](https://github.com/datokey/rouge-like-godot/blob/main/scenes/entities/Enemy.tscn) (Enemies)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_group_scenes["Scenes"]
  node_node_main_scene["Main<br/>entry scene<br/>[Main.tscn]"]
  node_node_world_arena["Arena<br/>world scene<br/>[TestArena.tscn]"]
  node_node_player_scene["Player<br/>actor scene<br/>[Player.tscn]"]
  node_node_enemy_scenes["Enemies<br/>actor scenes<br/>[Enemy.tscn]"]
  node_node_spawner_scene["Spawner<br/>world scene<br/>[EnemySpawner.tscn]"]
  node_node_projectile_scene["Projectile<br/>combat scene<br/>[Projectile.tscn]"]
  node_node_pickup_scene["Pickup<br/>item scene<br/>[PickupItem.tscn]"]
  node_node_vfx_scene["Impact VFX<br/>vfx scene<br/>[ImpactVFX.tscn]"]
end

subgraph group_group_scripts["Scripts"]
  node_node_main_logic["Main logic<br/>gameplay orchestrator<br/>[Main.gd]"]
  node_node_player_controller["Player ctrl<br/>player logic"]
  node_node_weapon_manager["Weapon mgr<br/>combat system<br/>[WeaponManager.gd]"]
  node_node_ability_system["Abilities<br/>upgrade system<br/>[AbilityManager.gd]"]
end

subgraph group_group_resources["Resources"]
  node_node_weapon_defs["Weapons<br/>weapon data<br/>[BasicGun.tres]"]
  node_node_enemy_config["Enemy config<br/>actor data<br/>[enemy_dummy.tres]"]
  node_node_difficulty["Difficulty<br/>phase data"]
  node_node_spawner_config["Spawner config<br/>spawn data"]
  node_node_player_config["Player config<br/>actor data"]
  node_node_xp_config["XP config<br/>progression data<br/>[default_xp.tres]"]
  node_node_ability_defs["Ability defs<br/>upgrade data<br/>[double_tap.tres]"]
end

subgraph group_group_autoloads["Autoloads"]
  node_node_run_manager["RunManager<br/>autoload run control<br/>[RunManager.gd]"]
  node_node_game_state["GameState<br/>autoload state<br/>[GameState.gd]"]
  node_node_event_bus["EventBus<br/>autoload messaging<br/>[EventBus.gd]"]
  node_node_rng["Rng<br/>autoload random<br/>[Rng.gd]"]
end

subgraph group_group_ui["UI"]
  node_node_hud["HUD<br/>ui screen<br/>[PlayerHud.tscn]"]
  node_node_ability_screen["Upgrade UI<br/>ui screen"]
  node_node_gameover_screen["Game over<br/>ui screen"]
  node_node_win_screen["Win screen<br/>ui screen<br/>[WinScreen.tscn]"]
end

node_node_main_scene -->|"drives"| node_node_main_logic
node_node_main_logic -->|"starts run"| node_node_run_manager
node_node_run_manager -->|"initializes"| node_node_game_state
node_node_run_manager -->|"signals state"| node_node_event_bus
node_node_main_scene -->|"contains"| node_node_world_arena
node_node_main_scene -->|"contains"| node_node_hud
node_node_world_arena -->|"spawns"| node_node_player_scene
node_node_world_arena -->|"spawns"| node_node_enemy_scenes
node_node_world_arena -->|"contains"| node_node_spawner_scene
node_node_player_scene -->|"uses"| node_node_player_controller
node_node_player_controller -->|"reads"| node_node_player_config
node_node_player_controller -->|"delegates combat"| node_node_weapon_manager
node_node_weapon_manager -->|"loads"| node_node_weapon_defs
node_node_weapon_manager -->|"emits"| node_node_projectile_scene
node_node_weapon_manager -->|"notifies"| node_node_event_bus
node_node_spawner_scene -->|"uses"| node_node_spawner_config
node_node_spawner_scene -->|"consults"| node_node_difficulty
node_node_difficulty -->|"selects"| node_node_enemy_config
node_node_enemy_scenes -->|"configured by"| node_node_enemy_config
node_node_enemy_scenes -->|"drops"| node_node_pickup_scene
node_node_enemy_scenes -->|"triggers"| node_node_vfx_scene
node_node_pickup_scene -->|"reports"| node_node_event_bus
node_node_pickup_scene -->|"advances"| node_node_xp_config
node_node_ability_screen -->|"driven by"| node_node_ability_system
node_node_ability_system -->|"loads"| node_node_ability_defs
node_node_ability_system -->|"emits offers"| node_node_event_bus
node_node_hud -->|"subscribes"| node_node_event_bus
node_node_gameover_screen -->|"reacts to"| node_node_run_manager
node_node_win_screen -->|"reacts to"| node_node_run_manager

click node_node_main_scene "https://github.com/datokey/rouge-like-godot/blob/main/scenes/Main.tscn"
click node_node_world_arena "https://github.com/datokey/rouge-like-godot/blob/main/scenes/world/TestArena.tscn"
click node_node_player_scene "https://github.com/datokey/rouge-like-godot/blob/main/scenes/entities/Player.tscn"
click node_node_enemy_scenes "https://github.com/datokey/rouge-like-godot/blob/main/scenes/entities/Enemy.tscn"
click node_node_spawner_scene "https://github.com/datokey/rouge-like-godot/blob/main/scenes/world/EnemySpawner.tscn"
click node_node_projectile_scene "https://github.com/datokey/rouge-like-godot/blob/main/scenes/entities/Projectile.tscn"
click node_node_pickup_scene "https://github.com/datokey/rouge-like-godot/blob/main/scenes/entities/PickupItem.tscn"
click node_node_vfx_scene "https://github.com/datokey/rouge-like-godot/blob/main/scenes/vfx/ImpactVFX.tscn"
click node_node_run_manager "https://github.com/datokey/rouge-like-godot/blob/main/autoload/RunManager.gd"
click node_node_game_state "https://github.com/datokey/rouge-like-godot/blob/main/autoload/GameState.gd"
click node_node_event_bus "https://github.com/datokey/rouge-like-godot/blob/main/autoload/EventBus.gd"
click node_node_rng "https://github.com/datokey/rouge-like-godot/blob/main/autoload/Rng.gd"
click node_node_main_logic "https://github.com/datokey/rouge-like-godot/blob/main/scripts/gameplay/Main.gd"
click node_node_player_controller "https://github.com/datokey/rouge-like-godot/blob/main/scripts/gameplay/PlayerController.gd"
click node_node_weapon_manager "https://github.com/datokey/rouge-like-godot/blob/main/scripts/gameplay/WeaponManager.gd"
click node_node_weapon_defs "https://github.com/datokey/rouge-like-godot/blob/main/resources/weapons/BasicGun.tres"
click node_node_enemy_config "https://github.com/datokey/rouge-like-godot/blob/main/resources/actors/enemy_dummy.tres"
click node_node_difficulty "https://github.com/datokey/rouge-like-godot/blob/main/resources/difficulty/default_difficulty.tres"
click node_node_spawner_config "https://github.com/datokey/rouge-like-godot/blob/main/resources/spawners/enemy_spawner_default.tres"
click node_node_player_config "https://github.com/datokey/rouge-like-godot/blob/main/resources/actors/player_default.tres"
click node_node_xp_config "https://github.com/datokey/rouge-like-godot/blob/main/resources/xp/default_xp.tres"
click node_node_ability_system "https://github.com/datokey/rouge-like-godot/blob/main/abilities/scripts/AbilityManager.gd"
click node_node_ability_defs "https://github.com/datokey/rouge-like-godot/blob/main/abilities/definitions/offense/double_tap.tres"
click node_node_hud "https://github.com/datokey/rouge-like-godot/blob/main/ui/screens/PlayerHud.tscn"
click node_node_ability_screen "https://github.com/datokey/rouge-like-godot/blob/main/ui/screens/AbilitySelectionScreen.tscn"
click node_node_gameover_screen "https://github.com/datokey/rouge-like-godot/blob/main/ui/screens/GameOverScreen.tscn"
click node_node_win_screen "https://github.com/datokey/rouge-like-godot/blob/main/ui/screens/WinScreen.tscn"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_node_main_scene,node_node_world_arena,node_node_player_scene,node_node_enemy_scenes,node_node_spawner_scene,node_node_projectile_scene,node_node_pickup_scene,node_node_vfx_scene toneBlue
class node_node_main_logic,node_node_player_controller,node_node_weapon_manager,node_node_ability_system toneAmber
class node_node_weapon_defs,node_node_enemy_config,node_node_difficulty,node_node_spawner_config,node_node_player_config,node_node_xp_config,node_node_ability_defs toneMint
class node_node_run_manager,node_node_game_state,node_node_event_bus,node_node_rng toneRose
class node_node_hud,node_node_ability_screen,node_node_gameover_screen,node_node_win_screen toneIndigo
```

## Components

### Scenes

Instantiated gameplay objects, world setup, and reusable views.

- [Main](https://github.com/datokey/rouge-like-godot/blob/main/scenes/Main.tscn): entry scene · Root scene that composes world and UI branches. · `scenes/Main.tscn`
- [Arena](https://github.com/datokey/rouge-like-godot/blob/main/scenes/world/TestArena.tscn): world scene · Primary gameplay space where combat and spawning happen. · `scenes/world/TestArena.tscn`
- [Player](https://github.com/datokey/rouge-like-godot/blob/main/scenes/entities/Player.tscn): actor scene · Player character instance used in the run. · `scenes/entities/Player.tscn`
- [Enemies](https://github.com/datokey/rouge-like-godot/blob/main/scenes/entities/Enemy.tscn): actor scenes · Enemy variants instantiated during combat. · `scenes/entities/Enemy.tscn`
- [Spawner](https://github.com/datokey/rouge-like-godot/blob/main/scenes/world/EnemySpawner.tscn): world scene · Enemy spawning infrastructure in the active world. · `scenes/world/EnemySpawner.tscn`
- [Projectile](https://github.com/datokey/rouge-like-godot/blob/main/scenes/entities/Projectile.tscn): combat scene · Projectile instance used by ranged weapons. · `scenes/entities/Projectile.tscn`
- [Pickup](https://github.com/datokey/rouge-like-godot/blob/main/scenes/entities/PickupItem.tscn): item scene · Dropped item instance for XP, HP, and magnet effects. · `scenes/entities/PickupItem.tscn`
- [Impact VFX](https://github.com/datokey/rouge-like-godot/blob/main/scenes/vfx/ImpactVFX.tscn): vfx scene · Pure visual feedback for combat impacts. · `scenes/vfx/ImpactVFX.tscn`

### Scripts

Behavior, control logic, and gameplay managers.

- [Main logic](https://github.com/datokey/rouge-like-godot/blob/main/scripts/gameplay/Main.gd): gameplay orchestrator · Wires scene branches and bootstraps the run. · `scripts/gameplay/Main.gd`
- [Player ctrl](https://github.com/datokey/rouge-like-godot/blob/main/scripts/gameplay/PlayerController.gd): player logic · Loads player stats and drives player behavior. · `scripts/gameplay/PlayerController.gd`
- [Weapon mgr](https://github.com/datokey/rouge-like-godot/blob/main/scripts/gameplay/WeaponManager.gd): combat system · Owns active weapons and their runtime modifiers. · `scripts/gameplay/WeaponManager.gd`
- [Abilities](https://github.com/datokey/rouge-like-godot/blob/main/abilities/scripts/AbilityManager.gd): upgrade system · Upgrade definitions, pools, and runtime selection logic. · `abilities/scripts/AbilityManager.gd`

### Resources

Data-driven tuning, content definitions, and balance tables.

- [Weapons](https://github.com/datokey/rouge-like-godot/blob/main/resources/weapons/BasicGun.tres): weapon data · Weapon definitions, configs, and scene-backed variants. · `resources/weapons/BasicGun.tres`
- [Enemy config](https://github.com/datokey/rouge-like-godot/blob/main/resources/actors/enemy_dummy.tres): actor data · Enemy stats and variant configuration resources. · `resources/actors/enemy_dummy.tres`
- [Difficulty](https://github.com/datokey/rouge-like-godot/blob/main/resources/difficulty/default_difficulty.tres): phase data · Time-based difficulty phases and spawn multipliers. · `resources/difficulty/default_difficulty.tres`
- [Spawner config](https://github.com/datokey/rouge-like-godot/blob/main/resources/spawners/enemy_spawner_default.tres): spawn data · Enemy spawn tuning used by the spawner. · `resources/spawners/enemy_spawner_default.tres`
- [Player config](https://github.com/datokey/rouge-like-godot/blob/main/resources/actors/player_default.tres): actor data · Base player stats and tuning. · `resources/actors/player_default.tres`
- [XP config](https://github.com/datokey/rouge-like-godot/blob/main/resources/xp/default_xp.tres): progression data · XP thresholds and level progression tuning. · `resources/xp/default_xp.tres`
- [Ability defs](https://github.com/datokey/rouge-like-godot/blob/main/abilities/definitions/offense/double_tap.tres): upgrade data · Data-driven level-up offers and stat effects. · `abilities/definitions/offense/double_tap.tres`

### Autoloads

Global run orchestration and shared state.

- [RunManager](https://github.com/datokey/rouge-like-godot/blob/main/autoload/RunManager.gd): autoload run control · Starts runs, advances time, and resolves win/lose state. · `autoload/RunManager.gd`
- [GameState](https://github.com/datokey/rouge-like-godot/blob/main/autoload/GameState.gd): autoload state · Shared runtime state for HP, XP, and progress. · `autoload/GameState.gd`
- [EventBus](https://github.com/datokey/rouge-like-godot/blob/main/autoload/EventBus.gd): autoload messaging · Decoupled event layer between gameplay and UI. · `autoload/EventBus.gd`
- [Rng](https://github.com/datokey/rouge-like-godot/blob/main/autoload/Rng.gd): autoload random · Central random source for reproducible gameplay decisions. · `autoload/Rng.gd`

### UI

Reactive screens and HUD presentation.

- [HUD](https://github.com/datokey/rouge-like-godot/blob/main/ui/screens/PlayerHud.tscn): ui screen · Displays HP, XP, and survival progress. · `ui/screens/PlayerHud.tscn`
- [Upgrade UI](https://github.com/datokey/rouge-like-godot/blob/main/ui/screens/AbilitySelectionScreen.tscn): ui screen · Three-choice level-up selection screen. · `ui/screens/AbilitySelectionScreen.tscn`
- [Game over](https://github.com/datokey/rouge-like-godot/blob/main/ui/screens/GameOverScreen.tscn): ui screen · Lose-state presentation. · `ui/screens/GameOverScreen.tscn`
- [Win screen](https://github.com/datokey/rouge-like-godot/blob/main/ui/screens/WinScreen.tscn): ui screen · Win-state presentation. · `ui/screens/WinScreen.tscn`

## Connections

- Main → Main logic: drives · Main scene is orchestrated by gameplay logic.
- Main logic → RunManager: starts run · Bootstraps survival session lifecycle.
- RunManager → GameState: initializes · Sets shared run state and progress.
- RunManager → EventBus: signals state · Broadcasts run state changes to listeners.
- Main → Arena: contains · World branch hosts combat simulation.
- Main → HUD: contains · UI branch shows reactive player info.
- Arena → Player: spawns · Arena instantiates the player actor.
- Arena → Enemies: spawns · Arena hosts enemy variants.
- Arena → Spawner: contains · Enemy spawning lives in the world.
- Player → Player ctrl: uses · Player scene behavior comes from controller script.
- Player ctrl → Player config: reads · Seeds stats from player tuning resource.
- Player ctrl → Weapon mgr: delegates combat · Player attack behavior is managed separately.
- Weapon mgr → Weapons: loads · Weapons are defined by data resources and scenes.
- Weapon mgr → Projectile: emits · Projectile weapons instantiate projectile scenes.
- Weapon mgr → EventBus: notifies · Weapon and combat events can be broadcast globally.
- Spawner → Spawner config: uses · Spawner tuning comes from resource data.
- Spawner → Difficulty: consults · Spawn cadence and limits depend on difficulty phase.
- Difficulty → Enemy config: selects · Phase resources determine eligible enemy configs.
- Enemies → Enemy config: configured by · Enemy variants are parameterized by actor resources.
- Enemies → Pickup: drops · Enemy death produces pickups.
- Enemies → Impact VFX: triggers · Combat impacts create visual feedback.
- Pickup → EventBus: reports · Pickup collection flows through shared events.
- Pickup → XP config: advances · XP pickups feed progression thresholds.
- Upgrade UI → Abilities: driven by · UI is populated from upgrade manager state.
- Abilities → Ability defs: loads · Ability offers and effects are data-driven.
- Abilities → EventBus: emits offers · Selection flow is broadcast decoupled from UI.
- HUD → EventBus: subscribes · HUD listens to gameplay state changes.
- Game over → RunManager: reacts to · Lose state originates from run manager.
- Win screen → RunManager: reacts to · Win state originates from run manager.
