# `Minga.Frontend.Adapter.GUI.SurfaceLayoutEncoder`
[🔗](https://github.com/jsmestad/minga/blob/main/lib/minga/frontend/adapter/gui/surface_layout_encoder.ex#L1)

Encodes `gui_surface_layout` (0xA4): the authoritative per-frame surface
placement carrier (#2219 child E / #2268).

This is the single emitter of `gui_surface_layout`. It takes wire-shaped
placement maps (already numbered by `MingaEditor.Layout.SurfaceRegistry`, the
one source of surface rects and z-order that also feeds BEAM mouse
hit-testing) and lays them out as a sectioned command using the
schema-generated pure encoder
`Minga.Protocol.Encode.encode_gui_surface_layout_placements/1`. Because both
the placement bytes and the BEAM hit-test read the same registry placements,
the emitted rect for every surface equals its hit-test rect by construction
(#2268 AC-1).

## Identity unification (#2268)

The schema carries `surface_id` as a raw `u16` and `hit_kind` as a raw `u8`
with no enum (a new schema vocabulary was explicitly avoided). The numeric
identity is authoritative in `SurfaceRegistry`, which projects each placement
to its wire shape (`SurfaceRegistry.wire_placements/1`). This encoder consumes
those plain maps and never depends on `MingaEditor.*`: one writer (the
registry owns the numbering), one reader (this encoder lays out bytes).

## Framing

Sectioned framing (`opcode + section_count + section{id, len16, body}`) reuses
the gui_window_content/picker counted-array carrier so the generator emits a
placement decoder both frontends already know how to size (the reviewer-
adjudicated carrier choice from child A). There is a single section,
`placements` (id 0x01), holding a counted array of `surface_placement`.

# `wire_placement`

```elixir
@type wire_placement() :: %{
  surface_id: non_neg_integer(),
  rect: %{
    row: non_neg_integer(),
    col: non_neg_integer(),
    width: non_neg_integer(),
    height: non_neg_integer()
  },
  z: non_neg_integer(),
  hit_kind: non_neg_integer()
}
```

A placement already projected to its wire shape (see SurfaceRegistry.wire_placement/0).

# `encode_command`

```elixir
@spec encode_command([wire_placement()]) :: binary()
```

Encodes the frame's wire-shaped surface placements into a `gui_surface_layout`
command.

Always emits (one section, possibly with an empty placement array). The
command is part of the frame transaction, so it ships every frame between
begin_frame and commit_frame; there is no skip-if-unchanged cache because the
placement list IS the per-frame layout authority. Cell fields are clamped to
u16/u8 so a degenerate rect can never produce a malformed packet (mirrors the
window encoder's clamp policy).

---

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