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::EventLoopWakerruns 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§
- Headless
Options - Options specific to the rendered headless mode. Sizing comes from
RunOptions::size/lumen.toml [window] sizeexactly 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.