# `MingaEditor.Renderer.Server`
[🔗](https://github.com/jsmestad/minga/blob/main/lib/minga_editor/renderer/server.ex#L1)

Standalone renderer GenServer. Owns the render pipeline and font registry
so a slow frame doesn't block input dispatch in the Editor process.

## Lifecycle

Started by `MingaEditor.Supervisor` for all non-headless backends.
The headless backend renders synchronously in-process for test
determinism; this server is not in the supervision tree in that case.

## Snapshot mechanics

The Editor pushes `RenderPipeline.Input` snapshots via
`cast_snapshot/3`. The Renderer holds an in-flight snapshot, a
pending one, and the latest frontend cache state it emitted. When a
snapshot arrives while a render is in progress, the previous pending
snapshot is dropped (most-recent-wins coalescing) and a
`[:minga, :render, :coalesced]` telemetry event fires. Each snapshot
is normalized against the renderer-owned cache state before it renders.
After each render emit completes, the Renderer stores the emitted
cache state and threads it into any pending snapshot before starting
the next frame; otherwise it goes idle. If the Editor emits a direct
bare frame boundary, that newer snapshot cache wins instead. That keeps
delta frame bases aligned with what the frontend just received, even
when the Editor has not yet processed the prior render writeback.

## Click-region writeback

The render pipeline computes `modeline_click_regions` and
`tab_bar_click_regions` as part of chrome rendering. These need to
flow back to the Editor so subsequent mouse events can resolve
click positions. The Renderer sends `{:render_done, writeback}`
back to the Editor after every emit; the Editor merges renderer-owned
fields from that payload via `apply_renderer_writeback/2`.

## Telemetry

- `[:minga, :render, :pipeline]` span around `RenderPipeline.run/1`.
- `[:minga, :render, :coalesced]` event when a pending snapshot is dropped.
- `[:minga, :render, :frame_latency]` measurement (push timestamp → emit complete).
- `[:minga, :render, :hop_latency]` (`hop: :cast_snapshot`) measures the
  Editor → Renderer.Server scheduling delay; (`hop: :render_done`) measures
  the Renderer.Server → Editor writeback scheduling delay.

## Determinism in tests

EditorCase tests use the headless backend, which renders
synchronously in-process. This server is not started in the test
supervision tree.

# `editor_ref`

```elixir
@type editor_ref() :: pid() | atom() | nil
```

Editor process reference used for renderer writebacks.

# `pipeline`

```elixir
@type pipeline() :: (MingaEditor.RenderPipeline.Input.t() -&gt; render_output())
```

Injected render pipeline function.

# `render_output`

```elixir
@type render_output() :: MingaEditor.RenderPipeline.Input.t()
```

Render pipeline output after a frame has run.

# `t`

```elixir
@type t() :: %MingaEditor.Renderer.Server{
  caches: MingaEditor.Renderer.Caches.t(),
  editor_pid: editor_ref(),
  font_registry: MingaEditor.UI.FontRegistry.t(),
  in_flight:
    {MingaEditor.RenderPipeline.Input.t(), non_neg_integer(), integer()} | nil,
  pending:
    {MingaEditor.RenderPipeline.Input.t(), non_neg_integer(), integer()} | nil,
  pipeline: pipeline(),
  rendering?: boolean()
}
```

Renderer server state.

# `writeback`

```elixir
@type writeback() :: %{
  caches: MingaEditor.Renderer.Caches.t(),
  layout: MingaEditor.Layout.t() | nil,
  focus_tree: MingaEditor.FocusTree.t() | nil,
  shell_id: atom(),
  shell_identity: MingaEditor.Shell.Identity.t() | nil,
  shell_state: term(),
  windows: term(),
  frame_seq: non_neg_integer(),
  keyframe?: boolean(),
  render_sent_at: integer()
}
```

Click-region writeback payload sent to the Editor after each frame.

# `cast_snapshot`

```elixir
@spec cast_snapshot(
  GenServer.server(),
  MingaEditor.RenderPipeline.Input.t(),
  non_neg_integer()
) :: :ok
```

Pushes a render snapshot. Returns immediately; the actual emit
happens asynchronously. If a previous snapshot is still rendering,
this snapshot replaces any prior pending one.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `rendering?`

```elixir
@spec rendering?(GenServer.server()) :: boolean()
```

Returns true while a render pass is in progress.

# `start_link`

```elixir
@spec start_link(keyword()) :: GenServer.on_start()
```

Starts the Renderer server. The `:editor_pid` option names the Editor
process to send `{:render_done, ...}` writebacks to; defaults to
`MingaEditor` (the registered name of the Editor GenServer).

---

*Consult [api-reference.md](api-reference.md) for complete listing*
