Types
Types and Zod schemas exported by @mcut/compositor.
Types
DisplaySizePatch
interface DisplaySizePatch {
width?: number
height?: number
preserveAspect?: boolean
}The requested display width or height for getTransformForDisplaySize, with a flag to keep the aspect ratio.
ElementSize
interface ElementSize {
width: number
height: number
}A width and height in pixels.
Handle
interface Handle {
id: HandleId
x: number
y: number
}One handle with its id and canvas position.
HandleId
type HandleId =
| 'nw'
| 'n'
| 'ne'
| 'e'
| 'se'
| 's'
| 'sw'
| 'w'
| 'rotate'The eight compass-point resize handles plus the rotate handle.
OBB
interface OBB {
cx: number
cy: number
width: number
height: number
rotation: number
}An oriented bounding box in canvas pixels with center, size, and clockwise rotation in degrees.
SizeHelpers
interface SizeHelpers {
getAssetSize?: (assetId: string) => ElementSize | null
measureText?: (text: string, style: TextStyle, box?: TextBox, runs?: readonly TextRun[]) => ElementSize
}Optional callbacks that report an asset's pixel size and measure text, used to size elements.
SlotBox
interface SlotBox {
sourceKey: string
obb: OBB
}Where a multicam shows one slot, as the key of the slot's source and the oriented box of the part the renderer shows, in canvas pixels.
ImageQuad
interface ImageQuad {
image: CanvasImageSource
src: { sx: number; sy: number; sw: number; sh: number } | null
dw: number
dh: number
cornerRadius: number
}One image draw into a centered rectangle with an optional source crop and corner radius.
LayerChrome
interface LayerChrome {
centerX: number
centerY: number
rotationDeg: number
scaleX: number
scaleY: number
opacity: number
blendMode?: BlendMode | undefined
effects?: readonly Effect[] | undefined
}The resolved transform, opacity, blend mode, and effect stack an element layer composites through.
RenderBackend
interface RenderBackend {
readonly kind: 'canvas2d' | 'webgpu' | (string & {})
readonly width: number
readonly height: number
pixelGrid(): PixelGrid
beginFrame(backgroundColor: string): void
endFrame(): void
acquireRaster(): Canvas2D
drawImageQuad(quad: ImageQuad, chrome: LayerChrome): void
pushRasterScope(): void
popRasterScope(): void
}The interface a compositing backend implements, with its pixel grid, frame begin and end, raster access, image quad drawing, and raster scopes. pixelGrid answers for the moment it is called, so it carries a transform a transition has set on the raster.
PixelGrid
interface PixelGrid {
transform: { a: number; b: number; c: number; d: number; e: number; f: number }
width: number
height: number
}The pixels a backend's raster lands on, as the raster's current transform from project units to pixels and the raster's size in pixels. A multicam composes on this grid, so its slots land on the pixels a direct draw would hit.
WebGPUBackendOptions
interface WebGPUBackendOptions {
canvas: HTMLCanvasElement | OffscreenCanvas
width: number
height: number
device?: GPUDevice
}Options for WebGPUBackend.create, the target canvas, its size, and an optional existing GPU device.
ColorOp
interface ColorOp {
kind: number
params: number[]
}One fused color operation with its shader kind and packed parameters.
EffectPass
type EffectPass =
| {
kind: 'color'
ops: ColorOp[]
curves: { r: Float32Array; g: Float32Array; b: Float32Array } | null
}
| { kind: 'blur'; radius: number }
| { kind: 'shadow'; offsetX: number; offsetY: number; blur: number; color: [number, number, number, number] }
| { kind: 'lut3d'; lutId: string; intensity: number }A single GPU effect pass, either a fused color pass, a blur, a shadow, or a 3D lookup table.
EffectPlan
interface EffectPlan {
passes: EffectPass[]
unsupported: boolean
}The GPU passes for an effect stack and whether any effect was unsupported.
TransitionRenderContext
interface TransitionRenderContext {
ctx: Canvas2D
project: Project
pair: TransitionPair
timeMs: number
completion: number
drawLeft: () => void
drawRight: () => void
}What a transition renderer receives, the context, project, pair, time, completion, and callbacks that draw each side.
TransitionRenderer
type TransitionRenderer = (context: TransitionRenderContext) => voidA function that blends a transition pair into the context.
CaptionLayout
interface CaptionLayout {
lines: { words: CaptionWordBox[]; width: number }[]
font: string
lineHeight: number
spaceWidth: number
}Laid-out caption lines with their word boxes and widths, plus the font, line height, and space width.
CaptionWordBox
interface CaptionWordBox {
text: string
x: number
width: number
startMs?: number
endMs?: number
}One caption word's text, horizontal position, width, and optional timing.
MeasureFn
type MeasureFn = (text: string, font: string, letterSpacingPx?: number) => numberA function that returns the width of text drawn with a font and optional letter spacing.
TextBlockLayout
interface TextBlockLayout {
lines: { text: string; width: number; segments?: TextSegment[] }[]
font: string
lineHeight: number
padding: number
overflow: TextBox['overflow'] | null
width: number
height: number
}Laid-out text lines with widths and style segments, plus the font, line height, padding, overflow mode, and block size.
Canvas2D
type Canvas2D = CanvasRenderingContext2D | OffscreenCanvasRenderingContext2DA 2D rendering context, on screen or off screen.
ElementRenderContext
interface ElementRenderContext {
ctx: Canvas2D
backend: import('./backend').RenderBackend
project: Project
track: Track
timeMs: number
viewTimeMs: number
source: FrameSource | undefined
acquireScratch: (width: number, height: number) => Canvas2D
}What an element renderer receives, the 2D context, backend, project, track, time, frame source, and a scratch surface. viewTimeMs is the time zoom views read. acquireScratch returns an off screen 2D context that is reused across frames. A renderer composes into it and draws it straight away, because the next renderer that asks gets the same surface. acquireScratch throws ScratchContextError where OffscreenCanvas is missing and no createScratchContext is given, and when createScratchContext returns null.
ElementRenderer
type ElementRenderer<E extends TimelineElement = TimelineElement> = (
element: E,
context: ElementRenderContext,
) => voidA function that draws one element into the render context.
FrameSource
interface FrameSource {
getFrame(assetId: AssetId, sourceTimeMs: number): CanvasImageSource | null
}Supplies the pixels of a media asset at a source time, approximately for preview and exactly for export.
RenderFrameOptions
interface RenderFrameOptions {
source?: FrameSource
backgroundColor?: string
skipElementIds?: ReadonlySet<string>
motionBlurSamples?: number
renderScale?: number
createScratchContext?: (width: number, height: number) => Canvas2D | null
}Options for rendering a frame, the frame source, background color, elements to skip, motion blur samples, the motion blur render scale, and a scratch context factory. renderScale renders motion blur samples at that fraction of the project resolution, for a preview drawn below full size. It defaults to 1. The renderer calls createScratchContext each time it needs a scratch surface, for a motion blur pass or a multicam composite. Without it the renderer keeps one OffscreenCanvas per purpose and reuses it across frames. No scratch surface is available where OffscreenCanvas is missing and no createScratchContext is given, or when createScratchContext returns null. Then motion blur is skipped, and a multicam throws ScratchContextError.