Miraiclip SDK
Concepts

Speed & freeze frames

Play a clip faster or slower, or hold one frame.

Coming in the next release

Clip speed and freeze frames are built and tested in @miraiclip/core, @miraiclip/renderer and @miraiclip/editor, and ship in the next SDK release.

// Play "screen" twice as fast. It keeps the same footage, so it gets half as long.
project.dispatch({ type: "clip/set-speed", payload: { clipId: "screen", speed: 2, ripple: true } });

// Hold the frame at 4 s for 1.5 s. Later clips on the track move back by 1.5 s.
project.dispatch({ type: "clip/freeze", payload: { clipId: "screen", atUs: 4_000_000, durationUs: 1_500_000 } });

Video and audio clips have a speed. Absent means 1. Preview, audio, browser export, worker export and server export all map time the same way, so a sped-up clip looks and sounds the same everywhere.

speedEffectClips
1 (or absent)Normal playbackvideo, audio
2Twice as fast: 4 s on the timeline shows 8 s of footagevideo, audio
0.5Half speedvideo, audio
0Freeze frame: every frame shows the source frame at trimStartUs, with no soundvideo only

Allowed values are 0 or 1/16 to 16 (MIN_CLIP_SPEED, MAX_CLIP_SPEED). Audio pitch follows speed, like a tape played faster.

Change speed

project.dispatch({
  type: "clip/set-speed",
  payload: { clipId: "screen", speed: 0.5, keepDuration: false, ripple: true },
});
FieldDefaultMeaning
clipIdrequiredA video or audio clip
speedrequired0 (video only) or 1/16..16
keepDurationfalsefalse: the clip keeps its footage and its timeline length changes (2× halves it). true: the length stays and the clip plays more or less footage
ripplefalseMove later clips on the same track by the change in length

Transitions touching the clip are removed, because the footage around its edges changes.

RejectionMeaning
no-sourceThe clip has no media to speed up (text, caption, html, image)
cannot-freezespeed: 0 on an audio clip

Freeze a frame

clip/freeze splits a video clip and inserts a freeze-frame clip that holds the frame at atUs.

project.dispatch({
  type: "clip/freeze",
  payload: {
    clipId: "screen",
    atUs: 4_000_000,       // inside the clip, or exactly at its end
    durationUs: 1_500_000,
    freezeClipId: "hold-1", // optional, for deterministic replay
    rightClipId: "screen-2", // optional: the part after the freeze
  },
});
FieldDefaultMeaning
atUsrequiredTimeline time of the frame to hold. At the clip's end, the last frame is held and there is no right part
durationUsrequiredHow long the freeze lasts
freezeClipId, rightClipIdgeneratedIds for the new clips. Supply them when commands are replayed, for example in collaboration
rippletruePush later clips on the track back by durationUs

The freeze clip is an ordinary video clip with speed: 0. It copies the original's transform and effects, but not its keyframes or fades. Delete it to remove the freeze, or change its length like any clip.

Markers don't move when a command ripples a track. Move them with marker/update if they need to follow. See Markers.

Map time

Use these helpers whenever you convert between timeline time and source time, for example to draw a waveform or thumbnails under a sped-up clip.

import { clipSpeed, isFrozenClip, toSourceUs, toTimelineUs, sourceSpanUs } from "@miraiclip/core";

const clip = project.getState().doc.clips["screen"]!;
const sourceAt = toSourceUs(clip, project.getState().playheadUs); // where in the file the playhead is
const onTimeline = toTimelineUs(clip, 12_000_000);              // undefined for a freeze frame
const footage = sourceSpanUs(clip);                              // 0 for a freeze frame
FunctionReturns
clipSpeed(clip)The clip's speed (1 for clips without a source)
isFrozenClip(clip)true when speed is 0
isValidClipSpeed(speed)Whether a value is allowed
toSourceUs(clip, timelineUs)Position in the source media
toTimelineUs(clip, sourceUs)Position on the timeline, or undefined for a freeze frame
sourceSpanUs(clip), sourceEndUs(clip)How much footage the clip uses, and where it ends in the source
durationForSource(sourceUs, speed)Timeline length needed to play that much footage at that speed
clipHeadroomTimelineUs(doc, clip, side)Spare footage on one side, in timeline time, for transitions

In an editor

@miraiclip/editor's command builders wrap both commands, and trimming a sped-up clip accounts for its speed.

import { createCommands } from "@miraiclip/editor";

const commands = createCommands(project);
commands.setClipSpeed("screen", 2, { ripple: true });
commands.freezeFrame("screen", 4_000_000, 1_500_000);

On this page