@miraiclip/react
React bindings for Miraiclip: providers, state hooks, playback, timeline behaviour hooks, and unstyled editor components.
npm install @miraiclip/react| Version | 0.2.0 |
| Runs in | Browser, React 18 or 19 |
| Exports | 72 |
| Guides | React, Components |
Functions
isEditableTarget
True for inputs, text areas, selects and contenteditable: keys there belong to the field.
function isEditableTarget(target: EventTarget | null): booleanPlaybackProvider
Playback and preview for the project above it: a preview controller (renderer, player, fallback clock, monitoring volume) exposed as React state. Transport state comes from player events, so it never drifts from what the player is doing.
function PlaybackProvider({ options, volumeStorageKey, children }: PlaybackProviderProps): react.JSX.ElementGuides: Preview & playback, Overview, Preview, Timeline
ProjectProvider
Provides one Miraiclip project to everything below it. Pass init (and
optionally seed) to have the provider create the project once for its
lifetime, or project to share one you created.
function ProjectProvider(props: ProjectProviderProps): react.JSX.ElementGuides: Overview, Timeline, Installation, React
ProjectSessionProvider
A <ProjectProvider> whose project can be swapped at runtime (Open / New).
Loading remounts everything below it, so engine, renderer and UI all
re-initialize cleanly from the loaded state.
function ProjectSessionProvider({ initial, children }: {
initial: SessionInit;
children: ReactNode;
}): react.JSX.ElementGuides: React
rulerStepUs
Smallest "nice" tick step that keeps ticks at least minGapPx apart.
function rulerStepUs(pxPerSecond: number, minGapPx?: number): UsshallowEqual
Shallow equality for arrays and objects of primitives — for list selectors.
function shallowEqual<T>(a: T, b: T): booleanGuides: React
useClip
function useClip(clipId: string | null | undefined): Clip | undefinedGuides: React
useClipCount
How many clips a track has.
function useClipCount(trackId: string): numberGuides: React
useClips
A track's clips, sorted by start time.
function useClips(trackId: string): Clip[]Guides: Reading state, Installation, React
useCommands
Typed command builders bound to the current project. Stable across renders.
function useCommands(): CommandsuseCompositorPlayhead
Moves a playhead-driven element without per-frame style recalcs.
While playing, the element runs a linear Web Animations transform from the
playhead to the end, so the browser's compositor moves it with no main-
thread work. The store's playhead only re-syncs it: the animation restarts
when the real playhead drifts more than toleranceUs from its prediction
(seek, loop, buffering stall). Paused, it gets a static transform.
toTransform maps a time to a CSS transform; list what it depends on in deps.
function useCompositorPlayhead(ref: RefObject<HTMLElement | null>, toTransform: (us: Us, durationUs: Us) => string, deps: readonly unknown[], toleranceUs?: number): voiduseDurationUs
Composition length: the end of the last clip. Recomputed only on edits.
function useDurationUs(): UsGuides: React
useEditorShortcuts
Binds the default editor keys (see matchEditorShortcut) on window,
limited to actions. Keys typed into text fields are left alone.
function useEditorShortcuts(actions?: readonly EditorAction[]): voidGuides: Selection & canvas editing, Blocks, Timeline, React
useGesture
Start a live edit that lands in history as one entry (see beginGesture).
function useGesture(): (label: string) => GestureuseHistoryState
function useHistoryState(): {
canUndo: boolean;
canRedo: boolean;
}Deprecated
useUndoRedo.usePlayback
Transport, preview and volume from the nearest <PlaybackProvider>.
function usePlayback(): PlaybackValueGuides: Preview, Installation, React
usePlayheadFollow
Keeps the playhead findable: while playing, pages the timeline so the playhead stays in view (pausing for 1.5 s after the user scrolls by hand), and reports when it is off screen, for an edge indicator.
function usePlayheadFollow(scrollRef: RefObject<HTMLElement | null>, pxPerSecond: number, headerWidthPx?: number): PlayheadFollowGuides: React
usePlayheadRef
The playhead in a ref that updates without re-rendering. Pass onChange to
write to the DOM directly on each change (e.g. a time label's textContent).
function usePlayheadRef(onChange?: (us: Us) => void): MutableRefObject<Us>Guides: React
usePlayheadUs
Playhead position in µs. Re-renders on every played frame (60×/s), so use
it only in small components; usePlayheadRef reads it without re-rendering.
function usePlayheadUs(): UsGuides: Reading state, Scrubber, React
usePreview
Size and status of the enclosing <Preview>, for overlays.
function usePreview(): PreviewStateGuides: Overview, Preview, React
useProject
The project from the nearest <ProjectProvider>.
function useProject(): ProjectGuides: React
useProjectSession
Open / New for the nearest <ProjectSessionProvider>.
function useProjectSession(): ProjectSessionGuides: React
useProjectState
Subscribe to a slice of project state. Re-renders only when the selected
value changes (per isEqual, default Object.is). Every other state hook
builds on this one; narrow selectors keep a busy timeline cheap.
function useProjectState<T>(selector: (state: ProjectState) => T, isEqual?: (a: T, b: T) => boolean): TGuides: Reading state, Scrubber, React
useSelectedClip
The selected clip when exactly one is selected.
function useSelectedClip(): Clip | undefineduseSelection
Selected clip ids.
function useSelection(): string[]Guides: Reading state, Preview, React
useSettings
Project settings (size, frame rate, name).
function useSettings(): ProjectSettingsGuides: React
useTimeline
The timeline's scale, layout and drag entry point. Use inside <Timeline.Root>.
function useTimeline(): TimelineContextValueuseTimelineClip
State of the enclosing <Timeline.Clip>, live while it is dragged.
function useTimelineClip(): TimelineClipStateGuides: Overview, Timeline, Waveform, React
useTimelineDrag
The clip being dragged, as it would land now; null when no drag is in progress.
function useTimelineDrag(): ClipDragPreview | nulluseTimelineRange
The time range the viewport shows (plus a margin), for virtualising custom rows.
function useTimelineRange(): {
fromUs: Us;
toUs: Us;
}useTimelineTrack
The track of the enclosing <Timeline.Track>.
function useTimelineTrack(): TrackuseTimelineZoom
Ctrl/⌘ + wheel zooms the timeline around the pointer; plain wheel keeps scrolling.
function useTimelineZoom(scrollRef: RefObject<HTMLElement | null>, options: TimelineZoomOptions): voiduseTrack
function useTrack(trackId: string): Track | undefinedGuides: React
useTrackOrder
Track ids in render order (index 0 = bottom layer).
function useTrackOrder(): string[]Guides: React
useTracks
All tracks, in render order.
function useTracks(): Track[]Guides: React
useTransformBox
State of the enclosing <TransformBox.Root>, for custom handles and drawing.
function useTransformBox(): TransformBoxStateGuides: Overview, Transform box, React
useTransitions
A track's transitions.
function useTransitions(trackId: string): Transition[]Guides: React
useUndoRedo
Undo and redo, with live availability for the buttons.
function useUndoRedo(): UndoRedoGuides: React
useVisibleRange
The time range a scrolling timeline should render (see visibleRange in
function useVisibleRange(scrollRef: RefObject<HTMLElement | null>, pxPerSecond: number, headerWidthPx?: number): {
fromUs: Us;
toUs: Us;
}useWaveformPeaks
Waveform peaks for an audio or video asset, or null while computing (and
when it has no audio). Computed once per asset src with a streamed
decode, shared by every component that asks, one asset at a time.
function useWaveformPeaks(asset: Asset | undefined): WaveformPeaks | nullGuides: Timeline, Overview, Waveform, React
Constants
Preview
The preview canvas, wired to <PlaybackProvider>: hands its <canvas> to
the renderer on mount, keeps the render target matched to its size, and
releases it on unmount. The element is position: relative and exactly the
canvas's size, so overlays can use position: absolute; inset: 0.
data-mode carries the playback mode; data-error is set after a render error.
const Preview: react.ForwardRefExoticComponent<PreviewProps & react.RefAttributes<HTMLDivElement>>Guides: Preview & playback, Overview, Preview, Transform box
Scrubber
Unstyled seek bar parts: <Scrubber.Root> with <Scrubber.Range> and <Scrubber.Thumb> inside.
const Scrubber: {
Root: react.ForwardRefExoticComponent<ScrubberRootProps & react.RefAttributes<HTMLDivElement>>;
Range: react.ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
children?: ReactNode;
} & react.RefAttributes<HTMLDivElement>>;
Thumb: react.ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
children?: ReactNode;
} & react.RefAttributes<HTMLDivElement>>;
}Guides: Overview, Preview, Scrubber, React
Timeline
Unstyled timeline parts. See the module comment for the structure.
const Timeline: {
Root: react.ForwardRefExoticComponent<TimelineRootProps & react.RefAttributes<HTMLDivElement>>;
Viewport: react.ForwardRefExoticComponent<TimelineViewportProps & react.RefAttributes<HTMLDivElement>>;
Ruler: react.ForwardRefExoticComponent<TimelineRulerProps & react.RefAttributes<HTMLDivElement>>;
Track: react.ForwardRefExoticComponent<TimelineTrackProps & react.RefAttributes<HTMLDivElement>>;
TrackHeader: react.ForwardRefExoticComponent<DivProps & {
children?: ReactNode;
} & react.RefAttributes<HTMLDivElement>>;
Lane: react.ForwardRefExoticComponent<Time …Guides: Timeline, Overview, Scrubber, Timeline
TransformBox
Unstyled transform-box parts for the preview. See the module comment for the structure.
const TransformBox: {
Root: react.ForwardRefExoticComponent<TransformBoxRootProps & react.RefAttributes<HTMLDivElement>>;
Outline: typeof Outline;
Guides: typeof Guides;
Body: typeof Body;
Handle: react.ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
children?: ReactNode;
} & {
corner: 0 | 1 | 2 | 3;
} & react.RefAttributes<HTMLDivElement>>;
RotateHandle: react.ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
children?: ReactNode;
} & {
distance?: number;
} & react.RefAttributes<HTM …Guides: Selection & canvas editing, Overview, Preview, Transform box
Waveform
Mirrored waveform bars for a media range, filling the canvas's CSS box.
Bars use currentColor, so the text color styles them. Redraws on resize
and when its inputs change; the backing store is capped so very wide clips
at high zoom stay within mobile memory limits.
const Waveform: react.ForwardRefExoticComponent<WaveformProps & react.RefAttributes<HTMLCanvasElement>>Guides: Timeline, Overview, Timeline, Waveform
Interfaces
PlaybackProviderProps
| Member | Type | Description |
|---|---|---|
options? | PreviewControllerOptions | Renderer and player options. Read when the provider mounts. |
volumeStorageKey? | string | Remember the monitoring volume in localStorage under this key (off by default). |
children | ReactNode |
PlaybackValue
| Member | Type | Description |
|---|---|---|
isPlaying | boolean | |
mode | PreviewMode | |
lastError | string | null | |
play | () => void | |
pause | () => void | |
toggle | () => void | |
seek | (us: Us) => void | |
attachCanvas | (canvas: HTMLCanvasElement, size: { width: number; height: number; }) => void | Hand the preview <canvas> to the renderer (once it is in the DOM). size is its CSS size. |
resizePreview | (width: number, height: number) => void | The preview's CSS size changed. |
detachCanvas | () => void | |
getClipBounds | (clipId: string) => ClipBounds | null | Where a clip is drawn now, in composition px (null when not drawn or not live). |
hitTest | (xPx: number, yPx: number, filter?: (clip: Clip) => boolean) => string | null | Topmost clip at a composition-px point (null when none or not live). |
volume | number | Monitoring volume, 0..1 (never written to the project or exports). |
muted | boolean | |
setVolume | (volume: number) => void | |
toggleMute | () => void | |
controller | PreviewController | The framework-free controller underneath, for anything not covered here. |
PlayheadFollow
| Member | Type | Description |
|---|---|---|
side | "left" | "right" | null | Which side the playhead is scrolled off, or null when visible. |
us | Us | Playhead time when it went off screen (refreshed every 0.5 s while off). |
reveal | () => void | Scroll the playhead back into view. |
PreviewProps
Extends Omit<HTMLAttributes<HTMLDivElement>, "children">.
| Member | Type | Description |
|---|---|---|
width? | number | CSS size of the canvas. Give both for a fixed size; leave both out to fit the composition's aspect inside the parent element (measured live). |
height? | number | |
fitPadding? | number | Fit mode only: space kept free around the preview inside the parent, px (default 0). |
canvasProps? | CanvasHTMLAttributes<HTMLCanvasElement> | Props for the <canvas>. |
children? | RenderChildren<PreviewState> | Drawn over the canvas (selection boxes, messages). A function receives the preview's state. |
PreviewState
| Member | Type | Description |
|---|---|---|
width | number | CSS size of the canvas, px. |
height | number | |
scale | number | Screen px per composition px. |
mode | PreviewMode | "live" (renderer drawing), "fallback" (clock only) or "unsupported" (no WebCodecs). |
lastError | string | null |
ProjectSession
| Member | Type | Description |
|---|---|---|
loadDocument | (doc: ProjectDocument) => void | Replace the current composition with a serialized document (Open). |
newProject | () => void | Start over from the initial project (New). |
Guides: MCP server
RulerTick
| Member | Type | Description |
|---|---|---|
us | Us | |
x | number | Offset from the ruler's left edge, px. |
label | string | formatClock(us). |
ScrubberRootProps
Extends DivProps.
| Member | Type | Description |
|---|---|---|
stepUs? | Us | Arrow-key step (default 1 s). |
largeStepUs? | Us | Page Up / Page Down and Shift + arrow step (default 5 s). |
SessionInit
| Member | Type | Description |
|---|---|---|
init | ProjectSettings | ProjectDocument | |
seed? | (project: Project) => void |
TimelineClipProps
Extends DivProps.
| Member | Type | Description |
|---|---|---|
clip | Clip | |
insetPx? | number | Pixels taken off the left edge (a gap between neighbouring clips; default 0). |
minWidthPx? | number | Narrowest drawn width, px (default 2). |
children? | RenderChildren<TimelineClipState> |
TimelineClipState
| Member | Type | Description |
|---|---|---|
clip | Clip | |
startUs | Us | Live position: the drag preview while this clip is dragged, else the clip's own. |
durationUs | Us | |
trimStartUs | Us | Media in-point, live while trimming the start (0 for clips without media). |
selected | boolean | |
dragging | ClipDragMode | null | What the current drag does to this clip, or null. |
locked | boolean | On a locked track: selectable, not draggable. |
TimelineContextValue
| Member | Type | Description |
|---|---|---|
pxPerSecond | number | |
headerWidth | number | Width of the sticky header column inside the viewport, in px. |
lengthUs | Us | Scrollable length of the timeline. |
viewportRef | RefObject<HTMLDivElement | null> | The scroll container (set by <Timeline.Viewport>). |
usAtClientX | (clientX: number) => Us | Timeline time under a viewport x (clamped at 0). |
beginClipDrag | (event: PointerEvent, clip: Clip, mode: ClipDragMode) => void | Start dragging a clip from a pointer event (what <Timeline.Clip> and <Timeline.TrimHandle> call). |
TimelineCut
Extends TrackCut.
| Member | Type | Description |
|---|---|---|
x | number | Offset of the cut from the lane's left edge, px. |
TimelineCutsProps
| Member | Type | Description |
|---|---|---|
children | (cut: TimelineCut) => ReactNode | Render one cut. Only cuts in the visible range are passed. |
hideWhileDragging? | boolean | Hide cut markers while a clip is dragged (default true). |
TimelineLaneProps
Extends DivProps.
| Member | Type | Description |
|---|---|---|
children | (clip: Clip) => ReactNode | Render one clip (usually a <Timeline.Clip>). Called only for clips in the visible range, plus a dragged clip. |
deselectOnClick? | boolean | Clicking the empty lane clears the selection (default true). |
overlay? | ReactNode | Extra content after the clips (cut markers, drop indicators). |
TimelineRootProps
Extends DivProps.
| Member | Type | Description |
|---|---|---|
pxPerSecond | number | Zoom: horizontal pixels per second. |
onPxPerSecondChange? | (pxPerSecond: number) => void | Called by Ctrl/⌘ + wheel zoom (around the pointer). Leave out to disable wheel zoom. |
minPxPerSecond? | number | |
maxPxPerSecond? | number | |
headerWidth? | number | Width of a sticky header column at the left of the viewport (default 0). |
lengthUs? | Us | Scrollable length. Default: the composition plus 5 s, at least 10 s. |
snapPx? | number | Clip edges snap within this many pixels (default 8; 0 turns snapping off). |
children? | ReactNode |
TimelineRulerProps
Extends DivProps.
| Member | Type | Description |
|---|---|---|
stepUs? | Us | ((pxPerSecond: number) => Us) | Tick spacing: a fixed step, or one picked from the zoom. Default: the smallest step at least 60 px apart. |
renderTick? | (tick: RulerTick) => ReactNode | Render one tick. Default: an absolutely placed <span data-tick> with the clock label. |
children? | ReactNode | Extra content after the ticks (a <Timeline.Playhead> knob, markers). |
TimelineTrackProps
Extends DivProps.
| Member | Type | Description |
|---|---|---|
track | Track | |
children? | ReactNode |
TimelineTrimHandleProps
Extends DivProps.
| Member | Type | Description |
|---|---|---|
side | "start" | "end" | Which edge it trims. |
children? | ReactNode |
TimelineViewportProps
Extends DivProps.
| Member | Type | Description |
|---|---|---|
contentProps? | DivProps | Props for the inner element sized to the timeline's length. |
children? | ReactNode |
TimelineZoomOptions
| Member | Type | Description |
|---|---|---|
pxPerSecond | number | |
setPxPerSecond | (pxPerSecond: number) => void | |
minPxPerSecond | number | |
maxPxPerSecond | number | |
headerWidthPx? | number | Sticky header column width inside the scroll container. |
enabled? | boolean | Set false to leave Ctrl/⌘ + wheel to the browser (default true). |
TransformBoxOutlineProps
Extends SVGProps<SVGPolygonElement>.
| Member | Type | Description |
|---|---|---|
target? | "selection" | "hover" | The selected clip (default) or the clip under the pointer. |
TransformBoxRootProps
Extends Omit<HTMLAttributes<HTMLDivElement>, "children">.
| Member | Type | Description |
|---|---|---|
snapPx? | number | Move snapping to the frame's edges and center, in screen px (default 6; 0 turns it off). Alt places freely. |
dragThresholdPx? | number | Movement below this many screen px is a click (default 2). |
nudge? | boolean | Arrow keys nudge the selection 1 px (Shift: 10 px) (default true). |
canSelect? | (clip: Clip) => boolean | Which clips a click can pick. Default: visual clips on unlocked tracks. |
onClipDoubleClick? | (clipId: string) => void | Double-click on a clip (e.g. open its text editor). |
children? | ReactNode |
TransformBoxState
| Member | Type | Description |
|---|---|---|
box | ClipBounds | null | The selected clip's bounds (composition px), when one visual clip is selected and drawn. |
hover | ClipBounds | null | The clip under the pointer, when it isn't the selection. |
guides | TransformGuides | Frame lines the current move snapped to (composition px). |
editable | boolean | True when the selected clip can be edited (visual, track not locked). |
dragging | TransformDragMode | null | The drag in progress, if any. |
scale | number | Screen px per composition px. |
width | number | |
height | number | |
startDrag | (event: PointerEvent, mode: TransformDragMode) => void | Start a drag on the selected box (what the handles call). |
UndoRedo
| Member | Type | Description |
|---|---|---|
canUndo | boolean | |
canRedo | boolean | |
undo | () => boolean | |
redo | () => boolean |
WaveformProps
Extends Omit<CanvasHTMLAttributes<HTMLCanvasElement>, "children">.
| Member | Type | Description |
|---|---|---|
peaks | WaveformPeaks | Peaks for the whole asset (from useWaveformPeaks or the renderer's computeWaveformPeaks). |
fromUs | Us | Media range to draw (for a clip: its trim start to trim start + duration). |
toUs | Us | |
gain? | number | Linear gain applied before drawing, so volume changes show (default 1). |
barWidth? | number | Bar width and gap, CSS px (default 2 and 1). |
barGap? | number | |
floorDb? | number | Quietest level drawn, dB (default −60). Heights use a decibel scale so quiet material stays visible. |
maxCanvasPx? | number | Longest side of the canvas backing store, device px (default 4096). |
Types
ProjectProviderProps
type ProjectProviderProps = {
init: ProjectSettings | ProjectDocument;
seed?: (project: Project) => void;
project?: never;
children: ReactNode;
} | {
project: Project;
init?: never;
seed?: never;
children: ReactNode;
};@miraiclip/editor
Headless editor logic for Miraiclip: timeline scale, clip drag and trim with snapping, selectors, typed commands, gestures, shortcuts, media import. No UI framework.
@miraiclip/templates
Parameterized videos for Miraiclip: a template project + a data payload → a hydrated document → export. Batch and personalized video generation, with field schemas that double as validation, UI forms, and LLM tools.