Skip to main content

Architecture

note

This page is a living document — fill it in as subsystems stabilise.

Subsystem overview

Initialisation order

  1. Register res:// and cache:// from SDL paths
  2. Load configuration in three layers (engine_defaults → workspace root → game overrides) → mConfig
  3. Configure logging — apply mConfig log levels to log_manager
  4. Register renderer factories (assemblyRegistration())
  5. Create renderer from config — looked up in RendererRegistry by name
  6. Load game.json — register per-game URI scheme roots with engine_defaults fallbacks
  7. Load keybinds (non-fatal if absent)
  8. Create SDL window with renderer flags
  9. Construct ShaderSystem, Scene, SceneGraph
  10. Load and run the game (scenes, scripts)

Design principles

  • Encapsulation — the Engine class handles its own complete setup; main.cpp only creates it and optionally overrides specific config values.
  • Config-driven — renderer type, resource paths, and log levels all come from engine.config.json. No hardcoded paths or types in C++.
  • No raw void* — all APIs use typed C++23 abstractions (std::span, tl::expected, etc.).
  • Reference-only scenes — scenes hold transforms and pointers; all geometry/material data lives in model descriptors.
  • tl::expected error handling — fallible public APIs return tl::expected<T, std::string> instead of throwing exceptions.
  • URI-based resources — all file access uses scheme-mapped URIs (scenes://, textures://, etc.) with fallback paths and .glitterpak archive support.