Ascii.Ink (Ascii v0.3.0)

Copy Markdown View Source

Colour for a piece drawn in one ink: one colour for every character, or several as a gradient across the picture, and colours for its parts.

Most pieces are text in one ink, the page's or the terminal's own. Given an ink (Ascii.new(piece, ink: ...)), their frames come with colours, so every renderer draws them as it draws a coloured piece: a canvas in the browser, 24-bit or xterm-256 escapes in a terminal, and plain text where colour cannot be shown (mode: :mono). The picture itself is unchanged, character for character: the ink is laid over it, never drawn by the piece.

A coloured piece keeps its own palette; drawn in one ink (color: false) it takes the ink like any other.

{:ok, anim} = Ascii.new("big-text", ink: ["#ff5f6d", "#ffc371"])
{:ok, anim} = Ascii.new("donut", ink: "#7fdbca")
{:ok, anim} = Ascii.new("wave-text", ink: "#36d1dc,#5b86e5", gradient: :vertical)

Pieces that know their parts (a file tree's folders, a boot log's statuses) take colours for those too, with :parts, over the ink or without one: see Ascii.Parts.

Colours

#rrggbb or #rgb, the # optional; several as a list or as one string, comma-separated (as from a form or a command line), up to 16. One colour is every character's. Several run evenly from the first to the last across the whole picture, in a straight line between each and the next, as CSS's linear-gradient does, so a piece whose text moves (a marquee, a wave) moves through them.

CSS variables

One ink, or a part's colour, can be a CSS custom property, so a piece on a page takes the page's own colours, and follows them into dark mode: "var(--color-success)", or with a colour for where there is no CSS, "var(--color-success, #3fb950)". In HTML (Ascii.Render.HTML, the Phoenix players, Ascii.Render.SVG) the variable is the colour; a terminal draws the fallback, or its own ink without one (resolve/1). Several inks run as a gradient, worked out here, so they must be colours.

Gradients

  • :horizontal (the default) - left to right.
  • :vertical - top to bottom.
  • :diagonal - top left to bottom right, at 45° on screen, cells being as tall as the piece's cell says.

A gradient is 65 steps, whatever the picture's size, so its palette is the same for every frame (a player sends it once) and a wide picture costs few escapes in a terminal and few spans in HTML.

Summary

Types

Which way several colours run.

t()

An ink: its colours, as #rrggbb or a CSS variable (nil for the renderer's own), which way they run, and colours for parts (see Ascii.Parts). Made by cast/2 and put_parts/2; the rest is its layout for one size of frame, filled in as it is needed.

Functions

An ink from outside (code, LiveView params, a command line): its colours and, for several, which way they run. No colours at all (nil, "" or []) is no ink. Never creates an atom.

A colour from outside, as this library keeps it: #rrggbb (from #rrggbb or #rgb, the # optional), or a CSS variable as var(--name) or var(--name, #rrggbb); nil if it is neither.

The ink with colours for parts (as Ascii.Parts.cast/2 makes them), laid over its own. Without an ink, the parts take theirs over the renderer's own ink; without parts, the ink is as it was.

The #rrggbb to draw a colour in where CSS cannot be read (a terminal, a framebuffer): the colour itself, a CSS variable's fallback, or nil for the renderer's own ink.

The frame in this ink: its text as it is, each cell given a colour, and no ground behind it. With parts, the frame's runs of parts (see Ascii.Parts), a part with a colour of its own takes it. A frame with colours of its own, or no ink (nil), is left as it is.

Types

gradient()

@type gradient() :: :horizontal | :vertical | :diagonal

Which way several colours run.

t()

@type t() :: %Ascii.Ink{
  cells: binary() | nil,
  colors: [String.t(), ...] | nil,
  gradient: gradient(),
  index: %{optional(String.t()) => non_neg_integer() | :base} | nil,
  palette: [String.t() | nil] | nil,
  parts: Ascii.Parts.colors(),
  size: {pos_integer(), pos_integer(), 1 | 2} | nil
}

An ink: its colours, as #rrggbb or a CSS variable (nil for the renderer's own), which way they run, and colours for parts (see Ascii.Parts). Made by cast/2 and put_parts/2; the rest is its layout for one size of frame, filled in as it is needed.

Functions

cast(colors, gradient \\ nil)

@spec cast(colors :: term(), gradient :: term()) ::
  {:ok, t() | nil} | Ascii.Options.error()

An ink from outside (code, LiveView params, a command line): its colours and, for several, which way they run. No colours at all (nil, "" or []) is no ink. Never creates an atom.

iex> Ascii.Ink.cast("#F80")
{:ok, %Ascii.Ink{colors: ["#ff8800"], gradient: :horizontal}}

iex> Ascii.Ink.cast("#ff5f6d,#ffc371", "vertical")
{:ok, %Ascii.Ink{colors: ["#ff5f6d", "#ffc371"], gradient: :vertical}}

iex> Ascii.Ink.cast("red")
{:error, {:invalid_option, :ink}}

color(color)

@spec color(color :: term()) :: String.t() | nil

A colour from outside, as this library keeps it: #rrggbb (from #rrggbb or #rgb, the # optional), or a CSS variable as var(--name) or var(--name, #rrggbb); nil if it is neither.

iex> Ascii.Ink.color("F80")
"#ff8800"
iex> Ascii.Ink.color("var( --accent ,#FFF)")
"var(--accent, #ffffff)"
iex> Ascii.Ink.color("var(--x);color:red")
nil

put_parts(ink, parts)

@spec put_parts(ink :: t() | nil, parts :: Ascii.Parts.colors()) :: t() | nil

The ink with colours for parts (as Ascii.Parts.cast/2 makes them), laid over its own. Without an ink, the parts take theirs over the renderer's own ink; without parts, the ink is as it was.

resolve(hex)

@spec resolve(color :: String.t() | nil) :: String.t() | nil

The #rrggbb to draw a colour in where CSS cannot be read (a terminal, a framebuffer): the colour itself, a CSS variable's fallback, or nil for the renderer's own ink.

iex> Ascii.Ink.resolve("var(--ok, #3fb950)")
"#3fb950"
iex> Ascii.Ink.resolve("var(--ok)")
nil

tint(frame, ink, parts \\ nil)

@spec tint(frame :: Ascii.Frame.t(), ink :: t() | nil, parts :: Ascii.Parts.t() | nil) ::
  Ascii.Frame.t()

The frame in this ink: its text as it is, each cell given a colour, and no ground behind it. With parts, the frame's runs of parts (see Ascii.Parts), a part with a colour of its own takes it. A frame with colours of its own, or no ink (nil), is left as it is.