Color matrix
FrameBuffer supports native 4x4 RGBA matrix transforms through two methods: colorMatrix(...) and
colorMatrixUniform(...).
Use colorMatrix(...) when you want to transform specific cells with per-cell strengths. Use
colorMatrixUniform(...) when you want to apply one transform to the entire buffer.
Both methods work on normalized RGBA values (0.0 to 1.0) and can target foreground, background, or both channels.
API
import { TargetChannel } from "@opentui/core"
frameBuffer.colorMatrix(
matrix: Float32Array,
cellMask: Float32Array,
strength = 1.0,
target = TargetChannel.Both,
)
frameBuffer.colorMatrixUniform(
matrix: Float32Array,
strength = 1.0,
target = TargetChannel.Both,
)
Matrix format
Matrix must be exactly 16 floats in row-major order.
Each row defines one output channel:
Row 0: [r->r, g->r, b->r, a->r] // output red
Row 1: [r->g, g->g, b->g, a->g] // output green
Row 2: [r->b, g->b, b->b, a->b] // output blue
Row 3: [r->a, g->a, b->a, a->a] // output alpha
Each cell is transformed in two stages:
newColor = M * color
output = original + (newColor - original) * strength
This means strength = 0.0 keeps original color, and strength = 1.0 applies full matrix result.
Target channels
Use the TargetChannel enum to choose which color buffers are affected:
TargetChannel.FG(1): foreground onlyTargetChannel.BG(2): background onlyTargetChannel.Both(3): foreground + background
colorMatrix cell mask format
cellMask uses packed triplets:
[x, y, perCellStrength, x, y, perCellStrength, ...]
xandyare cell coordinatesperCellStrengthis multiplied by methodstrength- incomplete trailing values (not a multiple of 3) are ignored
- out-of-bounds or non-finite coordinates are skipped
- non-finite effective strengths are skipped
This method is useful for effects that only affect part of the buffer, such as scanlines, vignettes, or localized color grading.
colorMatrixUniform behavior
colorMatrixUniform applies the same matrix to every pixel in the selected channel(s).
- optimized path processes 4 pixels at a time with SIMD
- scalar fallback handles any remaining pixels
strength === 0or non-finitestrengthreturns early
Use this method for full-frame color grading and global post-processing.
No clamping
Result values are not clamped to [0, 1]. Matrix coefficients and strengths can push channels above 1.0 or below
0.0.
Example: invert whole buffer
import { INVERT_MATRIX, TargetChannel } from "@opentui/core"
frameBuffer.colorMatrixUniform(INVERT_MATRIX, 1.0, TargetChannel.Both)
Example: apply sepia to selected cells
import { SEPIA_MATRIX, TargetChannel } from "@opentui/core"
// Affect only three cells at custom strengths
const cellMask = new Float32Array([
5,
2,
1.0, // full sepia at (5,2)
6,
2,
0.5, // half sepia at (6,2)
7,
2,
0.25, // subtle sepia at (7,2)
])
frameBuffer.colorMatrix(SEPIA_MATRIX, cellMask, 1.0, TargetChannel.FG)
Example: custom saturation matrix
import { TargetChannel } from "@opentui/core"
function createSaturationMatrix(saturation: number): Float32Array {
const rw = 0.299
const gw = 0.587
const bw = 0.114
const inv = 1 - saturation
return new Float32Array([
rw * inv + saturation,
gw * inv,
bw * inv,
0,
rw * inv,
gw * inv + saturation,
bw * inv,
0,
rw * inv,
gw * inv,
bw * inv + saturation,
0,
0,
0,
0,
1,
])
}
const saturation = createSaturationMatrix(1.25)
frameBuffer.colorMatrixUniform(saturation, 0.8, TargetChannel.Both)