# `Ascii.Render.ANSI`
[🔗](https://github.com/houllette/ascii_art/blob/main/lib/ascii/render/ansi.ex#L1)

A frame for a terminal: text with ANSI colour escapes.

Coloured frames take each cell's palette colour, as 24-bit colour
(`:truecolor`, the default), the nearest of xterm's 256 (`:ansi256`), or
none at all (`:mono`). Escapes are emitted once a run of one colour, and
spaces never start a run, so a frame costs little more than its text. A
piece with a `ground` gets it as the background, unless `ground: false`.
Each line ends by resetting the colours, so nothing bleeds past the
picture.

Frames without colours (text pieces, or `color: false`) are plain text in
every mode, in the terminal's own colours. A `nil` in a palette (cells in
no coloured part of a piece, see `Ascii.Parts`) is the terminal's own
foreground too, and a CSS variable (see `Ascii.Ink`) is its fallback
colour, or the terminal's own without one.

To animate in place, move the cursor home before each frame:

    IO.write([ANSI.hide_cursor(), ANSI.clear()])
    IO.write([ANSI.home(), ANSI.render(frame)])
    # ...
    IO.write([ANSI.reset(), ANSI.show_cursor()])

`Ascii.Player` and `mix ascii.play` do this for you.

# `mode`

```elixir
@type mode() :: :truecolor | :ansi256 | :mono
```

# `changes`

```elixir
@spec changes(
  prev :: Ascii.Frame.t() | nil,
  frame :: Ascii.Frame.t(),
  opts :: [mode: mode(), ground: boolean(), at: {pos_integer(), pos_integer()}]
) :: iodata()
```

What changed from `prev` to `frame`, as iodata that moves the cursor to
each run of cells that changed and writes it (see
`Ascii.Frame.changes/3`); nothing at all when the picture did not
change. With `prev` `nil`, the whole frame, each row placed.

A terminal that already shows `prev` needs only this, which for most
pieces is a few cells in a hundred: over SSH or a serial console, far less
to send than `render/2` every frame.

## Options

  * `:mode`, `:ground` - as for `render/2`.
  * `:at` - `{row, column}` of the screen where the frame's top left cell
    is, counting from 1 (default `{1, 1}`).

# `clear`

```elixir
@spec clear() :: String.t()
```

Clears the screen.

# `hide_cursor`

```elixir
@spec hide_cursor() :: String.t()
```

Hides the cursor.

# `home`

```elixir
@spec home() :: String.t()
```

Moves the cursor to the top left.

# `move`

```elixir
@spec move(row :: pos_integer(), column :: pos_integer()) :: String.t()
```

Moves the cursor to `row`, `column`, counting from 1.

# `render`

```elixir
@spec render(frame :: Ascii.Frame.t(), opts :: [mode: mode(), ground: boolean()]) ::
  iodata()
```

The frame as iodata.

## Options

  * `:mode` - `:truecolor` (default), `:ansi256` or `:mono`.
  * `:ground` - paint the piece's ground behind it (default `true`).

# `reset`

```elixir
@spec reset() :: String.t()
```

Resets colours.

# `show_cursor`

```elixir
@spec show_cursor() :: String.t()
```

Shows the cursor.

# `xterm256`

```elixir
@spec xterm256({byte(), byte(), byte()}) :: 16..255
```

The xterm-256 colour nearest an RGB colour: a step of the 6×6×6 cube or of the grey ramp.

---

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