Skip to main content

Module run_headless

Module run_headless 

Source
Expand description

Rendered offscreen headless mode (lumenc run --headless). True headless run mode: the full app pipeline - layout, real rendering through the app’s render backend and the shared Node-IR walker, the MCP server, input simulation, hot reload, and screenshots - with zero windows. No window backend runs, so the desktop / compositor is never touched. This is the automation / CI mode behind lumenc run <app> --headless.

§How it differs from crate::run::run_app_headless

The bare run_app_headless (kept as the FFI / SDK contract) only ticks the main-world schedule - no renderer, no pixels. This mode additionally installs the offscreen renderer of the backend [render] backend selects (under auto, the first that starts, GPU before CPU), driven by the same retained-scene walker the windowed backend runs - so extracted geometry, dpr scaling, and text shaping behave identically to the windowed path.

§Frame pacing

Ticks run on demand, mirroring the windowed RedrawScheduler semantics without the pause-on-unfocused gate (there is no focus):

  • a wake through lumen_core::app::EventLoopWaker runs a tick immediately: the MCP server thread (simulate push or screenshot request), a finished HTTP request, or a module event on the core bus;
  • while work is pending (animations mid-flight, undrained external property writes, dirty frame), ticks are paced at ~60 Hz - the stand-in for vsync;
  • a deadline a system asked to be woken at (a script timer, see lumen_core::tick::WakeDeadline) ends the park when it comes due;
  • otherwise the loop parks. With hot reload active it re-ticks every ~250 ms so the source watcher polls; without it, the loop sleeps until the next wake (SIGINT/SIGTERM are still observed within one 250 ms slice).

§Exit

SIGINT / SIGTERM (and the end of a bounded --ticks N run) take the graceful-close path: a CloseRequest { vetoed: false } is written to the message bus and one final tick runs so close-observing systems fire, then the fn returns Ok(()) (process exit code 0). Unlike the windowed close, a veto does not keep the app alive - a signalled CI run must terminate.

Structs§

HeadlessOptions
Options specific to the rendered headless mode. Sizing comes from RunOptions::size / lumen.toml [window] size exactly like the windowed path, so it is not duplicated here.

Functions§

run_app_headless_rendered
Run the full pipeline headless. See the module docs for semantics.