Pure TypeScript image-processing primitives. No DOM dependencies — safe in browsers and Node.js.
Exports: 39 functions, 22 types
PixelBuffer
The fundamental image currency. Every function reads or writes a PixelBuffer.
type PixelBuffer = {
width: number;
height: number;
data: Uint8ClampedArray;
};Related types
type RgbaColor = [number, number, number, number];
// RGBA color tuple. Components are 0–255. Alpha is typically 255 for opaque colors.
type SupportedInputFormat = "image/jpeg" | "image/png" | "image/webp";
type CropConfig = {
aspectRatio: "original" | "free" | "1:1" | "4:5" | "9:16" | "16:9";
zoom: number;
offsetX: number;
offsetY: number;
};
type OutputOptions = {
format: "png" | "jpeg" | "webp";
width: number;
height: number;
backgroundColor?: string;
quality?: number;
};Buffer Utilities
function createPixelBuffer(width: number, height: number, fill?: RgbaColor): PixelBufferCreate a new zero-initialized PixelBuffer. Optionally fill with a color.
function clonePixelBuffer(buffer: PixelBuffer): PixelBufferDeep-copy a PixelBuffer (new data array, same dimensions).
function fillPixelBuffer(buffer: PixelBuffer, color: RgbaColor): voidFill an existing buffer with a solid color in-place.
function pixelIndex(buffer: PixelBuffer, x: number, y: number): numberGet the data array index for pixel (x, y).
function clampByte(value: number): numberClamp a number to 0–255, rounding. Returns 0 for NaN/Infinity.
Color Transforms
All color functions modify the buffer in-place unless noted.
function toGrayscale(buffer: PixelBuffer): voidConvert to grayscale using luminance weights (0.299 R, 0.587 G, 0.114 B).
function adjustBrightnessContrast(buffer: PixelBuffer, brightness: number, contrast: number): voidAdjust brightness (-255 to 255) and contrast (-1 to 1).
function adjustSaturation(buffer: PixelBuffer, saturation: number): voidAdjust saturation (-1 to 1).
function applyDuotone(buffer: PixelBuffer, shadow: RgbaColor, highlight: RgbaColor): voidMap luminance to a gradient between two colors.
function applyPosterize(buffer: PixelBuffer, levels: number): voidReduce per-channel levels (2–256).
function reducePalette(buffer: PixelBuffer, colorCount: number): voidUniform per-channel quantization. colorCount 2–256. Actual output colors ≈ round(cbrt(colorCount))³.
function applyTint(buffer: PixelBuffer, tint: RgbaColor, amount: number): voidBlend each pixel toward a tint color. amount ranges 0–1.
function averageColor(buffer: PixelBuffer): RgbaColorCompute the average RGBA color of a buffer.
Viewport Transform
function applyViewportTransform(
source: PixelBuffer,
viewport: CropConfig,
outputWidth: number,
outputHeight: number
): PixelBufferApply a non-destructive crop/zoom/offset to a source buffer. Returns a new buffer with bilinear interpolation.
function getCroppedOutputSize(
sourceWidth: number,
sourceHeight: number,
aspectRatio: CropConfig["aspectRatio"],
longestEdge: number,
zoom?: number
): { width: number; height: number }Compute output dimensions for a given aspect ratio and longest-edge constraint.
function parseAspectRatio(ratio: CropConfig["aspectRatio"]): number | nullParse a CropConfig aspect ratio to a numeric W/H value. Returns null for "original".
Dithering
function applyOrderedDither(buffer: PixelBuffer, threshold?: number): voidApply 8×8 Bayer ordered dither in-place. Default threshold: 128.
function applyFloydSteinbergDither(buffer: PixelBuffer, threshold?: number): voidApply Floyd-Steinberg error diffusion dither in-place. Default threshold: 128.
function applyFloydSteinbergColorDither(
buffer: PixelBuffer,
threshold?: number,
channels?: readonly number[]
): voidApply Floyd-Steinberg error diffusion on per-channel basis. Default channels: [0, 1, 2]. Default threshold: 128.
type OrderedColorDitherOptions = {
cellSize: number;
threshold: number;
invert: boolean;
monochrome: boolean;
coloredInactive?: boolean;
};
function applyOrderedColorDither(
source: PixelBuffer,
options: OrderedColorDitherOptions
): PixelBufferCell-based ordered color dither with Bayer luminance offsets. Returns a new buffer.
Halftone
type HalftoneShape = "circle" | "square" | "diamond";
type HalftoneColorMode = "monochrome" | "source" | "palette";
type HalftoneOptions = {
dotSpacing: number;
maxDotSize: number;
inkColor: RgbaColor;
backgroundColor: RgbaColor;
angle?: number;
shape?: HalftoneShape;
colorMode?: HalftoneColorMode;
palette?: RgbaColor[];
saturationBoost?: number;
};
function renderHalftoneData(source: PixelBuffer, options: HalftoneOptions): PixelBufferRender a colored dot halftone with configurable dot spacing, size, shape, palette, and color mode.
ASCII Rendering
type AsciiColorMode = "monochrome" | "color" | "source";
type AsciiBackgroundMode = "solid" | "source" | "transparent";
type AsciiOptions = {
fontSize: number;
inkColor: RgbaColor;
backgroundColor: RgbaColor;
charset?: string;
colorMode?: AsciiColorMode;
backgroundMode?: AsciiBackgroundMode;
spacing?: number;
palette?: RgbaColor[];
invertLuminance?: boolean;
antialias?: boolean;
densityMap?: PixelBuffer;
minGlyphLuminance?: number;
};
function renderAscii(source: PixelBuffer, options: AsciiOptions): PixelBufferRender an image as ASCII art with configurable charset, font size, color mode, ink color, and background.
const ASCII_CHARSET_PRESETS: Record<string, string>Built-in character set presets: dense, standard, technical, blocks, minimal, bloom.
function normalizeCustomCharset(input: string, fallback?: string): stringValidate and normalize a custom character set for ASCII rendering.
ASCII sub-effects
type SymbolGlowOptions = {
cellSize: number;
blur: number;
brightness: number;
charset: string;
colorBoost?: number;
colorMode?: "colored" | "monochrome";
};
function renderSymbolGlow(source: PixelBuffer, options: SymbolGlowOptions): PixelBuffer
type LuminousAsciiBloomOptions = {
fontSize: number;
density: number;
bloomRadius: number;
glowAmount: number;
baseOpacity?: number;
minGlyphLuminance?: number;
customCharset?: string;
};
function renderLuminousAsciiBloom(
source: PixelBuffer,
options: LuminousAsciiBloomOptions
): PixelBuffer
type AsciiWeightMapOptions = {
highlightThreshold: number;
shadowThreshold: number;
edgeStrength: number;
shadowStrength: number;
};
function computeAsciiWeightMap(source: PixelBuffer, options: AsciiWeightMapOptions): PixelBuffer
function computeLuminanceBuffer(source: PixelBuffer): PixelBuffer
function computeGradientMagnitudeBuffer(source: PixelBuffer): PixelBuffer
function computeHighlightMask(source: PixelBuffer, threshold: number, falloff: number, edgeStrength?: number): PixelBufferDefault edgeStrength: 0.5.
Glow & Bloom
type GlowOptions = {
radius: number;
amount: number;
mode?: "screen" | "add" | "soft";
color?: RgbaColor;
};
function applyGlow(buffer: PixelBuffer, options: GlowOptions): void
type BloomOptions = {
radius: number;
threshold: number;
amount: number;
color?: RgbaColor;
};
function applyBloom(buffer: PixelBuffer, options: BloomOptions): void
type HeadroomBloomOptions = {
amount: number;
};
function applyHeadroomBloom(
base: PixelBuffer,
bloom: PixelBuffer,
options: HeadroomBloomOptions
): PixelBufferAdditive screen composite that preserves headroom — only lifts channels below 255.
type HighlightMaskOptions = {
threshold?: number;
knee?: number;
intensity?: number;
floor?: number;
};
function extractHighlightMask(source: PixelBuffer, options?: HighlightMaskOptions): PixelBufferExtract a luminance-keyed highlight mask with configurable threshold and knee width.
function applyBoxBlur(buffer: PixelBuffer, radius: number): voidApply a box blur in-place.
function invertColor(r: number, g: number, b: number): [number, number, number]
function applyBlueCyanGrade(r: number, g: number, b: number, intensity: number): [number, number, number]Utility color functions for glow effects.
Halftone (Print Effects)
function renderHalftoneData(source: PixelBuffer, options: HalftoneOptions): PixelBuffer(See Halftone section above for options type.)
Stipple
type StippleOptions = {
dotSize: number;
spacing: number;
density: number;
inkColor: RgbaColor;
backgroundColor: RgbaColor;
seed?: number;
};
function renderStipple(source: PixelBuffer, options: StippleOptions): PixelBufferRender a hand-drawn stipple illustration using dot density to model tone.
Distortion & Glass
function applyCubicGlass(
source: PixelBuffer,
tileSize: number,
distortion?: number,
frost?: number
): PixelBufferApply a faceted glass distortion effect with refraction-like offsets. Defaults: distortion=0, frost=0.6.
type CrtGlitchOptions = {
sliceHeight: number;
shiftAmount: number;
rgbShift: number;
scanlineStrength: number;
noiseAmount: number;
seed?: number;
};
function applyCrtGlitch(source: PixelBuffer, options: CrtGlitchOptions): PixelBuffer
type WaveSliceDirection = "horizontal" | "vertical";
type WaveSliceOptions = {
amplitude: number;
frequency: number;
direction?: WaveSliceDirection;
};
function applyWaveSlice(source: PixelBuffer, options: WaveSliceOptions): PixelBufferApply a sinusoidal wave distortion effect.
Bitmap Pixelation
type BitmapOptions = {
cellSize: number;
colorLevels: number;
ditherThreshold?: number;
};
function applyBitmap(source: PixelBuffer, options: BitmapOptions): PixelBufferHeavy pixelation with palette reduction and optional ordered dither.
LED Matrix
type LedShape = "circle" | "square";
type LedMatrixOptions = {
cellSize: number;
shape?: LedShape;
colorMode?: "source" | "white" | "tint";
tint?: RgbaColor;
glowAmount?: number;
backgroundColor?: RgbaColor;
};
function applyLedMatrix(source: PixelBuffer, options: LedMatrixOptions): PixelBufferGrain & Noise
function createSeededRandom(seed: number): () => number
function applyNoise(buffer: PixelBuffer, amount: number, seed?: number): voidDefault seed: 42.
function applyGrain(buffer: PixelBuffer, amount: number, seed?: number): voidApply film grain noise in-place. amount 0–1. Default seed: 42.
Vignette
function applyVignette(buffer: PixelBuffer, strength: number): voidApply a radial vignette darkening in-place. strength 0–1.
Scanlines & RGB Shift
function applyScanlines(buffer: PixelBuffer, strength: number, lineHeight?: number): voidApply CRT scanline overlay in-place. Default lineHeight: 4.
function applyRgbShift(buffer: PixelBuffer, shiftX: number): voidApply horizontal RGB channel separation.
Edge Detection
function applyEdgeDetect(buffer: PixelBuffer, strength: number): voidApply edge detection in-place. strength 0–1.
function renderEdgeBuffer(buffer: PixelBuffer): PixelBufferReturn a new buffer containing edge detection output.
Blend
type BlendMode = "normal" | "multiply" | "screen" | "overlay" | "soft" | "lighten";
function blendPixelBuffers(
bottom: PixelBuffer,
top: PixelBuffer,
mode?: BlendMode,
amount?: number
): PixelBufferBlend two buffers with the given mode and opacity. Default mode: "normal", default amount: 1.
Grid Overlay
type GridOverlayStyle = "darken" | "lighten" | "color";
type GridOverlayOptions = {
cellSize: number;
opacity: number;
style?: GridOverlayStyle;
color?: RgbaColor;
lineWidth?: number;
};
function applyGridOverlay(buffer: PixelBuffer, options: GridOverlayOptions): voidPencil Grain
type PencilGrainOptions = {
paperColor: RgbaColor;
edgeStrength: number;
grainAmount: number;
};
function applyPencilGrain(source: PixelBuffer, options: PencilGrainOptions): PixelBufferRender a graphite pencil sketch effect.
Inverted Glow
type InvertedGlowOptions = {
intensity: number;
};
function applyInvertedGlow(source: PixelBuffer, options: InvertedGlowOptions): PixelBufferHighlights / Split Tone
type SplitToneOptions = {
shadowColor: RgbaColor;
highlightColor: RgbaColor;
shadowAmount?: number;
highlightAmount?: number;
shadowAnchor?: number;
highlightAnchor?: number;
};
function applySplitTone(source: PixelBuffer, options: SplitToneOptions): PixelBufferManga Scanlines
type MangaScreenOptions = {
lineSpacing: number;
lineWidth: number;
angle?: number;
threshold?: number;
inkColor?: RgbaColor;
paperColor?: RgbaColor;
};
function applyMangaScreen(source: PixelBuffer, options: MangaScreenOptions): PixelBufferManga/comic-style screen tone pattern overlay.
Resize
function resizeNearestNeighbor(
source: PixelBuffer,
targetWidth: number,
targetHeight: number
): PixelBuffer
function resizeBilinear(
source: PixelBuffer,
targetWidth: number,
targetHeight: number
): PixelBufferResolve Glyph Bitmap
function resolveGlyphBitmap(char: string): number[]Resolve a character to a bitmap glyph representation for ASCII rendering.
See Also
- Presets API Reference —
EffectPreset,intensityMapper,createPipeline - Worker API Reference —
EffectsWorkerClientfor off-thread rendering - Concepts: Architecture — render flow overview