opentui

Build terminal UIs with OpenTUI. Covers Core, frameworks, components, application APIs, testing, extensions, integrations, deployment, and public API lookup.

Install
npx skills add 'https://github.com/anomalyco/opentui/tree/main/packages/web/src/content'
Download bundle ↓
main · ac753b4Scanned 2026-09-15

Contributors

GitHub-linked commit authors for this SKILL.md at the saved revision. Co-authors and history before file renames are not included.

File history ↗

docs/reference/color-matrix.mdx

docs/reference/color-matrix.mdxBrowse 89 files
View on GitHub
← Back to SKILL.md

title: FrameBuffer color matrices description: Apply exact 4x4 RGBA transforms to selected or uniform FrameBuffer cells and channels

FrameBuffer color matrices

This supported advanced API transforms stored foreground and background colors in an OptimizedBuffer. Use it when a FrameBuffer needs a cell-level color transform.

Buffer positions are terminal cells, not image pixels. Read Colors for normal color input and terminal palette behavior.

Methods

import { TargetChannel } from "@opentui/core"

frameBuffer.colorMatrix(
  matrix: Float32Array,
  cellMask: Float32Array,
  strength = 1,
  target = TargetChannel.Both,
)

frameBuffer.colorMatrixUniform(
  matrix: Float32Array,
  strength = 1,
  target = TargetChannel.Both,
)

Both methods mutate the buffer and return void. The matrix must contain exactly 16 floats. A different length throws RangeError before the native call.

colorMatrix() transforms only mask entries. colorMatrixUniform() transforms every buffer cell.

Matrix format

The matrix is row-major. Each row computes one output channel:

[m00, m01, m02, m03]  red output
[m10, m11, m12, m13]  green output
[m20, m21, m22, m23]  blue output
[m30, m31, m32, m33]  alpha output

For normalized input C = [r, g, b, a], OpenTUI calculates:

transformed = M * C
result = C + (transformed - C) * effectiveStrength

strength = 0 keeps the original value. strength = 1 uses the complete matrix result. Strength is not clamped, so a negative value or a value above one extrapolates.

Intermediate calculations can be below 0 or above 1. The stored buffer is RGBA8. Each final channel is clamped to 0..1, rounded to 0..255, and written to storage. The native source comments that say no clamping describe the float calculation, not the RGBA8 write.

Matrix coefficients are not checked for finite values. A non-finite calculated channel is stored as zero.

Target channels

EnumValueCells changed
TargetChannel.FG1Foreground only
TargetChannel.BG2Background only
TargetChannel.Both3Foreground and background

Use the enum values. Other runtime numbers are outside the supported TypeScript contract.

Cell mask

colorMatrix() reads packed triplets:

[x, y, perCellStrength, x, y, perCellStrength, ...]

The effective strength is methodStrength * perCellStrength.

Mask behavior is exact:

  • The TypeScript wrapper uses Math.floor(cellMask.length / 3). It ignores one or two trailing floats.
  • Negative, non-finite, or values above the native u32 coordinate range are skipped.
  • Positive fractional coordinates truncate toward zero.
  • Coordinates outside the buffer are skipped.
  • A non-finite or zero effective strength is skipped.
  • Duplicate coordinates apply the matrix more than once in mask order.

The mask ignores the active scissor stack. Limit coordinates in the mask when the transform must stay in a clipped region.

Uniform behavior

colorMatrixUniform() uses a four-cell SIMD path and a scalar remainder. strength === 0 returns in TypeScript. Non-finite strength returns in native code.

Uniform transforms ignore the active scissor and opacity stacks. They process width * height stored cells, including blank and continuation cells.

Cell color semantics

Each cell color stores RGBA8 values plus terminal color-intent metadata. The matrix reads the resolved RGBA channels. It then writes a new explicit RGB color. A transformed indexed or default color loses its palette or default intent.

The methods do not change characters, continuation tags, image placements, text attributes, or hyperlink IDs. They can change foreground and background alpha if the fourth matrix row does so.

The transform has no retained allocation or cleanup method. The supplied arrays are borrowed only for the synchronous call.

Exported matrices

@opentui/core exports these Float32Array values. Each keeps alpha unchanged.

ExportTransform
SEPIA_MATRIXSepia
PROTANOPIA_SIM_MATRIXProtanopia simulation
DEUTERANOPIA_SIM_MATRIXDeuteranopia simulation
TRITANOPIA_SIM_MATRIXTritanopia simulation
ACHROMATOPSIA_MATRIXLuminance grayscale simulation
PROTANOPIA_COMP_MATRIXProtanopia-oriented channel compensation
DEUTERANOPIA_COMP_MATRIXDeuteranopia-oriented channel compensation
TRITANOPIA_COMP_MATRIXTritanopia-oriented channel compensation
TECHNICOLOR_MATRIXIncreased and cross-reduced RGB channels
SOLARIZATION_MATRIXPartial channel inversion
SYNTHWAVE_MATRIXMagenta-biased channel mapping
GREENSCALE_MATRIXLuminance in the green channel only
GRAYSCALE_MATRIXLuminance copied to RGB
INVERT_MATRIX1 - channel through the alpha column

These constants encode calculations. Their names do not promise accessibility outcomes for every display or viewer.

Apply a uniform matrix

import { INVERT_MATRIX, TargetChannel } from "@opentui/core"

frameBuffer.colorMatrixUniform(INVERT_MATRIX, 1, TargetChannel.Both)

Apply a cell mask

import { SEPIA_MATRIX, TargetChannel } from "@opentui/core"

const cells = new Float32Array([5, 2, 1, 6, 2, 0.5, 7, 2, 0.25])

frameBuffer.colorMatrix(SEPIA_MATRIX, cells, 0.8, TargetChannel.FG)

The effective strengths in this example are 0.8, 0.4, and 0.2.

Next