The MVU runtime GenServer. Owns all application and component state.
Runs the main loop:
- Receive events (from DemoRunner or test harness)
- Route through EventManager
- Update component states
- Re-render the element tree
- Diff and output to terminal
Can run in two modes:
:live- driven by a real terminal:headless— for testing (no terminal, captures frames)
Summary
Functions
Returns a specification to start this module under a supervisor.
Dispatch an agent action. Synchronous — by the time this returns, the
UI has re-rendered and is ready for a follow-up snapshot/1.
Drop live mode by ref. Decrements live counter.
Find a single widget in the current snapshot by id. Returns the
semantic node or nil.
Get a component's current state.
Get the current focus state.
Get the current rendered frame as list of strings (headless mode).
Get the current element tree.
Set the root app module and initialize it.
Force a re-render.
Request live mode. Returns a ref that must be passed to drop_live/2.
Resize the runtime.
Resume the runtime — restores terminal and restarts tick loop. Must match each suspend.
Send a message to the app module's update/3 directly.
Send an event to the runtime for processing.
Send a message to a specific component.
Return a semantic snapshot of the UI for agent consumption.
Start continuous tick loop (explicit mode).
Start the runtime.
Stop continuous tick loop.
Suspend the runtime — pauses tick loop and suspends terminal. Supports nesting.
Types
@type model() :: %{ app_module: module() | nil, app_state: term(), component_states: %{optional(term()) => component_state()}, renderer: ElixirOpentui.Renderer.t(), event_manager: ElixirOpentui.EventManager.state(), tree: ElixirOpentui.Element.t() | nil, mode: :live | :headless, on_event: (term() -> :ok) | nil, control_state: :idle | :running | :stopping, target_frame_time: pos_integer(), last_tick_time: non_neg_integer(), live_refs: MapSet.t(reference()), explicit_start: boolean(), suspend_count: non_neg_integer(), tick_timer_ref: reference() | nil }
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec dispatch(GenServer.server(), ElixirOpentui.Accessibility.action()) :: :ok
Dispatch an agent action. Synchronous — by the time this returns, the
UI has re-rendered and is ready for a follow-up snapshot/1.
See ElixirOpentui.Accessibility.action/0 for the action vocabulary.
@spec drop_live(GenServer.server(), reference()) :: :ok
Drop live mode by ref. Decrements live counter.
@spec find_widget(GenServer.server(), term()) :: ElixirOpentui.Accessibility.node_snapshot() | nil
Find a single widget in the current snapshot by id. Returns the
semantic node or nil.
@spec get_component_state(GenServer.server(), term()) :: term() | nil
Get a component's current state.
@spec get_focus(GenServer.server()) :: ElixirOpentui.Focus.t()
Get the current focus state.
@spec get_frame(GenServer.server()) :: [String.t()]
Get the current rendered frame as list of strings (headless mode).
@spec get_tree(GenServer.server()) :: ElixirOpentui.Element.t() | nil
Get the current element tree.
@spec mount(GenServer.server(), module(), map()) :: :ok
Set the root app module and initialize it.
@spec render(GenServer.server()) :: :ok
Force a re-render.
@spec request_live(GenServer.server()) :: reference()
Request live mode. Returns a ref that must be passed to drop_live/2.
@spec resize(GenServer.server(), non_neg_integer(), non_neg_integer()) :: :ok
Resize the runtime.
@spec resume(GenServer.server()) :: :ok
Resume the runtime — restores terminal and restarts tick loop. Must match each suspend.
@spec send_app_msg(GenServer.server(), term()) :: :ok
Send a message to the app module's update/3 directly.
@spec send_event(GenServer.server(), term()) :: :ok
Send an event to the runtime for processing.
@spec send_msg(GenServer.server(), term(), term()) :: :ok
Send a message to a specific component.
@spec snapshot(GenServer.server()) :: ElixirOpentui.Accessibility.t()
Return a semantic snapshot of the UI for agent consumption.
See ElixirOpentui.Accessibility for the snapshot shape.
@spec start(GenServer.server()) :: :ok
Start continuous tick loop (explicit mode).
Start the runtime.
@spec stop(GenServer.server()) :: :ok
Stop continuous tick loop.
@spec suspend(GenServer.server()) :: :ok
Suspend the runtime — pauses tick loop and suspends terminal. Supports nesting.