Skip to content

Styling & Themes

Tachikoma provides a comprehensive styling system with ANSI 256 colors, true RGB colors, text attributes, and a theme engine with 24 built-in palettes across dark and light modes.

Style

Style controls how text and backgrounds appear:

julia
Style(; fg=NoColor(), bg=NoColor(), bold=false, dim=false,
        italic=false, underline=false)
julia
# Explicit style
s = Style(fg=Color256(196), bg=Color256(0), bold=false, italic=true)

# Theme-aware style (preferred)
s = tstyle(:primary, bold=true)
style_demo example

Color Types

Color256

ANSI 256-color palette (0–255):

julia
Color256(196)     # bright red
Color256(46)      # green
Color256(0)       # black
Color256(255)     # white
color256_swatches example

ColorRGB

True 24-bit RGB color:

julia
ColorRGB(255, 100, 50)   # orange
ColorRGB(0x1a, 0x1b, 0x2e)  # dark blue
colorrgb_swatches example

ColorRGBA

A 4-byte pixel color with red, green, blue, and alpha channels (each a UInt8). Used internally by PixelImage, PixelCanvas, and the raw RGBA rendering pipeline — not a subtype of AbstractColor and cannot be used in Style for terminal text.

julia
ColorRGBA(255, 0, 0)        # opaque red  (alpha defaults to 0xff)
ColorRGBA(255, 0, 0, 128)   # semi-transparent red
ColorRGBA(c::ColorRGB)      # promote ColorRGB → ColorRGBA (opaque)
ColorRGB(c::ColorRGBA)      # drop alpha channel → ColorRGB

Predefined constants:

julia
BLACK       # ColorRGBA(0x00, 0x00, 0x00, 0xff)  — opaque black
TRANSPARENT # ColorRGBA(0x00, 0x00, 0x00, 0x00)  — fully transparent

NoColor

Transparent / terminal default:

julia
NoColor()   # inherits terminal default

Theme-Aware Styles with tstyle

The tstyle function creates styles from the current theme's color fields:

julia
tstyle(:primary)                  # theme's primary color as fg
tstyle(:primary, bold=true)       # primary fg, bold
tstyle(:accent, dim=true)         # accent fg, dimmed
tstyle(:error, underline=true)    # error fg, underlined
tstyle_demo example

Available theme fields:

FieldUsage
:borderNormal border color
:border_focusFocused border color
:textStandard text
:text_dimSubdued text
:text_brightEmphasized text
:primaryPrimary accent
:secondarySecondary accent
:accentHighlight / interactive elements
:successSuccess indicators
:warningWarning indicators
:errorError indicators
:titleTitle text

Always prefer tstyle over hardcoded colors — your app automatically adapts when the user switches themes.

Themes

Tachikoma ships with 24 built-in themes split into dark and light packs. Use *Ctrl+* to open the theme selector and Tab to switch between dark and light mode. Your choice is saved via Preferences.jl.

Dark Themes

ThemeConstantDescription
KokakuKOKAKUDeep teal cyberpunk (default)
EsperESPERCool blue noir
MotokoMOTOKOWarm purple cyborg
KanedaKANEDAHot red/orange Neo-Tokyo
NeuromancerNEUROMANCERGreen-on-dark hacker
CatppuccinCATPPUCCINWarm pastel
SolarizedSOLARIZEDEthan Schoonover's palette
DraculaDRACULADark purple classic
OutrunOUTRUNNeon synthwave
ZenburnZENBURNLow-contrast warm
IcebergICEBERGCool blue minimal

Light Themes

ThemeConstantDescription
PaperPAPERClean minimal, black ink on white
LatteLATTECatppuccin Latte, soft pastels on cream
SolarisSOLARISSolarized Light, precision color science
SakuraSAKURACherry blossom pink on snow
AyuAYUWarm daylight, ochre accents
GruvboxGRUVBOXRetro groove, warm contrast on tan
FrostFROSTArctic clarity, ice blue on snow
MeadowMEADOWNatural greens on warm white
DuneDUNEDesert sand, warm earth tones
LavenderLAVENDERSoft purple haze on cool white
HorizonHORIZONCoastal sunrise, warm amber
OvercastOVERCASTBalanced mid-gray, works anywhere
DuskDUSKTwilight gray, warm mids with cool accents

Theme API

julia
theme()                    # get current Theme
set_theme!(KANEDA)         # set by Theme value
set_theme!(:kaneda)        # set by Symbol name
light_mode()               # true if light mode is active
set_light_mode!(true)      # switch to light mode
active_themes()            # themes for current mode
DARK_THEMES                # tuple of all dark themes
LIGHT_THEMES               # tuple of all light themes
ALL_THEMES                 # tuple of all themes (dark + light)

Theme changes take effect immediately — the next view call uses the new colors. Pixel canvases automatically use a white or black background to match the active mode.

ANSI Parsing Default

Strings passed to Paragraph and ScrollPane are automatically parsed for ANSI escape sequences (colors, bold, italic, etc.). Control this globally:

julia
ansi_enabled()              # true by default
set_ansi_enabled!(false)    # disable globally

Per-widget ansi=true or ansi=false overrides the global default. See Paragraph and ScrollPane for details.

theme_demo example

Theme Struct

Each Theme contains:

julia
struct Theme
    name::String
    border::Color256
    border_focus::Color256
    text::Color256
    text_dim::Color256
    text_bright::Color256
    primary::Color256
    secondary::Color256
    accent::Color256
    success::Color256
    warning::Color256
    error::Color256
    title::Color256
end

Color Utilities

Interpolation and Manipulation

julia
color_lerp(a::ColorRGB, b::ColorRGB, t)    # interpolate, t ∈ [0,1]
color_lerp(a::ColorRGBA, b::ColorRGBA, t)  # interpolate with alpha
brighten(c::ColorRGB, amount)  ColorRGB    # brighten by 0–1
dim_color(c::ColorRGB, amount)  ColorRGB   # dim by 0–1
hue_shift(c::ColorRGB, degrees)  ColorRGB  # rotate hue
desaturate(c::ColorRGB, amount)  ColorRGB  # reduce saturation

Color Conversion

julia
to_rgb(c::Color256)  ColorRGB    # ANSI palette → 24-bit RGB
to_rgb(c::ColorRGBA)  ColorRGB   # drop alpha channel
to_rgba(c::ColorRGB)  ColorRGBA  # promote to RGBA (opaque)
to_rgba(c::ColorRGBA)  ColorRGBA # identity

# Requires ColorTypes.jl (loaded via TachikomaColorTypesExt):
to_colortype(c::ColorRGB)   RGB{N0f8}   # Tachikoma → ColorTypes
to_colortype(c::ColorRGBA)  RGBA{N0f8}  # Tachikoma → ColorTypes
to_rgb(c::RGB{N0f8})        ColorRGB    # ColorTypes → Tachikoma
to_rgba(c::RGBA{N0f8})      ColorRGBA   # ColorTypes → Tachikoma

TachikomaColorTypesExt is a package extension that activates automatically when ColorTypes (or a package that re-exports it, such as Colors.jl or Makie) is loaded alongside Tachikoma. It provides two-way conversion between Tachikoma color types and the ColorTypes.jl ecosystem.

Animated Color

julia
# Smooth color cycling (see Animation section)
color_wave(tick, x, colors; speed=0.04, spread=0.08)  ColorRGB
colorwave_demo example

Render Backends

Tachikoma supports three rendering backends that affect how canvases and visual effects are drawn:

julia
@enum RenderBackend braille_backend block_backend sixel_backend

render_backend()                    # get current
set_render_backend!(braille_backend)  # set + save
cycle_render_backend!(1)            # cycle forward
cycle_render_backend!(-1)           # cycle backward
BackendResolutionDescription
braille_backend2×4 per cellUnicode braille dots, works everywhere
block_backend2×2 per cellQuadrant block characters, gap-free
sixel_backend~16×32 per cellPixel-perfect raster, Kitty or sixel

Decay Parameters

The decay system adds a "bit-rot" aesthetic — noise, jitter, and corruption effects:

julia
mutable struct DecayParams
    decay::Float64        # 0–1 master intensity
    jitter::Float64       # 0–1 RGB noise
    rot_prob::Float64     # 0–1 corruption probability
    noise_scale::Float64  # spatial noise scale
end

decay_params()  DecayParams   # get current (mutable)

Adjust via the settings overlay (Ctrl+S) or programmatically. Values are saved via Preferences.jl.

Box Styles

Four border box styles for Block:

julia
BOX_ROUNDED    # ╭─╮╰─╯  (default)
BOX_HEAVY      # ┏━┓┗━┛
BOX_DOUBLE     # ╔═╗╚═╝
BOX_PLAIN      # ┌─┐└─┘
julia
Block(title="Panel", box=BOX_HEAVY)

Visual Constants

julia
DOT = '·'                              # separator dot
BARS_V = ('▁','▂','▃','▄','▅','▆','▇','█')  # vertical bar chars
BARS_H = ('▏','▎','▍','▌','▋','▊','▉','█')  # horizontal bar chars
BLOCKS = ('█','▓','▒','░')             # density blocks
SCANLINE = '╌'                         # interlace separator
MARKER = '▸'                           # list selection marker
SPINNER_BRAILLE = ['⠋','⠙','⠹','⠸','⠼','⠴','⠦','⠧','⠇','⠏']
SPINNER_DOTS = ['⣾','⣽','⣻','⢿','⡿','⣟','⣯','⣷']