Project & time
The project store, its document, and microsecond timing.
A project holds everything: the composition document, undo history, and the playhead and selection. Create one per open video.
import { } from "@miraiclip/core";
const = ({ : 1920, : 1080, : 30 });createProject(init, options?) | |
|---|---|
init | Settings { width, height, fps, name? } for a new project, or a saved document from toJSON() |
options.historyLimit | Undo steps kept (default 500) |
State
const = .();
.; // the composition: saved, undoable
.; // ephemeral
.; // ephemeral, clip ids| Part | Changed by | Undoable | Saved by toJSON() |
|---|---|---|---|
doc | Commands only | Yes | Yes |
playheadUs | project.setPlayhead(us), the player | No | No |
selection | project.setSelection(ids) | No | No |
Never mutate state you read. Dispatch a command instead.
The document
const { , , , , , } = .().;| Field | Shape |
|---|---|
settings | { width, height, fps, frameRate?, name? } |
assets | Record<id, Asset>: Assets |
tracks | Record<id, Track>: Tracks |
trackOrder | Track ids, bottom layer first |
clips | Record<id, Clip>: Clips |
transitions | Record<id, Transition>: Transitions |
Subscribing
subscribe(selector, listener) calls the listener only when the selected value changes. It returns an unsubscribe function.
const = .(
() => ..,
(, ) => .("clips changed"),
);
();Wiring this into React, Vue or Svelte: Reading state.
Time is in microseconds
Every position and duration is a whole number of microseconds (µs): 1 second = 1,000,000 µs.
import { , , } from "@miraiclip/core";
(2.5); // 2_500_000
(1_500_000); // 1.5
5 * ; // 5_000_000Integer µs keep the math exact: no rounding drift, even over an hour at 29.97 fps.
Frames
A frame rarely lasts a whole number of µs (33,333.3… at 30 fps). One rule maps between them everywhere:
| Helper | Returns |
|---|---|
frameToUs(n, rate) | Start of frame n: the first whole µs inside it |
usToFrame(us, rate) | The frame that contains us |
snapToFrame(us, rate) | The nearest frame start |
frameCount(us, rate) | Frames in a duration |
frameDurationUs(rate) | Length of one frame (fractional) |
usToTimecode(us, rate, { dropFrame? }) | "HH:MM:SS:FF", or "HH:MM:SS;FF" with drop-frame |
import { , , , } from "@miraiclip/core";
(1, 30); // 33_334
(33_334, 30); // 1
(50_000, 30); // 33_334
(3_600_000_000, 30); // "01:00:00:00"Snap user input (drags, typed times) with snapToFrame so edits land on frame boundaries.
NTSC rates
fps accepts decimals. 29.97, 23.976 and 59.94 are stored as exact ratios:
import { } from "@miraiclip/core";
.({ : "project/set-settings", : { : 29.97 } });
.()...; // { num: 30000, den: 1001 }
(.()..); // { num: 30000, den: 1001 }Pass projectFrameRate(settings) to the frame helpers: they accept a number or a { num, den } ratio.
Save and load
import { createProject } from "@miraiclip/core";
const saved = project.toJSON(); // plain JSON: store it anywhere
const restored = createProject(saved); // history starts emptytoJSON() returns the document only. The playhead, selection and undo history aren't saved.