# Capability group: `gamedev-engine` — runtime de juego C++ multiplataforma (PC + WebAssembly)

Cluster de primitivas C++ que forman el núcleo de un runtime de juego 2D portable a
escritorio (Windows/Linux/macOS) y navegador (WebAssembly via emscripten). Stack:
**SDL3** (ventana + input + GL context) + **sokol_gfx** (render) + **miniaudio**
(audio). Nacido del Issue 0072b.

A diferencia del grupo hermano `gamedev-2d` (generación de *assets* 2D con ComfyUI y
puente a Godot), este grupo es el **motor que ejecuta el juego**: el bucle de
simulación, la cámara, el input, el render por lotes y el audio. No genera arte; lo
consume en tiempo de ejecución.

Tag: `gamedev-engine`. Filtro: `mcp__registry__fn_search query="" tag="gamedev-engine"`.

## Funciones del grupo

| ID | Firma corta | Qué hace | Pureza |
|---|---|---|---|
| `game_loop_cpp_gamedev` | `loop_run(SDL_Window*, const LoopCfg&) -> void` | Game loop fixed-timestep estilo Glenn Fiedler ("Fix Your Timestep"): desacopla `on_fixed_update` (dt fijo) de `on_render` (factor de interpolación), acumulador con cap anti spiral-of-death. Branch automático desktop (while loop) vs `__EMSCRIPTEN__` (`emscripten_set_main_loop`). | impure |
| `input_unified_cpp_gamedev` | `input_begin_frame(InputState&); input_process_event(InputState&, const SDL_Event*)` | Snapshot unificado de input por frame para SDL3: mapea teclado (WASD+flechas), ratón, gamepad y touch a botones lógicos (left/right/up/down/action_a..y/start/back) y ejes analógicos, con flags `*_pressed` de rising edge limpio. | impure |
| `camera_2d_cpp_gamedev` | `world_to_screen / screen_to_world(Camera2D, Vec2) -> Vec2; visible_world_rect(Camera2D) -> Rect; view_proj_matrix(Camera2D, float[16])` | Cámara ortográfica 2D pura (pos centro, zoom, rotación, viewport): conversiones world↔screen, AABB visible y matriz view-projection 4×4 column-major lista para cualquier renderer. Fast-path sin trig si `rotation==0`. | pure |
| `sokol_setup_cpp_gfx` | `make_environment() -> sg_environment; make_swapchain(int w, int h) -> sg_swapchain` | Builders puros para inicializar sokol_gfx sobre un GL context creado por SDL3 (no por sokol_app): `sg_environment` con defaults RGBA8 + depth/stencil y `sg_swapchain` del default framebuffer del contexto activo. | pure |
| `sprite_batch_cpp_gfx` | `sprite_batch_create(int cap=4096) -> SpriteBatch; sprite_batch_begin/draw/end` | Batched textured quad renderer sobre sokol_gfx: begin/draw/end con auto-flush por cambio de atlas o capacidad llena. Vertex layout pos+uv+color, alpha blending estándar, GLSL 330 / GLES 300. Base de plataformeros, top-down y UI sprites. | impure |
| `audio_engine_cpp_gamedev` | `engine_init() -> Engine; engine_shutdown(Engine&); engine_set_volume(Engine&, float)` | Lifecycle del engine de audio basado en miniaudio (single-header, public domain): inicializa device default, master volume, libera recursos. Cross-platform (WASAPI/ALSA/CoreAudio y WebAudio bajo emscripten). Única TU que define `MINIAUDIO_IMPLEMENTATION`. | impure |
| `audio_play_cpp_gamedev` | `sound_load(Engine&, const char*) -> Sound; sound_play/stop/set_volume/destroy(Sound&); play_sound_oneshot(Engine&, const char*, float)` | Reproducción de audio sobre `fn::audio::Engine`: carga con streaming desde disco (wav/mp3/flac/ogg), play/stop/volumen por sonido, y helper fire-and-forget para one-shots sin handle. | impure |
| `build_wasm_cpp_app_bash_infra` | `build_wasm_cpp_app(app_name, [--no-budget-check]) -> void` | Compila una app C++ del registry (`cpp/apps/<name>`) a WebAssembly via emscripten. Produce `build/wasm/<name>/<name>.{html,js,wasm,wasm.gz}`. Falla si el gzip supera 2 MB (budget). | impure |

## Ejemplo canónico (esqueleto de un juego 2D)

Las primitivas se componen así dentro del `main()` de una app C++ del registry. Cada
identificador (`fn::game_loop`, `fn::input`, `fn::camera2d`, `fn::gfx`, `fn::audio`)
proviene de la función homónima del registry; la app solo aporta la lógica de juego.

```cpp
// 1. Ventana + GL context con SDL3, sokol_gfx encima (sokol_setup)
sg_setup(...);                              // usa make_environment() del registry
auto swap   = fn::gfx::make_swapchain(W, H);
auto batch  = fn::gfx::sprite_batch_create(4096);
auto audio  = fn::audio::engine_init();
fn::audio::play_sound_oneshot(audio, "assets/music.ogg", 0.6f);

// 2. Estado de cámara e input
fn::game::Camera2D cam{ .pos = {0,0}, .zoom = 1.0f, .viewport = {W, H} };
fn::input::InputState in{};

// 3. Game loop fixed-timestep: simulación e interpolación desacopladas
fn::game::LoopCfg cfg{
  .on_event        = [&](const SDL_Event* e){ fn::input::input_process_event(in, e); },
  .on_fixed_update = [&](float dt){ /* mover entidades usando in.left_pressed... */ },
  .on_render       = [&](float alpha){
      fn::gfx::sprite_batch_begin(batch);
      // draw sprites con cam.view_proj_matrix(...) como transform
      fn::gfx::sprite_batch_end(batch);
  },
};
fn::game::loop_run(window, cfg);

// 4. Distribuir a navegador: build_wasm_cpp_app "<app>" -> build/wasm/<app>/
```

## Fronteras (qué NO cubre)

- **Generación de assets** (sprites, tiles, VFX): es el grupo hermano `gamedev-2d`
  (ComfyUI → post-proceso → Godot). Este grupo solo los *renderiza* en runtime.
- **Física / colisiones / ECS**: no incluidos. El `on_fixed_update` recibe el dt fijo;
  la simulación la pone la app.
- **TileSet / mapas / escenas**: no hay sistema de niveles; `sprite_batch` dibuja quads
  sueltos.
- **App end-to-end consumidora**: a fecha de hoy estas primitivas son el núcleo del
  runtime (Issue 0072b) pero **no hay todavía una app C++ que las componga end-to-end**
  (varias están marcadas `pendiente-usar`). El ejemplo de arriba es el esqueleto
  previsto, no un binario validado. Cuando exista la primera app, su `app.md`
  declarará estas IDs en `uses_functions` y servirá de validación e2e.

## Prerequisitos / notas

- **SDL3** para ventana + input + GL context; **sokol_gfx** (vendored en `cpp/vendor/`)
  para render; **miniaudio** (single-header) para audio.
- Target nativo: GLSL 330. Target WebAssembly (emscripten): GLES 300 — `sprite_batch`
  emite ambos shaders.
- `build_wasm_cpp_app` exige el SDK de emscripten en el entorno y respeta un budget de
  2 MB gzip por defecto (`--no-budget-check` para saltarlo).
