---
name: game_loop
kind: function
lang: cpp
domain: gamedev
version: "0.1.0"
purity: impure
signature: "loop_run(SDL_Window*, const LoopCfg&) -> void"
description: "Game loop fixed-timestep estilo Glenn Fiedler ('Fix Your Timestep'). Desacopla simulacion (on_fixed_update con dt fijo) de renderizado (on_render con factor de interpolacion). Acumulador con cap anti spiral-of-death. Branch automatico desktop (while loop bloqueante) vs __EMSCRIPTEN__ (emscripten_set_main_loop). Issue 0072b."
tags: [gamedev-engine, game-loop, sdl3, wasm, fixed-timestep]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: []
example: |
  struct State { bool quit = false; float t = 0; };
  State st;
  fn::game::LoopCfg cfg;
  cfg.user = &st;
  cfg.on_fixed_update = [](void* u, float dt) {
      auto s = (State*)u;
      s->t += dt;
  };
  cfg.on_render = [](void* u, float interp) {
      // render with interp factor between [0, 1)
  };
  cfg.should_quit = [](void* u) { return ((State*)u)->quit; };
  fn::game::loop_run(window, cfg);
tested: false
tests: []
test_file_path: ""
file_path: "cpp/functions/gamedev/game_loop.cpp"
params:
  - name: window
    desc: "SDL_Window activo (no usado actualmente; reservado para futuras integraciones swap/vsync)."
  - name: cfg
    desc: "LoopCfg con fixed_dt (default 1/60), max_steps_per_frame (cap), callbacks on_fixed_update/on_render/should_quit y user pointer."
output: "Bloquea hasta should_quit==true (desktop). En WASM retorna inmediatamente y registra emscripten_set_main_loop."
---

# game_loop

Loop canonico para apps gamedev del registry. Garantiza que la simulacion corra a `fixed_dt` constante (default 60 Hz) independientemente del framerate de render, y expone factor `interp` para que el renderer interpole posiciones entre estados de fisica.

Detalles:
- `frame_time` se cap a `fixed_dt * max_steps_per_frame` para evitar la espiral de la muerte cuando el debugger pausa.
- En `__EMSCRIPTEN__` el estado del acumulador vive en variable static (`g_rt`) — solo un loop activo por modulo WASM.
- `should_quit` se consulta antes de cada frame; en WASM dispara `emscripten_cancel_main_loop`.
- `loop_run` retorna sin hacer nada si ambos callbacks son nulos.
