# Architecture

## Singletons (Autoloads)

Never instantiate these — access only via the global handle.

| Handle | Role |
|---|---|
| `SCENE` | Current scene state; `SCENE.setScene(SceneSingleton.SceneType.X)` to switch |
| `TRANSITION` | Fade in/out; `TRANSITION.fade(FadeType, duration, color)` |
| `BATTLE` | Battle state and fighter map |
| `PARTY` | Party members (`PARTY.getFullParty()`) and `PARTY.BACKPACK` inventory |
| `OVERWORLD` | Map switching with threaded loading |
| `COOKING` | Cooking mini-game lifecycle |
| `SAVE` | Persistence (stub) |
| `SETTINGS` | Runtime settings — `invertCameraX:bool`, `invertCameraY:bool` |
| `QUEST` | Quest management (stub) |
| `CUTSCENE` | Cutscene global (stub) |
| `DialogueManager` | godot_dialogue_manager v3.10.4 — parses and steps through `.dialogue` files |
| `UI` | Root UI accessor — `UI.TEXTBOX`, `UI.DEBUG_MENU`, `UI.GAME_MENU` |

## Scene Graph

```
RootScene (Node3D)
  └─ overworld / battle / cooking / initial   ← one shown at a time
RootUI (Control, always visible)
  └─ VNTextbox, DebugMenu, PauseMenu, GameMenu
```

`RootScene` listens to `SCENE.sceneChanged` and shows/hides the correct sub-tree.

## Cutscene / Event Queue

`Cutscene` is the universal sequencing engine. It holds an `Array[Dictionary]` queue; each entry has a `"function": Callable` plus arbitrary data keys.

**Return codes from a callable:**
- `Cutscene.CUTSCENE_CONTINUE` — advance to next item
- `Cutscene.CUTSCENE_END` — stop the cutscene
- An integer index — jump to that position

**Insertion positions:**
- `Cutscene.CUTSCENE_ADD_END` — append (default)
- `Cutscene.CUTSCENE_ADD_NEXT` — insert immediately after current

**Callable pattern** — every action class exposes a pair:

```gdscript
# The actual callable (static, takes params:Dictionary, returns int)
static func myCallable(params:Dictionary) -> int:
    ...
    return Cutscene.CUTSCENE_CONTINUE

# Factory that builds the dictionary for addCallable()
static func getMyCallable(arg) -> Dictionary:
    return { "function": myCallable, "myArg": arg }
```

## Data Registry Pattern

Static registries (Item, Recipe) follow this pattern:
1. `enum Id { NULL, ... }` — typed identifier
2. `static var DATA:Array = []` — indexed by Id value
3. `static func define(params) -> Dictionary` — called at class load to populate `DATA`
4. `static var FOO = define({...})` — registers the entry as a static var
5. `static func get*(id) -> *` — typed accessors

## `_init(params:Dictionary)` Pattern

Non-Node data classes (`BattleFighter`, `BattleDecision`, `ItemStack`, etc.) use a single `params` dictionary constructor with `.get('key', default)` for optional fields.
