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
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.
The scenes/ layout
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:
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:
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 Mawfront_x.
Every path into gameplay — new game, continue, send a relative, start fresh — ends in the same transition:
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.
Autosave
Autosave is owned by Main.gd, not the world. It ticks a timer in _process() on a fixed interval:
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)inMain._ready(), so the close request is Underroot's to handle — quitting always routes throughSaveManager.save_game()first.
Key files
project.godot— setsrun/main_sceneand 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.