Skip to content

Compositing

Edit this page

Compositing lets you merge multiple layers of content into a single output. Each layer is a set of ANSI-formatted lines at a position, and layers can be transparent so the content below shows through.

This is useful for rendering effects like animated backgrounds with text on top, watermarks, or any scenario where a widget needs to combine independently rendered content.

The Compositor

The Compositor class merges layers in order. Layer 0 is the base (typically opaque, filling the entire screen); subsequent layers are painted on top:

1
2
3
4
5
6
7
use Symfony\Component\Tui\Render\Compositor;
use Symfony\Component\Tui\Render\Layer;

$lines = Compositor::composite(
    new Layer($backgroundLines),                     // opaque base
    new Layer($foregroundLines, transparent: true),   // transparent overlay
);

composite() returns string[], one ANSI-formatted string per terminal row, ready to be returned from a widget's render() method.

The canvas dimensions are derived from the first (base) layer: height is the number of lines, width is the visible width of the first line.

The Layer Value Object

A Layer describes content to composite:

1
2
3
4
5
6
7
8
9
10
use Symfony\Component\Tui\Render\Layer;

$layer = new Layer(
    lines: $lines,           // string[] of ANSI-formatted content
    row: 0,                  // vertical offset (default: 0)
    col: 0,                  // horizontal offset (default: 0)
    transparent: false,      // transparency flag (default: false)
    width: null,             // explicit canvas width (base layer only)
    height: null,            // explicit canvas height (base layer only)
);

All parameters except lines are optional.

The width and height parameters are only meaningful on the base layer (the first one passed to composite()). When set, they define the canvas dimensions explicitly. When null, the canvas dimensions are derived from the base layer's content.

How Transparency Works

When a layer is transparent (transparent: true):

  • Cells with content but no explicit background inherit the background from the layer below. The foreground character and color are painted on top of whatever background was already there.
  • Plain spaces with no styling are fully transparent: the entire cell from the layer below is preserved (character, foreground, background, and attributes).
  • Cells with an explicit background are opaque and overwrite the layer below completely.

When a layer is opaque (the default), every cell overwrites the layer below regardless of styling.

Positioned Layers

Layers can be offset from the top-left corner. This is useful for compositing smaller content at a specific position:

1
2
3
4
$lines = Compositor::composite(
    new Layer($fullScreenBackground),
    new Layer($smallWidget, row: 5, col: 10, transparent: true),
);

The offset applies to the entire content of the layer. Cells outside the layer's content area are unaffected.

Multiple Layers

Any number of layers can be composited. They are applied in order, so layer N can see the merged result of layers 0 through N-1:

1
2
3
4
5
$lines = Compositor::composite(
    new Layer($background),
    new Layer($midground, transparent: true),
    new Layer($foreground, transparent: true),
);
This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.
TOC
    Version