Editor API
Run editing actions on a mounted editor.
The editor API runs editing actions on the design of a mounted editor. Changes appear on the canvas at once, and the user can undo them like their own.
The mounted video API is available in every browser framework integration and does not require AI settings. Use the Editor API section in your framework guide for its lifecycle and complete host example. The standalone Headless Runtime is Coming soon while its public interface is simplified before launch.
Getting the handle
Pass onChatEvent. The first event is ready, and its api field is the handle:
import { useRef } from 'react';
import { VideoEditor, type ChatEvent, type EditorVerbApi } from '@layermetry/media-editor/react';
export default function App() {
const api = useRef<EditorVerbApi | null>(null);
function handleChatEvent(event: ChatEvent) {
if (event.type === 'ready') {
api.current = event.api;
const textActions = event.api.list({ category: 'text' }).map((action) => action.name);
console.log(`Text actions: ${textActions.join(', ')}`);
}
}
function applyBrand() {
if (!api.current) return;
const result = api.current.execute('canvasSetBackgroundFill', { fillColor: '#FFCC00', scopeReason: 'explicit' });
console.log(result.ok ? result.receipt?.summary : result.error);
}
return (
<main style={{ position: 'fixed', inset: 0, display: 'flex', flexDirection: 'column' }}>
<button onClick={applyBrand}>Use brand background</button>
<div style={{ flex: 1, minHeight: 0 }}>
<VideoEditor
licenseKey="YOUR_LICENSE_KEY"
onClose={() => console.log('The editor was closed')}
onChatEvent={handleChatEvent}
/>
</div>
</main>
);
}ready arrives even when the editor has no AI settings.
With the custom element, listen to the chatevent DOM event. event.detail is the chat event, and for ready it carries api.
The handle has these members:
| Member | Description |
|---|---|
execute(name, args) | Runs one action and returns its result. |
executeAsync(name, args) | Runs an action that waits before it can change anything, such as itemUnlock, and returns a Promise of its result. From version 1.0.0. |
list(filter) | Returns the actions, optionally only those of one category or one itemType. |
getItems() | Returns every item of the design. |
toolContracts | The actions, in the format that the chat service reads. |
executeTool | Runs an action for runChatTurn. See Custom chat UI. |
Running actions
api.execute(name, args) returns { ok, error } or { ok, receipt }. Actions that change items need scopeReason: 'explicit'.
Actions change the canvas the same way as the editor's own controls, and Undo in the editor reverses them. From version 1.0.0, they also obey item locks. See Item locks.
Some actions act on the editor itself, not only on the design: playbackPlay, playbackSeek, canvasSetSelection, and exportStart. readExportCapabilities asks the browser of the mounted editor which files it can export, so only the Editor API can answer it.
Item locks
@layermetry/media-editor. It needs version 1.0.0 or later; versions before 1.0.0 do not refuse an action because of a lock.A lock stops some kinds of change to one item, for example moving the logo. Your application passes the role prop to say who is editing: 'creator' ignores locks, 'adopter' obeys them, and 'viewer' changes nothing. Without role, the person is an 'adopter'. Your framework guide explains the props, the save fields and the server check, for example Item locking in React 19.
Every action obeys the locks, whether your code or the assistant runs it. A refused action changes nothing and adds no undo step. It returns ok: false, a fixed reason for your code, and an error sentence for a person:
reason | When | error, for example |
|---|---|---|
'locked' | Every item that the action names is locked in a scope that the action changes. | textSetColor was not run: headline-1 is locked (style). A locked item is never changed. An item locked in every scope is named without a list: headline-1 is locked. |
'locked' | The design does not allow new items. | clipSplit was not run: this design does not allow new items. |
'locked' | The assistant called a lock action. | itemSetLocks was not run: locks are changed only by a person, never by the assistant. |
'locked' | An ordinary action tried to write locks, isLocked or unlocks. | <action> was not run: the locks of headline-1 are changed only by the lock actions. |
'role-forbids' | The design is open as 'viewer', and the action would change it. | textSetColor was not run: this design is open as 'viewer', which may look at it but not change it. |
'role-forbids' | A lock action that only a creator may run was called by another role. | itemSetLocks was not run: only the design's creator may change locks, and this design is open as 'adopter'. |
'unlock-forbidden' | itemUnlock was called by a person who may not unlock. Your onUnlock is not called. | itemUnlock was not run: this design is open as 'adopter', and the host does not allow it to unlock items. |
'unlock-refused-by-host' | Your onUnlock said no, or failed. | itemUnlock was not run: the host refused the unlock. Its onUnlock answered false. |
When only some of the named items are locked, the action changes the others and returns ok: true. The locked items are listed in skipped, each with reason: 'locked'. An action that makes one change across several items is kept whole or refused whole: cutting and joining clips, grouping, ungrouping, a layer move, a canvas resize, and replacing part of a sound clip.
Three actions change the locks: itemSetLocks and designSetDefaultLocks for a creator, and itemUnlock for a creator or for an adopter whom you allow to unlock. They are for a person only, so the assistant is never offered them. itemUnlock waits for your onUnlock, so run it with executeAsync:
const result = await api.executeAsync('itemUnlock', {
ids: ['headline-1'],
scopes: ['style'],
scopeReason: 'explicit',
});
console.log(result.ok ? result.message : `${result.reason}: ${result.error}`);Editor actions lists the arguments of the three lock actions.
Listing actions
readTextTemplates lists the host and built-in text templates used by the Styles gallery. It accepts optional category or template ids; AI-saved templates are user-specific and are not included. See Text templates.
api.list() returns every action. Each entry has name, title, description, usage, category, and argsSchema, a JSON Schema of the arguments:
const textActions = api.list({ category: 'text' }).map((action) => action.name);The categories are text, subtitle, item, media, canvas, shape, audio, clip, read, export, playback, and label. Editor actions lists every action with its arguments.