@@ -0,0 +1,474 @@
# Arquitectura de **Aventures en Egipte (AEE)**
> Guía de orientación para un desarrollador nuevo en el proyecto.
>
> Cada afirmación está anclada a código real: se cita el fichero (y, cuando
> ayuda, la función o el número de línea) que la respalda. Donde no he
> encontrado algo, lo digo explícitamente en lugar de inventarlo.
>
> **Aventures en Egipte** es un juego de aventura/plataformas retro (el
> protagonista "Sam" explora pirámides esquivando momias y recogiendo
> tesoros), escrito en C++ + SDL3. Resolución de juego **320× 200**. El rasgo
> que más condiciona el código es que está **en plena migración** desde un
> motor legacy propio ("Jail") hacia C++ moderno (ver
> [§3](#3-el-motor-legacy-jail)). Los comentarios del código están en
> valenciano/español; este documento está en castellano.
>
> Existe además un `docs/scenes-migration-plan.md` (histórico) sobre la
> migración del sistema de escenas; aquí se documenta el **estado actual** del
> código, no el plan.
---
## Índice
1. [Visión general ](#1-visión-general )
2. [Punto de entrada y bucle principal ](#2-punto-de-entrada-y-bucle-principal )
3. [El motor legacy "Jail" ](#3-el-motor-legacy-jail )
4. [Escenas y máquina de estados ](#4-escenas-y-máquina-de-estados )
5. [Renderizado: de la lógica al píxel ](#5-renderizado-de-la-lógica-al-píxel )
6. [Entrada ](#6-entrada )
7. [Gameplay: `ModuleGame` y entidades ](#7-gameplay-modulegame-y-entidades )
8. [Sistema de escenas cinemáticas ](#8-sistema-de-escenas-cinemáticas )
9. [Recursos ](#9-recursos )
10. [Audio y localización ](#10-audio-y-localización )
11. [Configuración y persistencia ](#11-configuración-y-persistencia )
12. [Modo demo / IA ](#12-modo-demo--ia )
13. [Convenciones y patrones recurrentes ](#13-convenciones-y-patrones-recurrentes )
14. [Guía de navegación: "si quieres tocar X, mira Y" ](#14-guía-de-navegación-si-quieres-tocar-x-mira-y )
---
## 1. Visión general
El árbol `source/` separa **motor ** y **juego ** , pero con una particularidad:
el motor tiene **dos generaciones ** conviviendo (legacy "Jail" + capas nuevas).
- **`source/core/jail/` ** — el **motor legacy "Jail" ** (APIs C planas): `Jg`
(jgame), `Jd8` (jdraw8), `Ji` (jinput), `Jf` (jfile). En modernización (§3).
- **`source/core/` ** (resto) — capas **nuevas ** : `rendering` (`Screen` ,
`Overlay` , `Text` , `Menu` , `sdl3gpu` ), `input` , `system` (`Director` ),
`resources` , `audio` , `locale` .
- **`source/game/` ** — el juego: gameplay legacy en la raíz (`modulegame` ,
`prota` , `momia` , `engendro` , `bola` , `mapa` , `marcador` , `info` , `sprite` ) y
el sistema de **escenas ** nuevo en `scenes/` .
- **`source/utils/` ** — `easing` , `utils` .
- **`source/external/` ** — vendorizado (stb, fkyaml).
~117 ficheros C++, ~40.000 líneas.
**El `CLAUDE.md` define una frontera explícita "Original vs New Code" ** (§79):
`core/jail/` y `game/*.cpp` son * legacy en modernización * (modificar con
cuidado, preservando comportamiento); `core/rendering` , `core/input` ,
`utils/` , `options/defines/defaults` son * código nuevo * . Interiorizar esa
frontera es lo primero para no romper invariantes del juego original.
**Ideas-fuerza: **
1. Un solo hilo, **tick-based ** , vía callbacks de SDL3 (§2).
2. El render es **software paletizado 8-bit ** (`Jd8` , 320× 200) que al final se
convierte a ARGB y pasa por shaders GPU (§5).
3. El flujo de pantallas es una **máquina de estados ** apoyada en
`Info::ctx.num_piramide` , con un `SceneRegistry` que va sustituyendo
cinemáticas legacy por escenas nuevas (§4).
``` mermaid
graph TD
SDL[SDL3 callbacks · main.cpp] --> DIR[Director]
DIR -->|game_state_ + Info::ctx| DISP{createNextScene}
DISP -->|==0| MG["ModuleGame (gameplay)"]
DISP -->|==1| REG["SceneRegistry::tryCreate(num_piramide)"]
REG --> CINE["intro / banner / slides / mort / secreta / credits…"]
MG --> MAPA[Mapa] & PROTA[Prota] & MOMIA[Momia] & BOLA[Bola] & MARC[Marcador]
DIR --> INP["KeyConfig / GlobalInputs / Gamepad / KeyRemap / Mouse"]
MG -->|dibuja índices| JD8["Jd8 (8-bit 320× 200)"]
CINE --> JD8
JD8 -->|JD8_Flip → ARGB| SCREEN[Screen]
OVL[Overlay] --> SCREEN
SCREEN --> GPU["sdl3gpu PostFX / CrtPi / upscale"] --> WIN[Ventana]
RES["Resource::Cache / List"] -.-> MG & CINE
```
---
## 2. Punto de entrada y bucle principal
### 2.1. SDL conduce el bucle (callbacks)
`source/main.cpp` define `SDL_MAIN_USE_CALLBACKS` . No hay `while` propio (clave
para el port a Emscripten). `SDL_AppInit` monta todo y `SDL_AppIterate` llama a
`Director::iterate()` .
El arranque en `SDL_AppInit` inicializa, en orden: carpeta de config (`Jf` ),
sistema de recursos (`resources.pack` + fallback en Debug/WASM), `Options` ,
`KeyConfig` , `Locale` , presets de shaders, y luego el **motor ** : `Jg::init` ,
`Screen::init` , `Jd8::init` , `Audio::init` , `Overlay::init` , `Menu::init` ,
`Resource::List` /`Cache` (con `beginLoad()` ), y `Director::init` + `setup()` .
### 2.2. El `Director`
`source/core/system/director.{hpp,cpp}` . Es el **orquestador singleton, único
hilo del runtime** (sin fibers, mutex ni condition variables; el comentario de
`director.hpp:11` lo subraya). Posee el estado de escena como miembros:
`current_scene_` (`std::unique_ptr<Scenes::Scene>` ), `game_state_` ,
`last_tick_ms_` , y dos buffers de frame `[320*200]` (`game_frame_` ,
`presentation_buffer_` ).
Cada `iterate()` (modelo documentado en `CLAUDE.md:161` ):
```
Gamepad/KeyRemap/GlobalInputs/Mouse::update
JA_Update() ← bombeo de audio
if (!paused_) {
if (scene && (scene->done() || JG_Quitting())) game_state_ = scene->nextState(); scene.reset();
if (!scene) scene = createNextScene(); scene->onEnter(); ← ModuleGame o SceneRegistry
JI_Update()
scene->tick(now - last_tick_ms_)
JD8_Flip() ← índices → ARGB
memcpy → game_frame
}
memcpy game_frame → presentation_buffer
Overlay::render(presentation_buffer)
Screen::present(presentation_buffer)
SDL_Delay(frame_target - elapsed) ← cap de FPS
```
### 2.3. Tiempo, pausa y salida
Las escenas reciben `delta_ms` real (time-based). El gameplay (`ModuleGame` )
gatea su `Update()` a 10 ms fijos vía `Jg::shouldUpdate()` (ticker del motor
legacy, ya sin * yield * ). La **pausa ** (F11) simplemente salta el bloque de
`tick()` : el overlay y el present siguen, re-presentando el último frame
congelado. La **salida ** se solicita con `requestQuit()` (doble ESC o
`SDL_QUIT` ) y `requestRestart()` hace un reinicio suave (para audio, resetea
`Info::ctx` , vuelve a la intro).
---
## 3. El motor legacy "Jail"
`source/core/jail/` es el sustrato heredado, **APIs C planas con prefijo por
subsistema** (sin clases), que se está convirtiendo progresivamente a C++
idiomático manteniendo los nombres externos estables para no romper los
* call sites * (`CLAUDE.md:92` ). Es el rasgo más distintivo del proyecto.
| Subsistema | Fichero | Qué hace |
|---|---|---|
| * * `Jg` ** (jgame) | `jail/jgame.*` | * Timing * : init/finalize, fixed-timestep (`Jg::shouldUpdate()` a 10 ms), flag de salida (`JG_Quitting` ). |
| * * `Jd8` ** (jdraw8) | `jail/jdraw8.*` | **Renderer software 8-bit paletizado ** , buffer de pantalla 320× 200 (`Jd8::Surface = Uint8*` ), blits con * color key * , fades no bloqueantes (máquina de estados), `flip()` (paleta→ARGB) → `Screen::present` . |
| * * `Ji` ** (jinput) | `jail/jinput.*` | Sondeo de teclado, * debounce * , códigos * cheat * . Filtra las teclas de GUI del juego y llama a `GlobalInputs` /`Mouse` cada update. |
| * * `Jf` ** (jfile) | `jail/jfile.*` | I/O de ficheros: carpeta `data/` o pack; carpeta de config en `~/.config/jailgames/aee/` . |
### `Jd8` en detalle (el corazón del render)
`jail/jdraw8.hpp` . API representativa:
- `using Surface = Uint8*` (búfer de índices de paleta), `using Palette = Color*` .
- `loadSurface` /`newSurface` /`freeSurface` , `loadPalette` /`setScreenPalette` .
- Blits: `blit` , `blitCK` (con * color key * /transparencia), `blitCKCut` ,
`blitCKScroll` , `blitToSurface` /`blitCKToSurface` (blit entre surfaces).
- `fillRect` /`fillSquare` /`putPixel` /`getPixel` .
- **Fade no bloqueante** (`fadeStart*` + `fadeTickStep` que devuelve `true` al
acabar): sustituye los `JD8_FadeOut` bloqueantes del código original.
- `flip()` convierte el buffer indexado + paleta a ARGB y delega en
`Screen::present` ; `getFramebuffer()` devuelve el `Uint32*` resultante.
> Mentalidad clave: **todo el dibujo del juego ocurre sobre índices de 8 bits**
> en un buffer 320× 200; el color real y los shaders entran solo al final.
---
## 4. Escenas y máquina de estados
### 4.1. La base `Scene`
`source/game/scenes/scene.hpp` (`namespace Scenes` ):
``` cpp
class Scene {
public :
virtual void onEnter ( ) { } // una vez, antes del primer tick
virtual void tick ( int delta_ms ) = 0 ; // no bloquea, NO llama a Jd8::flip
virtual auto done ( ) const - > bool = 0 ;
virtual auto nextState ( ) const - > int { return 1 ; } // 1=siguiente, 0=gameplay, -1=salir
} ;
```
El `Director` hace avanzar la escena hasta que `done()` es cierto, consulta
`nextState()` y construye la siguiente.
### 4.2. El despachador: `game_state_` + `Info::ctx`
`Director::createNextScene()` decide la siguiente escena:
- `game_state_ == 0` → `new ModuleGame` (gameplay puro, §7).
- `game_state_ == 1` → `SceneRegistry::tryCreate(Info::ctx.num_piramide)`
(`game/scenes/scene_registry.hpp` ): un mapa `int → factory` que devuelve la
escena registrada para ese estado, o `nullptr` para caer al **path legacy ** .
Replica el viejo `ModuleSequence::Go` , incluido el * redirect * heredado
`num_piramide == 6 && diners < 200 → 7` (`CLAUDE.md:104` ).
- `game_state_ == -1` → salir.
### 4.3. `Info::ctx`: el estado del juego
`source/game/info.hpp` — `Info::GameContext ctx` (singleton inline) es la fuente
de verdad del estado:
``` cpp
struct GameContext {
int num_piramide , num_habitacio , diners , diamants , vida , momies , engendros ;
bool nou_personatge , pepe_activat ;
void reset ( ) ;
} ;
```
`num_piramide` es la pieza central: hace de **selector tanto de cinemáticas como
de nivel jugable**. El `SceneRegistry` va migrando cada estado de cinemática a
una `Scene` nueva; lo que no esté registrado cae a legacy. Por eso el registro
"crece" a medida que avanza la modernización.
``` mermaid
graph LR
SC[Scene activa] -->|done()| NS{nextState}
NS -->|0| MG[ModuleGame]
NS -->|1| REG["SceneRegistry(num_piramide)"]
NS -->|-1| QUIT[salir]
MG -->|muta Info::ctx| REG
REG --> SC
```
---
## 5. Renderizado: de la lógica al píxel
El pipeline tiene dos mitades: **software paletizado ** (`Jd8` ) y **GPU **
(`Screen` + shaders).
### 5.1. Software: dibujar índices
Escenas y `ModuleGame` dibujan sobre el buffer `screen` de `Jd8` (índices 8-bit,
320× 200) con blits y * color key * . `JD8_Flip()` aplica la paleta y produce un
buffer ARGB (formato **ABGR8888 ** : `0xFF000000 + R + (G<<8) + (B<<16)` ;
`CLAUDE.md:220` ).
### 5.2. `Overlay`: sobre el buffer ARGB
`source/core/rendering/overlay.*` pinta **directamente sobre el buffer ARGB **
antes de presentar: notificaciones (slide-in), info de render animada (4
segmentos), indicador de **PAUSA ** y la lógica de **doble-ESC para salir ** .
### 5.3. `Screen`: a la ventana (GPU o fallback)
`source/core/rendering/screen.*` (singleton). Doble camino
(`Screen::present` , `CLAUDE.md:204` ):
- **GPU con shaders** (primario, `sdl3gpu/` ): sube los píxeles a una textura
de escena 320× 200; opcionalmente * upscale * /**supersampling** (3× /6× /9× con
* downscale * Lanczos) y **estiramiento 4:3 ** fusionado en el * upscale * ; luego
el shader **PostFX ** o **CRT-Pi ** (con presets) a la * swapchain * con
* letterboxing * .
- **GPU sin shaders**: subida limpia a la * swapchain * .
- **Fallback**: `SDL_UpdateTexture` + `SDL_RenderPresent` (`SDL_Renderer` ).
`Screen` gestiona ventana, fullscreen, zoom, 4:3, * integer scaling * , VSync, FPS.
Apoyos de UI: `Text` (fuentes bitmap `.fnt` +`.gif` sobre el buffer ARGB, con
* clipping * 2D) y `Menu` (menú flotante de opciones con navegación por páginas,
animaciones y captura de teclas para * remapping * ).
---
## 6. Entrada
Toda la entrada de UI/sistema converge en * * `KeyConfig` ** como fuente única de
verdad de las teclas (`source/core/input/key_config.*` ): carga
`data/input/keys.yaml` (F1– F10 GlobalInputs + F11 pausa + F12 menú) y aplica
* overrides * del usuario; expone `scancode("id")` , `isGuiKey(sc)` (para que el
`Director` no propague teclas de UI al juego), y persiste solo lo que difiere
del default.
- **`GlobalInputs` ** (`global_inputs.*` ) — mapea las F-keys a acciones de
presentación (zoom, fullscreen, shaders, 4:3, supersampling, filtro, render
info, pausa, menú). Tabla completa en `CLAUDE.md:139` .
- **`Gamepad` ** (`gamepad.*` ) — primer mando con * hot-plug * y notificación;
D-pad/stick → flechas virtuales; botones frontales → Enter sintético;
SELECT → menú, START → pausa. Carga `gamecontrollerdb.txt` .
- **`KeyRemap` ** (`key_remap.*` ) — cada frame copia `Options::keys_game.*` al
estado virtual de scancodes estándar (UP/DOWN/LEFT/RIGHT). Permite remapear el
movimiento **sin tocar el código legacy ** de `prota.cpp` /`mapa.cpp` .
- **`Mouse` ** (`mouse.*` ) — auto-oculta el cursor tras 3 s de inactividad.
> Reparto deliberado: las teclas de **UI/sistema** viven en `KeyConfig`
> (`keys.yaml`); las de **movimiento del jugador** en `Options::keys_game`
> (`config.yaml`, sección `controls:`).
---
## 7. Gameplay: `ModuleGame` y entidades
`source/game/modulegame.{hpp,cpp}` es la **escena de gameplay puro **
(`game_state_ == 0` ). Hereda de `Scenes::Scene` y sustituye el viejo `Go()`
bloqueante por un `tick()` . Tres fases internas (`Phase` ):
`FADING_IN → PLAYING → FADING_OUT → DONE` (`modulegame.hpp:46` ), con un
`PaletteFade` para los fundidos no bloqueantes.
Coordina las entidades del nivel, todas con una `Jd8::Surface gfx_` compartida:
- **`Mapa` ** (`game/mapa.*` ) — la sala/pirámide: tiles con contenido
(`CONTE_RES` /`CONTE_TRESOR` /`CONTE_FARAO` …), colisión y dibujo del escenario.
- **`Prota` ** (`game/prota.*` ) — el protagonista "Sam" (hereda de `Sprite` ),
movimiento y colisión.
- **`Momia` ** (`game/momia.*` ) — enemigo que persigue al `Prota` (recibe
`Prota*` ); variante `dimoni` (demonio).
- **`Bola` ** (`game/bola.*` ) — bola/roca que interactúa con el `Prota` .
- **`Engendro` ** (`game/engendro.*` ) — entidad generada (su `update()` devuelve
`bool` ); `Info::ctx.engendros` lleva la cuenta.
- **`Marcador` ** (`game/marcador.*` ) — el marcador (vidas, dinero, diamantes),
lee del `Prota` /`Info::ctx` .
`ModuleGame::tick()` hace `draw()` (a `screen` , sin `flip` — lo hace el
`Director` ) y `update()` (gateado por `Jg::shouldUpdate` ). Cuando la partida
acaba (`final_ != 0` : muerte o cambio de sala), `applyFinalTransitions()` muta
`Info::ctx` y `nextState()` devuelve el estado siguiente.
Todas las entidades de gameplay derivan de * * `Sprite` ** (`game/sprite.*` ),
clase base con `draw()` /`update()` sobre `Jd8` .
---
## 8. Sistema de escenas cinemáticas
Las pantallas no jugables (`game_state_ == 1` ) son `Scene` s registradas en el
`SceneRegistry` . Las concretas viven en `source/game/scenes/` : `boot_loader`
(carga incremental, §9), `banner` , `intro` , `intro_new_logo` , `intro_sprites` ,
`slides` , `menu` (`menu_scene` ), `mort` (secuencia de muerte), `secreta`
(pantalla secreta) y `credits` .
Sobre ellas hay un **conjunto de utilidades de animación ** reutilizables —el
andamiaje "cinematográfico" del juego—:
- **`Timeline` ** (`scenes/timeline.*` ) — secuenciación temporal de eventos.
- **`FrameAnimator` ** (`scenes/frame_animator.*` ) — animación por fotogramas.
- **`SpriteMover` ** (`scenes/sprite_mover.*` ) — movimiento interpolado de
sprites (con `easing` ).
- **`PaletteFade` ** (`scenes/palette_fade.*` ) — fundidos por paleta no
bloqueantes (también usado por `ModuleGame` ).
- **`SurfaceHandle` ** (`scenes/surface_handle.*` ) — propiedad RAII de una
`Jd8::Surface` (las escenas poseen sus assets y los liberan en el destructor).
- **`scene_utils` ** — helpers compartidos.
---
## 9. Recursos
- **`Resource::List` ** (`core/resources/resource_list.*` ) — registro de rutas de
asset desde * * `data/config/assets.yaml` **, con consulta O(1).
- **`Resource::Cache` ** (`core/resources/resource_cache.*` ) — caché de assets con
**carga incremental ** : `beginLoad()` (en `SDL_AppInit` ) + la escena
`BootLoaderScene` que el `Director` arranca automáticamente mientras
`Resource::Cache::isLoadDone()` sea falso (una barra de progreso con la
ventana viva).
- **Pack y fallback**: `resource_pack.*` + `resource_helper.*` sirven desde
* * `resources.pack` ** (formato propio "AEE1", `CLAUDE.md:237` ); en release
nativo es estricto (solo pack), en Debug/WASM hay * fallback * a `data/` .
- **Formatos**: GIF/paletas para gráficos (vía `Jd8` ), fuentes `.fnt` +`.gif` ,
OGG/WAV para audio, GLSL para shaders.
---
## 10. Audio y localización
- **Audio**: `core/audio/audio.*` (singleton, aplica `Options::audio` ) sobre
* * `jail_audio` ** (`Ja` , `jail/jail_audio.hpp` / `core/audio/jail_audio.hpp` ),
mezcla propia con streams SDL3 (OGG vía `stb_vorbis` , WAV). `JA_Update()` se
bombea cada frame desde el `Director` ; pausa/resume con F11.
- **Localización**: `core/locale/locale.*` — mapa plano clave→cadena cargado de
YAML (`data/locale/ca.yaml` , valenciano por defecto). Claves con notación de
puntos (`menu.items.zoom` ); si falta una clave, devuelve la propia clave
(fallback visible para depurar).
---
## 11. Configuración y persistencia
- **`Options` ** (`source/game/options.*` ) — namespace con globals `inline` y
carga/guardado YAML. Structs: `KeysGame` (movimiento), `Video` , `RenderInfo` ,
`Audio` , `Window` , `Game` , `PostFXPreset` , `CrtPiPreset` .
- **`defines.hpp` ** — constantes del juego: `Texts::WINDOW_TITLE` /`VERSION` ,
`GameScreen::WIDTH=320` /`HEIGHT=200` /`BUFFER_SIZE=64000` .
- **`defaults.hpp` ** — valores por defecto (`Defaults::KeysGame` , `Video` ,
`Audio` , `Window` , `Game` ).
- **`KeyConfig` ** — teclas de UI (§6).
Ficheros persistentes en `~/.config/jailgames/aee/` (`CLAUDE.md:224` ):
`config.yaml` (vídeo/audio/ventana/render_info/controles), `keys.yaml`
(overrides de UI), `postfx.yaml` (6 presets), `crtpi.yaml` (4 presets), y en
Debug `debug.yaml` (estado inicial de gameplay para pruebas).
**Builds condicionales ** : `NDEBUG` (release: pack estricto, sin `debug.yaml` ),
`__EMSCRIPTEN__` (WASM: fuerza ventana/zoom/4:3, mantiene fallback de assets,
sin persistencia MEMFS).
---
## 12. Modo demo / IA
**No he encontrado un modo demo, * attract mode * ni IA de demostración en este
proyecto.** Lo he buscado explícitamente: la única aparición de "replay" es un
comentario en `jail_audio.hpp` sobre re-reproducción de pistas de audio, sin
relación con un modo demo.
A diferencia de los proyectos hermanos `coffee_crisis` (playback de input
grabado) o `jaildoctors_dilemma` (tour de habitaciones), aquí el flujo de
atracción —si lo hubiera— se construiría sobre el `SceneRegistry` y las escenas
cinemáticas (§8), pero **hoy no existe ** tal cosa implementada.
---
## 13. Convenciones y patrones recurrentes
- **Frontera legacy/nuevo** (`CLAUDE.md:79` ): lo más importante. `core/jail/` y
`game/*.cpp` son legacy en modernización (preservar comportamiento); el resto
es código nuevo. Los assets de `data/gfx` /`data/music` son **intocables ** .
- **Namespaces legacy abreviados** `Jg` /`Jd8` /`Ji` /`Jf` /`Ja` (APIs C planas),
con nombres externos estables durante la transición.
- **Single-thread, tick-based**: sin fibers/mutex; las escenas no bloquean ni
llaman a `Jd8::flip` (lo hace el `Director` ).
- **Render paletizado 8-bit** sobre buffer 320× 200; color y shaders solo al
final (`JD8_Flip` → `Screen` ).
- **Singletons con `init()` /`destroy()` /`get()` ** (`Screen` , `Audio` ,
`Director` , `Menu` , `Overlay` , `Resource::*` , `Jd8` /`Jg` como módulos),
creados/destruidos en orden explícito en `SDL_AppInit` /`SDL_AppQuit` .
- **Máquina de estados por `Info::ctx.num_piramide` ** + `SceneRegistry` que
migra cinemáticas legacy a `Scene` s nuevas de forma incremental.
- **Fades y timing no bloqueantes**: lo que antes eran bucles bloqueantes
(`JD8_FadeOut` ) ahora son máquinas de estados que avanzan un paso por tick.
- **Comentarios** en valenciano/español; muchos `#include` con comentario de
justificación (estilo IWYU).
---
## 14. Guía de navegación: "si quieres tocar X, mira Y"
| Quiero… | Empieza por… |
|---|---|
| Entender el arranque | `source/main.cpp` (`SDL_AppInit` ) + `core/system/director.cpp` |
| El bucle / orden del frame | `Director::iterate()` (`director.cpp` ) |
| Tocar el motor de dibujo | `core/jail/jdraw8.*` (`Jd8` ) |
| Timing / fixed-timestep | `core/jail/jgame.*` (`Jg::shouldUpdate` ) |
| Añadir/editar una pantalla | `game/scenes/` (hereda de `Scenes::Scene` ) + `SceneRegistry::registerScene` |
| Cómo se decide la siguiente pantalla | `Director::createNextScene` + `Info::ctx.num_piramide` + `scene_registry.*` |
| El estado del juego | `game/info.hpp` (`Info::ctx` ) |
| **Gameplay ** | `game/modulegame.*` (fases) + entidades `prota/momia/bola/engendro/mapa/marcador` |
| Animaciones de cinemáticas | `game/scenes/{timeline,frame_animator,sprite_mover,palette_fade,surface_handle}.*` |
| Composición final / shaders | `core/rendering/screen.*` + `sdl3gpu/` + presets `postfx.yaml` /`crtpi.yaml` |
| Overlays (notificaciones/PAUSA/info) | `core/rendering/overlay.*` |
| Texto / menú | `core/rendering/text.*` , `core/rendering/menu.*` |
| Teclas de UI / F1– F12 | `core/input/key_config.*` + `global_inputs.*` + `data/input/keys.yaml` |
| Remapear movimiento | `core/input/key_remap.*` + `Options::keys_game` |
| Mando | `core/input/gamepad.*` |
| Cargar recursos / barra de carga | `core/resources/resource_cache.*` + `resource_list.*` + `scenes/boot_loader_scene.*` |
| Audio | `core/audio/audio.*` + `jail_audio.hpp` (`Ja` ) |
| Idiomas | `core/locale/locale.*` + `data/locale/` |
| Opciones / constantes | `game/options.*` , `game/defines.hpp` , `game/defaults.hpp` |
| Carpetas y pack | `core/jail/jfile.*` (`Jf` ) + `core/resources/resource_pack.*` |
---
*Documento generado a partir de la lectura directa del código en el commit
actual de la rama `main` . Si algo aquí no cuadra con el código, el código
manda: actualiza este documento.*