# `Ascii.Frame`
[🔗](https://github.com/houllette/ascii_art/blob/main/lib/ascii/frame.ex#L1)

One frame of a piece, ready for any renderer.

`text` is the picture: `rows` lines of `cols` characters joined by `\n`,
and `lines` the same split into rows. `colors`, for a coloured piece drawn
in colour, is a binary of `cols * rows` bytes, one palette index a cell,
row by row; `palette` holds the `#rrggbb` colours they index and `ground`
the colour behind them. A palette entry may be `nil`, for cells drawn in
the renderer's own ink: a piece in one ink with only some of its parts
coloured (see `Ascii.Parts`). A palette is the same for every frame of
an animation. `cell` is a cell's height in widths (2 for the
shape of a character, 1 for square).

Renderers in this library (`Ascii.Render.Text`, `Ascii.Render.ANSI`,
the Phoenix components) all take a frame. To draw cells yourself, on a
framebuffer say, walk `lines` and `colors` together:

    for {line, y} <- Enum.with_index(frame.lines),
        {char, x} <- Enum.with_index(String.graphemes(line)) do
      index = :binary.at(frame.colors, y * frame.cols + x)
      draw(x, y, char, Enum.at(frame.palette, index) || my_ink)
    end

# `run`

```elixir
@type run() ::
  {y :: non_neg_integer(), x :: non_neg_integer(), String.t(), binary() | nil}
```

A run of cells along row `y` from column `x`: their text and colours.

# `t`

```elixir
@type t() :: %Ascii.Frame{
  cell: 1 | 2,
  colors: binary() | nil,
  cols: pos_integer(),
  ground: String.t() | nil,
  lines: [String.t()],
  palette: [String.t() | nil] | nil,
  rows: pos_integer(),
  t: float(),
  text: String.t()
}
```

# `changes`

```elixir
@spec changes(prev :: t() | nil, frame :: t(), opts :: [{:gap, pos_integer()}]) :: [
  run()
]
```

What changed from `prev` to `frame`, as runs of cells along a row:
`{y, x, text, colors}`, the colours being the run's palette indices (or
`nil` without colours). A cell counts as changed if its character or its
colour did. Changed cells less than `:gap` cells apart (default 4) are
taken into one run, since each run costs a little to place.

With no frame before (`nil`), or one of another size, palette or kind, every row is
a run. Most pieces change a few cells in a hundred a frame, so this is
what to send to a terminal or a browser that already shows `prev`.

# `color_at`

```elixir
@spec color_at(frame :: t(), x :: non_neg_integer(), y :: non_neg_integer()) ::
  String.t() | nil
```

The `#rrggbb` colour of the cell at `x`, `y`, or `nil` without colours or
in the renderer's own ink.

---

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