# How Omarchy Processes Theme .tpl Templates with {{ Variable }} Placeholders

> Discover how Omarchy processes theme .tpl templates using a sed-based engine to replace {{ variable }} placeholders with values from the colors.toml palette.

- Repository: [Omacom/omarchy](https://github.com/omacom/omarchy)
- Tags: internals
- Published: 2026-09-09

---

**Omarchy renders theme `.tpl` templates into concrete configuration files by using a sed‑based substitution engine defined in `bin/omarchy-theme-set-templates`, which replaces `{{ variable }}` placeholders with values derived from the theme’s [`colors.toml`](https://github.com/omacom/omarchy/blob/main/colors.toml) palette.**

The Omarchy desktop environment ([omacome/omarchy](https://github.com/omacome/omarchy)) uses a template-driven theming system that converts abstract color palettes into application-specific config files. When you activate a theme with `omarchy-theme-set`, the system processes hidden-hand `.tpl` templates located in `default/themed/` and `~/.config/omarchy/themed/` to generate finalized configs like [`hyprland.lua`](https://github.com/omacom/omarchy/blob/main/hyprland.lua) and [`alacritty.toml`](https://github.com/omacom/omarchy/blob/main/alacritty.toml). This pipeline—validated by the test suite in [`test/shell.d/theme-staging-test.sh`](https://github.com/omacom/omarchy/blob/main/test/shell.d/theme-staging-test.sh)—handles everything from simple hex colors to interpolated gradients.

## The Theme Activation Pipeline

When a user runs `omarchy-theme-set <theme_name>`, the command creates a clean staging directory at `~/.local/state/omarchy/current/next-theme`. It copies the selected theme assets, including [`colors.toml`](https://github.com/omacom/omarchy/blob/main/colors.toml), and then invokes `bin/omarchy-theme-set-templates` to perform the actual rendering. This separation keeps the activation logic distinct from the template engine, as documented in [`docs/theming.md`](https://github.com/omacom/omarchy/blob/main/docs/theming.md).

## Building the Color Palette Map

Before any substitution occurs, the engine loads the palette into an associative array named `THEME_COLORS`. The script reads the theme’s [`colors.toml`](https://github.com/omacom/omarchy/blob/main/colors.toml) via `omarchy-theme-color --file "$COLORS_FILE" --all`, parsing tab-delimited key-value pairs.

```bash
while IFS=$'\t' read -r key value; do
  THEME_COLORS[$key]="$value"
done < <(omarchy-theme-color --file "$COLORS_FILE" --all)

```

This array maps keys like `accent` to hex values like `#7aa2f7`, forming the lookup table for all subsequent replacements.

## Processing Simple Color Placeholders

For every entry in `THEME_COLORS`, the `add_template_value` function generates three distinct sed substitution rules. These allow template authors to request colors in different formats without manual conversion.

### Hex, Strip, and RGB Variants

- ** `{{ key }}`** → Raw hex value (e.g., `#7aa2f7`)
- ** `{{ key_strip }}`** → Hex without the hash (e.g., `7aa2f7`)
- ** `{{ key_rgb }}`** → Comma-separated decimal RGB (e.g., `122,162,247`)

The script constructs these rules using `printf` (see lines 100‑107):

```bash
printf 's|{{ %s }}|%s|g\n' "$key" "$value"
printf 's|{{ %s_strip }}|%s|g\n' "$key" "${value#\#}"
printf 's|{{ %s_rgb }}|%s|g\n' "$key" "$(hex_to_rgb "$value")"

```

Example usage in `default/themed/alacritty.toml.tpl`:

```toml
[colors]
foreground = "{{ foreground }}"
background = "{{ background_strip }}"
cursor = "{{ accent_rgb }}"

```

## Advanced Variable Processing

Beyond static color lookups, the engine supports computed values through color mixing and gradient parsing helpers defined in the same `bin/omarchy-theme-set-templates` script.

### Color Mixing with mix, mix_strip, and mix_rgb

Templates can interpolate between two palette colors using the syntax `{{ mix <start_key> <end_key> <amount> }}`. The engine detects these tokens via `grep -Eo` in the `add_mix_values` function (lines 49‑51).

For each match, `add_mix_value` performs four operations:

1. Retrieves the start and end colors from `THEME_COLORS`.
2. Uses an `awk` function `mix_color` to linearly interpolate the two hex values.
3. Optionally strips the leading `#` or converts to decimal RGB based on the token suffix.
4. Emits a sed substitution rule that replaces the entire token with the computed value.

Example usage:

```toml
selection = "{{ mix background foreground 20% }}"

```

This mixes 20% of the foreground color into the background color, outputting a new hex value.

### Gradient Helpers

When a palette entry contains Hyprland-style gradient strings like `rgba(33ccffee) rgba(00ff99ee) 45deg`, three helpers parse and reformat them:

- **`{{ hypr_gradient <key> <fallback> }}`** → Generates a Lua table: `{ colors = { "rgba(33ccffee)", "rgba(00ff99ee)" }, angle = 45 }`
- **`{{ gradient_start <key> <fallback> }}`** → Returns the first solid color as hex: `#33ccff` (or the fallback if parsing fails)
- **`{{ shell_gradient <key> <fallback> }}`** → Emits the raw gradient string: `rgba(33ccffee) rgba(00ff99ee) 45deg`

The implementation lives in `add_gradient_function_value` and its helpers `hypr_gradient_value`, `gradient_start_value`, and `shell_gradient_value` (lines 54‑78), with regex parsing in `add_gradient_function_values` (lines 84‑90).

Example in a Lua template:

```lua
local active_border = {{ hypr_gradient hyprland_active_border accent }}

```

## Rendering the Final Configuration Files

After collecting all sed rules into a temporary script file (`$sed_script`), the engine iterates over template files. User-provided templates in `~/.config/omarchy/themed/` are processed first; if a generated file already exists, built-in templates are skipped.

```bash
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

```

The `[[ ! -f $output_path ]]` check enforces **user‑overrides‑built‑in** ordering. The rendered files land in the staging directory and are moved to the active theme location by the parent `omarchy-theme-set` process.

## Summary

- Omarchy uses `bin/omarchy-theme-set-templates` to render `.tpl` files into concrete configs during theme activation.
- The engine loads [`colors.toml`](https://github.com/omacom/omarchy/blob/main/colors.toml) into a `THEME_COLORS` associative array to fuel substitutions.
- Simple placeholders support three formats: raw hex (`{{ key }}`), stripped hex (`{{ key_strip }}`), and decimal RGB (`{{ key_rgb }}`).
- The `mix` function performs linear interpolation between two palette colors with `_strip` and `_rgb` variants.
- Gradient helpers parse Hyprland-style color lists into Lua tables, hex values, or raw strings.
- User templates in `~/.config/omarchy/themed/` override built-in defaults in `default/themed/`.

## Frequently Asked Questions

### Where are the template files located in Omarchy?

Omarchy ships with default templates in `default/themed/` (e.g., `default/themed/shell.toml.tpl`). Users can create custom overrides in `~/.config/omarchy/themed/`, which take precedence over the built-in versions during the rendering process.

### What file handles the actual template rendering logic?

The `bin/omarchy-theme-set-templates` script contains the complete rendering engine. It is invoked by `bin/omarchy-theme-set` after the theme has been staged in `~/.local/state/omarchy/current/next-theme`.

### Can I use color mixing in my custom templates?

Yes. The template engine supports `{{ mix <color1> <color2> <percentage> }}` syntax, which linearly interpolates between two palette colors. You can also use `mix_strip` or `mix_rgb` suffixes to output the result in different formats.

### How does Omarchy handle conflicting template files?

The rendering loop processes user templates first and skips built-in templates if the output file already exists. This user‑overrides‑built‑in behavior ensures that custom configurations in `~/.config/omarchy/themed/` always take priority over files in `default/themed/`.