mcut
@mcut/compositor

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) => void

A 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) => number

A 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 | OffscreenCanvasRenderingContext2D

A 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,
) => void

A 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.

On this page