# Repository Layout and Boot Flow

The top-level directory map, and how the game boots: from the main scene in `project.godot`, through the intro and title screens, into gameplay. Autosave too.

## Top-level directories

| Directory | Contents |
|---|---|
| `scripts/` | All GDScript logic that is not attached to a scene: autoload singletons, resources, and per-system managers. |
| `scenes/` | Scene scripts and the few `.tscn` scene files. Subfolders: `ui/`, `world/`, `village/`, `forest/`, `maw/`, `main/`. |
| `data/` | JSON data files loaded at startup by `DataRegistry` — materials, tools, recipes, machines, balance, and more. |
| `tools/` | Headless verification scripts: `parse_check.ps1`, `validate_data.gd`, `smoke_test.gd`. |
| `assets/` | Art, fonts, music, and the UI theme (`assets/ui/underroot.tres`). |
| `addons/` | The one bundled editor addon, `copy_all_errors` (enabled in `project.godot`). |
| `.github/workflows/` | `ci.yml` — the three headless CI gates. |

### The `scripts/` layout

```text
scripts/
  core/       EventBus, GameManager, SaveManager, ToolState, TimeManager, AudioManager,
              CraftingUnlockManager, GameConstants, AstrolabeManager, WeatherManager,
              PerfMonitor, PerformanceMode, PerfSetup, FontSetup, CosmeticManager,
              CodeManager, ChallengeManager, HarrowManager, SessionTelemetry, TutorialNudges
  resources/  DataRegistry, Inventory, MaterialDef, ToolDef, RecipeDef
  world/      WorldManager, RockManager, TerrainDigging, DiscoveryManager, LayerGenerator,
              TileData, SurfaceRock
  building/   BuildManager, WallData
  maw/        MawController, MawAdaptation
  forest/     ForestManager, ForestNode, BerryBush
  village/    SurvivalManager, VillageManager, ProjectManager, SpecialistManager
  machines/   MachineManager, MachineData
  idle/       TaskQueue, OfflineSimulator
  ui/         GameOverScreen, OfflineSummaryController, UITheme, HudShell, LayerNav
```

`UITheme` (tokens + tooltips), `HudShell` (HUD-skin state), and `LayerNav` (shared click-to-travel) are static `class_name` helpers, not autoloads — see [The Talismans HUD](/docs/underroot/the-talismans-hud).

### The `scenes/` layout

```text
scenes/
  ui/          HUD, menus, overlays, popups, plus IntroStory.tscn and TitleScreen.tscn
  village/     VillageBackdrop (procedural surface scenery)
  world/       World.tscn + dig/gather/build/particle controllers and terrain display
  forest/      ForestDisplay
  maw/         MawDisplay
  main/        Main.tscn / Main.gd — the runtime root
```

Most UI is built procedurally in code, so `scenes/ui/` holds many `.gd` scripts that are attached to plain `CanvasLayer`/`Control`/`Node2D` instances at runtime rather than authored `.tscn` files. The two authored entry scenes are `IntroStory.tscn` and `TitleScreen.tscn`. Both HUD skins live here side by side — the classic surfaces (`MawBar`, `VillageBar`, `BottomBar`) and the talisman instruments (`MawMedallion`, `HearthCrest`, `DiggerCharm`, `MaterialRail`, `LedgerOverlay`, `SpeechBubbleLayer`).

## Boot flow

The engine starts at the scene named in `project.godot`:

```text
run/main_scene="res://scenes/ui/IntroStory.tscn"
```

The chain is: **IntroStory → TitleScreen → Main**.

### 1. Autoloads initialize

Before any scene runs, Godot instantiates the 33 autoloads in the order listed in `project.godot`. Order matters here: `FontSetup` and `PerfSetup` come first so fonts and Low Performance Mode are ready before any renderer draws, and data/state singletons (`DataRegistry`, `SaveManager`, `Inventory`, and the world/village managers) load ahead of the scenes that read them.

### 2. IntroStory — the studio card and story slideshow

`scenes/ui/IntroStory.gd` (a `Node2D`) plays a procedural "SWAVVY presents" pixel-tile title card, then fades through five story images (`underroot_story_1.png` … `underroot_story_5.png`) with per-image display times. It runs a small `_state` machine (`card_show → card_fade → fade_in → hold → fade_out`) in `_process()` and draws each frame in `_draw()`. A "SKIP ›" button and the Space/Enter/Esc keys call `_finish()`, which advances the scene:

```gdscript
func _finish() -> void:
	if _state == "done":
		return
	_state = "done"
	get_tree().change_scene_to_file("res://scenes/ui/TitleScreen.tscn")
```

### 3. TitleScreen — save slots and run entry

`scenes/ui/TitleScreen.gd` reads the save slots via `SaveManager.list_slots()` and decides what to show:

- With one or more slots and no pre-selected slot, it builds a **slot picker** (a grid of digger tiles plus a trailing "+ New save" tile).
- Otherwise it shows a state panel: `_build_fresh()` (no saves), `_build_alive()` (Continue an in-progress run), or `_build_dead()` (the fallen-digger / lineage screen). Save state is classified by `_check_save_state()` from the slot's food, water, and Maw `front_x`.

Every path into gameplay — new game, continue, send a relative, start fresh — ends in the same transition:

```gdscript
get_tree().change_scene_to_file("res://scenes/main/Main.tscn")
```

The title screen also hosts the TOP RUNS ledger, Import Save, and (once unlocked) the Challenges selection overlay.

### 4. Main — the runtime root

`scenes/main/Main.tscn` is a single `Node` running `scenes/main/Main.gd`. Its `_ready()` instantiates the `World.tscn` scene and then adds every runtime overlay `CanvasLayer` (offline summary, game-over screen, cutscenes, weather, popups). Main also decides whether to run offline catch-up (`_check_offline_return()`), shows breach toasts, and either starts normal music or defers to Wren's tutorial intro on a fresh run.

The full node tree that `World.tscn` and `Main.gd` build is documented in [The Scene Tree](/docs/underroot/the-scene-tree).

## Autosave

Autosave is owned by `Main.gd`, not the world. It ticks a timer in `_process()` on a fixed interval:

```gdscript
const AUTO_SAVE_INTERVAL := 20.0

func _process(delta: float) -> void:
	_save_timer -= delta
	if _save_timer <= 0.0:
		_save_timer = AUTO_SAVE_INTERVAL
		SaveManager.save_game()
```

So the game persists to the active slot every 20 seconds. `Main.gd` also saves on a clean window close (`_notification(NOTIFICATION_WM_CLOSE_REQUEST)`), warning first via a `ConfirmModal` if crafts are still underway (`GameManager.crafts_underway > 0`).

> The window is set with `get_tree().set_auto_accept_quit(false)` in `Main._ready()`, so the close request is Underroot's to handle — quitting always routes through `SaveManager.save_game()` first.

## Key files

- `project.godot` — sets `run/main_scene` and the autoload boot order.
- `scenes/ui/IntroStory.gd` — studio card + story slideshow; hands off to TitleScreen.
- `scenes/ui/TitleScreen.gd` — save slots, run entry, TOP RUNS; hands off to Main.
- `scenes/main/Main.gd` — instantiates World, loads overlays, runs the 20 s autosave.
- `.github/workflows/ci.yml` — the headless verification gates run on push/PR.

## Related

- [Introduction and Tech Stack](/docs/underroot/introduction-amp-tech-stack)
- [The Scene Tree](/docs/underroot/the-scene-tree)
- [Local Setup and Running](/docs/underroot/local-setup-and-running)
- [Save System and Migration](/docs/underroot/save-system-and-migration)
- [The Autoload Model](/docs/underroot/the-autoload-model)