# F1 Debug Menu Design ## Overview An F1-toggled debug menu overlay that works regardless of the current scene. Introduces a new root scene (`game.tscn`) that hosts both the debug menu and the active game scene as children. The game pauses underneath while the debug menu is open. ## Scene Tree Structure ``` Game (Node, process_mode = PROCESS_MODE_ALWAYS) ├── DebugMenu (CanvasLayer, layer 100) │ ├── Panel (PanelContainer) │ │ ├── SceneList (VBoxContainer of Buttons) │ │ └── CommandInput (LineEdit) │ └── ResultLabel (Label, brief flash for command output) └── ActiveSceneContainer (Node) └── ``` - `Game` is the new main scene, replacing `strategy_phase.tscn` as the entry point in `project.godot`. - `DebugMenu` uses a high `CanvasLayer` (layer 100) so it always renders above the active scene. - `ActiveSceneContainer` is a plain `Node` whose child gets swapped when changing scenes. - `Game` has `process_mode = PROCESS_MODE_ALWAYS` so it can receive F1 input even while the tree is paused. ## Responsibilities ### Game (`game.gd`) Thin shell only: - F1 input toggles `DebugMenu` visibility. - When debug menu opens: sets `ActiveSceneContainer.process_mode = PROCESS_MODE_DISABLED`. - When debug menu closes: sets `ActiveSceneContainer.process_mode = PROCESS_MODE_INHERIT`. - Loads the default scene (strategy_phase) into `ActiveSceneContainer` at startup. - Passes a reference to `ActiveSceneContainer` to `DebugMenu` at `_ready()`. ### DebugMenu (`debug_menu.gd`) Owns all debug functionality: - **Scene registry**: hardcoded array of scene entries. - **Scene swapping**: frees old child of `ActiveSceneContainer`, instantiates new scene, applies setup if present. - **Command console**: parses input, dispatches to registered commands or falls back to expression eval. - **Command registration**: holds an explicit `Array[ConsoleCommand]` populated at `_ready()`. ## Scene Swapping ### Registry Format A hardcoded array in `DebugMenu`: ```gdscript var scene_registry: Array = [ { "name": "Strategy Phase", "path": "res://scenes/strategy_phase.tscn" }, { "name": "Strategy Phase (Test Data)", "path": "res://scenes/strategy_phase.tscn", "setup": "test_data" }, { "name": "Main Menu", "path": "res://scenes/main_menu.tscn" }, { "name": "Visual Novel", "path": "res://scenes/vn_scene.tscn" }, { "name": "Dialogue", "path": "res://scenes/dialogue_scene.tscn" }, ] ``` ### Swap Flow 1. Free the current child of `ActiveSceneContainer`. 2. Instantiate the new scene from `path` and add as child. 3. If the entry has a `"setup"` key, call a setup method on `DebugMenu` that applies that configuration to the new scene instance. 4. Close the debug menu and signal `Game` to unpause. ### Setup Hooks Setup functions live in `DebugMenu`, dispatched by matching the `"setup"` string key. This keeps test configurations self-contained within the debug system. ## Command Console ### Input A `LineEdit` at the bottom of the debug panel. On Enter: 1. Split input text — first token is the command name, rest are arguments. 2. Check against registered commands by matching `get_command_name()`. 3. If found, call `run()` with args and context. 4. If no match, fall back to Godot's `Expression` class (evaluated with the active scene as base instance). 5. Show the result (or error) in `ResultLabel`, then hide it after 2 seconds using a `Timer` or `create_tween()`. ### Command Pattern Base class: ```gdscript class_name ConsoleCommand func get_command_name() -> String: return "" func get_help_text() -> String: return "" func run(args: Array, context: Dictionary) -> String: return "" ``` Each command extends `ConsoleCommand` and overrides these three methods. The `context` dictionary provides access to the active scene container, debug menu reference, and other shared state without coupling commands to specific nodes. Commands are explicitly registered in an `Array[ConsoleCommand]` in `DebugMenu._ready()`. ### Starter Commands - **`help`** — lists all registered commands with their help text. - **`swap `** — scene swap by name (matches against registry entry names). - **`list_scenes`** — prints available scene registry entries. ### Expression Eval Fallback Uses Godot's `Expression` class. The expression executes with the current active scene as the base instance, allowing direct access to nodes and properties in the loaded scene. Errors are displayed in `ResultLabel`. ## File Organization ``` nodes/ ├── game.gd # Thin shell ├── debug_menu.gd # Scene registry, command console, swap logic resources/resource_definitions/ ├── console_command.gd # Base class resources/console_commands/ ├── swap_command.gd ├── help_command.gd ├── list_scenes_command.gd scenes/ ├── game.tscn # New root scene (new main_scene in project.godot) prefabs/ ├── debug_menu.tscn # CanvasLayer with panel, buttons, input, result label ``` Existing scenes are unchanged — they are loaded as children of `ActiveSceneContainer` instead of being the root. ## Key Decisions - **No autoload**: The debug menu is a UI node, not a headless service. The `XXXServer` autoload pattern is reserved for game services like a future `SceneManagerServer`. - **Explicit command registration**: Commands are listed in an array rather than auto-discovered from a folder. Simpler and more readable for a small number of commands. Can be swapped to auto-discovery later if needed. - **Single-line output**: `ResultLabel` shows one result at a time with a brief display. No scrollable history for now. - **Hardcoded scene list**: Entries can carry setup data/context, which auto-discovery from `.tscn` files wouldn't support.