Skip to main content
The Colour module provides comprehensive ANSI colour and text styling support with three colour depths: 4-bit (16 colours), 8-bit (256 colours), and 24-bit true colour (16 million colours).

Colour depth overview

The module supports three colour depths:
  • 4-bit — 16 colours (black, red, green, yellow, blue, magenta, cyan, white + bright variants)
  • 8-bit — 256 colours (16 named + 216 RGB cube + 24 greyscale)
  • 24-bit — 16 million colours (true colour, R,G,B 0-255 each)
Colour name formats:
  • 4-bit/8-bit: black, red, green, yellow, blue, magenta, cyan, white
  • Bright variants: bright red, brightred, bright_red
  • 8-bit RGB cube: rgb0,0,0 to rgb5,5,5 or bare 0,0,0 to 5,5,5
  • 8-bit greyscale: grey0 to grey23 (or gray0 to gray23)
  • 24-bit RGB: R,G,B where each is 0-255 (e.g., 255,128,0)

Capability detection

Functions for detecting terminal colour capabilities.

colour::supports()

Check if the terminal supports any colour (at least 8 colours).
if colour::supports; then
    echo "Colour is available"
fi
Returns: Exit code 0 if colour is supported and stdout is a TTY, 1 otherwise.

colour::depth()

Return the number of colours the terminal supports.
depth=$(colour::depth)
echo "Terminal supports $depth colours"
Returns: Number of colours (0, 8, 16, 256, etc.).

colour::supports_256()

Check if terminal supports 256 colours.
if colour::supports_256; then
    echo "Can use 8-bit colour"
fi
Returns: Exit code 0 if 256-colour is supported, 1 otherwise.

colour::supports_truecolor()

Check if terminal supports true colour (24-bit). Checks $COLORTERM environment variable.
if colour::supports_truecolor; then
    echo "True colour available"
fi
Returns: Exit code 0 if $COLORTERM is “truecolor” or “24bit”, 1 otherwise.

Escape code generation

Core functions for generating ANSI escape sequences.

colour::esc()

Generate a raw ANSI escape sequence for any colour depth.
# 4-bit colour
colour::esc 4 fg red
echo "Red text"
colour::reset

# 8-bit RGB cube
colour::esc 8 bg rgb3,1,4
echo "Custom background"
colour::reset

# 24-bit true colour
colour::esc 24 fg 255,128,0
echo "Orange text"
colour::reset
Parameters:
  • $1 - Bit depth: 4, 8, or 24
  • $2 - Foreground or background: fg or bg
  • $3+ - Colour value (format depends on bit depth)
4-bit escape sequences:
  • \033[30-37m — foreground colours
  • \033[40-47m — background colours
  • \033[90-97m — bright foreground
  • \033[100-107m — bright background
8-bit escape sequences:
  • \033[38;5;Nm — foreground colour N (0-255)
  • \033[48;5;Nm — background colour N (0-255)
24-bit escape sequences:
  • \033[38;2;R;G;Bm — foreground RGB
  • \033[48;2;R;G;Bm — background RGB
Returns: Exit code 1 on invalid input.

colour::safe_esc()

Generate escape code only if terminal supports the requested depth. Gracefully degrades by returning empty string if unsupported.
# Only outputs colour code if terminal supports it
colour::safe_esc 24 fg 255,100,50
echo "Text (coloured only if supported)"
colour::reset
Parameters: Same as colour::esc() Returns: Escape sequence if supported, empty string otherwise.

Index lookup (internal helpers)

These functions return numeric colour indices for escape codes.

colour::index::4bit()

Get 4-bit ANSI colour code index (30-37, 40-47, 90-97, 100-107).
index=$(colour::index::4bit red fg)
echo "Red foreground code: $index"  # 31

index=$(colour::index::4bit "bright blue" bg)
echo "Bright blue background: $index"  # 104
Parameters:
  • $1 - Colour name (e.g., red, bright green)
  • $2 - fg or bg (default: fg)
Returns: ANSI code number.

colour::index::8bit()

Get 8-bit colour index (0-255).
# Named colour
index=$(colour::index::8bit red)  # 1

# RGB cube
index=$(colour::index::8bit rgb5,0,0)  # 196 (bright red)

# Greyscale
index=$(colour::index::8bit grey12)  # 244 (mid grey)
Parameters:
  • $1 - Colour specification (named, RGB, or greyscale)
Returns: Index 0-255. 8-bit colour ranges:
  • 0-15: Named colours (0-7 normal, 8-15 bright)
  • 16-231: 6×6×6 RGB cube (216 colours)
  • 232-255: Greyscale ramp (24 shades)

Text attributes

Functions for text styling (not colour-depth dependent).

colour::reset()

Reset all attributes and colours to default.
colour::fg::red
colour::bold
echo "Bold red text"
colour::reset
echo "Normal text"
Escape sequence: \033[0m

colour::bold()

Enable bold text.
colour::bold
echo "Bold text"
colour::reset
Escape sequence: \033[1m

colour::dim()

Enable dim/faint text.
colour::dim
echo "Dimmed text"
colour::reset
Escape sequence: \033[2m

colour::italic()

Enable italic text (not supported in all terminals).
colour::italic
echo "Italic text"
colour::reset
Escape sequence: \033[3m

colour::underline()

Enable underlined text.
colour::underline
echo "Underlined text"
colour::reset
Escape sequence: \033[4mEnable blinking text (rarely supported).
colour::blink
echo "Blinking text"
colour::reset
Escape sequence: \033[5m

colour::reverse()

Enable reverse video (swap foreground and background).
colour::reverse
echo "Reversed text"
colour::reset
Escape sequence: \033[7m

colour::hidden()

Enable hidden/invisible text.
colour::hidden
echo "Secret text"
colour::reset
Escape sequence: \033[8m

colour::strike()

Enable strikethrough text.
colour::strike
echo "Strikethrough text"
colour::reset
Escape sequence: \033[9m
Reset individual attributes without affecting others.

colour::reset::bold()

Reset bold/dim to normal intensity.Escape sequence: \033[22m

colour::reset::dim()

Reset dim (same as reset::bold).Escape sequence: \033[22m

colour::reset::italic()

Reset italic.Escape sequence: \033[23m

colour::reset::underline()

Reset underline.Escape sequence: \033[24mReset blink.Escape sequence: \033[25m

colour::reset::reverse()

Reset reverse video.Escape sequence: \033[27m

colour::reset::hidden()

Reset hidden.Escape sequence: \033[28m

colour::reset::strike()

Reset strikethrough.Escape sequence: \033[29m

colour::reset::fg()

Reset foreground colour to default.Escape sequence: \033[39m

colour::reset::bg()

Reset background colour to default.Escape sequence: \033[49m

4-bit named colour shortcuts

Convenience functions for direct colour application.

Basic foreground colours

colour::fg::black   # \033[30m
colour::fg::red     # \033[31m
colour::fg::green   # \033[32m
colour::fg::yellow  # \033[33m
colour::fg::blue    # \033[34m
colour::fg::magenta # \033[35m
colour::fg::cyan    # \033[36m
colour::fg::white   # \033[37m
Example:
colour::fg::green
echo "Success!"
colour::reset

Bright foreground colours

colour::fg::bright_black   # \033[90m (dark grey)
colour::fg::bright_red     # \033[91m
colour::fg::bright_green   # \033[92m
colour::fg::bright_yellow  # \033[93m
colour::fg::bright_blue    # \033[94m
colour::fg::bright_magenta # \033[95m
colour::fg::bright_cyan    # \033[96m
colour::fg::bright_white   # \033[97m
Example:
colour::fg::bright_red
echo "ERROR!"
colour::reset

Basic background colours

colour::bg::black   # \033[40m
colour::bg::red     # \033[41m
colour::bg::green   # \033[42m
colour::bg::yellow  # \033[43m
colour::bg::blue    # \033[44m
colour::bg::magenta # \033[45m
colour::bg::cyan    # \033[46m
colour::bg::white   # \033[47m
Example:
colour::bg::blue
colour::fg::white
echo "White on blue"
colour::reset

Bright background colours

colour::bg::bright_black   # \033[100m
colour::bg::bright_red     # \033[101m
colour::bg::bright_green   # \033[102m
colour::bg::bright_yellow  # \033[103m
colour::bg::bright_blue    # \033[104m
colour::bg::bright_magenta # \033[105m
colour::bg::bright_cyan    # \033[106m
colour::bg::bright_white   # \033[107m
Example:
colour::bg::bright_yellow
colour::fg::black
echo "Warning banner"
colour::reset

Higher-level helpers

Convenience functions for common colour operations.

colour::print()

Print text wrapped in colour with automatic reset.
# 4-bit colour
colour::print 4 fg red "Error message"

# 8-bit colour
colour::print 8 bg rgb2,4,1 "Highlighted"

# 24-bit colour
colour::print 24 fg 255,165,0 "Orange text"
Parameters:
  • $1 - Bit depth: 4, 8, or 24
  • $2 - fg or bg
  • $3 - Colour specification
  • $4 - Text to print
Output: Coloured text without trailing newline, followed by reset.

colour::println()

Same as colour::print() but adds a newline after text.
colour::println 4 fg green "Success!"
colour::println 8 fg rgb5,2,0 "Custom orange"
Parameters: Same as colour::print() Output: Coloured text with trailing newline, followed by reset.

colour::wrap()

Wrap text in escape codes and return as string (no direct print).
coloured_text=$(colour::wrap 4 fg red "Error")
echo "Status: $coloured_text"
Parameters:
  • $1 - Bit depth: 4, 8, or 24
  • $2 - fg or bg
  • $3 - Colour specification
  • $4 - Text to wrap
Returns: String with embedded escape codes.

colour::strip()

Strip all ANSI escape codes from a string.
coloured="\033[31mRed\033[0m text"
plain=$(colour::strip "$coloured")
echo "$plain"  # "Red text"
Parameters:
  • $1 - Text containing escape codes
Returns: Plain text with all escape codes removed.

colour::visible_length()

Return the visible length of a string (excluding escape codes). Useful for padding and alignment with coloured strings.
coloured=$(colour::wrap 4 fg red "Hello")
length=$(colour::visible_length "$coloured")
echo "Visible length: $length"  # 5
Parameters:
  • $1 - Text (may contain escape codes)
Returns: Number of visible characters.

colour::has_colour()

Check if a string contains any ANSI escape codes.
if colour::has_colour "$text"; then
    echo "Text is coloured"
fi
Parameters:
  • $1 - Text to check
Returns: Exit code 0 if escape codes present, 1 otherwise.

Usage examples

#!/usr/bin/env bash
source terminal.sh
source colour.sh

if ! colour::supports; then
    echo "No colour support"
    exit 1
fi

# Direct shortcuts
colour::fg::red
colour::bold
echo "ERROR: Something went wrong"
colour::reset

# Using colour::print
colour::print 4 fg green "Success!"
echo  # newline

# Combining attributes
colour::bg::blue
colour::fg::bright_white
colour::bold
echo "=== Header ==="
colour::reset
#!/usr/bin/env bash
source colour.sh

if ! colour::supports_256; then
    echo "256-colour not supported"
    exit 1
fi

# RGB cube colours (6×6×6)
for r in {0..5}; do
    for g in {0..5}; do
        for b in {0..5}; do
            colour::esc 8 bg "rgb$r,$g,$b"
            printf " "
        done
    done
    colour::reset
    echo
done

# Greyscale ramp
for i in {0..23}; do
    colour::esc 8 bg "grey$i"
    printf "  "
done
colour::reset
echo
#!/usr/bin/env bash
source colour.sh

if ! colour::supports_truecolor; then
    echo "True colour not supported"
    exit 1
fi

# Gradient effect
for i in {0..255}; do
    colour::esc 24 bg "$i,0,$(( 255 - i ))"
    printf " "
done
colour::reset
echo

# Custom brand colours
colour::println 24 fg 255,102,0 "Orange brand colour"
colour::println 24 fg 0,180,216 "Cyan brand colour"
colour::println 24 fg 88,57,128 "Purple brand colour"
#!/usr/bin/env bash
source colour.sh

# Status messages
info() {
    colour::fg::blue
    echo "[INFO] $*"
    colour::reset
}

success() {
    colour::fg::bright_green
    colour::bold
    echo "[SUCCESS] $*"
    colour::reset
}

warning() {
    colour::fg::yellow
    echo "[WARNING] $*"
    colour::reset
}

error() {
    colour::fg::bright_red
    colour::bold
    echo "[ERROR] $*" >&2
    colour::reset
}

# Usage
info "Starting build..."
success "Build completed"
warning "Using deprecated API"
error "Failed to connect"

Build docs developers (and LLMs) love