mcut
@mcut/timeline

Engine, commands, and selectors

The editor engine, the command table, and read-only project selectors.

Types

BuiltinCommand

type BuiltinCommand = {
  [K in CommandType]: { type: K } & z.input<CommandDefinitions[K]['payloadSchema']>
}[CommandType]

The closed union of every command the engine accepts, one arm per entry of the command table, each a type plus the input shape of that command's payload schema.

CommandOfType

type CommandOfType<K extends CommandType> = Extract<BuiltinCommand, { type: K }>

The one arm of BuiltinCommand whose type is K.

CommandType

type CommandType = keyof CommandDefinitions

The union of command type names, the keys of the command table.

CommandDefinition

interface CommandDefinition {
  type: CommandType
  description: string
  payloadSchema: z.ZodObject
}

A command's type, description, and Zod payload schema, as listed by listCommands.

ToolDefinition

interface ToolDefinition {
  name: CommandType
  description: string
  inputSchema: z.core.JSONSchema.BaseSchema
}

An MCP tool entry with a command name, description, and JSON Schema input, as produced by listToolDefinitions.

DispatchOptions

interface DispatchOptions {
  history?: boolean
  selection?: ElementId[]
}

Per-dispatch options, whether to record undo history and the selection the edit produces.

EditorEngineOptions

interface EditorEngineOptions {
  project?: Project
  maxHistorySize?: number
}

Options for a new engine, an initial project and the number of undo entries to keep.

EditorState

interface EditorState {
  project: Project
  selection: SelectionState
  canUndo: boolean
  canRedo: boolean
}

The engine store state, the project, selection, and undo and redo availability.

PlaybackState

interface PlaybackState {
  currentTimeMs: number
  isPlaying: boolean
  playbackRate: number
  volume: number
  muted: boolean
}

The playback store state, current time, playing flag, rate, volume, and mute.

SelectionState

interface SelectionState {
  elementIds: ElementId[]
}

The selected element ids.

TransactionOptions

interface TransactionOptions {
  selection?: ElementId[]
}

Options for transact, the selection the whole gesture produces.

ActiveElement

interface ActiveElement {
  track: Track
  trackIndex: number
  element: TimelineElement
}

An element under the playhead with its track and track index.

ElementLocation

interface ElementLocation {
  track: Track
  trackIndex: number
  element: TimelineElement
  elementIndex: number
}

An element with its track, track index, and index within the track.

Functions

applyCommand

function applyCommand(project: Project, command: unknown): Project

Looks the command up in the table by its type, validates its payload, and returns the new project it produces, throwing CommandError on rejection.

listCommands

function listCommands(): CommandDefinition[]

Returns every command definition in table order.

listToolDefinitions

function listToolDefinitions(): ToolDefinition[]

Returns every command as an MCP-shaped tool definition with its payload schema converted to JSON Schema.

parseCommand

function parseCommand(value: unknown): BuiltinCommand

Narrows an unknown value to a BuiltinCommand by checking its type against the table and parsing the payload, throwing CommandError with code invalid-payload or unknown-command otherwise.

assertNever

function assertNever(value: never): never

Throws for a value the type checker has already excluded, closing the default arm of a switch over a closed union.

canPlace

function canPlace(
  track: Track,
  startMs: number,
  durationMs: number,
  ignoreElementId?: ElementId,
): boolean

Returns true when a clip at startMs with durationMs fits on the track without overlapping any element other than the ignored one.

findNearestFreeSlot

function findNearestFreeSlot(
  track: Track,
  desiredStartMs: number,
  durationMs: number,
  ignoreElementId?: ElementId,
): number

Returns the start time nearest to desiredStartMs where a clip of durationMs fits on the track without overlap.

getActiveElements

function getActiveElements(project: Project, timeMs: number): ActiveElement[]

Returns the elements under timeMs on every track in paint order, bottom track first, including hidden and muted tracks.

getElement

function getElement(project: Project, elementId: ElementId): TimelineElement | undefined

Returns the element with the given id from any track, or undefined.

getElementLocation

function getElementLocation(
  project: Project,
  elementId: ElementId,
): ElementLocation | undefined

Returns the element together with its track, track index, and index within the track, or undefined.

getGroupedElementIds

function getGroupedElementIds(project: Project, elementId: ElementId): ElementId[]

Returns the element id followed by every element sharing its groupId, or only the id when ungrouped.

getLinkedElementIds

function getLinkedElementIds(project: Project, elementId: ElementId): ElementId[]

Returns the element id followed by every element sharing its linkId, or only the id when unlinked.

getProjectDurationMs

function getProjectDurationMs(project: Project): number

Returns the end time of the last element across all tracks, or 0 for an empty project.

getTrack

function getTrack(project: Project, trackId: TrackId): Track | undefined

Returns the track with the given id, or undefined.

isElementActiveAt

function isElementActiveAt(element: TimelineElement, timeMs: number): boolean

Returns true when timeMs falls inside the element's half-open time range.

rangesOverlap

function rangesOverlap(
  aStartMs: number,
  aDurationMs: number,
  bStartMs: number,
  bDurationMs: number,
): boolean

Returns true when two half-open time ranges overlap.

Classes

CommandError

class CommandError extends Error {
  readonly code: string
  constructor(code: string, message: string, options?: { cause?: unknown })
}

Error thrown when a command is rejected for an unknown id, an invalid payload, or a violated invariant, with a machine-readable code.

EditorEngine

class EditorEngine {
  readonly store: Store<EditorState>
  readonly playback: Store<PlaybackState>
  constructor(options: EditorEngineOptions = {})
  get project(): Project
  get selection(): SelectionState
  dispatch(command: BuiltinCommand, options: DispatchOptions = {}): Project
  transact(fn: () => void, options: TransactionOptions = {}): void
  beginTransaction(): void
  endTransaction(): void
  cancelTransaction(): void
  canUndo(): boolean
  canRedo(): boolean
  undo(): boolean
  redo(): boolean
  select(elementIds: ElementId[]): void
  clearSelection(): void
  loadProject(project: Project): void
  toJSON(): Project
  static fromJSON(data: unknown, options: Omit<EditorEngineOptions, 'project'> = {}): EditorEngine
  seek(timeMs: number): void
  play(): void
  pause(): void
  setVolume(volume: number): void
  setMuted(muted: boolean): void
  setPlaybackRate(playbackRate: number): void
}

The headless editor that applies validated commands to a project with undo history and transactions, holds the selection, and keeps a playback store for transport state.

Transactions nest. endTransaction closes the innermost open transaction, and closing the outermost one records everything inside as one undo step. cancelTransaction restores the project and selection the innermost transaction began with and leaves any outer transaction open.

transact(fn) records every dispatch inside fn as one undo step. If fn throws, the project and selection return to where that transact began, no undo step is recorded, and the error propagates. A nested transact that throws rolls back only its own dispatches.

On this page