# `Alaja.Components.ColorWheel`
[🔗](https://github.com/Lorenzo-SF/alaja/blob/2.1.0/lib/alaja/components/color_wheel.ex#L1)

Color visualization component for the terminal.

Provides multiple rendering modes:

- **Native image** (Kitty/iTerm2/Sixel): generates a real bitmap of the color
  wheel using the detected terminal protocol, with the harmony colours
  marked at their hue position.
- **ASCII half-block** (universal fallback): renders a circle using Unicode
  `▀`/`▄` characters with true-color ANSI (24-bit), yielding 2 pixels per
  vertical cell. This is the Buffer-first canonical rendering.

The canonical entry point is `render/2`, which returns an
`Alaja.Buffer.t/0`. Callers that want native-image output should
use `render_for_terminal/2` (returns a tagged value so the caller
decides whether to embed the bytes directly or feed a Buffer to
the printer).

## Contracts

Este módulo usa los tipos definidos en `Pote` como fuente canónica.

## Examples

    alias Alaja.Components.ColorWheel

    # Canonical Buffer-first render (works in any terminal)
    buffer = ColorWheel.render([{255, 0, 0}, {0, 255, 0}], harmony: :triad)
    Alaja.Printer.print_raw(buffer)

    # Native image when supported, ASCII fallback otherwise
    case ColorWheel.render_for_terminal([{255, 0, 0}], harmony: :triad) do
      {:image, iodata} -> IO.write(iodata)
      {:ascii, buffer} -> Alaja.Printer.print_raw(buffer)
    end

    # Legacy IO-based helpers (deprecated but still work)
    ColorWheel.show_color_info({255, 87, 51})
    ColorWheel.show_harmony_ring({255, 0, 0}, :triad)
    ColorWheel.show_swatches([{255, 0, 0}, {0, 255, 0}, {0, 0, 255}])

# `rgb`

```elixir
@type rgb() :: Pote.rgb()
```

# `compute_harmony`

```elixir
@spec compute_harmony(rgb(), atom()) :: [rgb()]
```

Computes the harmony colors for a given type and base RGB.

# `default_opts`

```elixir
@spec default_opts() :: keyword()
```

Returns the default options for the wheel renderer.

# `extract_angles`

```elixir
@spec extract_angles([rgb()]) :: [number()]
```

Extracts HSL hue angles from a list of RGB tuples.

# `get_ascii_wheel_lines`

```elixir
@spec get_ascii_wheel_lines([number()], atom(), keyword()) :: [String.t()]
```

Renders the ASCII color wheel and returns the lines (for layout composition).

# `harmony_display_name`

```elixir
@spec harmony_display_name(atom()) :: String.t()
```

# `render`

```elixir
@spec render(
  [rgb()],
  keyword()
) :: Alaja.Buffer.t()
```

Canonical Buffer-first render entry point.

Returns an `Alaja.Buffer.t/0` containing the colour wheel drawn with
Unicode half-block characters (▀/▄) at the requested harmony colours'
hue positions. The buffer is sized `4*radius+1` cells wide by `radius`
cells tall, where the x-scale of 2.0 makes the wheel appear circular
on terminals whose cells are taller than wide.

## Options

  - `:radius` — wheel radius in cells (default: 10)
  - `:thickness` — ring thickness as a fraction of the radius (default: 0.4)
  - `:harmony` — atom for the harmony type, draws the marker label in
                 the centre (`:triad`, `:complementary`, etc.)
  - `:harmony_angles` — explicit list of hue angles to mark (overrides
                        `:harmony` for the marker positions)

When `:harmony` is set, a centred label is embedded in the centre row
using a white-on-black pill. When `:harmony_angles` is set, no label is
drawn (the wheel is "unlabelled").

# `render_color_formats`

```elixir
@spec render_color_formats(rgb()) :: :ok
```

Renders color format information as formatted terminal output.

# `render_color_variants`

```elixir
@spec render_color_variants(rgb()) :: :ok
```

Shows lighter/darker variants of a color.

# `render_for_terminal`

```elixir
@spec render_for_terminal(
  [rgb()],
  keyword()
) :: {:image, iodata()} | {:ascii, Alaja.Buffer.t()}
```

Render the wheel using the best protocol for the current terminal.

Returns:
  * `{:image, iodata}` — when the terminal supports native images
    (Kitty, iTerm2, Sixel); `iodata` contains the terminal escape codes
    for an inline PNG with the wheel and harmony markers.
  * `{:ascii, Buffer.t()}` — otherwise; the Buffer can be passed to
    `Alaja.Printer.print_raw/2`.

The caller dispatches on the tag because PNG escapes cannot be embedded
in a Buffer cell — they have to be written directly to stdout by the
caller.

# `render_png_wheel`

```elixir
@spec render_png_wheel(
  [rgb()],
  keyword()
) :: iodata()
```

Renders the color wheel as a PNG image and prints it to the terminal.

This function generates a bitmap of the color wheel with harmony markers
and outputs it using the detected image protocol (Kitty/iTerm2/Sixel).

## Parameters

  - `rgb_list` - List of RGB tuples representing colors to mark on the wheel
  - `opts` - Options (same as `get_ascii_wheel_lines`)

# `render_swatch_list`

```elixir
@spec render_swatch_list([rgb()]) :: :ok
```

Renders a list of color swatches with hex labels.

# `show_color_info`

```elixir
@spec show_color_info(
  Pote.Orchestrator.color_input(),
  keyword()
) :: :ok
```

Displays detailed color information: swatch, formats, and optional variants.

# `show_gradient`

```elixir
@spec show_gradient(
  Pote.Orchestrator.color_input(),
  Pote.Orchestrator.color_input(),
  pos_integer()
) ::
  :ok
```

Shows a horizontal gradient between two colors.

# `show_harmony_ring`

```elixir
@spec show_harmony_ring(Pote.Orchestrator.color_input(), atom(), keyword()) :: :ok
```

Shows a harmony ring using ASCII rendering with autodetection of terminal
capabilities. Falls back to ASCII half-block when the terminal does not
support native image protocols.

# `show_swatches`

```elixir
@spec show_swatches(
  [Pote.Orchestrator.color_input()],
  keyword()
) :: :ok
```

Shows a list of colors as linear swatches.

---

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