How Omarchy Theme Templates Use `{{ Variable }}` Placeholders: Complete Guide
Omarchy replaces {{ variable }} placeholders in .tpl template files with color values from colors.toml through the omarchy-theme-set-templates script, supporting direct hex insertion, RGB conversion, hex stripping, interpolated color mixing, and gradient parsing.
Omarchy’s theming engine transforms abstract color palettes into concrete application configurations by processing template files (.tpl) containing {{ variable }} placeholders. Located in the omaccom/omarchy repository, this system allows themes to define colors once in colors.toml and propagate them across diverse configuration formats including TOML, Lua, and shell scripts.
Template Rendering Pipeline in Omarchy
The rendering process initiates when a user executes omarchy-theme-set <name>. This command orchestrates the theme activation through a specific lifecycle:
- Creates a clean staging directory at
~/.local/state/omarchy/current/next-theme - Copies the selected theme’s
colors.tomland assets - Invokes
bin/omarchy-theme-set-templatesto process all.tplfiles - Atomically moves the staging directory to the active theme location
This staging approach ensures that configuration files are fully rendered before becoming active, preventing partial state updates in running applications.
How {{ Variable }} Placeholders Work
At the core of the system is bin/omarchy-theme-set-templates, a Bash script that constructs a sed substitution script from the palette defined in colors.toml. The script populates an associative array THEME_COLORS by parsing the color file, then generates substitution rules for each key.
Building the Palette Map
The script first loads all color definitions into memory:
while IFS=$'\t' read -r key value; do
THEME_COLORS[$key]="$value"
done < <(omarchy-theme-color --file "$COLORS_FILE" --all)
Each key (e.g., accent, background) maps to a hex value (e.g., #7aa2f7), forming the lookup table for all subsequent placeholder resolutions.
Simple Color Placeholders
For every entry in THEME_COLORS, the add_template_value function generates three distinct placeholder variants:
{{ key }}— Inserts the raw hex value (e.g.,#7aa2f7){{ key_strip }}— Inserts the hex value without the leading#(e.g.,7aa2f7){{ key_rgb }}— Converts the hex value to decimal RGB format (e.g.,122,162,247)
These variants are produced using printf statements that build sed substitution patterns, as documented in docs/theming.md and implemented at lines 100–107 of the rendering script.
Advanced Placeholder Types
Beyond simple value insertion, Omarchy supports computed placeholders for dynamic color generation and gradient handling.
Color Mixing with {{ mix }}
Templates can interpolate between two palette colors using the mix directive. The syntax follows {{ mix[_strip|_rgb] <start_key> <end_key> <amount> }}, where <amount> is a fraction or percentage (e.g., 20%).
The add_mix_values function detects these tokens using grep -Eo (lines 49–51), then processes each match through add_mix_value:
- Retrieves the start and end hex values from
THEME_COLORS - Executes an awk function
mix_colorto linearly interpolate the two values based on the specified amount - Optionally strips the
#prefix or converts to decimal RGB depending on whether_stripor_rgbsuffixes are present - Appends a sed substitution rule to replace the entire token with the computed result
This enables smooth transitions between theme colors without manual hex calculation.
Gradient Helpers (hypr_gradient, gradient_start, shell_gradient)
When a palette entry contains Hyprland-style gradient definitions (e.g., rgba(33ccffee) rgba(00ff99ee) 45deg), Omarchy exposes three specialized helpers:
{{ hypr_gradient <key> <fallback> }}— Generates a Lua table structure:{ colors = { "rgba(33ccffee)", "rgba(00ff99ee)" }, angle = 45 }{{ gradient_start <key> <fallback> }}— Extracts the first solid color as a hex value (e.g.,#33ccff){{ shell_gradient <key> <fallback> }}— Returns the raw gradient string for shell consumption
These are implemented in add_gradient_function_value and helper functions spanning lines 54–78, with parsing logic at lines 84–90 that detects the specific helper patterns.
Template Processing Flow
After collecting all substitution rules, the script applies them to template files found in default/themed/ and ~/.config/omarchy/themed/.
The rendering sequence follows this pattern:
for tpl in "${template_files[@]}"; do
filename=$(basename "$tpl" .tpl)
output_path="$NEXT_THEME_DIR/$filename"
[[ ! -f $output_path ]] && sed -f "$sed_script" "$tpl" >"$output_path"
done
User templates take precedence: Files in ~/.config/omarchy/themed/ are processed first. If a generated file already exists from the default set, the script skips generation, effectively allowing user templates to override built-in defaults. This creates a cascading configuration system where customizations persist across theme updates.
Practical Examples
Example 1: Basic Color Substitution
Input (default/themed/alacritty.toml.tpl):
[colors]
foreground = "{{ foreground }}"
background = "{{ background_strip }}"
cursor = "{{ accent_rgb }}"
Output (assuming foreground = "#a9b1d6", background = "#1a1b26", accent = "#7aa2f7"):
[colors]
foreground = "#a9b1d6"
background = "1a1b26"
cursor = "122,162,247"
Example 2: Color Mixing
Input:
[colors]
selection = "{{ mix background foreground 20% }}"
Processing: The script interpolates 20% of foreground into background, yielding a blended hex value like #2f3a4f.
Output:
[colors]
selection = "#2f3a4f"
Example 3: Gradient Parsing
Input:
hyprland_active_border = "rgba(33ccffee) rgba(00ff99ee) 45deg"
Template usage:
local active_border = {{ hypr_gradient hyprland_active_border accent }}
Output:
local active_border = { colors = { "rgba(33ccffee)", "rgba(00ff99ee)" }, angle = 45 }
Summary
- Omarchy theme templates use
.tplfiles with{{ variable }}placeholders that are processed bybin/omarchy-theme-set-templatesduring theme activation. - Three variants of simple placeholders exist:
{{ key }}for hex values,{{ key_strip }}for hex without#, and{{ key_rgb }}for decimal RGB tuples. - Color mixing supports linear interpolation between two palette colors via
{{ mix }}, with optional_stripor_rgbsuffixes for format control. - Gradient helpers parse Hyprland-style color lists into Lua tables, single colors, or raw strings using
hypr_gradient,gradient_start, andshell_gradient. - User overrides are respected: custom templates in
~/.config/omarchy/themed/take precedence over defaults indefault/themed/.
Frequently Asked Questions
Where are Omarchy theme templates stored?
Default templates reside in default/themed/ within the repository, while user customizations belong in ~/.config/omarchy/themed/. The rendering script processes both locations, with user-provided files taking precedence when filenames collide.
How does Omarchy handle user customizations versus default templates?
The omarchy-theme-set-templates script processes user templates from ~/.config/omarchy/themed/ before default templates. It checks for existing output files and skips generation if a file already exists, ensuring that user configurations persist even when switching themes or updating the system defaults.
What color formats do Omarchy variable placeholders support?
Placeholders support hexadecimal values with or without the # prefix, decimal RGB tuples (comma-separated), and rgba() strings for gradients. The system automatically converts between these formats using variant suffixes like _strip and _rgb, eliminating manual conversion in theme files.
How are color mixtures calculated in Omarchy templates?
Mixtures use linear interpolation implemented in an awk function called mix_color. When processing {{ mix start end amount }}, the script extracts the two boundary colors from THEME_COLORS, converts the hex values to RGB components, interpolates each channel based on the fraction provided (e.g., 20%), then reconverts to hexadecimal for insertion.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →