ai.morphareels/morpha · v1.0.395 · ai-and-media
MorphaReels is healthy: it completed an MCP handshake in 2168 ms and exposes 100 tools. It scores 56/100.
AI editor to build, animate & export layered short-form video projects via one tool catalog.
Endpoint: https://morphareels.ai/mcp (streamable-http)
No repository listed · JSON · Add to my inventory
| health | 17.3 / 25 |
| authEase | 15 / 15 |
| toolQuality | 12 / 15 |
| maintenance | 7 / 15 |
| adoption | 0 / 10 |
| usage | 0 / 10 |
| security | 5 / 10 |
Scoring v0.3, computed 2026-10-15T02:26:19.228Z.
| Checked (UTC) | Status | Latency | Error |
|---|---|---|---|
| 2026-10-14T09:00:59.152Z | Healthy | 2168 |
list_projects | List projects as { id, name, editorUrl } entries. The id is what every other tool's `projectId` argument takes. `name` is the human-readable label shown in the editor's project picker ("Untitled" when no name has been set; ids are opaque and the editor never shows them). `editorUrl` is a link that o |
list_workspaces | List the workspaces (shared team spaces) the account belongs to, as { id, name, role, memberCount } entries. `role` is the caller's role in that workspace (owner / admin / editor / viewer) — only owner/admin/editor can add projects. The `id` is the `workspaceId` argument of create_project, move_proj |
create_workspace | Create a new workspace (a shared team space) owned by the caller, and return it as { id, name, role, memberCount }. Use this when the user wants a new place to group projects — then move_project_to_workspace files projects into it, and create_project can place new ones there directly. The caller bec |
rename_workspace | Rename an existing workspace. Requires an owner or admin role in it (the same roles that may change its membership); an editor or viewer is refused. Takes the workspace id from list_workspaces. Touches only the label — membership, projects and roles are unchanged. |
open_project | Get a link that opens a project directly in the editor (the editor loads exactly this project from the URL), where the person can see the work, change it by hand and export it. Returns { name, editorUrl }; `name` is the project's label. |
show_project | Show the project in the chat as a live preview that plays and follows every edit; a multi-page project turns its pages in the preview. Call it once per project, right after creating or opening it; later edits appear in the preview without calling again. Answers { name, pages, placards, durationSecon |
create_project | Create a new project and return its server-minted id. The id is an opaque v4 UUID assigned automatically, not chosen by the caller; people see the project's `name`. By default this mints a fresh BLANK project (empty canvas, no layers) — creation is independent from cloning. Pass `fromProjectId` ONLY |
move_project_to_workspace | Move a project into a workspace, or back to the caller's personal space. Pass `workspaceId` (from list_workspaces) to place the project in that workspace — every member then sees it, with their workspace role deciding edit vs view. Pass `workspaceId: null` to detach it back to personal. Requires an |
list_collection | List the user's reusable Collection — layers they added with add_to_collection (lower-thirds, logo stings, brand intros, or any single layer). Returns { items: [{ scope, workspaceId, sourceProjectId, sourceProjectName, ownerEmail, elementId, name, kind, childCount }] }. `scope` is "personal" (from t |
add_from_collection | Add an item from the user's Collection into a project as a self-contained COPY. Pass the destination `projectId`, plus the `sourceProjectId` + `elementId` of an item from list_collection. Copies that layer (a whole group brings its children) plus its image/clip/font bytes into the destination at fre |
duplicate_project | Duplicate an existing project into a brand-new one — a full copy of its layers, animations, styles, uploaded assets, and clips. Pass the SOURCE project's `projectId`; the copy gets a fresh id automatically (ids are opaque; people see the name). Defaults the copy's name to "<source name> copy" unless |
rename_project | Update a project's human-readable name (shown in the editor's project picker). Pass an empty string to clear the name and fall back to the id. Doesn't touch any layers, animations, or styles — only the picker label. |
reid_project | Change a project's id LOSSLESSLY — re-keys its JSON, every saved version, and all assets + clips, then deletes the old id. Unlike create_project (clone), version history is preserved. Enforces the id policy: the new id is always a v4 UUID — pass `newId` to choose one, or omit to mint a fresh UUID. A |
delete_project | Move a project to Recently deleted. It leaves every project list at once and can be restored for 30 days, with restore_project or from the person's projects page; after that it is deleted for good, with its saved versions, uploaded images and clips. Returns { name, purgeAt, restorable: true }, where |
list_trash | List the projects in Recently deleted as { id, name, trashedAt, purgeAt, deletedBy, canEdit } entries. Each can be restored with restore_project until purgeAt (epoch ms), 30 days after it was deleted. `deletedBy` is { kind: "you" | "person" | "agent", label }: the caller, a teammate (label is their |
restore_project | Bring a project back from Recently deleted, with its versions, files, workspace and sharing as they were. Returns { projectId, name }. Scheduled social posts cancelled by the delete stay cancelled. Requires edit access, as delete_project does; take the id from list_trash. |
save_version | Save a version of the current project state. The person flicks between versions in the editor to compare or roll back, so one version per logical change-set (not one per tool call) is what they can revisit. `name` is shown verbatim in the version picker, so a short description reads best (e.g. "add |
list_versions | List every saved version of a project, newest-first. Returns summaries (id, name, timestamp, source, kind, version_number, cp) — not the inner project JSON. `kind` is `"bookmark"` (deliberate save, gets a v<N> label, partner-pinnable in the <morpha-video> embed) or `"auto"` (editor auto-snapshot eve |
restore_version | Load a saved version over the live project. Accepts either the version's UUID `id` or the `v<N>` shorthand (e.g. `"v6"` finds the bookmark with version_number=6); auto-snapshots are addressable by UUID only. Without `page_index` this replaces the ENTIRE project (every page) — an auto checkpoint name |
rename_version | Rename a saved version's human-readable label (what the user sees in the picker). The `v<N>` partner-facing identifier is unaffected — only the display name changes. Accepts the version's UUID `id` or the `v<N>` shorthand. Empty / whitespace-only names are rejected. |
delete_version | Permanently delete one saved version (bookmark or auto-snapshot). Accepts the version's UUID `id` or the `v<N>` shorthand. The bookmark v<N> sequence keeps gaps — numbers never re-shuffle — so any external snippet referencing the deleted `v<N>` will fail to resolve afterwards. Idempotent: deleting a |
upload_image | Upload an image into a project from a public http(s) URL or a file attached in the chat, fetched server-side. Pass `url` for a public http(s) link, or `file` for a file the person attached in the chat (a host that supports file inputs, such as ChatGPT, fills `file` with a temporary download link its |
upload_audio | Upload an audio track into a project from a public http(s) URL or a file attached in the chat, fetched server-side — the ONLY way to get an audio file's bytes into a project over MCP/HTTP (add_audio_overlay / update_audio_overlay only reference a file that is already uploaded). Pass `url` for a publ |
detect_text_regions | Return the OCR text regions detected in a clip's video frames OR a still image asset. Pass either `clip` (a video.<id>.clip filename) or `image` (an image layer's filename) — not both. Video clips are sampled every 0.3s at upload time; images are OCR'd once. Results are cached in R2 next to the sour |
safe_zones | Return horizontal 'safe band' y-ranges of the canvas where a clip's burned-in video text (subtitles, lower thirds, titles) does NOT appear, plus the inverse 'text bands' (where it does). Reads the OCR cache built at clip-upload time (see detect_text_regions). Coordinates returned in BOTH source pixe |
transcribe_clip | Return the cached transcript of a clip's audio. Generated client-side in the Morpha editor (transformers.js Whisper) and cached in R2 next to the clip; if absent, it is produced when the clip is opened in the editor. Independent of the clip's video codec — runs on the audio track only, so it works o |
clip_processing_status | Report whether a clip — or every video clip in the project, if `clip` is omitted — has been through the browser-side video-processing pipeline: proxy build, audio split, transcription, OCR (text regions). Processing never runs on the server. The preview proxy is mandatory: every processing run build |
render_video | Render the project to an MP4 on Morpha's servers, for an agent that has no browser to drive (a chat app, a Linux box). Returns { renderId, status: 'rendering', next } — call render_status with that renderId after about 30 seconds. It needs a subscription and draws on the account's render allowance, |
render_status | Check a server render started by render_video, and get its download link. Returns { ok: true, status: 'not-ready' } while it is still rendering (wait and call again), or { ok: true, status: 'ready', data: { downloadUrl, editorUrl, expiresAt, videoSeconds, scale } } once the MP4 is ready. `downloadUr |
describe_video | Structural OVERVIEW of the composition (the table of contents) — canvas size, duration, platform_safe_area (the part of the canvas TikTok / Reels UI and Instagram's feed crop leave visible: keep text, captions, logos and buttons inside it; null when nothing is covered or cropped), the backdrop summa |
inspect_layers | Full per-element drill-in — the 'open this layer' half of the browser. Returns each named element's COMPLETE record: all of its own fields plus its animation tracks (every keyframe), colour/fill tracks, track-loop (extrapolation) modes, and style. Pass the elementIds you read from describe_video; pu |
move_layer | Set a layer's static base transform. Writes x/y/w/h/rotation directly on image.<id>, video.<id>, and shapes.<id>; for group.<id> sets pivotX/pivotY (no width/height/rotation — use add_keyframe for group rotation). Also sets `scale` and `opacity`, which every layer kind carries. Note: when a layer ha |
set_pivot | Set the rotation / scale pivot anchor for an image, video, shape, or text leaf. Picks one of the 9 standard bbox anchors — corners, edge midpoints, or centre — so the layer rotates and scales around that point instead of its centre. The pivot is normalized to the bbox, so resizing the layer keeps th |
add_keyframe | Add or overwrite a keyframe on a layer's animation track. For leaves (image/video/shape), x/y/rotation keyframes are ABSOLUTE canvas-space values: x and y are the layer centre's pixel position (canvas is 1080×1920), rotation is degrees. For groups, x/y keyframes are translation offsets applied aroun |
set_keyframes_batch | Add or overwrite MANY keyframes across MANY layers in ONE call — functionally equivalent to N add_keyframe calls but with one HTTP/MCP round-trip. Pass an array of entries; each entry has the same fields as add_keyframe. Validated atomically: any invalid entry rejects the whole batch. Use this whene |
add_keyframes | Add many keyframes to ONE element's ONE property in a single call, with an optional loop mode applied in the same call. The idiomatic form when every layer in a multi-element animation gets its own track (ripple dot pulse, snowflake fall, equaliser-bar wave). Factors elementId + property out of the |
remove_keyframe | Remove the keyframe at frame N on a layer's track. Removing the last keyframe from a track restores the layer's static base value across the timeline. |
shift_track | Bulk-shift every keyframe's VALUE on one property of one layer by `delta`. Mirrors the 'select all keyframes + nudge layer' gesture in After Effects / Premiere / FCP — preserves the relative spacing of the animation but slides the whole curve. Keyframe TIMES are untouched. Use for 'move all x by -30 |
set_track_loop | Set the extrapolation mode for one property's animation track. Modes: "hold" (default — holds the boundary keyframe's value past the ends), "loop" (wraps frames past the last keyframe back to the first, restarting the animation), "ping-pong" (alternates direction each cycle, bouncing back and forth) |
add_image_layer | Add an image layer. The image must already be uploaded: upload_image takes a web URL or a file attached in the chat, and a file from the person's disk is uploaded in the editor. Every upload returns { filename, name, width, height }: pass `filename` (the stored file's id) here, and `name` as the lay |
add_video_layer | Add a video layer. The clip must already be uploaded; clips are uploaded in the MorphaReels editor. An upload returns { filename, name }: pass `filename` (the stored clip's id) as `clip`, and `name` as the layer's label. To duplicate an existing layer, reuse its clip filename — the editor auto-assig |
add_shape | Add a shape layer. `kind` selects the primitive: rect | ellipse | triangle | star | pentagon | hexagon | arrow | heart | rounded-rect | diamond | parallelogram | trapezoid | semicircle | ring | pill | cross | heptagon | octagon | star-4 | star-6 | sparkle | burst | arrow-left | double-arrow | chevro |
add_curve | Draw an editable arrow / curved line — a stroked quadratic bezier with an arrowhead. Specify the two endpoints (x1,y1)→(x2,y2) in canvas pixels; `bend` pushes the midpoint perpendicular (px, 0 = straight line, positive/negative curves either way). `color` #rrggbb, `stroke_width` px, `arrow_head` non |
duplicate_layer | Composition primitive: clone a leaf (image.<id> / video.<id> / shapes.<id> / text.<id>) `count` times, applying a cumulative per-step transform — copy i is offset by i·(dx,dy) px, rotated by i·d_rotation°, and scaled by d_scale^i. One call instead of dozens: a circle of stars (dx/dy + d_rotation), a |
remove_layer | Delete a video, image, text, or shape LEAF layer. Errors on a group.<id> (dissolve it with ungroup_layers instead) and on a pinned layer such as the canvas backdrop. Deleting a video layer also takes everything welded to that clip: its welded audio overlay(s) and its welded caption lines, both of wh |
reorder_layer | Move a layer within its parent's siblings. newIndex is 0-based among siblings (root list when ungrouped, or the parent group's children when nested). 0 = bottom of that subtree; last = top. |
set_style | Set style fields on a layer. Only the fields you pass are changed; omit a field to leave it untouched. Covers border/radius/shadow (including borderAlign — inner|center|outer border position) plus image-only fields: fit (stretch|cover|contain), anchorX/anchorY (0..1, where the source anchors when cr |
set_layer_fill | Set a layer's fill. The canvas backdrop is the pinned is_background image_layer (its element id is exposed via describe_video as background.elementId; the literal 'background.canvas' is also accepted as a synonym); null is rejected on the backdrop. Shapes require a Fill (null/missing is rejected). I |
set_text_background | Add or update the rounded background box behind a TEXT layer (text.<id>) in one call — sets the backdrop fill plus the box's padding, corner radius, and optional stroke. Pass only the fields you want to change. New text layers are already text_autofit "hug", so padding alone shrink-wraps the box to |
set_group_box | Set a group's backdrop rect size. The rect is centred on (pivotX, pivotY) in group-local space and transforms with the group. Either dimension at 0 hides the backdrop entirely. |
add_color_keyframe | Add or overwrite a colour keyframe on a fill track. Targets a leaf (shapes.<id>, image.<id>, video.<id>, group.<id>). The canvas backdrop is the pinned is_background image_layer (the literal 'background.canvas' is accepted as a synonym for its element id). The value is a Fill — adjacent keyframes cr |
remove_color_keyframe | Remove the colour keyframe at an exact frame on a fill track. No-op when no track or no matching keyframe exists. Removing the last keyframe drops the track entry. |
fade_layer | Fade a layer's opacity between two frames in one call. |
set_layer_visible | Show or hide a layer instantly by writing a single opacity keyframe (1 or 0) at frame 0. |
apply_preset | Apply a canned animation preset to a layer. |
apply_preset_stagger | Apply the same preset to a LIST of layers with a per-element startFrame offset — one call instead of N apply_preset calls. For diagonal pop-in grids, sequential list reveals, ring-pulse sweeps. The startFrame for entry i is `startFrame + i * stagger`. Order the elementIds in the visual order you wan |
group_layers | Wrap sibling elements in a new group, which the Layers panel shows as one named row the person can select, move and animate as one thing (a butterfly assembled from wings + body + antennae, an icon built from primitives, a card + its title + badge, a lower-third). `name` is that row's label. The gro |
ungroup_layers | Dissolve a group: its children are spliced into the group's parent at the group's old position. The group's animation tracks are discarded — children survive at their last positions but inherit none of the group's keyframes. |
set_group_parent | Move an element into a group (or out to root). Refuses to place a group inside its own descendants. |
rename_group | Rename a group. Pure cosmetic — labels appear in the Inspector and describe_video output. |
add_to_collection | Add a layer to the user's reusable Collection. Pass ANY element id — a leaf (text.<id>, image.<id>, …) or a whole group.<id> (a lower-third, logo sting, brand intro). It then appears in the user's Collection (list_collection), where they — and, if this project is in a workspace, every teammate — can |
remove_from_collection | Remove a layer from the user's Collection so it's no longer offered for reuse. Pass the element id that was added with add_to_collection. Copies already placed in other projects are unaffected (they're self-contained). No-op if the id isn't in the collection. |
embed_project | Embed another of the user's projects ("a morpha") inside this one as a version-pinned band. The source's layers are inlined into the host as a collapsible group, re-keyed to fresh ids, pinned to one immutable version of the source. Pass the source project's id as source_morpha_id (and optionally a v |
add_audio_overlay | Add an audio overlay (mp3/m4a/wav/ogg) scheduled at a frame-aligned start. The asset must already be uploaded (upload_audio, or the editor for a file from the person's disk); pass the upload's returned `filename`, and its `name` as the track's label. 30 fps; convert seconds with frames = round(s * 3 |
remove_audio_overlay | Delete an audio overlay by id. |
update_audio_overlay | Patch an existing audio overlay. Only the fields you pass are changed. Pass endFrame:null to clear it (revert to natural-length playback). |
set_video_layer_trim | Patch a video layer's trim window: source_in_frame (frame in source to start), source_out_frame (frame in source to stop, or null for natural end), timeline_start_frame (where on the project timeline the slice begins). Only the fields you pass are changed. Use this to clip out a segment of a source |
set_layer_block | Set (or replace) a layer's timeline BLOCK — the [start, start+duration) window it exists for. The layer is drawn ONLY inside that window, and its animation keyframes are sampled RELATIVE to the block start, so moving or trimming the block re-anchors its intro instead of leaving it behind. This is ho |
set_layer_transition | Set how a layer ENTERS at the start of its on-timeline window and LEAVES at the end, instead of popping. The transition is EDGE-RELATIVE — only a length and a look are stored — so it rides the edge through every later trim, slide or clip retime. Prefer this over fade_layer / apply_preset whenever th |
set_embed_start | Place an embedded morpha band on the host timeline: set its TIME ORIGIN (the frame it starts). The band's whole inner reel plays relative to this frame, so its intro animations fire when the band appears instead of at 0:00 (the fix for 'the embedded intro doesn't animate'). Keeps the band's current |
shift_group | MOVE a group and everything inside it along the timeline, keeping its internal timing intact — the 'slide this whole section later' operation. A plain group is a relative CONTAINER: it has no window of its own, so on the timeline it spans the hull of its contents, and moving it slides the whole subt |
set_group_window | TRIM a group's own visible window — the [start, start+duration) range over which the group and its subtree are drawn. The contents are NOT moved or deleted: this clips what is shown, so use it to hide the head or tail of a whole section. Writing a window overrides the group's derived contents-hull f |
set_duration | Author an EXPLICIT composition length in seconds, pinning it (duration_authored=true) so the auto-fit no longer drives it. Morpha normally DERIVES the comp length from content (the furthest keyframe / video window / audio end); this overrides that with a fixed length — the stage becomes a fixed canv |
fit_duration_to_content | Clear an authored composition length and return to AUTO-FIT — the comp length tracks the furthest content (keyframe / video window / audio end) again, with a 1-second floor. The inverse of set_duration. NOTE: headless (no loaded media) this can UNDER-fit when a video layer's source_out_frame is null |
cut_range | Ripple-delete a time window [startFrame, endFrame) — remove that span and pull all later content earlier by delta = endFrame - startFrame (the NLE 'ripple delete' / 'close gap'). Shifts every keyframe, colour keyframe, marker, audio overlay, loop region, and start_at through the cut (a speed ramp is |
set_embed_origins | Replace the project's embed allowlist — the hostnames permitted to load this project through the public <morpha-video> embed. Pass the full desired list; it overwrites the previous one. An empty array turns embedding OFF (the public embed endpoint 404s the project). Each entry is normalized to a bar |
add_embed_origin | Add one hostname to the project's embed allowlist (the hostnames permitted to load the public <morpha-video> embed). Idempotent — re-adding an existing entry is a no-op. The origin is normalized to a bare lowercased hostname (scheme/port/path stripped). Morpha sends that website no request; any page |
remove_embed_origin | Remove one hostname from the project's embed allowlist. Idempotent — removing an entry that isn't present is a no-op. Removing the last entry turns embedding OFF (the public embed endpoint 404s the project). Morpha sends that website no request; a page on it stops loading the project. Reference: htt |
set_custom_font | Register a typeface Morpha does NOT ship, so text layers can use it by family name via font_family (exactly like a built-in family). Families already in the built-in catalogs (anything list_fonts returns from google/bunny/fontshare/fontsource/velvetyne) are REJECTED — they need no registration; just |
list_fonts | List available font families across every source the editor knows about (Google + Bunny + Fontshare + Fontsource + Velvetyne) PLUS the project's user-uploaded custom_fonts (surfaced as source: "custom"). Use this to discover families before set_layer_text / add_text_layer when you don't know what to |
set_layer_text | Edit an existing text layer (text.<id>). Patches its text content, font, size, colour, and full type styling — pass only the fields you want to change. Does NOT create layers and does NOT touch image layers; use add_text_layer to make a new one. `font_family` is a Google Fonts family name (e.g. "Ant |
add_text_layer | Create a new text layer — a first-class leaf that animates, groups, and z-orders exactly like an image or shape. The renderer draws live typeset text (multi-line, auto-fit to the box). Defaults: x/y = canvas centre, width 900, height 320, font_family "Hanken Grotesk", text_size derived from existing |
add_caption_track | Build a caption track from pre-timed lines (e.g. derived from transcribe_clip's word timings). mode "line-sync" (default) creates one text layer per line, each shown only during its [startFrame, endFrame) window via hold-eased opacity keyframes — the active-line karaoke read; mode "static" makes a s |
split_caption_line | Split one caption line into two at a COMPOSITION frame strictly inside its window (in the editor this is the playhead). The right half is a full clone — style, band geometry, weld — and the text divides at the word gap nearest the split point (a single-word line keeps its text on the left; the right |
merge_caption_lines | Merge two or more caption lines into one. The earliest line survives with the union window and the time-ordered texts joined by spaces; the others are removed. All lines must share one flavour — every one welded to the SAME clip, or every one standalone — and no other caption line on that track may |
rename_layer | Set the human-readable name of a video / image / shape / text layer — the label shown in the Inspector, and the basis for the layer's auto-derived <morpha-video> embed attribute (so renaming a layer to "caption" makes the embed attribute `caption`). Pass an empty string to clear the name. For groups |
set_loop | Set the project's loop section: the whole composition repeats once per value, with one field of one layer varying across the repeats. Builds one pass per value, each setting `field` of `elementId` to that value — e.g. a caption text layer cycling through several strings. Pass an empty `values` array |
set_canvas_size | Resize the ACTIVE page's canvas to width × height pixels. The composition is scaled UNIFORMLY to fit the new frame (a single factor s = min(newW/oldW, newH/oldH), so nothing distorts — a circle stays a circle) and then re-centred so the old composition centre maps to the new canvas centre. Every lay |
set_image_filename | Repoint an existing image layer at a different uploaded asset — keeps the layer's id, position, size, animations, and styles; only the bitmap changes. The image must already be uploaded (upload_image for a web URL or a file attached in the chat; the editor for a file from the person's disk); pass th |
set_video_clip | Repoint an existing video layer at a different uploaded clip — keeps the layer's id, position, size, animations, styles, and trim window; only the source mp4 changes. The clip must already be uploaded (the editor's Add video); pass the `filename` the upload returned, and its `name` as the label. Use |
set_matte_source | Set (or clear) a track matte — the host shows only where the matte source is opaque. The HOST can be a leaf (image.<id>, video.<id>, shapes.<id>, text.<id>) OR a group.<id> (a group is a layer of sorts): a group host clips ALL its composited children to the source shape's path — e.g. a marching chev |
freeze_frame | Freeze the picture at a frame: the clip is CUT there and a still of that frame is inserted between the halves, pushing everything after it later (the NLE 'frame hold'). This is how you hold a moment — play, freeze, continue. The still is an ordinary IMAGE layer showing that frame for `holdFrames` (d |
set_clip_speed | Play a clip slower or faster at a CONSTANT rate — the normal way to retime a clip. 1 = source speed, 0.5 = half speed, 2 = double speed; range [0.1, 8]. The trim is unchanged, so the clip's length on the timeline changes to suit: at 0.5x it occupies twice as many frames, at 2x half as many. Audio is |
add_speed_keyframe | Add or overwrite a speed-ramp (time-remap) keyframe on a video layer, for a rate that CHANGES over the clip. `frame` is a PROJECT-timeline frame and must sit on the clip (at or after its timeline_start_frame); the curve itself is anchored to the clip, so moving the clip carries the ramp with it and |
remove_speed_keyframe | Remove the speed-ramp keyframe at `frame` (a PROJECT-timeline frame — the same value add_speed_keyframe and inspect_layers report) on a video layer. Removing the last keyframe clears the speed_keyframes array entirely (restoring 1× playback). |
set_video_layer_muted | Mute or unmute a video layer's baked audio (silenced in both preview and export). The processing pipeline's audio-split step sets this true after demuxing the clip's audio into a standalone overlay track (NLE-style linked A/V), so the source audio doesn't double with the overlay. Pass muted:false to |
add_page | Append a page to the project — works on any project, turning a single-page video into a multi-page one. Without duplicate_index a blank page is appended, sized to the project's canvas. With duplicate_index the page at that position is deep-copied (a fresh id is minted). There is no limit on page cou |
delete_page | Remove the page at `index`. Fails on an out-of-range index or when only one page remains — a project must keep at least one page. The active page stays active; when the active page itself is deleted, active_index falls to the neighbouring page (the one that slid into its position, or the new last pa |
reorder_pages | Move a page from `from_index` to `to_index`. The remaining pages shift to fill the gap; active_index is rewritten so it keeps pointing at the same page it did before the move. Fails on out-of-range indices. |
select_page | Switch which page is ACTIVE — the page the content tools target. Subsequent describe_video / inspect_layers / all content tools read and write this page until the active page changes again. Pages are addressed by 0-based index from describe_video's pages block. Selecting the already-active page is a |