Commands
Commands are the only write path into the engine. Instead of calling imperative methods that mutate state directly, you dispatch descriptive intents:
project.dispatch({
type: "clip/move",
payload: { clipId: "clip-1", trackId: "video-1", startUs: 1_000_000 },
});Properties
- Descriptive — a command says what should happen, not how. The engine decides how to apply it.
- Validated — every command is checked against its schema before execution; invalid commands are rejected with typed errors and never touch state.
- Deterministic — the same state plus the same command always produces the same result. This is a hard requirement for collaboration and AI replay.
- Invertible — each executed command records inverse patches, so history is exact.
- Serializable — commands are plain JSON, so they can be logged, synced, stored, or generated by an LLM.
Transactions
Group commands into a single history entry that undoes and redoes as a unit:
project.transaction(() => {
project.dispatch({ type: "clip/split", payload: { clipId: "clip-1", atUs: 2_000_000 } });
project.dispatch({ type: "clip/remove", payload: { clipId: "clip-1b" } });
});Custom commands
Consumers can register their own command types alongside the built-in catalog, with the same validation, history, and patch semantics.
AI integration
Because the command catalog ships with JSON schemas, it doubles as a tool definition for LLMs: give a model the current project state and the catalog, and it can emit a valid command sequence to perform an edit.