# How to Create Custom Color Blends Using Color and ColorTriplet Classes in Rich

> Learn to create custom color blends in Rich using Color and ColorTriplet classes. Blend RGB values programmatically for your terminal applications.

- Repository: [Textualize/rich](https://github.com/Textualize/rich)
- Tags: how-to-guide
- Published: 2026-03-06

---

**To create custom color blends in Rich, parse colors into `Color` objects, extract their `ColorTriplet` RGB values, use `blend_rgb()` to interpolate between them, and wrap the result back into a `Color` instance for styling.**

The Textualize/Rich library provides a sophisticated terminal color system that supports creating smooth gradients and custom color blends. Whether you're building progress bars with dynamic colors or implementing color transitions in CLI applications, understanding how to manipulate the `Color` and `ColorTriplet` classes unlocks precise control over RGB interpolation. This guide demonstrates how to leverage the blending utilities implemented in [`rich/color.py`](https://github.com/Textualize/rich/blob/main/rich/color.py) to create seamless color transitions.

## Understanding Rich's Color Architecture

Rich implements a layered approach to color management with three distinct components working together. The **`Color`** class serves as the terminal-aware abstraction that handles color names, terminal color systems (standard, 8-bit, truecolor, or Windows), and ANSI code generation. It encapsulates an optional **`ColorTriplet`** when dealing with truecolor values. The `ColorTriplet` class, defined in [`rich/color_triplet.py`](https://github.com/Textualize/rich/blob/main/rich/color_triplet.py), provides an immutable RGB tuple with helper methods for hex conversion, CSS-style formatting, and normalized value access. Finally, the **`blend_rgb`** utility function in [`rich/color.py`](https://github.com/Textualize/rich/blob/main/rich/color.py) performs the actual linear interpolation between two triplets.

When you parse a color string such as `"#ff8800"` using `Color.parse()`, the library creates a `Color` instance containing a `ColorTriplet` representing the RGB values. This architecture separates the terminal rendering concerns from the mathematical color operations, allowing you to blend colors mathematically while maintaining automatic downgrade capabilities for limited terminals.

## The Color Blending Workflow

Creating custom color blends follows a predictable four-step process. First, parse input strings into `Color` objects using the `parse()` method. Second, extract the underlying RGB data via `get_truecolor()`, which returns a `ColorTriplet` with red, green, and blue components as integers (0-255). Third, pass these triplets to `blend_rgb()` along with a cross-fade factor between 0.0 and 1.0 to generate an interpolated result. Fourth, convert the blended triplet back into a `Color` object using `Color.from_triplet()` for use in Rich styles and text objects.

This workflow ensures that color mathematics occurs at the RGB triplet level while the final `Color` wrapper maintains Rich's terminal-aware capabilities, including automatic conversion to 8-bit or standard colors when necessary.

## Practical Implementation Examples

### Blend Two Hex Colors for Styled Text

The following example demonstrates blending red and blue to create a purple intermediate, using the exact methods found in [`rich/color.py`](https://github.com/Textualize/rich/blob/main/rich/color.py):

```python
from rich.console import Console
from rich.text import Text
from rich.color import Color, blend_rgb

# Parse the input colours (hex strings)

red   = Color.parse("#ff0000")          # pure red

blue  = Color.parse("#0000ff")          # pure blue

# Get their true‑color triplets

red_triplet   = red.get_truecolor()
blue_triplet  = blue.get_truecolor()

# Blend 30 % red → 70 % blue

purple_triplet = blend_rgb(red_triplet, blue_triplet, cross_fade=0.3)

# Wrap the blended triplet back into a Color object

purple = Color.from_triplet(purple_triplet)

# Use the colour in a Rich Text object

text = Text("Custom purple text", style=f"color({purple_triplet.hex})")
Console().print(text)

```

The `Color.parse` method handles the initial conversion at lines 31-48 of [`rich/color.py`](https://github.com/Textualize/rich/blob/main/rich/color.py), while `get_truecolor` (lines 49-78) ensures you receive a `ColorTriplet` regardless of the original color system. The `blend_rgb` function at lines 80-91 performs the linear interpolation.

### Dynamic Runtime Color Transitions

For applications requiring animated or data-driven color shifts, you can wrap the blending logic in a function that accepts runtime parameters:

```python
import random
from rich.console import Console
from rich.style import Style
from rich.color import Color, blend_rgb
from rich.color_triplet import ColorTriplet

def random_color():
    return Color.from_triplet(
        ColorTriplet(random.randint(0,255), random.randint(0,255), random.randint(0,255))
    )

def blended_style(c1: Color, c2: Color, factor: float) -> Style:
    triplet = blend_rgb(c1.get_truecolor(), c2.get_truecolor(), factor)
    return Style(color=triplet.hex)          # hex works directly in Style

console = Console()
c_a = random_color()
c_b = random_color()

for i in range(5):
    factor = i / 4  # 0.0 → 1.0

    style = blended_style(c_a, c_b, factor)
    console.print(f"Blend {i}", style=style)

```

The `ColorTriplet` class definition resides in [`rich/color_triplet.py`](https://github.com/Textualize/rich/blob/main/rich/color_triplet.py) at lines 4-13, providing the immutable container that `blend_rgb` expects.

### Handling Terminal Color Limitations with Downgrade

Rich's color system automatically adapts to terminal capabilities. When you need to explicitly control this behavior or support legacy terminals, use the `downgrade()` method demonstrated below:

```python
from rich.console import Console
from rich.color import Color, blend_rgb, ColorSystem

# Blend two colours

c1 = Color.parse("#ff8800")
c2 = Color.parse("#00ff88")
blended = Color.from_triplet(blend_rgb(c1.get_truecolor(),
                                     c2.get_truecolor(),
                                     cross_fade=0.5))

# Simulate a limited terminal (8‑bit only)

downgraded = blended.downgrade(ColorSystem.EIGHT_BIT)

console = Console()
console.print("Original (truecolor)", style=f"color({blended.triplet.hex})")
console.print("Downgraded (8‑bit)", style=f"color({downgraded.triplet.hex})")

```

The `downgrade` method implementation at lines 112-155 of [`rich/color.py`](https://github.com/Textualize/rich/blob/main/rich/color.py) maps truecolor values to the closest available color in the target color system, ensuring your blends remain visible even on restricted terminals.

## Summary

- **Parse input strings** using `Color.parse()` to create terminal-aware color objects from hex codes, RGB values, or color names.
- **Extract RGB data** with `get_truecolor()` to obtain immutable `ColorTriplet` instances suitable for mathematical operations.
- **Interpolate colors** by calling `blend_rgb()` with two triplets and a cross-fade factor between 0.0 and 1.0 to generate intermediate shades.
- **Reconstruct Color objects** using `Color.from_triplet()` to apply blended results to Rich `Style` and `Text` components.
- **Maintain compatibility** by leveraging automatic or explicit `downgrade()` to adapt blended colors for terminals with limited color support.

## Frequently Asked Questions

### What is the difference between Color and ColorTriplet in Rich?

`Color` is a terminal-aware abstraction defined in [`rich/color.py`](https://github.com/Textualize/rich/blob/main/rich/color.py) that tracks the color system (standard, 8-bit, truecolor, or Windows), color names, and ANSI escape sequences. `ColorTriplet`, defined in [`rich/color_triplet.py`](https://github.com/Textualize/rich/blob/main/rich/color_triplet.py), is a simple immutable tuple of three integers (0-255) representing red, green, and blue values. While `Color` handles rendering concerns, `ColorTriplet` provides the raw RGB data needed for mathematical operations like blending.

### How does the blend_rgb function calculate the interpolated color?

The `blend_rgb` function performs linear interpolation between two `ColorTriplet` instances. It accepts a `cross_fade` parameter between 0.0 and 1.0, where 0.0 returns the first color and 1.0 returns the second. For each RGB component, it calculates the weighted average: `color1 + (color2 - color1) * cross_fade`. This implementation appears at lines 80-91 in [`rich/color.py`](https://github.com/Textualize/rich/blob/main/rich/color.py).

### Can blended colors be used with Rich's Style and Text classes?

Yes. After blending `ColorTriplet` instances and converting back to a `Color` object via `Color.from_triplet()`, you can apply the result anywhere Rich expects color specifications. Pass the `Color` instance to `Style(color=...)` or use the hex representation (accessible via `.triplet.hex`) in style strings for `Text` objects.

### How do I handle terminals that don't support truecolor?

Rich handles this automatically through the `downgrade()` method found at lines 112-155 of [`rich/color.py`](https://github.com/Textualize/rich/blob/main/rich/color.py). You can explicitly convert a blended color to 8-bit or standard colors by calling `color.downgrade(ColorSystem.EIGHT_BIT)` or `color.downgrade(ColorSystem.STANDARD)`. This maps the RGB values to the closest available color in the target palette, ensuring your blends display correctly on older terminals.