Agent, CLI, API and plugins
Every edit in Edit mode is a command: run it from the command palette, ask the agent, script it with the popcraft CLI, call it over the REST API, or from a plugin.
The timeline doesn't edit the file itself: every cut, trim, blend and mix it does is the sequence.edit command,
and reading a sequence is sequence.get. The same two commands are the agent's edit_sequence and
get_sequence, the plugin methods editSequence and getSequence, and popcraft run … sequence.edit on the command
line, so all of them edit exactly alike, one undo step each, and sync to everyone in the file.
The command palette
Description
The AI trailer in Edit with the playhead inside the second shot. ⌘K opens the command palette; typing razor finds Add edit to all tracks, and Enter cuts every track at the playhead.
- Press ⌘K.
- Type what to do: razor, ripple, mark in, duck, next edit. Edit's rows are under Video editing, with their shortcuts; a row that needs picked clips is greyed out until you pick some.
- Press Enter.
| Palette row | Keys |
|---|---|
| Open Edit workspace | ⌘⇧E |
| Add edit at playhead | ⌘B |
| Add edit to all tracks | ⌘⇧B |
| Ripple delete | Shift+Backspace |
| Delete clips (leave gap) | Backspace |
| Ripple trim start to playhead | Q |
| Ripple trim end to playhead | W |
| Mark in, Mark out | I, O |
| Clear in and out | ⌘⇧X |
| Lift in to out | ; |
| Extract in to out | ' |
| Close gap | |
| Enable / disable clips | Shift+E |
| Duck music under voice | |
| Go to next edit, Go to previous edit | ↓, ↑ |
The agent
Ask in words: "cut a 20-second version of this sequence", "put the logo frame over the last three seconds at 80%
screen", "duck the music under the voiceover", "add a one-second push between every scene". The agent reads the
sequence with get_sequence and edits it with edit_sequence, plus the composition tools for making sequences and
transitions.
| Tool | What it does |
|---|---|
get_sequence | Reads sequences by track: V1's scenes, the clips on V2 and up (with opacity, blend, fades, speed), the audio clips on A1 and down (with gain keys), each track's lock, hide, mute, solo, level and pan, the in and out marks, markers, and every edit point. Ids for edit_sequence |
edit_sequence | One edit (op) on one sequence (id): every kind in the table below |
create_composition | A new sequence from frames |
edit_composition | Adds, moves and removes V1 scenes, sets transitions, renames, markers |
get_compositions | Lists the file's sequences |
add_audio, generate_audio | Adds sound from the media store, or generates music or effects |
generate_video | Generates a video clip from a prompt |
export_mp4, export_webm, export_gif, export_png_sequence | Exports |
The edits
sequence.edit takes { id, op }: id is the sequence and op one edit, with a kind. Times are in ms of the
sequence; tracks are V1, V2… and A1, A2….
kind | What it does | Main fields |
|---|---|---|
razor | Cut at a time | at, tracks? (default: every unlocked track), clips? |
delete | Delete clips | clips, ripple? (close the gap; V1 always closes) |
range | Lift or extract between two times | in, out, extract? |
closeGap | Close the gap at a time | track, at |
trim | Move a clip's edge | clip, edge (in or out), to, ripple? |
trimToPlayhead | Q and W | track, at, side (start or end) |
slip | Change what part of the source plays | clip, dt |
roll | Move the cut after a clip | clip, dt |
slide | Move a V2+ clip, its neighbours trimming | clip, dt |
place | Put a frame on V2 and up | track (1 is V2), frame, start, length?, in?, mode? (overwrite or insert) |
move | Move a clip in time or to another track | clip, start?, track? (0 is V1), mode? |
stretch | Change a clip's speed by its length | clip, length |
clip | A clip's settings | clip, opacity?, blend?, disabled?, muted?, reverse?, fadeIn?, fadeOut?, name? |
track | A track's settings | track, locked?, hidden?, muted?, solo?, name?, gain? (1 is unity), pan? |
addTrack | Add a track | type (video or audio), at? |
removeTrack | Delete a track and its clips | track (not V1) |
duck | Duck a music track under voice tracks | track, under, level? (0.25), ramp? (250 ms) |
marks | Set or clear in and out | in?, out? (null clears) |
addAudio | Add a sound from the media store | mediaHash, start?, lane?… |
audio | An audio clip's settings | clip, start?, lane?, fadeIn?, fadeOut?, fadeCurve?, pan?, muted?, loop?… |
trimAudio | Trim an audio clip | clip, edge, delta |
gainKey | A volume key on an audio clip | clip, t, v |
removeAudio | Remove an audio clip | clip |
splitAudio | Cut an audio clip | clip, at |
crossfade | Crossfade two audio clips | clip, with, duration? |
Blend modes are NORMAL, MULTIPLY, SCREEN, OVERLAY, DARKEN, LIGHTEN, COLOR_DODGE, COLOR_BURN,
HARD_LIGHT, SOFT_LIGHT, DIFFERENCE, EXCLUSION, HUE, SATURATION, COLOR and LUMINOSITY.
The CLI
popcraft run runs a command on a .popcraft file (or a cloud file) and saves it. See Command line.
# Read the sequence: tracks, clips and their ids
popcraft run trailer.popcraft sequence.get --json
# Cut every track at 6 s, then ripple-delete the second half of the first shot
popcraft run trailer.popcraft sequence.edit --id comp-1 --op '{"kind":"razor","at":6000}'
popcraft run trailer.popcraft sequence.edit --id comp-1 --op '{"kind":"delete","clips":["clip-9"],"ripple":true}'
# A logo frame over the last 3 s on V2, screened at 80%
popcraft run trailer.popcraft sequence.edit --id comp-1 --op '{"kind":"place","track":1,"frame":"12:40","start":29000,"length":3000}'
popcraft run trailer.popcraft sequence.edit --id comp-1 --op '{"kind":"clip","clip":"$LAYER","opacity":0.8,"blend":"SCREEN"}'
# Several edits saved once, in order
popcraft run trailer.popcraft --batch @edits.jsonedits.json:
[
{ "command": "sequence.edit", "params": { "id": "comp-1", "op": { "kind": "addTrack", "type": "audio" } } },
{ "command": "sequence.edit", "params": { "id": "comp-1", "op": { "kind": "duck", "track": "A2", "under": ["A1"] } } },
{ "command": "sequence.edit", "params": { "id": "comp-1", "op": { "kind": "track", "track": "A2", "gain": 0.8 } } }
]Export from a script
popcraft run trailer.popcraft export.mp4 --composition comp-1 --resolution 1080p --out trailer.mp4The CLI renders it in a headless editor, with the sound. popcraft commands export.mp4 lists every option.
The REST API
The same commands run on a cloud file with POST /api/v1/files/{key}/commands (see Editing a design):
curl -X POST -H "Authorization: Bearer pop_…" -H "content-type: application/json" \
"https://popcraft.app/api/v1/files/$KEY/commands" -d '{
"commands": [
{ "command": "sequence.get", "params": {} },
{ "command": "sequence.edit", "params": { "id": "comp-1", "op": { "kind": "razor", "at": 6000 } } },
{ "command": "sequence.edit", "params": { "id": "comp-1", "op": { "kind": "marks", "in": 12000, "out": 15000 } } },
{ "command": "sequence.edit", "params": { "id": "comp-1", "op": { "kind": "range", "in": 12000, "out": 15000, "extract": true } } }
]
}'Up to 100 commands run in order and are saved as one edit; anyone in the file sees it merge in. Exports don't run over the REST API: use the CLI. Every command's request and answer: Endpoints.
Plugins
A plugin with the write permission calls the same edits (see the plugin API):
// Read the open sequence (or every one): { sequences, open }
const { sequences } = await popcraft.getSequence({})
const seq = sequences[0]
// Cut every track at each marker, then duck A2 under A1
for (const m of seq.markers ?? []) await popcraft.editSequence({ id: seq.id, op: { kind: 'razor', at: m.t } })
await popcraft.editSequence({ id: seq.id, op: { kind: 'duck', track: 'A2', under: ['A1'] } })