Miraiclip SDK
API reference

@miraiclip/core

Headless, command-driven engine for building video editors — state, commands, history, patches, events.

npm install @miraiclip/core
Version0.5.8
Runs inBrowser, worker, Node, edge
Exports161
GuidesProject & time, Commands, History & transactions

Functions

animationCommands

The commands that give clip exactly recipe: clear its visual keyframes (volume automation stays), then set the recipe's. Dispatch them in one transaction for a single undo step. An empty recipe removes the animation.

function animationCommands(clip: Clip, recipe: AnimationRecipe): BuiltinCommand[]

Guides: Keyframes & animation

applyCommands

Apply a batch of commands as ONE transaction: all-or-nothing (a failure rolls back every command already applied — the engine's transaction rollback), one undo step on success, and the failing index reported so an agent can fix exactly the command that broke.

function applyCommands(project: Project, commands: readonly Command[], options?: {
    label?: string;
}): ApplyCommandsResult

Guides: MCP server, Tools from the command catalog, Collaboration, History & transactions

applyJsonPatches

Apply RFC-6902 add/replace/remove operations (the subset this engine emits) to a plain JSON document, returning a new document. The input is not mutated. Use this to replay a peer's patches events onto a local copy of the document for sync/collaboration.

function applyJsonPatches<T>(doc: T, ops: readonly JsonPatchOp[]): T

Guides: Collaboration, Events & patches

captionClipsFromAsrWords

ASR word timestamps → caption clips with TRUE word timing (karaoke). Words group into clips on silence gaps and a max-words cap.

function captionClipsFromAsrWords(words: readonly AsrWord[], options: CaptionImportOptions & AsrGroupingOptions): BuiltinCommand[]

Guides: Captions

captionClipsFromSubtitles

SRT/VTT → one caption clip per cue (words evenly split across the cue). Dispatch the result in one transaction.

function captionClipsFromSubtitles(text: string, options: CaptionImportOptions): BuiltinCommand[]

Guides: Captions

captionsToSrt

Caption clips → SubRip (.srt), one cue per clip, in timeline order.

function captionsToSrt(clips: readonly CaptionCueSource[]): string

Guides: Captions

captionsToText

Caption clips → plain transcript text, one line per clip.

function captionsToText(clips: readonly CaptionCueSource[]): string

Guides: Captions

captionsToVtt

Caption clips → WebVTT (.vtt), one cue per clip, in timeline order.

function captionsToVtt(clips: readonly CaptionCueSource[]): string

Guides: Captions

clipHeadroomUs

Source footage past a clip's end ("out") or before its start ("in"). Generated clips are unlimited.

function clipHeadroomUs(doc: ProjectDocument, clip: Clip, side: "in" | "out"): number

Guides: Timeline, Clips, Transitions

clipKindRegistration

function clipKindRegistration(kind: string): ClipKindRegistration | undefined

Guides: Custom clip kinds

commandCatalog

The machine-readable command catalog: one JSON Schema per command type. Suitable for handing to an LLM as tool definitions.

function commandCatalog(extra?: Record<string, z.ZodType>): Record<string, unknown>

Guides: Editing assistant, Tools from the command catalog, Properties panel, Commands

commandTypeForTool

Reverse of toolNameForCommand, resolved against the known types.

function commandTypeForTool(toolName: string, commandTypes: Iterable<string>): string | undefined

Guides: Tools from the command catalog

createProject

function createProject(init: ProjectSettings | ProjectDocument, options?: CreateProjectOptions): Project

Guides: Editing assistant, Asset import, Collaboration, Commands

creditsFor

Credit lines for the assets the project uses whose license asks for attribution (or that carry an attribution anyway), de-duplicated, in a stable order — ready for an end card, a description box, or a sidecar file.

function creditsFor(doc: ProjectDocument): string[]

Guides: Assets, Audio, Personalized video

cubicBezierProgress

CSS-convention cubic bézier: control points map input progress x∈[0,1] to eased progress y. Solve x(t)=progress for t (Newton with bisection fallback), then evaluate y(t).

function cubicBezierProgress(x1: number, y1: number, x2: number, y2: number, progress: number): number

defaultEffectParams

A kind's default params — what effect/add fills in when params are omitted.

function defaultEffectParams(kind: string): Record<string, number | string> | undefined

Guides: Effects

describeAnimation

Plain-language summary of a recipe ("Fade in · Pulse · Slide down out").

function describeAnimation(r: AnimationRecipe): string

Guides: Keyframes & animation

describeProject

A compact, deterministic summary of the document, written for LLM prompts: everything an agent needs to place commands (ids, kinds, time ranges in the same microsecond unit commands take), nothing it doesn't.

function describeProject(doc: ProjectDocument, options?: DescribeProjectOptions): string

Guides: Editing assistant, MCP server, Tools from the command catalog, Roadmap

effectParamsSchema

function effectParamsSchema(kind: string): z.ZodType | undefined

Guides: Custom effects

evaluateClipAt

Convenience allocating variant of evaluateClipInto.

function evaluateClipAt(clip: Clip, clipTimeUs: Us): EvaluatedClip

Guides: Properties panel, Keyframes & animation

evaluateClipInto

Evaluate a clip's animated properties at a clip-relative time into out (alloc-free — call per tick with a reused object). Static clip values are the fallback for properties without keyframes.

function evaluateClipInto(clip: Clip, clipTimeUs: Us, out: EvaluatedClip): EvaluatedClip

Guides: Keyframes & animation

evaluateKeyframes

Evaluate one property's keyframe list at a clip-relative time. Keyframes must be in stored order (the keyframe/set command maintains it). Pass clipDurationUs when the list may hold end-anchored keyframes. Before the first keyframe the first value holds; after the last, the last value holds; between, the LEFT keyframe's easing shapes the segment.

function evaluateKeyframes(keyframes: readonly Keyframe[], timeUs: Us, fallback: number, clipDurationUs?: Us): number

Guides: Keyframes & animation

findCuts

Every cut on the project's video tracks, top track first, in time order.

function findCuts(doc: ProjectDocument, options?: {
    minTransitionUs?: Us;
}): Cut[]

Guides: Timeline, Transitions, Custom clip kinds, Headless editor logic

fitAnimation

In/Out lengths that fit the clip (they share it, leaving a sliver between).

function fitAnimation(recipe: AnimationRecipe, clipUs: Us): AnimationRecipe

Guides: Keyframes & animation

formatFrameRate

Display form: "30", "29.97", "23.976".

function formatFrameRate(rate: FrameRateLike): string

frameCount

Frames needed to cover durationUs (the frames that start before it ends).

function frameCount(durationUs: Us, rate: FrameRateLike): number

Guides: Project & time

frameDurationUs

Duration of one frame in µs (fractional at NTSC rates — use frameToUs for positions).

function frameDurationUs(rate: FrameRateLike): number

Guides: Selection & canvas editing, Timeline, Project & time

frameToUs

Timeline position where the given frame starts: the first whole µs inside it.

function frameToUs(frame: number, rate: FrameRateLike): Us

Guides: Selection & canvas editing, Timeline, Project & time

fromJsonPointer

function fromJsonPointer(pointer: string): string[]

getEffectInfo

Editor/UI metadata for a built-in effect kind (undefined for custom kinds).

function getEffectInfo(kind: string): EffectInfo | undefined

Guides: Properties panel, Effects, Custom effects

isBuiltinClipKind

function isBuiltinClipKind(kind: string): boolean

keyframeTimeUs

A keyframe's time from the clip's visible start, given the clip's duration.

function keyframeTimeUs(keyframe: Keyframe, clipDurationUs: Us): Us

licenseReport

License check for the assets the project uses. commercial: true reports non-commercial assets; assets without license info are reported only when they came from a provider (plain uploads are the user's own business).

function licenseReport(doc: ProjectDocument, options?: {
    commercial?: boolean;
}): LicenseIssue[]

Guides: Assets, Audio, Personalized video

parseSubtitles

Parse SubRip (.srt) or WebVTT (.vtt) text into cues. Tolerant subset: numeric counters, WEBVTT headers, NOTE/STYLE blocks, and cue settings are ignored; HTML-ish tags inside cue text are stripped.

function parseSubtitles(text: string): CaptionCue[]

Guides: Captions

planAnimation

Every keyframe a recipe produces on a clip, plus the properties it owns.

function planAnimation(recipe: AnimationRecipe, base: Base, clipUs: Us): {
    keyframes: PlannedKeyframe[];
    props: Set<Prop>;
}

projectFrameRate

The project's exact frame rate: settings.frameRate when set, else read from settings.fps.

function projectFrameRate(settings: Pick<ProjectSettings, "fps" | "frameRate">): FrameRate

Guides: Selection & canvas editing, Timeline, Project & time

readAnimation

Recognize the recipe that produced a clip's keyframes. Each In / Out candidate (preset × easing, its length read off the keyframes) must reproduce a subset of them on its own; the surviving combinations, with each loop, are checked against the whole set. A clip moved on the canvas after animating still reads, because bases come from the keyframes.

function readAnimation(clip: Clip): ReadAnimation

Guides: Keyframes & animation

registerClipKind

function registerClipKind(kind: string, registration: ClipKindRegistration): void

Guides: Custom clip kinds

registerEffectKind

Register a custom effect kind's param schema (renderer registers its filter separately).

function registerEffectKind(kind: string, paramsSchema: z.ZodType): void

Guides: Custom effects

registerTransitionKind

function registerTransitionKind(kind: string, paramsSchema: z.ZodType): void

Guides: Custom transitions

resolveEasing

Accepts a preset name or an explicit easing; returns the stored form.

function resolveEasing(input: EasingPreset | Easing | undefined): Easing

Guides: Keyframes & animation

resolveKeyframes

Keyframes with every time measured from the clip's visible start, sorted. End-anchored keyframes are placed using clipDurationUs; when a clip is shorter than its In + Out animations the two interleave by time (ties keep the start-anchored one first). Returns the input array itself when nothing is end-anchored.

function resolveKeyframes(keyframes: readonly Keyframe[], clipDurationUs: Us): readonly Keyframe[]

Guides: Keyframes & animation

retimeWords

New text for a caption clip, re-timed: when the word count is unchanged each word keeps its original timing (a typo fix keeps karaoke sync); otherwise the words split the clip's span evenly. Returns clip-relative words for clip/set-property { words }; empty text returns [].

function retimeWords(previous: readonly CaptionWord[], text: string, durationUs: Us): CaptionWord[]

Guides: Captions

secondsToUs

function secondsToUs(seconds: number): Us

Guides: Project & time

snapToFrame

Snap a position to the nearest frame start (halfway rounds to the later frame).

function snapToFrame(us: Us, rate: FrameRateLike): Us

Guides: Timeline, Project & time, Headless editor logic

toFrameRate

The exact rate for a number or ratio. NTSC rates written as decimals (23.976, 23.98, 29.97, 59.94, 119.88…) become base·1000/1001; whole numbers become n/1; other decimals are read to 1/1000 (12.5 → 25/2). Ratios are reduced. Throws a RangeError for non-positive or non-finite input.

function toFrameRate(rate: FrameRateLike): FrameRate

toJsonPatches

Convert Immer patches to RFC-6902 JSON Patch operations.

function toJsonPatches(patches: readonly Patch[]): JsonPatchOp[]

toJsonPointer

function toJsonPointer(path: readonly (string | number)[]): string

toolNameForCommand

"clip/add" → "clip_add" — the sanitized name used in tool definitions.

function toolNameForCommand(type: string): string

Guides: Tools from the command catalog

toToolDefinitions

The command catalog as ready-to-send LLM tool definitions. Pass the result of project.commandCatalog() so registered custom commands are included.

function toToolDefinitions(catalog: Record<string, unknown>, options?: ToToolDefinitionsOptions): unknown[]

Guides: Tools from the command catalog, Roadmap

transitionParamsSchema

function transitionParamsSchema(kind: string): z.ZodType | undefined

Guides: Custom transitions

tryDispatch

Dispatch one command, returning a structured result instead of throwing on command failures. Non-command errors (bugs) still throw.

function tryDispatch(project: Project, command: Command): CommandResult

Guides: MCP server, Tools from the command catalog, Properties panel, Commands

usedAssets

Assets referenced by at least one clip (fonts count when a clip names their family).

function usedAssets(doc: ProjectDocument): Asset[]

Guides: Assets

usToFrame

Index of the frame containing the given timeline position.

function usToFrame(us: Us, rate: FrameRateLike): number

Guides: Selection & canvas editing, Timeline, Project & time

usToSeconds

function usToSeconds(us: Us): number

Guides: Project & time

usToTimecode

Format µs as "HH:MM:SS:FF" timecode. Frames count from the exact rate, with the nominal rate (30 for 29.97) as frames per second — non-drop-frame, which runs about 3.6 s per hour behind the clock at 29.97. Pass { dropFrame: true } for "HH:MM:SS;FF" drop-frame timecode at 29.97 / 59.94.

function usToTimecode(us: Us, rate: FrameRateLike, options?: TimecodeOptions): string

Guides: Timeline, Project & time

wordsFromCue

Fallback word timing: split a cue's span evenly across its words.

function wordsFromCue(cue: CaptionCue): CaptionWord[]

Classes

CommandRejectedError

The command was well-formed but cannot be applied to the current state (unknown entity, track/clip kind mismatch, …). State was not touched.

Extends Error.

new CommandRejectedError(commandType: string, code: string, message: string)
MemberTypeDescription
commandTypestring
codestring

Guides: Properties panel, Timeline, Commands, Tracks

CommandValidationError

The command's payload failed schema validation. State was not touched.

Extends Error.

new CommandValidationError(commandType: string, error: ZodError)
MemberTypeDescription
commandTypestring
issuesZodError["issues"]

Guides: Timeline, Commands

Emitter

MemberTypeDescription
on(event: K, listener: Listener<Events[K]>) => () => void
off(event: K, listener: Listener<Events[K]>) => void
emit(event: K, payload: Events[K]) => void

UnknownCommandError

Dispatched a command type that is not registered.

Extends Error.

new UnknownCommandError(commandType: string)
MemberTypeDescription
commandTypestring

Guides: Commands

Constants

ANIMATION_DEFAULT_SLOT_US

const ANIMATION_DEFAULT_SLOT_US: 600000

ANIMATION_EASINGS

const ANIMATION_EASINGS: {
    id: AnimationEasing;
    label: string;
}[]

Guides: Keyframes & animation

ANIMATION_MAX_SLOT_US

const ANIMATION_MAX_SLOT_US: 3000000

ANIMATION_MIN_SLOT_US

const ANIMATION_MIN_SLOT_US: 200000

ANIMATION_PRESETS

const ANIMATION_PRESETS: readonly AnimationPreset[]

Guides: Keyframes & animation

animationPreset

A preset by id ("in:pop", "loop:pulse", …).

const animationPreset: (id: string) => AnimationPreset | undefined

Guides: Keyframes & animation

builtinEffectParamSchemas

Kind registries — the extension seam. Built-in effect, transition, and clip kinds are pre-registered here with their Zod param schemas, which is what puts them in the AI command catalog and validates their commands. register*Kind lets consumers add custom kinds (the renderer's factory registries are the rendering half of the same seam).

const builtinEffectParamSchemas: {
    readonly colorAdjust: z.ZodObject<{
        brightness: z.ZodDefault<z.ZodNumber>;
        contrast: z.ZodDefault<z.ZodNumber>;
        saturation: z.ZodDefault<z.ZodNumber>;
        hue: z.ZodDefault<z.ZodNumber>;
    }, z.core.$strip>;
    readonly blur: z.ZodObject<{
        amount: z.ZodDefault<z.ZodNumber>;
    }, z.core.$strip>;
    readonly chromaKey: z.ZodObject<{
        color: z.ZodDefault<z.ZodString>;
        similarity: z.ZodDefault<z.ZodNumber>;
        smoothness: z.ZodDefault<z.ZodNumber>;
        spill: z.ZodDefault<z.ZodNumber>;
    }, z.core.$strip>;
}

builtinPayloadSchemas

const builtinPayloadSchemas: {
    readonly "project/set-settings": z.ZodObject<{
        width: z.ZodOptional<z.ZodNumber>;
        height: z.ZodOptional<z.ZodNumber>;
        fps: z.ZodOptional<z.ZodNumber>;
        frameRate: z.ZodOptional<z.ZodObject<{
            num: z.ZodNumber;
            den: z.ZodNumber;
        }, z.core.$strip>>;
        name: z.ZodOptional<z.ZodString>;
    }, z.core.$strip>;
    readonly "asset/add": z.ZodObject<{
        id: z.ZodString;
        kind: z.ZodEnum<{
            video: "video";
            audio: "audio";
            image: "image";
            font: "font";
        }>;
       …

Guides: Properties panel

builtinTransitionParamSchemas

const builtinTransitionParamSchemas: {
    readonly crossDissolve: z.ZodObject<{}, z.core.$strip>;
    readonly dipToBlack: z.ZodObject<{}, z.core.$strip>;
    readonly dipToWhite: z.ZodObject<{}, z.core.$strip>;
    readonly wipe: z.ZodObject<{
        direction: z.ZodDefault<z.ZodEnum<{
            left: "left";
            right: "right";
            up: "up";
            down: "down";
        }>>;
    }, z.core.$strip>;
    readonly slide: z.ZodObject<{
        direction: z.ZodDefault<z.ZodEnum<{
            left: "left";
            right: "right";
            up: "up";
            down: "down";
        }>>;
    }, z.core.$s …

DEFAULT_TRANSFORM

const DEFAULT_TRANSFORM: Transform

EASING_PRESETS

Named presets, stored expanded — CSS cubic-bezier() control points.

const EASING_PRESETS: Record<EasingPreset, Easing>

EFFECT_CATALOG

Every built-in effect kind, grouped by category (catalog order = picker order).

const EFFECT_CATALOG: readonly EffectInfo[]

Guides: Effects, Custom effects

EFFECT_CATEGORIES

const EFFECT_CATEGORIES: readonly {
    id: EffectCategory;
    label: string;
}[]

Guides: Effects

isAudioClip

const isAudioClip: (clip: Clip) => clip is AudioClip

Guides: Clips

isCaptionClip

const isCaptionClip: (clip: Clip) => clip is CaptionClip

Guides: Clips, Captions

isHtmlClip

const isHtmlClip: (clip: Clip) => clip is HtmlClip

Guides: Clips

isImageClip

const isImageClip: (clip: Clip) => clip is ImageClip

Guides: Clips

isTextClip

const isTextClip: (clip: Clip) => clip is TextClip

Guides: Clips

isVideoClip

const isVideoClip: (clip: Clip) => clip is VideoClip

Guides: Clips

TRACK_ACCEPTS

Which clip kinds a track kind accepts (custom kinds declare theirs at registration).

const TRACK_ACCEPTS: Record<TrackKind, readonly ClipKind[]>

Guides: Timeline, Tracks

transformSchema

const transformSchema: z.ZodObject<{
    x: z.ZodNumber;
    y: z.ZodNumber;
    scale: z.ZodNumber;
    rotation: z.ZodNumber;
    opacity: z.ZodNumber;
}, z.core.$strip>

TYPOGRAPHY_DEFAULTS

What an absent typography field means. Renderers and editor UIs read these rather than hard-coding them; the schema deliberately has no .default()s for these fields, so parsed documents never gain keys nobody set.

const TYPOGRAPHY_DEFAULTS: {
    readonly fontWeight: 400;
    readonly fontStyle: "normal";
    readonly letterSpacing: 0;
    readonly textAlign: "left";
    /** Caption line height multiple (text clips default to the font's natural line height). */
    readonly captionLineHeight: 1.3;
}

Guides: Text & typography

US_PER_SECOND

const US_PER_SECOND: 1000000

Interfaces

AnimationPreset

MemberTypeDescription
idstring
labelstring
slotAnimationSlot
build(base: Base, lengthUs: Us, easing: AnimationEasing) => TrackBuild the slot's keyframes. In: ends at base. Out: starts at base. Loop: spans lengthUs.
fixed?booleanLoops only: fixed timing, no duration / easing choice.

AnimationRecipe

MemberTypeDescription
in?AnimationSlotChoice
loop?AnimationSlotChoice
out?AnimationSlotChoice

AnimationSlotChoice

MemberTypeDescription
presetstring
durationUsUs
easingAnimationEasing

AsrGroupingOptions

MemberTypeDescription
maxGapUs?UsStart a new caption clip when the gap between words exceeds this (default 600ms).
maxWordsPerGroup?numberMaximum words per caption clip (default 8).

AsrWord

One ASR word, in seconds — the shape Whisper-style pipelines emit.

MemberTypeDescription
textstring
startSnumber
endSnumber

Asset

MemberTypeDescription
idstring
kindAssetKind
srcstring
name?stringDisplay name (e.g. a stock track's title).
source?AssetSourceProvenance — set by importers; absent for plain uploads.
license?AssetLicense
attribution?stringThe credit line to show when the license requires it, e.g. "“Calm Piano” by Jane Doe (CC BY 4.0)".
durationUs?UsIntrinsic duration of the media, if applicable (video/audio).
width?number
height?number
fps?number
family?stringFont assets: the CSS font-family name clips reference.
weight?FontWeightFont assets: the face's weight descriptor (100–900; default 400).
style?FontStyleFont assets: the face's style descriptor (default "normal").
weightRange?[FontWeight, FontWeight]Font assets: a VARIABLE font's weight axis range, e.g. [100, 900]. The face is declared over the whole range, so every weight in it renders from the font's own axis instead of a synthesized bold. Takes precedence over weight.

AssetLicense

The terms an asset may be used under.

MemberTypeDescription
idstringSPDX-style id, e.g. "CC0-1.0", "CC-BY-4.0", "CC-BY-NC-4.0", or a provider's own name.
url?string
commercialbooleanMay the asset be used in commercial work?
attributionRequiredbooleanMust the work credit the author (see Asset.attribution)?

Guides: Audio

AssetSource

Where an asset came from (a stock library, a generator, a recording, an upload).

MemberTypeDescription
providerstringProvider id, e.g. "openverse", "freesound", "recording", "upload".
idstringThe provider's own id for the item (empty for uploads/recordings).
url?stringHuman-facing page for the item (license and credits live there).

AudioClip

Extends ClipBase, AudioFades.

MemberTypeDescription
kind"audio"
assetIdstring
trimStartUsUs
volumenumber

AudioFades

Linear fades at a sound-making clip's edges (absent = none). Clamped to the clip's length when rendered.

MemberTypeDescription
fadeInUs?Us
fadeOutUs?Us

CaptionClip

Reels-style karaoke caption: word-level timing with an active-word style.

Extends ClipBase.

MemberTypeDescription
kind"caption"
wordsCaptionWord[]
styleCaptionStyle

CaptionCue

Caption import — pure text parsing that produces clip/add commands, so importing subtitles is just a transaction of ordinary commands (undoable, replayable, and visible to the AI command catalog like everything else).

Two sources: SRT/VTT cues (line-level timing; words get an even split as the fallback) and ASR word timestamps (Whisper-shape; real karaoke timing).

MemberTypeDescription
startUsUs
endUsUs
textstring

CaptionCueSource

The caption-clip fields subtitle export reads (any CaptionClip fits).

MemberTypeDescription
startUsUs
durationUsUs
wordsreadonly CaptionWord[]

CaptionImportOptions

MemberTypeDescription
trackIdstring
style?Partial<CaptionStyle>Merged over the default caption style.
idPrefix?stringDeterministic clip ids: ${idPrefix}-<n> (default "caption").

CaptionStyle

Caption lines are always centered, so captions take no textAlign.

Extends Typography.

MemberTypeDescription
preset"plain" | "highlight" | "karaoke" | "pop" | "reveal"How words react to timing: plain (static), highlight (active word in highlightColor), karaoke (every started word lit), pop (active word enlarged + lit), reveal (words appear as they are spoken).
fontFamilystring
fontSizeFracnumberFont size as a fraction of composition height (resolution-independent).
colorstring
highlightColorstring
backgroundColor?stringOptional box behind the caption block.
display?"block" | "word"word shows only the active word (word-by-word captions); default block (the whole clip).
textTransform?"uppercase" | "lowercase"Case transform applied when drawing (the words keep their original text).
strokeColor?stringOutline color; width is strokeWidthFrac × font size (default 0.08 when a color is set).
strokeWidthFrac?number
shadowColor?stringDrop shadow / glow color. Blur and downward offset are fractions of font size (defaults 0.15 / 0.06). An offset of 0 is a glow.
shadowBlurFrac?number
shadowOffsetFrac?number
activeBackgroundColor?stringRounded box behind each emphasized word (highlight / karaoke / pop).

CaptionWord

One word of a caption, timed relative to the clip's start.

MemberTypeDescription
textstring
startUsUs
durationUsUs

ClipBase

MemberTypeDescription
idstring
trackIdstring
startUsUsTimeline placement.
durationUsUs
transformTransform
animations?Partial<Record<AnimatableProperty, Keyframe[]>>Keyframes per animated property; a property without keyframes uses the clip's static value.
effects?EffectInstance[]Effect stack, applied pre-transform in array order.

ClipKindRegistration

MemberTypeDescription
propsSchemaz.ZodType
trackKindsreadonly TrackKind[]

Guides: Custom clip kinds

Command

MemberTypeDescription
typestring
payloadunknown

CommandDefinition

MemberTypeDescription
typestring
schemaS
handlerCommandHandler<z.output<S>>

CommandFailure

MemberTypeDescription
kind"unknown-command" | "invalid-payload" | "rejected"What went wrong, as a category an agent can branch on.
commandTypestring
messagestringHuman-readable summary (same text the thrown error carries).
code?stringrejected only: the engine's rejection code (e.g. "unknown-clip").
issues?{ path: string; message: string; }[]invalid-payload only: one entry per schema violation.
validTypes?string[]unknown-command only: every type the project accepts.

CreateProjectOptions

MemberTypeDescription
historyLimit?numberMaximum number of history entries kept (default 500).

CustomClip

A clip of a registered custom kind (see registerClipKind). Its payload lives under props, validated by the kind's registered schema.

Extends ClipBase.

MemberTypeDescription
kindstring
propsRecord<string, unknown>

Cut

Cuts: where one clip ends exactly where the next starts on the same video track — the only places transition/add accepts. A transition is centered on the cut, so it borrows half its length from footage past the outgoing clip's end and half from before the incoming clip's start ("handles"); maxTransitionUs is what those handles (and both clips' lengths) allow.

Editor panels and AI tools share this, so "every cut" means the same thing everywhere.

MemberTypeDescription
trackIdstring
fromClipIdstring
toClipIdstring
atUsUsTimeline position of the cut.
transition?TransitionThe transition on this cut, if any.
maxTransitionUsUsLongest transition the media allows here (0 when a side has no spare footage).
short?"from" | "to" | "both"Which side lacks spare footage, when one does.

Guides: Transitions

DescribeProjectOptions

MemberTypeDescription
maxClipsPerTrack?numberElide the middle of very long tracks (default 50 clips per track).

EffectInfo

MemberTypeDescription
kindstring
labelstring
categoryEffectCategory
paramsreadonly EffectParamInfo[]

Guides: Effects

EffectInstance

One effect in a clip's stack. kind resolves through the effect registry (built-ins: see EFFECT_CATALOG); params are validated against the kind's schema at command time. Length-denoting params are normalized to composition units — absolute pixels would render differently between a scaled preview and a full-resolution export.

MemberTypeDescription
idstring
kindstring
enabledboolean
paramsRecord<string, unknown>

EphemeralState

Ephemeral session state: lives in the store, excluded from undo history and from serialization.

MemberTypeDescription
playheadUsUs
selectionstring[]

EvaluatedClip

Flat evaluated state — reusable output object keeps evaluation alloc-free.

MemberTypeDescription
xnumber
ynumber
scalenumber
rotationnumber
opacitynumber
volumenumber

FrameRate

An exact frame rate as a ratio of positive integers: NTSC 29.97 is { num: 30000, den: 1001 }.

MemberTypeDescription
numnumber
dennumber

HtmlClip

HTML rendered into the composition: the template (with {{param}} placeholders) is rasterized via SVG foreignObject at widthPx×heightPx (default: the composition size) and composited like any other clip — keyframes, effects, and transitions all apply to the raster.

Extends ClipBase.

MemberTypeDescription
kind"html"
templatestringHTML markup; {{name}} placeholders substitute from params.
paramsRecord<string, HtmlParamValue>
widthPx?numberRaster size in composition pixels (default: the composition size).
heightPx?number
animated?booleanRe-rasterize every frame at the clip's local time, so CSS animations inside the template play (and seek, and export) frame-exactly. The renderer pauses every animation and sets its delay to calc(var(--d, 0s) - var(--t)), with --t = seconds into the clip and --T = the clip's animation length on the root element: write @keyframes + animation as usual and stagger with style="--d:.4s". Static (false/absent) clips raster once per param change.
animationOffsetUs?numberAnimated clips: animation time at the clip's start (default 0). A split advances the right half's offset so the animation continues across the cut instead of restarting.

ImageClip

Extends ClipBase.

MemberTypeDescription
kind"image"
assetIdstring

JsonPatchOp

RFC-6902 JSON Patch operation (the subset Immer produces).

MemberTypeDescription
op"add" | "replace" | "remove"
pathstringRFC-6901 JSON Pointer, e.g. "/doc/clips/clip-1/startUs".
value?unknown

Keyframe

MemberTypeDescription
timeUsUsClip-relative time. By default measured from the clip's visible start (0 = start; never moves with trims). With anchor: "end" it is measured BACK from the clip's visible end (0 = the last instant), so Out animations stay glued to the end when the clip is trimmed or resized.
anchor?"end"Omitted = "start".
valuenumber
easingEasingThe curve from THIS keyframe to the next one.

LicenseIssue

MemberTypeDescription
assetIdstring
kind"non-commercial" | "unknown-license" | "missing-attribution"
messagestring

PlannedKeyframe

MemberTypeDescription
propertyProp
timeUsUs
valuenumber
easingEasing
anchor?"end"

Project

MemberTypeDescription
getState() => ProjectStateRead the current state. Never mutate it — dispatch commands instead.
subscribe<T>(selector: (state: ProjectState) => T, listener: (value: T, previous: T) => void) => () => voidSubscribe to a slice of state. Returns an unsubscribe function.
storeStoreApi<ProjectState>The underlying Zustand store, for framework adapters.
eventsEmitter<ProjectEvents>
dispatch(command: BuiltinCommand | Command) => voidDispatch a command. Throws typed errors; on error, state is untouched.
transaction(fn: () => void, label?: string) => voidRun several dispatches as one undoable history entry (atomic: all or nothing).
registerCommand<S extends z.ZodType>(definition: CommandDefinition<S>) => voidRegister a custom command type.
commandCatalog() => Record<string, unknown>JSON Schema per command type — hand this to an LLM as its tool catalog.
undo() => boolean
redo() => boolean
canUndo() => boolean
canRedo() => boolean
clearHistory() => void
setPlayhead(positionUs: Us) => voidEphemeral (not undoable, not serialized).
setSelection(ids: string[]) => void
toJSON() => ProjectDocumentSerialize the document. Feed the result back to createProject to restore.

Guides: MCP server, Collaboration, Stills

ProjectDocument

The document: everything that is part of the composition, serialized and covered by undo history.

MemberTypeDescription
schemaVersion1
settingsProjectSettings
assetsRecord<string, Asset>
tracksRecord<string, Track>
trackOrderstring[]Render order: index 0 is the bottom layer.
clipsRecord<string, Clip>
transitionsRecord<string, Transition>Transitions between adjacent clips, keyed by id.

Guides: Collaboration, Stills, Defining templates

ProjectEvents

Extends Record<string, unknown>.

MemberTypeDescription
patches{ patches: JsonPatchOp[]; inverse: JsonPatchOp[]; source: PatchSource; }Emitted on every document change, as RFC-6902 patches relative to the document root.
history{ kind: "commit" | "undo" | "redo"; label?: string; }
playhead{ positionUs: Us; }
selection{ ids: string[]; }

ProjectSettings

MemberTypeDescription
widthnumber
heightnumber
fpsnumberFrames per second. A decimal NTSC rate (29.97, 23.976, 59.94) is read as its exact /1001 ratio; read the exact rate with projectFrameRate(settings).
frameRate?FrameRateThe exact rate, kept when it isn't a whole number (fps then mirrors num/den). project/set-settings keeps the two in sync.
name?string

ProjectState

Extends EphemeralState.

MemberTypeDescription
docProjectDocument

ReadAnimation

MemberTypeDescription
recipeAnimationRecipe
custombooleanKeyframes exist that no preset explains.
stale?booleanThe loop's keyframes no longer span the clip (it was trimmed): re-apply to refresh.

TextClip

Extends ClipBase, Typography.

MemberTypeDescription
kind"text"
textstring
fontFamilystring
fontSizePxnumber
colorstring
textAlign?TextAlignAlignment of lines within the text block (default "left"). Independent of the clip's anchor/transform.

TimecodeOptions

MemberTypeDescription
dropFrame?booleanSMPTE drop-frame timecode ("HH:MM:SS;FF"): skips frame numbers 0 and 1 (0–3 at 59.94) at each minute except every tenth, so the timecode tracks the clock at 29.97 / 59.94. Only for those rates; ignored otherwise.

ToToolDefinitionsOptions

MemberTypeDescription
style?"anthropic" | "openai"Wire shape: "anthropic" (default) → { name, description, input_schema }; "openai" → { type: "function", function: { name, description, parameters } }.
mode?"per-command" | "dispatch""per-command" (default): one tool per command type — best when the host allows ~25+ tools. "dispatch": ONE miraiclip_dispatch tool taking { type, payload } — for tool-count-constrained hosts (MCP servers); pair it with handing the agent the catalog for payload schemas.
descriptions?Record<string, string>Extra or overriding descriptions, keyed by command type (custom commands).

Track

MemberTypeDescription
idstring
kindTrackKind
namestring
mutedboolean
soloboolean
lockedboolean
hidden?booleanVisual tracks: when true, the track's clips aren't drawn (preview, export, stills). Audio is unaffected — use muted.

Guides: Timeline, React

Transform

MemberTypeDescription
xnumberNormalized center position: 0.5/0.5 = canvas center.
ynumber
scalenumber
rotationnumberDegrees.
opacitynumber0..1

Transition

MemberTypeDescription
idstring
trackIdstring
fromClipIdstringThe clip ending at the cut.
toClipIdstringThe clip starting at the cut.
kindstringRegistry-resolved kind (built-ins: crossDissolve, dipToBlack, dipToWhite, wipe, slide).
durationUsUs
alignment"centered"Reserved: only "centered" in v4.
paramsRecord<string, unknown>

Typography

Optional typography shared by text clips and caption styles. Absent fields mean the default (see TYPOGRAPHY_DEFAULTS) — which is exactly how clips rendered before these fields existed. Documents only carry what was set, so older projects load, render, and serialize unchanged.

MemberTypeDescription
fontWeight?FontWeight100–900 (default 400).
fontStyle?FontStyleDefault "normal".
lineHeight?numberLine box height as a multiple of font size. Absent = today's rendering: the font's natural line height for text clips, 1.3 for captions.
letterSpacing?numberExtra space between characters in em — scales with font size (default 0).

VideoClip

Extends ClipBase, AudioFades.

MemberTypeDescription
kind"video"
assetIdstring
trimStartUsUsSource trim: offset into the asset where playback starts.
volumenumber

Types

AnimatableProperty

type AnimatableProperty = "x" | "y" | "scale" | "rotation" | "opacity" | "volume";

AnimationEasing

type AnimationEasing = "smooth" | "linear" | "snappy";

AnimationSlot

Animation presets, built on ordinary keyframes so they play in preview and every export with no special support.

A clip's animation is a RECIPE of up to three slots: In (from the start), Loop (between In and Out) and Out (into the end, end-anchored so it follows trims). Applying a recipe regenerates the clip's visual keyframes. The recipe isn't stored anywhere: readAnimation recognizes it from the keyframes (presets are deterministic), so it survives save / reload and undo. Hand-made keyframes that match no preset read as "custom".

Editor panels and AI tools share this module, so "pop in" means the same keyframes wherever it's applied.

type AnimationSlot = "in" | "out" | "loop";

ApplyCommandsResult

type ApplyCommandsResult = {
    ok: true;
    applied: number;
} | {
    ok: false;
    applied: 0;
    failedIndex: number;
    error: CommandFailure;
};

AssetKind

type AssetKind = "video" | "audio" | "image" | "font";

BuiltinClip

type BuiltinClip = VideoClip | AudioClip | ImageClip | TextClip | CaptionClip | HtmlClip;

BuiltinCommand

A built-in command as dispatched.

type BuiltinCommand = {
    [T in BuiltinCommandType]: {
        type: T;
        payload: BuiltinCommandPayload<T>;
    };
}[BuiltinCommandType];

BuiltinCommandPayload

type BuiltinCommandPayload<T extends BuiltinCommandType> = z.input<(typeof builtinPayloadSchemas)[T]>;

BuiltinCommandType

type BuiltinCommandType = keyof typeof builtinPayloadSchemas;

Clip

type Clip = BuiltinClip | CustomClip;

Guides: Timeline, React

ClipKind

type ClipKind = "video" | "audio" | "image" | "text" | "caption" | "html";

CommandHandler

Applies a validated payload to a draft of the document.

type CommandHandler<P = unknown> = (doc: Draft<ProjectDocument>, payload: P) => void;

CommandResult

type CommandResult = {
    ok: true;
} | {
    ok: false;
    error: CommandFailure;
};

Easing

Easings are STORED as cubic-bézier control points (CSS convention: progress x → eased y) — named presets are input sugar that expands at command time. "hold" steps to the next keyframe with no interpolation.

type Easing = {
    kind: "bezier";
    x1: number;
    y1: number;
    x2: number;
    y2: number;
} | {
    kind: "hold";
};

EasingPreset

type EasingPreset = "linear" | "hold" | "easeIn" | "easeOut" | "easeInOut";

EffectCategory

The built-in effect library: every built-in effect kind's name, category and params, as plain data. One declaration feeds three consumers:

  • validation — each entry's param schema is derived from it (see registry.ts), so effect/add / effect/update validate and fill defaults;
  • the AI command catalog — kinds and ranges reach LLM tools;
  • editor UIs — labels, categories, slider ranges and display hints for property panels and effect pickers (EFFECT_CATALOG, getEffectInfo).

The renderer draws every kind listed here (its shaders are keyed by kind). Length params (length: true) are fractions of COMPOSITION HEIGHT — never pixels — so a scaled preview and a full-resolution export look identical.

type EffectCategory = "color" | "film" | "stylize" | "glitch" | "light" | "distort" | "frame";

EffectParamFormat

How a UI should display a number param's value.

type EffectParamFormat = "percent" | "int" | "deg" | "stops" | "decimal";

EffectParamInfo

type EffectParamInfo = {
    key: string;
    label: string;
    type: "number";
    min: number;
    max: number;
    step: number;
    default: number;
    format?: EffectParamFormat;
    length?: true;
} | {
    key: string;
    label: string;
    type: "color"; default: string;
};

Guides: Effects

FontStyle

type FontStyle = "normal" | "italic";

FontWeight

CSS font weight: 100–900 in steps of 100 (validated by the command schemas).

type FontWeight = number;

FrameRateLike

Anything the frame helpers accept: a plain number (29.97 → 30000/1001) or an exact ratio.

type FrameRateLike = number | FrameRate;

HtmlParamValue

A template parameter value — plain data, so html clips serialize and cross process boundaries.

type HtmlParamValue = string | number | boolean;

Listener

Minimal typed event emitter.

type Listener<T> = (payload: T) => void;

PatchSource

type PatchSource = "dispatch" | "undo" | "redo" | "transaction-rollback";

TextAlign

type TextAlign = "left" | "center" | "right";

TrackKind

type TrackKind = "video" | "audio";

Us

Microseconds — the timeline unit. 1 second = 1_000_000 µs.

type Us = number;

On this page

FunctionsanimationCommandsapplyCommandsapplyJsonPatchescaptionClipsFromAsrWordscaptionClipsFromSubtitlescaptionsToSrtcaptionsToTextcaptionsToVttclipHeadroomUsclipKindRegistrationcommandCatalogcommandTypeForToolcreateProjectcreditsForcubicBezierProgressdefaultEffectParamsdescribeAnimationdescribeProjecteffectParamsSchemaevaluateClipAtevaluateClipIntoevaluateKeyframesfindCutsfitAnimationformatFrameRateframeCountframeDurationUsframeToUsfromJsonPointergetEffectInfoisBuiltinClipKindkeyframeTimeUslicenseReportparseSubtitlesplanAnimationprojectFrameRatereadAnimationregisterClipKindregisterEffectKindregisterTransitionKindresolveEasingresolveKeyframesretimeWordssecondsToUssnapToFrametoFrameRatetoJsonPatchestoJsonPointertoolNameForCommandtoToolDefinitionstransitionParamsSchematryDispatchusedAssetsusToFrameusToSecondsusToTimecodewordsFromCueClassesCommandRejectedErrorCommandValidationErrorEmitterUnknownCommandErrorConstantsANIMATION_DEFAULT_SLOT_USANIMATION_EASINGSANIMATION_MAX_SLOT_USANIMATION_MIN_SLOT_USANIMATION_PRESETSanimationPresetbuiltinEffectParamSchemasbuiltinPayloadSchemasbuiltinTransitionParamSchemasDEFAULT_TRANSFORMEASING_PRESETSEFFECT_CATALOGEFFECT_CATEGORIESisAudioClipisCaptionClipisHtmlClipisImageClipisTextClipisVideoClipTRACK_ACCEPTStransformSchemaTYPOGRAPHY_DEFAULTSUS_PER_SECONDInterfacesAnimationPresetAnimationRecipeAnimationSlotChoiceAsrGroupingOptionsAsrWordAssetAssetLicenseAssetSourceAudioClipAudioFadesCaptionClipCaptionCueCaptionCueSourceCaptionImportOptionsCaptionStyleCaptionWordClipBaseClipKindRegistrationCommandCommandDefinitionCommandFailureCreateProjectOptionsCustomClipCutDescribeProjectOptionsEffectInfoEffectInstanceEphemeralStateEvaluatedClipFrameRateHtmlClipImageClipJsonPatchOpKeyframeLicenseIssuePlannedKeyframeProjectProjectDocumentProjectEventsProjectSettingsProjectStateReadAnimationTextClipTimecodeOptionsToToolDefinitionsOptionsTrackTransformTransitionTypographyVideoClipTypesAnimatablePropertyAnimationEasingAnimationSlotApplyCommandsResultAssetKindBuiltinClipBuiltinCommandBuiltinCommandPayloadBuiltinCommandTypeClipClipKindCommandHandlerCommandResultEasingEasingPresetEffectCategoryEffectParamFormatEffectParamInfoFontStyleFontWeightFrameRateLikeHtmlParamValueListenerPatchSourceTextAlignTrackKindUs