Skip to content

Highlight

Demo

Quick Start

highlight.py
from terminaltexteffects import Gradient
from terminaltexteffects.effects.effect_highlight import Highlight

effect = Highlight("YourTextHere")

with effect.terminal_output() as terminal:
    effect.effect_config.final_gradient_direction = Gradient.Direction.HORIZONTAL
    for frame in effect:
        terminal.print(frame)

Highlight Directions and Sorts

--highlight-direction accepts every CharacterOrder. Group directions activate whole rows, columns, diagonals, or radial bands. Sort directions activate individual characters in the exact order returned by Terminal.get_characters(), using their input coordinates. All text remains visible while the highlight travels through it.

The spiral sorts wind inward from the input's bounds:

Clockwise Counterclockwise Starting corners
spiral_clockwise spiral_counter_clockwise Top-left
spiral_clockwise_double spiral_counter_clockwise_double Top-left and bottom-right
spiral_clockwise_quad spiral_counter_clockwise_quad All four corners

Double and quad spirals interleave their arms in the character sequence. Both grouped and sorted modes retain the same easing schedule, so multiple characters may start highlighting in one frame. highlight_width controls the duration of each character's bright highlight; it does not set the number of characters in a sorted trail. The default remains diagonal_bottom_left_to_top_right.

tte highlight --highlight-direction spiral_clockwise
tte highlight --highlight-direction spiral_counter_clockwise_quad --highlight-width 12

Use --reverse-highlight-direction to reverse the complete traversal while preserving group membership. The flag defaults to off. Reversed spirals travel outward along the selected path; changing clockwise to counterclockwise instead selects a different inward path.

tte highlight --highlight-direction spiral_clockwise --reverse-highlight-direction

Configurations normalize to CharacterOrder. Existing CharacterGroup and CharacterSort values and their CLI spellings remain accepted as compatibility inputs.

For library use, assign a native enum or its CLI spelling:

from terminaltexteffects.effects.effect_highlight import Highlight
from terminaltexteffects import CharacterOrder

effect = Highlight("YourTextHere")
effect.effect_config.highlight_direction = CharacterOrder.SPIRAL_CLOCKWISE_DOUBLE

Runs a specular highlight across the text.

Classes:

Name Description
Highlight

Runs a specular highlight across the text.

HighlightConfig

Configuration for the Highlight effect.

HighlightIterator

Effect iterator for the Highlight effect.

Highlight

Bases: BaseEffect[HighlightConfig]

Run a specular highlight across the text.

Source code in terminaltexteffects/effects/effect_highlight.py
class Highlight(BaseEffect[HighlightConfig]):
    """Run a specular highlight across the text."""

    @property
    def _config_cls(self) -> type[HighlightConfig]:
        return HighlightConfig

    @property
    def _iterator_cls(self) -> type[HighlightIterator]:
        return HighlightIterator

HighlightConfig dataclass

Bases: BaseConfig

Configuration for the Highlight effect.

Attributes:

Name Type Description
highlight_brightness float

Brightness of the highlight color. Values less than 1 will darken the highlight color, while values greater than 1 will brighten the highlight color.

reverse_highlight_direction bool

Reverse the complete traversal while preserving group membership.

highlight_direction `CharacterOrder`

Grouping or character order for highlight activation. Sort values follow the exact sorted order, including spiral patterns.

highlight_width int

Width of the highlight. n >= 1

final_gradient_stops tuple[Color, ...]

Tuple of colors for the final color gradient. If only one color is provided, the characters will be displayed in that color.

final_gradient_steps tuple[int, ...] | int

Int or Tuple of ints for the number of gradient steps to use. More steps will create a smoother and longer gradient animation.

final_gradient_direction Direction

Direction of the final gradient.

Source code in terminaltexteffects/effects/effect_highlight.py
@dataclass
class HighlightConfig(BaseConfig):
    """Configuration for the Highlight effect.

    Attributes:
        highlight_brightness (float): Brightness of the highlight color. Values less than 1 will darken the highlight
            color, while values greater than 1 will brighten the highlight color.
        reverse_highlight_direction (bool): Reverse the complete traversal while preserving group membership.
        highlight_direction (`CharacterOrder`): Grouping or character order for
            highlight activation. Sort values follow the exact sorted order, including spiral patterns.
        highlight_width (int): Width of the highlight. n >= 1
        final_gradient_stops (tuple[Color, ...]): Tuple of colors for the final color gradient. If only one color is
            provided, the characters will be displayed in that color.
        final_gradient_steps (tuple[int, ...] | int): Int or Tuple of ints for the number of gradient steps to use.
            More steps will create a smoother and longer gradient animation.
        final_gradient_direction (Gradient.Direction): Direction of the final gradient.

    """

    parser_spec: argutils.ParserSpec = argutils.ParserSpec(
        name="highlight",
        help="Run a specular highlight across the text.",
        description="highlight | Run a specular highlight across the text.",
        epilog=(
            f"{argutils.EASING_EPILOG}Example: terminaltexteffects highlight --highlight-brightness 1.75 "
            "--highlight-direction "
            "diagonal_bottom_left_to_top_right --highlight-width 8 --final-gradient-stops 8A008A 00D1FF FFFFFF "
            "--final-gradient-steps 12 --final-gradient-direction vertical"
        ),
    )

    highlight_brightness: float = argutils.ArgSpec(
        name="--highlight-brightness",
        type=argutils.PositiveFloat.type_parser,
        default=1.75,
        metavar=argutils.PositiveFloat.METAVAR,
        help="Brightness of the highlight color. Values less than 1 will darken the highlight color, while values "
        "greater than 1 will brighten the highlight color.",
    )  # pyright: ignore[reportAssignmentType]
    (
        "float : Brightness of the highlight color. Values less than 1 will darken the highlight color, while "
        "values greater than 1 will brighten the highlight color."
    )

    highlight_direction: argutils.CharacterOrder | argutils.CharacterGroup | argutils.CharacterSort = argutils.ArgSpec(
        name="--highlight-direction",
        default=argutils.CharacterOrder.DIAGONAL_BOTTOM_LEFT_TO_TOP_RIGHT,
        metavar=" ".join(argutils.CharacterOrderArg.METAVAR),
        help="Character order for highlight activation: spatial groups or individual traversal, including spirals.",
        type=argutils.CharacterOrderArg.type_parser,
    )  # pyright: ignore[reportAssignmentType]
    ("CharacterOrder : Grouping or character order for highlight activation.")

    reverse_highlight_direction: bool = argutils.ArgSpec(
        name="--reverse-highlight-direction",
        default=False,
        action="store_true",
        help="Reverse the complete highlight direction traversal.",
    )  # pyright: ignore[reportAssignmentType]
    "bool : Reverse the complete traversal, preserving group membership."

    highlight_width: int = argutils.ArgSpec(
        name="--highlight-width",
        type=argutils.PositiveInt.type_parser,
        default=8,
        metavar=argutils.PositiveInt.METAVAR,
        help="Width of the highlight. n >= 1",
    )  # pyright: ignore[reportAssignmentType]
    "int : Width of the highlight. n >= 1"

    final_gradient_stops: tuple[Color, ...] = FinalGradientStopsArg(
        default=(Color("#8A008A"), Color("#00D1FF"), Color("#FFFFFF")),
    )  # pyright: ignore[reportAssignmentType]
    (
        "tuple[Color, ...] : Tuple of colors for the final color gradient. If only one color is provided, the "
        "characters will be displayed in that color."
    )

    final_gradient_steps: tuple[int, ...] | int = FinalGradientStepsArg(
        default=12,
    )  # pyright: ignore[reportAssignmentType]
    (
        "tuple[int, ...] | int : Int or Tuple of ints for the number of gradient steps to use. More steps will "
        "create a smoother and longer gradient animation."
    )

    final_gradient_direction: Gradient.Direction = FinalGradientDirectionArg(
        default=Gradient.Direction.VERTICAL,
    )  # pyright: ignore[reportAssignmentType]
    "Gradient.Direction : Direction of the final gradient."

final_gradient_direction = FinalGradientDirectionArg(default=(Gradient.Direction.VERTICAL)) class-attribute instance-attribute

Gradient.Direction : Direction of the final gradient.

final_gradient_steps = FinalGradientStepsArg(default=12) class-attribute instance-attribute

tuple[int, ...] | int : Int or Tuple of ints for the number of gradient steps to use. More steps will create a smoother and longer gradient animation.

final_gradient_stops = FinalGradientStopsArg(default=(Color('#8A008A'), Color('#00D1FF'), Color('#FFFFFF'))) class-attribute instance-attribute

tuple[Color, ...] : Tuple of colors for the final color gradient. If only one color is provided, the characters will be displayed in that color.

highlight_brightness = argutils.ArgSpec(name='--highlight-brightness', type=(argutils.PositiveFloat.type_parser), default=1.75, metavar=(argutils.PositiveFloat.METAVAR), help='Brightness of the highlight color. Values less than 1 will darken the highlight color, while values greater than 1 will brighten the highlight color.') class-attribute instance-attribute

float : Brightness of the highlight color. Values less than 1 will darken the highlight color, while values greater than 1 will brighten the highlight color.

highlight_direction = argutils.ArgSpec(name='--highlight-direction', default=(argutils.CharacterOrder.DIAGONAL_BOTTOM_LEFT_TO_TOP_RIGHT), metavar=(' '.join(argutils.CharacterOrderArg.METAVAR)), help='Character order for highlight activation: spatial groups or individual traversal, including spirals.', type=(argutils.CharacterOrderArg.type_parser)) class-attribute instance-attribute

CharacterOrder : Grouping or character order for highlight activation.

highlight_width = argutils.ArgSpec(name='--highlight-width', type=(argutils.PositiveInt.type_parser), default=8, metavar=(argutils.PositiveInt.METAVAR), help='Width of the highlight. n >= 1') class-attribute instance-attribute

int : Width of the highlight. n >= 1

reverse_highlight_direction = argutils.ArgSpec(name='--reverse-highlight-direction', default=False, action='store_true', help='Reverse the complete highlight direction traversal.') class-attribute instance-attribute

bool : Reverse the complete traversal, preserving group membership.

HighlightIterator

Bases: BaseEffectIterator[HighlightConfig]

Effect iterator for the Highlight effect.

Source code in terminaltexteffects/effects/effect_highlight.py
class HighlightIterator(BaseEffectIterator[HighlightConfig]):
    """Effect iterator for the Highlight effect."""

    def __init__(self, effect: Highlight) -> None:
        """Initialize the Highlight effect iterator.

        Args:
            effect (Highlight): The Highlight effect to iterate over.

        """
        super().__init__(effect)
        self.character_final_color_map: dict[EffectCharacter, Color | None] = {}
        self.pending_characters: list[list[EffectCharacter]] = []
        groups = self.terminal.get_characters_grouped(
            order=self.config.highlight_direction,
            reverse=self.config.reverse_highlight_direction,
        )
        self.easer = easing.SequenceEaser(
            sequence=groups,
            easing_function=easing.in_out_circ,
        )
        self.build()

    def build(self) -> None:
        """Build the effect."""
        final_gradient = Gradient(
            *self.config.final_gradient_stops,
            steps=self.config.final_gradient_steps,
        )
        final_gradient_mapping = final_gradient.build_coordinate_color_mapping(
            self.terminal.canvas.text_bottom,
            self.terminal.canvas.text_top,
            self.terminal.canvas.text_left,
            self.terminal.canvas.text_right,
            self.config.final_gradient_direction,
        )
        for character in self.terminal.get_characters():
            input_bg_color = None
            if self.terminal.config.existing_color_handling == "dynamic":
                base_color = character.animation.input_fg_color
                input_bg_color = character.animation.input_bg_color
            else:
                base_color = final_gradient_mapping[character.input_coord]
            self.character_final_color_map[character] = base_color
            base_colors = ColorPair(fg=base_color, bg=input_bg_color)
            if base_color:
                highlight_color = Animation.adjust_color_brightness(
                    base_color,
                    self.config.highlight_brightness,
                )
                highlight_gradient = Gradient(
                    base_color,
                    highlight_color,
                    highlight_color,
                    base_color,
                    steps=(3, self.config.highlight_width, 3),
                )
                character.animation.set_appearance(character.input_symbol, base_colors)
            else:
                highlight_gradient = None
                character.animation.set_appearance(character.input_symbol, base_colors)
            specular_highlight_scn = character.animation.new_scene(scene_id="highlight")
            if highlight_gradient:
                for color in highlight_gradient:
                    specular_highlight_scn.add_frame(
                        character.input_symbol,
                        2,
                        colors=ColorPair(fg=color, bg=input_bg_color),
                    )
            else:
                specular_highlight_scn.add_frame(
                    character.input_symbol,
                    2,
                    colors=base_colors,
                )
            self.terminal.set_character_visibility(character, is_visible=True)

    def __next__(self) -> str:
        """Return the next frame in the animation."""
        if self.active_characters or not self.easer.is_complete():
            self.easer.step()
            for group in self.easer.added:
                for character in group:
                    character.animation.activate_scene("highlight")
                    self.active_characters.add(character)

            self.update()
            return self.frame

        raise StopIteration

__init__(effect)

Initialize the Highlight effect iterator.

Parameters:

Name Type Description Default
effect Highlight

The Highlight effect to iterate over.

required
Source code in terminaltexteffects/effects/effect_highlight.py
def __init__(self, effect: Highlight) -> None:
    """Initialize the Highlight effect iterator.

    Args:
        effect (Highlight): The Highlight effect to iterate over.

    """
    super().__init__(effect)
    self.character_final_color_map: dict[EffectCharacter, Color | None] = {}
    self.pending_characters: list[list[EffectCharacter]] = []
    groups = self.terminal.get_characters_grouped(
        order=self.config.highlight_direction,
        reverse=self.config.reverse_highlight_direction,
    )
    self.easer = easing.SequenceEaser(
        sequence=groups,
        easing_function=easing.in_out_circ,
    )
    self.build()

__next__()

Return the next frame in the animation.

Source code in terminaltexteffects/effects/effect_highlight.py
def __next__(self) -> str:
    """Return the next frame in the animation."""
    if self.active_characters or not self.easer.is_complete():
        self.easer.step()
        for group in self.easer.added:
            for character in group:
                character.animation.activate_scene("highlight")
                self.active_characters.add(character)

        self.update()
        return self.frame

    raise StopIteration

build()

Build the effect.

Source code in terminaltexteffects/effects/effect_highlight.py
def build(self) -> None:
    """Build the effect."""
    final_gradient = Gradient(
        *self.config.final_gradient_stops,
        steps=self.config.final_gradient_steps,
    )
    final_gradient_mapping = final_gradient.build_coordinate_color_mapping(
        self.terminal.canvas.text_bottom,
        self.terminal.canvas.text_top,
        self.terminal.canvas.text_left,
        self.terminal.canvas.text_right,
        self.config.final_gradient_direction,
    )
    for character in self.terminal.get_characters():
        input_bg_color = None
        if self.terminal.config.existing_color_handling == "dynamic":
            base_color = character.animation.input_fg_color
            input_bg_color = character.animation.input_bg_color
        else:
            base_color = final_gradient_mapping[character.input_coord]
        self.character_final_color_map[character] = base_color
        base_colors = ColorPair(fg=base_color, bg=input_bg_color)
        if base_color:
            highlight_color = Animation.adjust_color_brightness(
                base_color,
                self.config.highlight_brightness,
            )
            highlight_gradient = Gradient(
                base_color,
                highlight_color,
                highlight_color,
                base_color,
                steps=(3, self.config.highlight_width, 3),
            )
            character.animation.set_appearance(character.input_symbol, base_colors)
        else:
            highlight_gradient = None
            character.animation.set_appearance(character.input_symbol, base_colors)
        specular_highlight_scn = character.animation.new_scene(scene_id="highlight")
        if highlight_gradient:
            for color in highlight_gradient:
                specular_highlight_scn.add_frame(
                    character.input_symbol,
                    2,
                    colors=ColorPair(fg=color, bg=input_bg_color),
                )
        else:
            specular_highlight_scn.add_frame(
                character.input_symbol,
                2,
                colors=base_colors,
            )
        self.terminal.set_character_visibility(character, is_visible=True)

get_effect_resources()

Get the command, effect class, and configuration class for the effect.

Returns:

Type Description
tuple[str, type[BaseEffect], type[BaseConfig]]

tuple[str, type[BaseEffect], type[BaseConfig]]: The command name, effect class, and configuration class.

Source code in terminaltexteffects/effects/effect_highlight.py
def get_effect_resources() -> tuple[str, type[BaseEffect], type[BaseConfig]]:
    """Get the command, effect class, and configuration class for the effect.

    Returns:
        tuple[str, type[BaseEffect], type[BaseConfig]]: The command name, effect class, and configuration class.

    """
    return "highlight", Highlight, HighlightConfig