Skip to content

Colors

Termina provides a flexible color system supporting terminal defaults, 256-color palettes, and true color (24-bit RGB).

Color Modes

Default

Uses the terminal's default foreground or background color:

csharp
Color.Default

Named Colors (256-color palette)

Standard terminal colors:

csharp
// Basic colors
Color.Black
Color.Red
Color.Green
Color.Yellow
Color.Blue
Color.Magenta
Color.Cyan
Color.White

// Bright variants
Color.BrightBlack
Color.BrightRed
Color.BrightGreen
Color.BrightYellow
Color.BrightBlue
Color.BrightMagenta
Color.BrightCyan
Color.BrightWhite

// Grayscale
Color.Gray
Color.DarkGray
Color.LightGray

Indexed Colors

Access any of the 256-color palette:

csharp
Color.FromIndex(42)  // Index 0-255

The 256-color palette includes:

  • 0-7: Standard colors
  • 8-15: Bright colors
  • 16-231: 6×6×6 color cube
  • 232-255: Grayscale ramp

RGB Colors (True Color)

24-bit color for modern terminals:

csharp
// From RGB values
Color.FromRgb(255, 128, 0)  // Orange

// From hex string
Color.FromHex("#FF8000")
Color.FromHex("FF8000")     // # is optional

Applying Colors

Foreground Color

csharp
new TextNode("Colored text")
    .WithForeground(Color.Cyan)

Background Color

csharp
new TextNode("Highlighted")
    .WithBackground(Color.Yellow)
    .WithForeground(Color.Black)

Both Colors

csharp
new TextNode("Styled")
    .WithForeground(Color.White)
    .WithBackground(Color.Blue)

Color Interpolation

Color.Lerp linearly interpolates between two RGB colors:

csharp
var midpoint = Color.Lerp(Color.FromRgb(255, 0, 0), Color.FromRgb(0, 0, 255), 0.5f);
// Result: purple (127, 0, 127)

If either color is not in RGB mode, Lerp returns the first color unchanged.

Gradients

The Gradient record defines a series of color stops and interpolates between them. Use gradients with GraphNode and ProgressBarNode for smooth color transitions.

csharp
// Evenly spaced stops
var gradient = Gradient.Create(Color.Red, Color.Yellow, Color.Green);

// Custom stop positions
var custom = Gradient.Create(
    (0.0f, Color.FromRgb(255, 0, 0)),
    (0.3f, Color.FromRgb(255, 200, 0)),
    (1.0f, Color.FromRgb(0, 255, 0)));

// Sample at any position (0–1)
Color color = gradient.Sample(0.5f);

At least two colors are required. Positions outside the 0–1 range are clamped.

Color Support by Component

ComponentForegroundBackgroundOther
TextNode-
PanelNode--Border, Title
SpinnerNode--Spinner, Label
TextInputNodePlaceholder, Cursor, Selection
StreamingTextNodePrefix
GraphNode--Gradient, Single color
ProgressBarNode--Gradient, Single color, Empty color

Terminal Compatibility

WARNING

Not all terminals support all color modes:

  • Default - Works everywhere
  • Indexed (0-15) - Works in almost all terminals
  • Indexed (16-255) - Requires 256-color support
  • RGB - Requires true color support (most modern terminals)

When RGB colors are used in a terminal that doesn't support them, results may vary.

Common Terminal Support

Terminal256-colorTrue Color
Windows Terminal
iTerm2
GNOME Terminal
VS Code Terminal
macOS Terminal.appLimited
cmd.exeLimited

Color API Reference

View Color implementation
csharp
// Copyright (c) Petabridge, LLC. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace Termina.Terminal;

/// <summary>
/// Represents a color for terminal rendering.
/// Supports default, 256-color, and true color (24-bit RGB) modes.
/// </summary>
public readonly struct Color : IEquatable<Color>
{
    /// <summary>
    /// The color mode.
    /// </summary>
    public ColorMode Mode { get; }

    /// <summary>
    /// For 256-color mode, the palette index (0-255).
    /// </summary>
    public byte Index { get; }

    /// <summary>
    /// Red component for RGB mode (0-255).
    /// </summary>
    public byte R { get; }

    /// <summary>
    /// Green component for RGB mode (0-255).
    /// </summary>
    public byte G { get; }

    /// <summary>
    /// Blue component for RGB mode (0-255).
    /// </summary>
    public byte B { get; }

    private Color(ColorMode mode, byte index = 0, byte r = 0, byte g = 0, byte b = 0)
    {
        Mode = mode;
        Index = index;
        R = r;
        G = g;
        B = b;
    }

    /// <summary>
    /// Default terminal color (no explicit color set).
    /// </summary>
    public static Color Default => new(ColorMode.Default);

    /// <summary>
    /// Create a color from a 256-color palette index.
    /// </summary>
    public static Color FromIndex(byte index) => new(ColorMode.Indexed, index);

    /// <summary>
    /// Create a color from RGB values.
    /// </summary>
    public static Color FromRgb(byte r, byte g, byte b) => new(ColorMode.Rgb, 0, r, g, b);

    /// <summary>
    /// Create a color from a hex string (e.g., "#FF0000" or "FF0000").
    /// </summary>
    public static Color FromHex(string hex)
    {
        hex = hex.TrimStart('#');
        if (hex.Length != 6)
            throw new ArgumentException("Hex color must be 6 characters", nameof(hex));

        var r = Convert.ToByte(hex[0..2], 16);
        var g = Convert.ToByte(hex[2..4], 16);
        var b = Convert.ToByte(hex[4..6], 16);
        return FromRgb(r, g, b);
    }

    // Standard colors (using 256-color palette indices)
    public static Color Black => FromIndex(0);
    public static Color Red => FromIndex(1);
    public static Color Green => FromIndex(2);
    public static Color Yellow => FromIndex(3);
    public static Color Blue => FromIndex(4);
    public static Color Magenta => FromIndex(5);
    public static Color Cyan => FromIndex(6);
    public static Color White => FromIndex(7);

    // Bright variants
    public static Color BrightBlack => FromIndex(8);
    public static Color BrightRed => FromIndex(9);
    public static Color BrightGreen => FromIndex(10);
    public static Color BrightYellow => FromIndex(11);
    public static Color BrightBlue => FromIndex(12);
    public static Color BrightMagenta => FromIndex(13);
    public static Color BrightCyan => FromIndex(14);
    public static Color BrightWhite => FromIndex(15);

    // Extended grayscale (from 256-color palette)
    public static Color Gray => FromIndex(244);       // Medium gray
    public static Color DarkGray => FromIndex(240);   // Darker gray
    public static Color LightGray => FromIndex(248);  // Lighter gray

    /// <summary>
    /// Get the ANSI escape sequence for this color as a foreground color.
    /// </summary>
    public string ToForegroundAnsi() => Mode switch
    {
        ColorMode.Default => AnsiCodes.ForegroundDefault,
        ColorMode.Indexed => AnsiCodes.Foreground256(Index),
        ColorMode.Rgb => AnsiCodes.ForegroundRgb(R, G, B),
        _ => AnsiCodes.ForegroundDefault
    };

    /// <summary>
    /// Get the ANSI escape sequence for this color as a background color.
    /// </summary>
    public string ToBackgroundAnsi() => Mode switch
    {
        ColorMode.Default => AnsiCodes.BackgroundDefault,
        ColorMode.Indexed => AnsiCodes.Background256(Index),
        ColorMode.Rgb => AnsiCodes.BackgroundRgb(R, G, B),
        _ => AnsiCodes.BackgroundDefault
    };

    public bool Equals(Color other) =>
        Mode == other.Mode && Index == other.Index && R == other.R && G == other.G && B == other.B;

    public override bool Equals(object? obj) => obj is Color other && Equals(other);

    public override int GetHashCode() => HashCode.Combine(Mode, Index, R, G, B);

    public static bool operator ==(Color left, Color right) => left.Equals(right);

    public static bool operator !=(Color left, Color right) => !left.Equals(right);

    /// <summary>
    /// Linearly interpolate between two RGB colors.
    /// If either color is not RGB mode, returns <paramref name="a"/> unchanged.
    /// </summary>
    public static Color Lerp(Color a, Color b, float t)
    {
        if (a.Mode != ColorMode.Rgb || b.Mode != ColorMode.Rgb)
            return a;

        t = Math.Clamp(t, 0f, 1f);
        var r = (byte)(a.R + (b.R - a.R) * t);
        var g = (byte)(a.G + (b.G - a.G) * t);
        var bl = (byte)(a.B + (b.B - a.B) * t);
        return FromRgb(r, g, bl);
    }

    public override string ToString() => Mode switch
    {
        ColorMode.Default => "Default",
        ColorMode.Indexed => $"Index({Index})",
        ColorMode.Rgb => $"RGB({R},{G},{B})",
        _ => "Unknown"
    };
}

/// <summary>
/// The mode of color specification.
/// </summary>
public enum ColorMode
{
    /// <summary>
    /// Use terminal's default color.
    /// </summary>
    Default,

    /// <summary>
    /// Use 256-color palette index.
    /// </summary>
    Indexed,

    /// <summary>
    /// Use 24-bit RGB color.
    /// </summary>
    Rgb
}

Released under the Apache 2.0 License.