Agents & MCPTool reference

Build scenes

Read a scene's context, write its HTML and land it through the real checks. 63 tools.

On the main list

The tools a client sees when it connects.

get_scene_context

Main listRead-only

Scene context

Everything to write ≤10 scenes against: brief, beats, words on the scene clock, bars, cues, look, neighbours. Free.

InputTypeDescription
scene_ids requiredarrayScene ids (≤10).
detail"compact" | "full"Default compact.

get_authoring_contract

Main listRead-only

The vocabulary you author in

Optional kernels and document rules. No args = index; kernel:"<name>" = one in full (names:"a,b" = just those records); view:"shell" = skeletons (kernel:"<skeleton>" for one). Free.

InputTypeDescription
kernelstringKernel (shell: skeleton)
view"index" | "records" | "shell" | "full"
role"knob" | "machinery" | "marker" | "receipt" | "published"Narrow the records.
namesstring

put_scenes

Main listSpends credits

Land compositions

Land ≤20 HyperFrames compositions, one per scene, through the real gates; verdicts inline. <audio> is not mixed: voice goes in speech. SPENDS CREDITS for speech text. check:true lands AND looks in one call. Scenes alike: one template + per-scene data.

InputTypeDescription
scenes requiredarrayOne per scene.
dry_runbooleanValidate only.
checkboolean | stringThen look: true, or a preset (quick, layout-check, sync-check, player-check, dense-motion).
asyncboolean
templatestringOne document for every scene that sends data: {{key}} is filled HTML-escaped, {{{key}}} raw.

project_read

Main list

Read project files

Read ≤20 project files. Free.

InputTypeDescription
project_id requiredstringProject id.
paths requiredarray

project_write

Main list

Write a project file

Write a file (.json merges) through its owning service; a new scene folder creates the scene there. Diagnostics + diff. Guide: "Project as files".

InputTypeDescription
project_id requiredstringProject id.
path requiredstringA file path.
content requiredstring | object
dry_runbooleanVerdict only.

Callable by name

Not listed on connect, to keep the list short. Call them directly by name, or find them with tools.

add_element

Spends credits

Add an element to a scene

Add one element — motion design, an image, or a text box — to an existing scene. SPENDS CREDITS (the new element is generated). Use for "put a chart in scene 4" or "add a title card". Asynchronous; the scene shows as generating until it resolves.

InputTypeDescription
scene_id requiredstringScene id.
kind required"motion-design" | "image" | "text"What to add.
prompt requiredstringCreative prompt for motion-design/image, or the literal copy for text.
at_secondsnumberScene-local start time in seconds. Default 0.
reference_scene_idstringmotion-design only: author the element to MATCH that resolved scene's composition design (layout, type, palette, motion).
reference_image_urlstringmotion-design only: a picture the author should LOOK AT (a library asset url, an import_asset result, a generate_image result). Keep prompt to intent — what to keep, what to change — rather than describing the picture.

author_formula

Invent a new look — brand-mark motion or caption motion

Author a NEW look as a FORMULA: ingredients in a row, linted at write, instead of waiting for a code drop. One tool for both systems, chosen with slot.

slot:"bug" — the brand mark's motion. spec is {recipe, params} over seven carriers: three on the NOTATED clock, three on the MEASURED one, and one that BUILDS something. Notated (a list of moments): "entry-exit" (in, out, rise, from, ease), "beat-envelope" (on, to, attack, decay, cooldown, prop) and "trigger-lift" (on, rest, attack, hold, release); on is a ruler — bar, beat, 2beat, hit, cam. Measured (a value per frame off the analysed audio): "signal-follow" (channel, prop, to, rest, floor, gain, smooth) rides a channel continuously; "blob" (channel, size, color, wobble, swell) puts a backdrop behind the mark whose CONTOUR deforms; "ring" (channel, bars, radius, length, width, reach) surrounds it with a field of bars. The last two emit LAYERS behind the mark rather than moving the mark itself. Built: "cta" (label, every | on, first, attack, hold, release, reach, pad, side, fill, color, size, weight, tracking, case, font) is the one recipe that does not just move the uploaded logo — the mark opens into a PILL, shows a line of type, and closes again. Use it for a subscribe prompt, a handle, a URL: anything the film should SAY periodically rather than wear permanently. The copy is a real text element in the render's own fonts, so it can be re-worded without touching the logo and it is sharp at any export size. Cadence is editorial — every seconds from first — because a call to action belongs every twenty seconds, not on every downbeat; name a ruler with on (usually "hit", from set_cues) when it should land on a moment instead. side is which way it opens, away from the frame edge the mark sits on. Reacts to no audio, so it works on a film with neither narration nor a bed. channel is always qualified by its source — "vo:speech.loud", "music:band.low" — because a project with narration AND a bed has two different answers for "the audio". get_scene_context reports which sources a scene actually has, and draws the waveform. You choose the slug. The row is HELD until you set status:"active".

slot:"caption" — how words move. spec is a caption formula: recipe, succession, accent, entry, life, exit, field, slot, paint, fonts. The id is MINTED from the title, because the renderer keys the compiled template on the row id; the reply tells you the id it used. Saved private — reaching the shared catalog is moderated, not a status flip.

Both are validated by COMPOSING the real thing and checking what comes out, not by matching a schema: either grammar can be valid JSON and still name an ingredient that does not exist, which renders as a duller look with no error anywhere. A bug spec that could strobe, reach outside its own element, or stop being the shape it claims to be is refused outright — amplitudes are capped, a blob's corners cannot leave the band where it is still a blob, and a layer cannot grow past the backdrop budget. Use list_formulas to see what exists. Free.

InputTypeDescription
slotstring"bug" (brand mark motion, the default) or "caption" (how words move).
slugstringbug only: lowercase name for the look, e.g. "judder". Cannot shadow a built-in.
title requiredstringDisplay name, up to 80 characters. For a caption formula the id is minted from this.
hintstringbug only: one line the picker shows — what the viewer will SEE.
spec requiredobjectThe ingredients. bug: {recipe, params}. caption: {recipe|entry|life|exit|field|…}.
tiersarraybug only: mark tiers this suits — raster, svg, lockup, template.
statusstringbug only: "held" (default), "active" to make it usable, "disabled" to retire it.

batch_add_elements

Spends credits

Add an element to many scenes

Add the SAME element to MANY scenes in one call. Pick scenes with where (see get_inventory) or scene_ids; prompt is a template filled per scene with {chapter_title} {chapter_number} {scene_number} {scene_title} {index}. kind motion_design / image spend credits PER SCENE (text is free): call with dry_run:true first, show the targets and cost_estimate, confirm, then run. Elements resolve in place (poll get_project_status).

InputTypeDescription
project_id requiredstringProject id.
whereobjectScene selector: scene_ids[], chapter_ids[], family (title-card|stat|list|diagram|illustration|caption|media|engine|mixed, or an array), text_contains, title_contains, state (resolved|prompted|placeholder|generating|error), position (first-in-chapter|last-in-chapter), has_composition, cast.
scene_idsarray
kind required"motion_design" | "image" | "text"
prompt requiredstringPrompt template.
at_secondsnumberScene-local start time (default 0).
areaobjectGrid placement {col,row,w?,h?}; omit for a centered 6×6.
dry_runbooleanTargets + quote only.
max_targetsnumberCap on targets (default 20, max 60).
reference_scene_idstringmotion_design only: author every added element to MATCH that scene's composition design.

browse_themes

Read-only

Browse themes as palettes

Show the available themes as what they actually are — palette, type and a description — instead of a list of slugs. Free. Use this whenever the user is CHOOSING a look, or when you are about to choose one for them: a theme picked by name alone is a guess at a visual decision, in a product where the visual decision is the point.

In a client that renders MCP Apps the user sees the palettes directly and can tell you which one they want. Elsewhere the same data comes back as text and you should describe two or three candidates and say why. Either way, name the reason for your pick so they can correct it.

PASS project_id WHENEVER THERE IS A PROJECT IN PLAY. With it the user can apply a theme by clicking it and you have nothing further to do; without it the picker can only tell them a slug to repeat back to you, which is a worse version of the same conversation.

To SUGGEST rather than list everything, pass slugs — your shortlist of 3-6, best first — and prompt, the question you are asking ("Three looks that suit a calm finance explainer — which one?"). The picker then shows only those.

InputTypeDescription
project_idstringThe project the user is choosing a look FOR. Turns the picker from a poster into a control: clicking a theme applies it. Omit only when no project exists yet.
current_slugstringThe theme the project uses now, so it shows as already-chosen rather than as one of fifty equals. From get_project or get_theme.
slugsarrayA shortlist to show instead of the whole catalog, best first. Omit to show every theme.
promptstringThe question the picker asks, shown above it — when you are asking the user to choose.

build_footprints

A place's real plan from OpenStreetMap, as a 3D model

The mapped plan of a place (lat/lon centre, a square size_km across, up to 4 km) as ONE 3D model in your library, for window.__tcThree scenes: buildings extruded from their OpenStreetMap outlines (height from the map, else 5 m historic / 8 m modern), streets as paving, city walls as walls, with per-vertex colour; one mesh per part (walls, roofs, streets, city-walls) with UVs in metres, so each part can take its own tiling texture. roofs:"hip" gives every building a pitched four-sided roof instead of a flat top. historic_only:true keeps an archaeological site (features tagged historic, and features inside a mapped site of 5 ha or more) and drops the modern town around it. Pass origin_lat/origin_lon = a build_terrain frame's lat/lon and the plan shares its frame (metres; +x east, -z north, +y up; base at y = 0, so drape it by adding the ground height). frame also carries the city walls and every building centre, so procedural fill goes only where the map has nothing. Filed with its licence (ODbL: credit © OpenStreetMap contributors). The same request returns the same asset. Free.

InputTypeDescription
lat requirednumberCentre latitude, degrees.
lon requirednumberCentre longitude, degrees.
size_kmnumberWidth of the square, km (0.1–4). Default 1.5.
origin_latnumberThe frame's origin latitude (a build_terrain frame's lat). Default the centre.
origin_lonnumberThe frame's origin longitude (a build_terrain frame's lon). Default the centre.
historic_onlybooleanKeep only the historic site: what is tagged historic or lies inside a mapped archaeological site (default false).
roofs"flat" | "hip"Roof form: 'flat' (default) or 'hip' (a pitched, four-sided tile roof on every building).
namestringModel name in your scenes and library, e.g. "pompeii-plan".

build_terrain

Real terrain for a place, as a 3D model

The real ground around a place (lat/lon centre, a square size_km across) as ONE 3D model in your library, for window.__tcThree scenes: elevation from the open Terrain Tiles (SRTM, GMTED2010, ETOPO1 …), meshed on a grid with per-vertex colour (water, shore, lowland, hills, rock, snow), filed with its licence (cc-by: credit the elevation sources). A film shot in one place builds ONE terrain and every scene shoots it: a flyover, a dive to street level, a city you build on top. Returns asset_id, frame (metres; +x east, -z north, +y up; origin = lat/lon at sea level; m_per_deg_lat / m_per_deg_lon place any lat/lon on it; min_m / max_m) and usage: load it with { models: [{ name, src: "tc-asset:<asset_id>" }] } and the gltf@1 module. resolution is vertices per side (default 256, up to 512); exaggeration stretches height (default 1); sea_level:false keeps the sea floor. The same request returns the same asset. Free.

InputTypeDescription
lat requirednumberCentre latitude, degrees.
lon requirednumberCentre longitude, degrees.
size_kmnumberWidth of the square, km (0.5–200). Default 20.
resolutionintegerGrid vertices per side (32–512). Default 256.
exaggerationnumberHeight multiplier (0.1–10). Default 1.
sea_levelbooleanDraw ground below 0 m as flat water (default true).
namestringModel name in your scenes and library, e.g. "bay-of-naples".

claim_scene

Say you are working on a scene

Take an ADVISORY, time-limited claim on a scene: "I am working on this" — shown as a lock on the scene in the editor, with your label. It never blocks anyone (other writers still land), and others holding the scene do not stop yours: they come back in held_by_others so you can back off or carry on. Call it again to renew (the heartbeat: about every third of the ttl while you work); it lapses on its own after ttl_seconds (default 90, max 900) or when you release_scene. Use it around a multi-step pass on a scene (read, author, check, land): claim at the START of the pass, so the person watching the editor sees you working through the thinking time between writes, and release_scene when you land it. Skip it for one quick write: a write already shows in the editor on its own. put_scene_composition / update_scene / edit_elements answer with claimed_by when ANOTHER actor holds the scene you just wrote to, so you can tell you may have overwritten them. Free.

InputTypeDescription
scene_id requiredstringScene id (from get_storyboard).
labelstringWhat the lock reads, e.g. "Claude · scene 4 pass". Defaults to the connection's name and session.
ttl_secondsintegerSeconds the claim lasts unless renewed. Default 90.

copy_scenes

Copy scenes into another project

Copy scenes (scene_ids, or every scene of a chapter_id) from from_project into to_project BY REFERENCE: the composition is shared by its immutable url, so its pinned modules and linked kernels come along and nothing is pasted; the call and its answer are a few hundred bytes. Carries the source, scene metadata, entry/exit state, length, title and the scene's own sound (include_sound:false drops it). Narration and voice travel with a scene when every scene of its script block is copied (the block and its voice file land in the target chapter); a scene whose block is only partly selected is a silent scene of the same length (narration:false forces that). move:true then soft-deletes the source scenes and archives the narration blocks they emptied, so it moves rather than copies; organize op restore {archive_id} undoes it. A whole chapter_id copied into a new chapter also brings the chapter's sound: its score cue and music/sfx clips, the conductor (bar 1 moved with the chapter) when the target has no tempo map, and the music/ program files when the target has none, so it plays as it did with no re-render (result.sound says what came). Lands in to_chapter_id, or in a new chapter named after the source one; position is 1-based. A scene made for another shape than the target (16:9 into 9:16) takes the target's frame and fits whole inside it when it is all full-frame gen:html; otherwise it keeps its own (scenes[].frame says which). Needs read on the source and write on the target. Returns the new scene ids. dry_run:true plans it. Free.

InputTypeDescription
from_project requiredstringSource project (read only).
scene_idsarrayScenes to copy, in this order.
chapter_idstringOr: every scene of this source chapter.
to_project requiredstringTarget project (written).
to_chapter_idstringTarget chapter. Omit for a new one.
positionnumber1-based position among the target chapter's scenes. Omit to append.
include_soundbooleanCarry each scene's own music and sfx, and for a whole chapter into a new one its score cue, clips, conductor and music/ files. Default true.
narrationbooleanCarry the narration and voice of whole script blocks. Default true.
movebooleanAfter copying, soft-delete the source scenes (restorable). Default false.
dry_runbooleanPlan only; nothing written.

create_scene

Create a scene in a chapter

Create ONE scene in an existing chapter. A scene need not have narration: give it a duration and describe it (brief); add narration only when words should be spoken. Free — a prompt makes a DRAFT composition scene (no visuals until someone writes it: put_scene_composition with your own HTML, or resolve_project to have Typecut compose it), a media_url makes a resolved media scene. In an anchored chapter pass block_id + anchor_text — an EXACT quote from that block's narration where the scene starts; the first scene of a block anchors at its opening words. Adding several scenes to the same block: one call at a time, never in parallel. Pass reference_image_url when the scene should be made FROM or LIKE a picture. Ids come from get_storyboard. For bulk structure (many scenes, chapters) use apply_changes.

InputTypeDescription
chapter_id requiredstringChapter id (from get_storyboard).
block_idstringNarration block to attach the scene to.
anchor_textstringEXACT substring of the block's text where the scene starts. Requires block_id.
narrationstringSPOKEN words only. Put the scene at the END of the chapter, in a NEW narration block with this text — what "add a scene at the end of chapter 2" means. The block is voiced on the next resolve and its voiceover sets the scene's duration. Do NOT pass block_id/anchor_text/brief with it. A scene need not have narration — for one with nothing spoken use brief.
briefstringFor a scene with NO spoken words ("no narration", "just the music"): what it shows. Written at the END of the chapter as a non-spoken script line — never voiced — and the scene keeps duration (default 8s). Also its prompt when none is given. Do NOT pass narration/block_id/anchor_text with it.
titlestringShort scene title.
promptstringCreative brief for a draft composition scene — intent, not a picture description.
durationnumberSeconds — the scene's own length when nothing spoken sets it (with brief: default 8, otherwise 5).
media_urlstringPublic image/video url for a resolved media scene (use a library url).
is_videobooleanWhether media_url is a video.
positionnumber1-based insert position in the chapter. Omit to append.
reference_image_urlstringA picture the author should LOOK AT (library asset url from list_media / import_asset / generate_image). Draft scenes only.

edit_composition_unit

Spends credits

Edit a unit inside a composition

Edit ONE unit inside a gen:html motion-design composition. Deterministic ops are instant and free: delete_unit, hide_unit, show_unit, set_text (pure-text units), move_unit (left/top design px), resize_unit (width/height px), set_style (whitelisted CSS: color, background, background-color, opacity, fill, stroke, stroke-width, border-color, border-radius, font-size, font-weight, letter-spacing, font-family — single quotes in font stacks, never double), duplicate_unit, reorder_unit (direction front|forward|backward|back), retime_tween / delete_tween (pass at = the segment's current start from inspect_composition's lanes; retime also takes start). llm_edit is the free-form fallback — an instruction executed by the edit model (~30-60s, SPENDS CREDITS, asynchronous); prefer a deterministic op whenever one fits. Unit keys come from inspect_composition; "sel:"/"@" keys are not editable.

InputTypeDescription
scene_id requiredstringScene id.
element_id requiredstringThe composition element id (from inspect_composition).
op required"delete_unit" | "hide_unit" | "show_unit" | "set_text" | "move_unit" | "resize_unit" | "set_style" | "duplicate_unit" | "reorder_unit" | "retime_tween" | "delete_tween" | "llm_edit"The edit to apply.
unit_keystringUnit key from inspect_composition. Required for every op except llm_edit.
textstringset_text: replacement text (1-400 chars).
leftnumbermove_unit: new left (design px).
topnumbermove_unit: new top (design px).
widthnumberresize_unit: new width (design px).
heightnumberresize_unit: new height (design px).
stylesobjectset_style: 1-8 whitelisted CSS property -> value entries.
direction"front" | "forward" | "backward" | "back"reorder_unit: z-order move among visual siblings.
atnumberretime_tween/delete_tween: the segment's CURRENT start (seconds).
startnumberretime_tween: the new start (seconds).
instructionstringllm_edit: what to change (1-4000 chars).
idempotency_keystringOptional retry-dedup key: pass the same key when retrying an identical call so it is not applied twice (matters for duplicate_unit/reorder_unit).

edit_elements

Edit elements in a scene

Move, resize, retime, recolour or delete elements already in a composition, by patching the scene source line-by-line. Free — no generation. Call get_scene first: patches address source by line number, and passing the scene's composition_version as expected_version turns the write into a compare-and-set, so a concurrent editor save returns a 409 instead of one of you silently losing work.

InputTypeDescription
scene_id requiredstringScene id.
patches requiredarrayElementEditPatch objects — each targets a sourceLine and carries edits (find/replace, setToken, shiftPosition, setTimingPrefix, …).
expected_versionnumberThe scene's composition_version from get_scene.
expect_linesarrayStaleness gate: [{line, text}] pairs from your last read of the source. If any line no longer matches, the write returns a conflict instead of silently applying patches to moved lines. Strongly recommended alongside expected_version.

export_hyperframes

Export the project as a HyperFrames folder

The whole project as a plain HyperFrames folder, zipped and hosted (the url is in the result): index.html is the film, each scene a sub-composition at its window on the film clock (data-chapter names its chapter), with the captions layer and the voice, music and SFX as <audio> tracks; compositions/ holds one document per scene (a scene you authored is your own document back; a structured scene is compiled output, read-only); typecut.json lists node paths, windows and versions. Upstream npx hyperframes render . plays it as is. Edit the folder locally, then send it back with import_hyperframes. Free.

InputTypeDescription
project_id requiredstringProject id.

export_scene

Spends credits

Export one scene

Export ONE scene as a file, the same way the app does. Formats: mp4, png, gif, png_sequence, webp_animated, mov_prores_alpha (coming), web_block. png answers at once with full-size frames from the MP4 renderer (t, or times up to 24; counts toward the look allowance). mp4 starts a render (SPENDS CREDITS; a current cached clip comes back at once; force: true renders again) and returns generation_id for get_status. web_block takes options.manifest (see export_web_block). A format marked coming is refused with not_available until the server makes it. Finished pieces or on request only: check work with preview_frames.

InputTypeDescription
scene_id requiredstringScene id.
format required"mp4" | "webm_alpha" | "png" | "gif" | "png_sequence" | "webp_animated" | "mov_prores_alpha" | "audio" | "srt" | "vtt" | "premiere" | "resolve" | "finalcut" | "nle_package" | "hyperframes" | "web_block"Format id (export_formats).
optionsobjectFormat options (export_formats lists each format's), e.g. {t: 2.5} for png, {resolution: "720p"} for mp4.

find_exemplars

Read-only

Find worked shots for a beat

The k worked shots of a skill nearest to the beat you are writing, as references by default: id, title, brief, intents, duration and code_chars. Pass code:true for the shot code too (it can be large: check code_chars first). Adapt them; do not copy their places. Free.

InputTypeDescription
skillstringThe skill slug, e.g. "history-map". Omit it (or "*") to search every active skill and merge by score.
brief requiredstringOne line: what happens in the beat (travel, a deal, a recolour, a crowd, a reveal…).
knumberHow many (default 3, max 12).
intentsarrayOptional tags that should match: travel, deal, recolour, crowd, river, reveal.
codebooleanInline each shot's code (default false: references only, with code_chars so you can size the read before asking).

generate_scene

Spends credits

Generate a single scene

Author ONE motion-designed scene from intent — no project needed. SPENDS CREDITS. Use when the user wants a single piece rather than a whole video: a title card, an explainer beat, a visual for something they are writing.

You supply the INTENT and the materials; Typecut decides how it looks and moves. Describe what the scene should convey rather than how to build it. If you would rather write the HTML yourself, skip this tool: create_project authoring:"own", then get_authoring_context → put_scene_composition. To make it SPEAK, pass speech clips (a line in a voice, a speak asset, or a recording) — they are resolved once, placed by their anchors, mixed with a music bed, and the motion, captions and word: cues follow the heard words. narration alone is only text for the author, not a voice.

Asynchronous — returns a scene id AND a share_url immediately. Hand the user the share_url straight away: the page is live before the scene finishes and fills in as it generates, so they can watch rather than wait on you to poll.

InputTypeDescription
workspace_id requiredstringWorkspace the scene belongs to (from list_workspaces).
prompt requiredstringWhat the scene should show and do — the creative brief for this one scene.
narrationstringWhat the scene is about in words, for the author. NOT voiced — use speech for a voice.
speecharraySpeech placed by the scene, one clip per line. source: {text, voice_id|clone_id} (spoken on landing, SPENDS CREDITS, cached), {asset_id} (a speak result) or {media_id, from?, to?} (a slice of a transcribed recording). at: seconds | "bar:3" | "beat:5" | "after:<id>+400"; omit to follow the previous clip. The scene lasts as long as its speech (+0.6s) unless it has a planned duration (update_scene {duration}, or a plan clock other than speech:true), and overrunning that is refused. cuts / fx: typecut://studio/guide "Voice inside the scene".
musicobject
scoreobject
theme_slugstringTheme from list_catalog("themes"). Defaults to the workspace look.
duration_secondsnumberScene length in seconds. Default: the speech length (+0.6s) when the scene speaks, else 10.
aspect_ratiostringFrame shape: "16:9", "9:16", "4:3" or "1:1" — anything else is rejected. Defaults to the scene's current shape when regenerating, otherwise the workspace default. Pass "9:16" for vertical/social.
media_asset_idsarrayLibrary asset ids to build the scene around.
scene_idstringRe-author an EXISTING scene instead of creating one — a standalone scene, or a project's motion-design scene. Pair it with media_asset_ids to make footage or a photo the ground the composition is built over: attach_media would REPLACE the composition, this authors it AROUND the asset. The scene keeps its duration and frame.
reference_image_urlstringA picture the author should LOOK AT — make the scene FROM or LIKE it. A library asset url (list_media / import_asset / generate_image). Keep prompt to intent.

get_authoring_context

Read-only

What is known about this beat

Everything the pipeline knows about a beat, BEFORE you author it. Read this first whenever you are going to write or rewrite a composition — without it you are guessing at numbers the system already has.

Per composition element it returns: the BRIEF it was planned with; the numbered BEATS resolved to real seconds (the director quotes a narration phrase, the pipeline joins it to the word timeline — a beat that never matched says so); the canvas and this element's own window and start on the scene clock; this scene's VO WORD TIMELINE, scene-relative, so a reveal can land on the word that says it (for a scene with its own speech clips, their words — fx marks a word heard through an audio effect; top-level audio lists the clips, their FX and the music bed); the MUSICAL GRID re-based to the element's own zero; the theme's resolved COLOUR and TYPE ROLES, its image style and the actual ground; the CAMERA ITINERARY that will move over the composition; measured ANCHORS; the previous and next scene, so the picture neither repeats nor pre-empts them; and the CAST, generated IMAGERY and user LIBRARY it may reuse verbatim instead of inventing something new.

Timing, theme resolution, text-fit geometry and camera authority are the pipeline's, not yours: read them here and author AGAINST them rather than hard-coding equivalents, which is the single most common way a composition comes out wrong. Free, read-only. Pair it with inspect_composition, which describes what is already IN a composition; this describes what the composition is FOR.

Each element carries packet: the same facts resolved and layered for an author — the contract rules for its KIND, the job (intent, canvas, words, beats, assets, and the exact theme CSS var names injected at mount), neighbours, signals, and gaps naming what the pipeline does not know yet. The packet IS the answer: by default the reply is lean and states each fact once (the brief is packet.job.intent, the words packet.job.words, the beats packet.job.beats). view:"full" adds the raw envelope our own composer is handed, for debugging only.

A project made with a SKILL (get_project_skill) returns top-level look instead of theme variables: the skill ref and its resolved tokens (the skill defaults overlaid with the project's palette/type). Paste those tokens on your own explicit-size .stage. The look is THIS scene's: a style set for its scene or chapter beats the project's. Top-level skills lists what else is in force: the style ref, the recipe(s) (how the film is made: load with get_skill) and the cast (characters shared across scenes). Refs only, never skill bodies: get_skill loads one on demand.

Authoring several scenes? Each reply carries known; pass it back on the next scene and the project-wide sections you already hold come back as {same: hash}.

InputTypeDescription
scene_id requiredstringScene id (from get_storyboard or get_inventory).
element_idstringNarrow to ONE composition element. Omit for every gen:html in the scene.
detailstringPacket detail: "compact" (default) or "full" (adds the project gist, every word, all signals and references).
kindstringForce a composition kind: explainer-beat, data-chart, music-visualizer, sticker, title-card or media-frame. Omit to use the inferred one.
viewstring"lean" (default): each fact once, in the packet. "full": also the raw envelope and the brief repeated — several KB more per scene; only for debugging.
knownstringThe known token from your previous get_authoring_context reply in this project. The sections you already have (assets, chapter voiceover, contract, theme, gaps, look) come back as {same: hash}, about half of each reply. Omit on the first scene.

get_composition_source

Read-only

Read the composition a scene mounts

The HTML text of the composition a scene mounts — the hosted document put_scene_composition (or a generation) landed — with its url and size in bytes. Read it back to see exactly what you landed, edit it, and land it again. A scene with several compositions: pass element_id (the result lists them). Free.

InputTypeDescription
scene_id requiredstringScene id.
element_idstringWhich composition, when the scene mounts several. Omit for the first.
authoredbooleanYour last-sent source (what edits patch).

get_module

Read-only

Read a module

One hosted module: its url, parameter schema (params, state), exports, requirements, every hosted version, and the pin tag to reference it from a scene. id is "cast:pip" (latest) or "cast:pip@2". Its API MANIFEST (api_text): every function with its parameters and one line on what it does, and the name tables its string arguments draw from (name ∈ CUTS — the values that exist) — read that to call a kit, never its body. Purposes come from the module header's api block, else the author's comments, else a model (marked [inferred]). source:true also returns the file. Free.

InputTypeDescription
id requiredstring"cast:pip" for the latest, or "cast:pip@2".
versionnumberA specific version.
sourcebooleanAlso return the file itself.
structuredbooleanReturn the same content as a JSON object (text and structuredContent) instead of the prose alone (default false). The /v1 route always carries both.

get_project_skill

Read-only

Read the project's skills

The skills the project is made with. skill is the project-wide STYLE (ref slug@version, the palette and type overrides, the legacy theme roles derived from its tokens), or null; skills lists every entry: {ref, role: style|recipe|cast, scope: 'project'|{chapter_id}|{scene_id}, palette?, type?, note?}. A project can hold several: styles that differ by chapter or scene (a synthwave chapter, a blueprint chapter), a RECIPE for the whole film (explainer-film, long-film-structure…) that sits on top of a style, and CAST (character skills shared across scenes). With scene_id you also get effective: what is in force for that scene (style = scene > chapter > project, the recipes, the cast) with the style's resolved tokens: refs and tokens only, never skill bodies (get_skill loads one). get_authoring_context returns the same for the scene it describes. Free.

InputTypeDescription
project_id requiredstringProject id.
scene_idstringAlso resolve what is in force for this scene.

get_scene

Read-only

Get one scene

Read a single scene in full: prompt, background media, timing, caption overrides, and the composition source of a scene Typecut designed. Before edit_elements, read it — and keep the returned composition_version, which edit_elements takes as expected_version so a save from someone with the editor open cannot be silently clobbered.

InputTypeDescription
scene_id requiredstringScene id (from get_storyboard).

get_scene_brief

One scene, studied — frames, what arrives when, colours, its place in the arc

Study ONE scene in about a thousand tokens: real frames (stored for this scene version, else one quick capture, else older ones labelled older), WHAT ARRIVES WHEN against the spoken words (each on-screen element's arrival time, whether it stays to the cut, and the narration word it names and how far its arrival is from that word), the colours measured from the pixels, the authoring brief, the narration, its neighbours, what the project's cached gist made of it (job, device, role), and for a hand-written scene its OWN CODE (the author's script, not the stored document: no runtimes, no module body, no preamble the gist already named). The drill-down from get_project_gist: the gist names each technique's best example scene; read that scene here before building something like it, instead of reading 150KB of markup or guessing. Unlike the gist it may name the subject — you are studying this scene on purpose. Works for a scene of any project you can read. capture:false reads only stored frames. Free; stores any frames it captures for the next reader.

InputTypeDescription
scene_id requiredstringScene id (from get_storyboard, or a gist's device example).
capturebooleanCapture frames when none are stored (default true). false = read what is stored only.
structuredbooleanReturn the same content as a JSON object (text and structuredContent) instead of the prose alone (default false). The /v1 route always carries both.

get_theme

Read-only

Get the project theme

Read the project's visual identity — theme slug, colour roles, font roles, light/dark. Read before restyling so you patch roles that exist.

InputTypeDescription
project_id requiredstringProject id.

get_world_manifest

Read-only

Map of a world

What a world module (env:rome...) contains, in one small answer (~5 KB, not its 30 KB source): regions (what each builds, tri and build budgets), anchors (name, bounds, regions that build it), seeds, units. Read it before framing shots so you pick the region that builds what you frame. With region + camera {pos, target, fov, aspect?} it also checks that region builds everything the camera sees: framing.omitted lists anchors that would be missing from the frame, suggest_region the cheapest region that builds them all. module is "env:rome" (latest) or "env:rome@5". Free.

InputTypeDescription
module requiredstring"env:rome" for the latest, or "env:rome@5".
regionstringWith camera: the region the shot builds.
cameraobjectThe shot's camera in world units: pos [x,y,z], target [x,y,z], fov (vertical degrees), aspect (default 16/9).

harvest_skill

Draft worked shots from a finished project

Staff only. Draft exemplars for a skill from a finished project: per scene the shot code, the heard words, the camera keys and three preview frames, as draft rows to curate with put_skill_exemplars. Pages ≤12 scenes a call (offset, next_offset). frames:false skips the previews. Free.

InputTypeDescription
skill requiredstringThe skill slug the shots belong to.
project_id requiredstringThe finished project.
scene_idsarrayOnly these scenes.
offsetnumberStart at this scene (from next_offset).
limitnumberScenes this call (default 6, max 12).
framesbooleanRender preview frames (default true).
overwritebooleanRedraft scenes already curated.

import_html

Import a single-file HTML video and split it into scenes

Bring a video you (or Claude) already made as ONE HTML file — a master GSAP timeline, every scene inline, often an <audio> tag — into Typecut as a chapter of scenes on the timeline, each editable, re-renderable and exportable on its own. New project: workspace_id (+ name). Existing one: project_id (a chapter is appended).

How it splits. Inline HyperFrames sub-compositions (a <template id="X-template"> + host, or a self-contained inline composition) become scenes with their own documents on their own clock. Anything else is cut by TIME, at the first of: GSAP labels (tl.addLabel), the visibility windows of the root's top-level sections, full-frame clears, and — when the file has none of those — shot changes found on a low-res render; cuts: [seconds] overrides all of it. The file is hosted ONCE and each scene is a small wrapper that plays its window of that one copy, so every scene is pixel-identical to the original by construction. To really edit a scene, replace its document with put_scene_composition (local t=0); its neighbours do not move.

Audio. The root <audio> becomes the project music (audio: "music", default, when the chapter opens the film), or the VOICE (audio: "voice": each scene gets its part as a speech clip on the transcript — words, captions, cues — and cuts move off spoken words; the recording needs a transcript first: the result names the media_id to run transcribe_media on, then call again with chapter_id), or is left out ("none"). Relative src/href in the file need base_url.

Non-seekable code (requestAnimationFrame loops, timers, Date.now) is flagged: the renderer seeks, it never plays. verify runs the render-twice check on every scene; with video_url (your own render of the file) a scene that fails it becomes a clip of that render. dry_run returns the analysis and the proposed cuts and creates nothing — do it first. Large files: create_upload, curl, then src_url. Free (transcribe_media is priced on its own).

InputTypeDescription
htmlstringThe HTML file. Or src_url.
src_urlstringA create_upload public_url you PUT the file to (for files over ~100 KB).
base_urlstringWhere the file lived (e.g. its folder URL), so its relative images, fonts and audio resolve.
workspace_idstringCreate a new project here.
namestringNew project name. Defaults to the file's <title>.
project_idstringAppend a chapter to this project instead.
chapter_idstringFinish an earlier import into this chapter (same file, same options): re-lands its scenes.
chapter_titlestringDefaults to the file's <title>.
cutsarrayCut at these seconds of the file instead of detecting.
duration_secnumberThe film length, when the file does not declare it.
min_scene_secnumberDrop cuts closer than this. Default 1.
max_scene_secnumberSplit longer stretches evenly. Default 20.
audio"music" | "voice" | "none"What the root <audio> becomes. Default music.
shot_detection"auto" | "off" | "force"auto (default): only when the file offers no structure.
subcompsbooleanSplit inline sub-compositions into their own documents. Default true.
video_urlstringYour own render of the file (mp4): a scene that fails the render check becomes a clip of it.
verifybooleanRender-check every scene (seek-order). Default: when the file has non-seekable code.
captionsbooleanBurn in captions on a new project. Default false (the file has its own type).
dry_runbooleanAnalyse and propose the cuts; create nothing.

import_hyperframes

Import a HyperFrames folder

Send an edited HyperFrames folder back: the files you changed (compositions/*.html, each keeping its <meta name="typecut:scene"> line) or the whole folder with index.html. Only documents that differ from the project's current ones land (through put_scene_composition, same gates), so only those scenes re-render. A top-level sub-composition in index.html with no scene behind it becomes a new scene, in the chapter its data-chapter names (else the last). A document exported from an older version of its scene is refused as a conflict unless force. Voice, music and captions stay Typecut's; root <audio> is not imported. dry_run validates every changed document and lands nothing. Scene documents are large: upload each changed one with create_upload and pass {path, src_url} rather than pasting it. Free; asset slots in a composition may spend.

InputTypeDescription
project_id requiredstringProject id.
files requiredarrayThe folder files: changed scene documents, optionally index.html. ≤200 files, ≤12 MB.
dry_runbooleanValidate every changed document; land nothing.
forcebooleanLand even when a document was exported from an older version of its scene.

list_formulas

Read-only

List every look you can pick or author

The whole formula catalog across both systems: brand-mark motion (slot "bug" — the built-ins marked built_in, every active authored row, and your own held drafts) and caption motion (slot "caption" — the published catalog plus your own private ones). Pass slot to narrow it. Use before set_branding or set_captions to see which values are valid, and after author_formula to check a draft landed. Free, reads only.

InputTypeDescription
slotstringNarrow to "bug" or "caption". Omit for both.

list_modules

Read-only

List modules

The modules hosted on this account — cast, devices, UI, kits — each at its latest version. Default is COMPACT and 25 per page (id, kind, version, bytes, description; the whole list is ~14k tokens): narrow with kind (id prefix: env, model, kit, rig, cast, map...) or q (words: "mocap", "walk", "pick up" match ids, descriptions and api lines), page with cursor (the answer carries total and next_cursor), set limit up to 500. view:"full" adds schema, url and pin tag; id returns every version of one module in full. Free.

InputTypeDescription
idstringOnly this module, every version (full view).
kindstringOnly this kind: the id prefix before ":" (env, model, kit, rig, cast, map...).
qstringWords to find (case-insensitive): an id substring, or every word in the description or api. Id matches first.
limitnumberPage size (default 25, max 500).
cursorstringThe previous answer's next_cursor.
view"full" | "compact"compact (default unless id): id, kind, version, bytes, description. full: schema, url, pin tag.

list_recipes

Read-only

List or read saved recipes

Free. Your saved recipes: the model choices you (or an earlier session) settled on, as steps {tool, model, params, fallbacks, note}. With no name, lists them; with a name, returns that recipe in full. Re-apply one by passing each step's model and params to its tool; if a step's model fails, try its fallbacks in order. Models are ids from list_catalog("models").

InputTypeDescription
namestringA recipe name. Omit to list every recipe.

merge_scenes

Merge two adjacent scenes

Join two ADJACENT scenes of one chapter into ONE scene that plays the first, then the second: both compositions on one clock (the second's lines move by the first's length; a clashing element id of the second gets a _b suffix, listed in renamed), lengths summed, and every voice kept. In one narration block the scene covers both slices; across two adjacent voiced blocks both blocks and both voices stay and the scene carries on over the second one. Free, nothing re-voiced. A pair it cannot combine exactly (differing canvas or world, a time form it cannot move, a voiced block next to an unvoiced one) is refused with the reason and nothing changes. To merge a run of scenes, plan the whole run as merge_scenes ops in ONE apply_changes with dry_run: true (it checks each merge against the scenes and lists what each would do), then apply the same ops. Runs as one changeset: undo_changes with the returned changeset_id reverts it. dry_run:true projects it without writing. Free.

InputTypeDescription
scene_ids requiredarrayThe two scenes, in either order.
dry_runbooleanCheck it and say what it would do; nothing written.

move_scene

Move a scene to another chapter

Move a scene to a position in another chapter of the same project (the same chapter just reorders it). The scene travels with its composition and length; its narration stays behind (the words belong to that chapter's voice, and its neighbours cover them). In a narrated target chapter it is placed with a non-spoken line holding its title, like a create_scene brief. Runs as one changeset: undo_changes with the returned changeset_id reverts it. dry_run:true projects it without writing. Free.

InputTypeDescription
scene_id requiredstringThe scene to move.
chapter_id requiredstringTarget chapter (get_storyboard).
positionnumber1-based position among the target chapter's scenes. Omit to append.
dry_runbooleanProject only; nothing written.

project_ls

List the project as files

Any directory segment may be the id instead, or the number alone. Each entry carries its id, size and state (scene lifecycle, tts ready/stale/missing, a composition hosted or empty). path narrows to one chapter or scene directory. Read with project_read, change with project_write / project_mv / project_rm. Free.

InputTypeDescription
project_id requiredstringProject id.
pathstringOnly this directory (a chapter or scene). Default: the whole project.
afterstringnext_cursor from the previous page; omit for the first page. A page is about 40 KB.

project_mv

Move a scene or chapter

Move a scene directory to a position (chapters/<chapter>/<NNN>, or chapters/<chapter>/ to append) — within its chapter, or into another one (re-created there with its script block and composition copied; it gets a NEW id, returned in created). Move a chapter directory to chapters/<NN>. One apply_changes batch: recorded and undoable with undo_changes. dry_run returns the plan. Free.

InputTypeDescription
project_id requiredstringProject id.
from requiredstringA path in the project tree, e.g. "chapters/02-setup/003-the-map/scene.json". An id works for any directory segment.
to requiredstringThe target path.
dry_runbooleanValidate and return the diff and verdict; write nothing. Free.

project_rm

Delete a scene or chapter

Delete a scene directory (with its script block when no other scene shares it) or a chapter directory (with its scenes). Recorded and undoable with undo_changes. Files are views of those entities: write them instead. dry_run returns the plan. Free.

InputTypeDescription
project_id requiredstringProject id.
path requiredstringA path in the project tree, e.g. "chapters/02-setup/003-the-map/scene.json". An id works for any directory segment.
dry_runbooleanValidate and return the diff and verdict; write nothing. Free.

put_module

Host a module once, pin it by version

Host a piece of HyperFrames code that many scenes share — a character rig (cast:pip), a recurring device or UI element (device:world, device:prompt-box), helpers (kit) — ONCE, at an immutable url per version, instead of pasting it into every scene. Copies drift; a pinned reference does not.

The file declares itself in a header: /*@module {"id":"cast:pip","version":2,"exports":"CastPip","requires":["kit@1"],"params":{"face":{"type":"enum","values":["curious","worried"]},"lean":{"type":"number","unit":"deg"}},"state":{…}} */. params is the vocabulary a shot may pass (types: number integer string boolean enum object array function any). Every problem comes back at once.

Readers learn a module from its API manifest (api_text, also on get_module), derived from the file: each exported function's signature, the comment line above it, and the name tables its arguments draw from. Write a one-line comment above each function, or name them in the header's "api":{"wave":"Raise one arm and wave twice"} — that wins; uncommented ones get a model-written line, marked [inferred].

A scene pins it with the returned pin tag: <script data-tc-module="cast:pip@2" src="…"></script>, requirements first. A version never changes; putting a new version (a bump) returns rebase: your scenes still pinned to an older one. Upload the file with create_upload and pass src_url so it never enters this conversation. dry_run:true checks the header and reports the rebase list, hosting nothing. Same access as landing authored compositions. Free.

InputTypeDescription
id requiredstringThe module id without its version, e.g. "cast:pip", "device:world", "kit".
versionnumberThe version to host. Default: the header's, else the latest + 1.
sourcestringThe module file. Exactly one of source / src_url.
src_urlstringA create_upload public_url holding the file.
project_idstringOnly look for older pins in this project.
dry_runbooleanValidate and report, host nothing.

put_report

Answer as an animated scene from a compact spec

Turn a short report into an animated 16:9 scene WITHOUT writing HTML: send a JSON spec of beats and the server sets the scene length, mounts the kit:report runtime and lands it through the same gates as put_scene_composition. About 300 tokens of JSON for a 6-beat report; use it whenever speed and density matter more than a custom look.

spec = {look? "doodle" (hand-drawn marker-on-paper), title?, sub?, accent? "#hex", light? true, theme? false (a themed project is followed by default; false keeps the built-in palette), speed? 0.5-3, beats: [BEAT, …]} (4-6 beats is a good answer; the first beat is the verdict). BEAT = {k, h (heading), d? seconds (default from content)} plus: every beat may also carry say "a spoken line" (write it FIRST in the beat: it is voiced in the browser on the live page and sets the beat length when it is the longer; keep it under ~100 characters) and sfx tick|pop|whoosh|chime|pen|thud|ding|none (each kind already has a sound; rarely needed). Top level: voice "fast" (server Kokoro voice for every say, all lines spoken at once when you write; ~1 s extra, small credit cost; "fast:Michael" picks another library voice), "studio:Adrian" (any library voice by name, e.g. a Fish voice; costs that voice rate), "kokoro:af_heart" (in the browser) or "device", music {mood?, src? https audio url, volume? 0-1} (a soft pad for the mood when there is no src). Sound plays only on /share/{token}/live after the viewer taps for sound. svg svg "<path/>…" (freeform drawing on a 1600x640 canvas: path line circle ellipse rect polyline polygon text only, drawn on stroke by stroke), h? img src https url (e.g. a preview_composition frame url) or handle "tc:scene/<id>" / "tc:asset/<id>", cap? (a taped picture) track handle "tc:audio/<analysis id>" (from analyze_audio / get_audio_analysis), from? seconds, d? seconds (default 12): section bands by energy, downbeat ticks, kick and snare lanes, salient pins, tempo and key, a playhead; the live page plays the track itself audio items [[label, https audio url, seconds]] (≤6, e.g. audition_voices clips): cards that light up as each clip plays in turn, text? the line compare items [[label, image url or tc: handle], [label, image]], rows? [[metric, a, b]] (≤6, measured numbers, e.g. from look compare), text? layer handle "tc:layer/<scene id>" (bake_layer makes it, any project you can read): plays that scene's baked frames once, cap? a caption (no video render needed) code escape hatch: code "<body of function (box, tl, t, d, gsap)>" draws into the beat box with DOM/SVG/canvas and adds its tweens to tl at time t (≤3000 chars, d seconds). It runs only in a landed scene (call without live:true); the live page shows a placeholder. Use it for the one moment the data beats cannot say. kpi items [[label, value, delta?, tone?]] (≤4; numbers count up; tone ok|warn|bad) bars items [[label, number]], u? "%", max? (≤6, bars grow) list items [[text, status, detail?]] status ok|warn|bad|todo (≤5) steps items [[label, done|now|next]] horizontal progress (≤5) spark items [numbers], v? headline, label? trend line draws on table cols [str], rows [[cell…]] (≤5 rows reads well) note text, who? one big sentence or ask

GROW IT AS YOU THINK: call once with spec (title + first beat) so the viewer sees something at once, then append_beats with more beats; each call lands the whole scene again with the new beats added (about 4-7 s a call). live: true skips the landing and only stores the spec (about 1 s a call): the scene plays at /share/{token}/live (share_scene gives the token), which shows beats as they are appended. Finish with one call without live to land it as a normal scene. Exactly one of spec / append_beats. dry_run checks the spec for free; check: true looks at the landed scene. Free.

InputTypeDescription
scene_id requiredstringThe scene to put the report on (create_scene, or any scene whose composition you are replacing).
specobjectThe whole report: {title?, sub?, accent?, light?, speed?, beats: [{k, h, items…}]}. Replaces what the scene has.
append_beatsarrayMore beats for the report already on the scene.
dry_runbooleanValidate the spec and report the length without landing. Free.
livebooleanStore the spec only, no landing (about 1 s): plays at /share/{token}/live and picks up appended beats. Land it with a final call without live.
checkboolean | string | objectAfter landing, look at the scene and return the findings as check, so one call lands and verifies. true = frame sheet + motion filmstrip; or a look preset (quick | motion-check | layout-check | sync-check | player-check | dense-motion); or {preset?, show: ["frames","motion","sync","player","sound"], frames?, fps?}. Fix what it flags with edits.

put_scene_composition

Spends credits

Land a composition you wrote

Land a composition YOU authored onto a scene's element, through the same gates, scoping, theme injection and hosting a generated one takes. Read get_authoring_contract (shell: what is accepted, refused and warned about) and author against the values get_authoring_context gave you; a number you calculated instead of declaring is the most common reason a scene comes out wrong.

SEND ordinary HyperFrames: a full document (one root with data-composition-id and a paused GSAP timeline on window.__timelines[<id>]), a <template> sub-comp or the bare root. Large: upload it (create_upload) and pass src_url. Shared code: put_module, then link it with <script data-tc-module="kit:globe@2"></script>; modules in the answer lists what was linked.

Refusals cost nothing and carry the gate's words, so dry_run:true first is free. Expect: an unclosed <template>, no registered timeline, nodes appended to document.body. requestAnimationFrame or wall-clock motion lands with a WARNING and renders FROZEN (the renderer seeks a paused timeline); preview_composition with determinism judges it. The answer carries cost (bytes, class, lints with their fix) and revision. Refuses a scene mid-generation, a scene that changed while yours was in flight, and a landing that moves a module back to an older version (see if_revision). Free unless the HTML declares generated assets.

VOICE: <audio> is NOT mixed. Give the scene speech clips (one per line, its own voice_id, at on the scene clock); text lines are spoken on landing (SPENDS CREDITS, cached) and quoted by dry_run. Omit to keep the scene's; [] removes it.

PICTURES: <img data-gen="what it shows" data-gen-ratio="16:9"> is made on landing (SPENDS CREDITS, one batch; dry_run prices it) and baked as src + data-gen-key. Found again by key, so re-landing, even without src, is free and changing one prompt re-makes only that picture. The result's images says which were kept, reused or made.

FIXING WHAT YOU LANDED: send edits ([{find, replace}], each find matching once) instead of html; the server patches the source you sent last time (get_composition_source authored:true) and lands it through every gate. Refused, nothing written, if a find misses or the scene changed since: then send the full html.

async: true answers at once with a job_id; jobs {id} reads the result (no 60 s timeout).

InputTypeDescription
scene_id requiredstringScene id (from get_storyboard or get_inventory).
htmlstringThe composition source: a full HyperFrames document, a <template> sub-comp, or the bare root. Max 2,000,000 characters. Pass exactly one of html / src_url.
src_urlstringAn https URL to fetch the composition from instead of html (the worker fetches it; private and internal addresses are refused). Use it for documents too large to inline.
editsarrayInstead of html: patch the source you sent at the last landing. Applied in order; each find must match exactly once.
element_idstringWhich composition element. Omit only when the scene has exactly one; a scene with several refuses rather than guessing, and names them.
dry_runbooleanValidate and report without hosting or writing. Free — do this first.
speecharraySpeech placed by the scene, one clip per line. source: {text, voice_id|clone_id} (spoken on landing, SPENDS CREDITS, cached), {asset_id} (a speak result) or {media_id, from?, to?} (a slice of a transcribed recording). at: seconds | "bar:3" | "beat:5" | "after:<id>+400"; omit to follow the previous clip. The scene lasts as long as its speech (+0.6s) unless it has a planned duration (update_scene {duration}, or a plan clock other than speech:true), and overrunning that is refused. cuts / fx: typecut://studio/guide "Voice inside the scene".
skillstringThe skill (slug or slug@version) this scene is authored with; recorded on the scene so get_scene_reference and copy_scenes know its look. Default: the scene's effective style skill (get_project_skill with scene_id).
as_takebooleanLand as a DRAFT TAKE: same gates, mount and hosting, written to a new scene take instead of the scene, which stays exactly as it is. Iterate on a scene someone is watching without touching it; preview the draft with preview_composition src_url, then scene_takes switch to make it live.
take_labelstringWith as_take: a short name for the take.
take_notestringWith as_take: why it exists / what it tries.
if_revisionstringThe scene revision from your last read or landing. Refused if another writer landed since. Also confirms a landing that moves a module back to an older version, which is otherwise refused.
checkboolean | string | objectAfter landing, look at the scene and return the findings as check, so one call lands and verifies. true = frame sheet + motion filmstrip; or a look preset (quick | motion-check | layout-check | sync-check | player-check | dense-motion); or {preset?, show: ["frames","motion","sync","player","sound"], frames?, fps?}. Fix what it flags with edits.
asyncbooleanStart the call as a job and answer at once with {job_id}. Read it with jobs {id, wait_sec: 50}: the same result this call returns. Use it whenever the call may take more than about 30 s.
idempotency_keystringWith async: any string unique to this call. A retry with the same key joins the job already started instead of starting another.

put_scene_compositions

Spends credits

Land several authored compositions

put_scene_composition for up to 20 scenes in ONE call: each item is landed exactly as put_scene_composition would (same gates, same speech rules), and every verdict comes back inline, in order. One refused item does not stop the others. dry_run: true checks them all for free. SPENDS CREDITS only for speech text lines not yet spoken (see put_scene_composition).

MANY SCENES, ONE DESIGN: send template once (a full document with {{key}} slots, HTML-escaped, or {{{key}}} raw) and per scene data ({key: value}) instead of html. check:true looks at every landed scene and returns the findings with the verdicts. Over about 6 scenes, add async:true.

async: true answers at once with a job_id; jobs {id} reads the result (no 60 s timeout).

InputTypeDescription
scenes requiredarrayOne per scene: {scene_id, html | src_url | edits | data, element_id?, speech?, skill?} — the fields of put_scene_composition.
templatestringOne document for every scene that sends data: {{key}} is filled HTML-escaped, {{{key}}} raw.
dry_runbooleanValidate and report without hosting or writing. Free.
checkboolean | string | objectAfter landing, look at the scene and return the findings as check, so one call lands and verifies. true = frame sheet + motion filmstrip; or a look preset (quick | motion-check | layout-check | sync-check | player-check | dense-motion); or {preset?, show: ["frames","motion","sync","player","sound"], frames?, fps?}. Fix what it flags with edits.
asyncbooleanStart the call as a job and answer at once with {job_id}. Read it with jobs {id, wait_sec: 50}: the same result this call returns. Use it whenever the call may take more than about 30 s.
idempotency_keystringWith async: any string unique to this call. A retry with the same key joins the job already started instead of starting another.

put_skill

Publish a skill version

Staff only. Publish a new immutable version of a skill: title, summary, the SKILL.md (body_md) and the structured record (when_to_use, kits, stub, vocabulary, recipe, rules, image_recipes, pacing, checks, theme_slot). Kits you host are resolved to pin tags. STATUS-ONLY: send just {slug, version, status} (no title/body_md/record) to move an existing version draft ⇄ active → deprecated without re-sending its content; a full re-put with byte-identical content does the same, a differing body is a 409. Readers are served the highest-numbered ACTIVE version (promoting never demotes another). dry_run validates. Free.

InputTypeDescription
slug requiredstringLowercase slug, e.g. "history-map".
versionnumberDefault: latest + 1.
status"draft" | "active" | "deprecated"Default active.
titlestringOne-line name. Required for a new version; omit for a status-only call.
summarystringOne sentence for list_skills.
body_mdstringThe whole SKILL.md.
recordobjectThe structured record (see description).
dry_runbooleanValidate only.

put_skill_exemplars

Curate a skill's worked shots

Staff only. Upsert worked shots of a skill by n: {n, title, brief, intents[], duration_s, code, words[], state{entry,exit}, frames[{t,url}], provenance}. status curated (default) serves them; draft hides them; retired removes them. replace:true retires every exemplar not in the list. Free.

InputTypeDescription
skill requiredstringThe skill slug.
exemplars requiredarrayThe exemplars (≤60 per call).
replacebooleanRetire the skill's exemplars not in this list.

read_composition_unit

Read-only

Zoom into one composition unit

Read ONE unit of a gen:html composition in full: its markup (outerHTML), the CSS rules that mention it, the timeline statements that animate it, its parent chain and sibling keys. A few hundred tokens instead of the whole document — use it AFTER inspect_composition to decide whether a change is additive (a sibling-shaped new unit) or a rewrite of this unit, and to quote exact text for a precise edit instruction. Read-only, free.

InputTypeDescription
scene_id requiredstringScene id.
unit_key requiredstringUnit key from inspect_composition.
element_idstringOptional composition element filter (when a scene mounts several).

refresh_scenes

Refresh copied scenes from their source

A scene made by copy_scenes remembers the scene it came from (metadata.copied_from). refresh_scenes pulls that source's CURRENT composition, look and sound into the copy, so a scene reused across projects follows its source on request. The copy keeps its own title, place, narration link and length. Only copies whose source has changed are touched (status refreshed | current | no_source). Never automatic. Undo like any scene edit (undo_scene_edit). dry_run:true reports which are behind. Free.

InputTypeDescription
scene_ids requiredarrayThe copied scenes to refresh.
include_soundbooleanPull the source's music and sfx too. Default true.
dry_runbooleanReport which are behind; write nothing.

regenerate_elements

Spends credits

Re-make a scene's generated elements

Re-make the generated elements of an ALREADY-RESOLVED scene, keeping its scene source. SPENDS CREDITS — send dry_run true first to see which elements would be re-made and what that costs, and show the user the number before you spend it.

This is the call that actually dispatches the worker, and nothing else does it for an existing scene: edit_elements rewrites the source and recompiles, but a gen element it touched stays unresolved until something re-makes it; resolve_project skips the scene, because that gates on scenes never resolved at all; and generate_scene on an existing scene throws the edited source away and re-authors from the prompt. So reach for this when you have edited a gen:html / gen:image line and the scene still shows the old picture, or when a composer-level fix has landed and the already-generated scenes have to pick it up.

Name element_ids to keep a repair surgical — omitted, every resolved gen element in the scene is re-made and re-charged. Asynchronous: poll get_scene or get_project_status rather than assuming it landed.

InputTypeDescription
scene_id requiredstringScene id.
element_idsarrayElement ids to re-make (from get_scene or inspect_composition). Omit to re-make every resolved gen element in the scene, which costs more — prefer naming them.
dry_runbooleanTrue = report which elements would be re-made and the cost, and change nothing. Do this first.

release_scene

Let go of a scene you claimed

Drop your claim on a scene (the lock clears for everyone). Idempotent: releasing a claim you do not hold (or that already lapsed) is fine and returns released:false. Free.

InputTypeDescription
scene_id requiredstringScene id.

repin_modules

Bring a project's scenes onto its runtime's module versions

After a module bump (put_module of kit3d@12, then set_project_runtime to move the project to it), the scenes already landed still carry the old version until they are landed again. This does that loop: for every scene of the project whose composition carries a module at a different version than its runtime lists, it takes the authored source kept at the last landing, rewrites any explicit pin of that module to the runtime's, and lands it again through the ordinary gates. A scene with no kept source, changed since, or opted out (data-tc-runtime="none") is reported with the reason and left alone. ALWAYS dry_run:true first. Also the way a theme set after landing reaches scenes you authored: refresh_theme:true. Free; every land is in the History panel.

InputTypeDescription
project_id requiredstringProject id.
dry_runbooleantrue = report which scenes would be repinned (each re-validated by the worker) and write nothing.
refresh_themebooleantrue = also re-land every scene you authored, module-stale or not, so a theme set (set_theme) AFTER landing reaches it: the theme's CSS variables (--font-display, colour roles) are injected at land, so an authored scene keeps the look it was landed with.

report_friction

Report friction using Typecut

Tell the Typecut team what cost you extra work: a call that failed or needed retries, a result too big to read, a task that took many round trips, information you had to fetch in several calls. OPTIONAL. Offer it once at the end of a task or when you hit a real wall, never mid-task, and only for friction you actually met doing real work (not preferences or redesigns). observed is a fact: what happened, which tool, the numbers. suggested is an optional idea, stored apart because it may be wrong. At most 3 per session; after that the call is answered but not stored. Each report becomes an issue in an inbox that a watcher works through (issues); it never comes back to you as a task. Free.

InputTypeDescription
observed requiredstringWhat happened, one or two lines, with the tool name and numbers (calls, KB, error). Required.
suggestedstringOptional: what would have helped. Kept separate from observed.
toolstringThe tool it concerns, if one.
model_tier"opus" | "sonnet" | "haiku" | "other"Your model tier.
costobjectNumbers only, e.g. {"calls":9,"kb":72}.
project_idstringThe project you were working in, if any.
kind"gap" | "bug" | "slow" | "missing_tool" | "docs"gap: something you needed that Typecut does not offer; bug; slow; missing_tool; docs: a guide or description that misled you.

resync_compositions

Re-derive a project's compositions from their scene source

Recompile every scene in a project from its own scene source and store the result. A scene's stored composition is what every surface renders — editor, scene player, export — and it is written ONCE, at save. So a compiler fix only ever applies to the next save, and a project made before it keeps whatever the old compiler produced. This is how a fix reaches scenes that already exist. ALWAYS run dry_run:true first and read the per-element changes: the scene source is the truth and the compile is deterministic, so this is a recomputation rather than an edit, but it rewrites whole compositions. A scene whose compile fails is reported and left untouched. Free, and every write is recoverable from the History panel.

InputTypeDescription
project_id requiredstringProject id.
dry_runbooleantrue = report what would change and write nothing. Do this first.

save_recipe

Save the model choices that worked as a recipe

Free. Save what you settled on so it can be re-applied to a later project or by another agent: steps [{tool: "generate_image"|"generate_video", model, params, fallbacks (up to 3, same tool), note}]. Models must be ids from list_catalog("models", tool). params are the method (aspect, duration), never the prompt or an image url. Saving an existing name replaces it; pass fork_of to copy a recipe under a new name (steps optional then, to change it).

InputTypeDescription
name requiredstring2 to 60 characters, unique on the account.
descriptionstringWhat it is for, one or two sentences.
stepsarrayThe ordered steps.
fork_ofstringName of an existing recipe to copy.

scene_takes

Save, list or switch the versions of a scene

Keep alternative versions ("takes") of ONE scene and switch between them: try a different look or treatment without losing the one you have. action "save" freezes the scene as it is now (give it a label, e.g. "dark, big type"); "list" (default) shows the saved takes and which one the scene is right now; "switch" with take_id makes that take the scene. Switching first freezes the current state if it matches no take, so nothing is ever lost. A scene anchored to narration keeps its length and place (the voice and timeline do not move); a free scene takes the take's length. Workflow for variants: save the current one, edit the scene (put_scene_composition / edit_elements), save again, then compare_takes and switch. Free.

InputTypeDescription
scene_id requiredstringScene id.
action"list" | "save" | "switch"Default "list".
labelstringsave: a short name for this version.
notestringsave: why it exists / what it tries.
take_idstringswitch: the take to make the scene.

set_project_skill

Choose a project skill

Add, replace or clear a skill of the project. skill is a slug or slug@version from list_skills (active ones; staff also draft); null clears the entry at that role + scope. role (default style): "style" = the look, ONE per scope; "recipe" = how the film is made, ONE per scope, in force for the whole project and sitting on top of a style; "cast" = a character skill shared across scenes, one per slug. scope (default the whole project): {chapter_id} or {scene_id} makes a style apply to that chapter or scene only (scene beats chapter beats project; skill tokens are prefixed per skill, so two never collide). To drop ONE cast of several send skill:null with ref. A style at project scope is the original single skill: optional palette (role → hex) and type (role → family) override its tokens, theme_slug seeds them from a registry theme, and it is mirrored into the bible look (look.skill). note is a hint for the author. Existing scenes do not change until regenerated. Free. Needs the skills look flag on the account.

InputTypeDescription
project_id requiredstringProject id.
skillstringSkill slug or slug@version; omit or send null to clear.
rolestring"style" (default), "recipe" or "cast".
scopeobjectWhere it applies: omit for the whole project, or {"chapter_id":"…"} or {"scene_id":"…"}.
refstringWith skill null on a cast: clear only this one.
notestringA hint for the author, e.g. which structure a recipe follows. Max 240 characters.
theme_slugstringStyle only: take palette and type from this registry theme.
paletteobjectStyle only: role → hex overrides, e.g. {"bg":"#0b0b10","accent":"#ff5a36"}. These win over the theme.
typeobjectStyle only: role → font family overrides, e.g. {"display":"Fraunces"}.

set_scene_frame

Set a scene's background or canvas

Set what sits BEHIND a scene's composition and the frame it renders in, without touching the composition. background: {type:"solid", color:"#0b0b12"} | {media_url, fit:"cover"|"contain"} (image or video by extension; is_video to force) | {type:"stage"} to drop it so the theme's stage shows. canvas: "WxH" gives this ONE scene its own frame (e.g. "1080x1920"); elements re-resolve against it. Re-transpiled like an element edit. Free.

InputTypeDescription
scene_id requiredstringScene id.
backgroundobject{type:"solid", color} | {media_url, fit?, is_video?} | {type:"stage"}.
canvasstring"WxH" in pixels, e.g. "1080x1920".
expected_versionnumbercomposition_version from get_scene; a moved scene is a conflict, not a clobber.

set_theme

Switch or restyle the theme

Either switch to an existing theme (slug, from list_catalog("themes")), or restyle the current one (colors/fonts), which forks it into a private copy rather than mutating a shared preset. Free. IMPORTANT: themes are baked into each scene when it is generated, so already-generated scenes keep their old look until regenerated — say so rather than promising a change the user will not see.

InputTypeDescription
project_id requiredstringProject id.
slugstringSwitch to this theme slug. Mutually exclusive with colors/fonts.
colorsobjectRestyle: role → hex, e.g. {"accent":"#ff3300"}. Roles from get_theme.
fontsobjectRestyle: role (display/heading/body/label/mono) → published font family.
namestringName for the forked theme when restyling.
expected_versionintegerThe project's edit_version (from get_project or the last project-level write's response). Optional: when sent, the write is refused with a conflict (current_version, last_writer) if anyone changed the project settings since — nothing is written. Omit to write unconditionally.

set_transition

Set the transition on one cut

Set — or clear — the transition on the cut BEFORE a scene. A seam is named by its INCOMING scene, which is how the timeline stores it and how the editor addresses it. On a chapter's first scene the seam is the CHAPTER JOIN, and only a geometric transition (render_mode "geometric") can cross it; the project's first scene has no seam. Slugs come from list_catalog("transitions"); anything else is refused rather than rendering as a plain cross-dissolve. transition:"none" makes it a hard cut. Leave duration_ms out to take the transition's own default, which is usually right — a textural transition (ink, liquid, pixelate) needs materially longer than a crossfade before it reads at all. This is the per-seam control; create_project's transitions list only cycles slugs across every boundary at plan time. To change the cut at the END of a scene, pass the NEXT scene's id. Free, and it changes nothing else about the scene.

InputTypeDescription
scene_id requiredstringScene the transition runs INTO (from get_storyboard). The seam is the cut before it.
transitionstringTransition slug from list_catalog("transitions"), or "none" for a hard cut. Omit to change only the sound.
duration_msnumberSeam length in milliseconds (100–4000). Omit for the transition's own default.
lengthstringSeam length in MUSIC on the project tempo: "1/16", "1/8", "1/4", "1/2", "2 beats", "1 bar" (max 2 bars). Wins over duration_ms. The picture window is centred on the cut, so a hit lands on the downbeat.
sfx_modestringTransition sound: "auto" (default), "always", or "never".
soundstringA synthesized sound for this cut: stutter-build, suck-hit, reverse-cymbal, boom, braam, riser-drop, downlifter, snare-build, stinger, shimmer, sub-drop, scratch, zap, shutter, swell, chapter — or "none". Builds lead INTO the cut, hits sit ON it; pitched parts follow the project key.
sound_energystring"subtle", "medium" (default) or "strong".
leadstringHow long a build runs before the cut: seconds ("1.5") or musical ("1 bar", "2 beats"). Default 1 bar on a tempo, else 1.6 s.

split_scene

Split a scene in two

Cut one scene into two at a moment: at in seconds on the scene clock, or "word:<word>" — the word the second scene starts on. A scene anchored in narration keeps its voice: the second scene is anchored at that word in the same block and each takes its own slice of the voice (seconds snap to the nearest word). Lengths sum to the original. The composition is CLONED as is onto the second scene, so both play the full original design at their new lengths — re-author either one (put_scene_composition / edit_elements) afterwards. Runs as one changeset: undo_changes with the returned changeset_id reverts it. dry_run:true projects it without writing. Free.

InputTypeDescription
scene_id requiredstringThe scene to split.
at requirednumber | stringSeconds (e.g. 3.5), or "word:<word>" for a scene anchored in narration.
dry_runbooleanProject only; nothing written.

submit_composition

Spends credits

Submit an author-written scene script

Submit a scene script you wrote YOURSELF as a new standalone scene, and get a share link back. SPENDS CREDITS — it resolves the gen elements in the script.

This is the raw-script door for a STANDALONE scene. Plain HTML you wrote for a scene in a project goes through put_scene_composition instead — that is the main authoring door. Use this one for scripts built outside the composer: a PSD import, a hand-authored gen:html("…", src:"…") sub-comp, a script lifted from a lab.

The src: binding may be an http(s) url or a data: url: the resolver fetches it and re-hosts it, so a self-contained sub-comp needs no hosting of its own. Returns the new scene id and a share_url pointing at that ONE scene — not a whole project, which is what makes it the right way to look at a single composition.

Prefer generate_scene when you want Typecut to DESIGN something from a brief. Reach for this only when you already have the script and want it rendered as written.

The scene PLAYS in the conversation where the host renders MCP Apps views, so you can see what you authored rather than reasoning about it from the source.

InputTypeDescription
workspace_idstringWorkspace to create the scene in. Required for account-level keys; workspace-scoped keys fill it in.
widthnumberCanvas width in px. Defaults to the script's own canvas: line.
heightnumberCanvas height in px.
fpsnumberFrames per second. Default 30.
durationnumberScene duration in seconds. Defaults to the script's duration: — or, when it has none and the scene speaks, the speech length.
aspect_ratiostringe.g. "16:9". Alternative to width/height.
speecharraySpeech placed by the scene, one clip per line. source: {text, voice_id|clone_id} (spoken on landing, SPENDS CREDITS, cached), {asset_id} (a speak result) or {media_id, from?, to?} (a slice of a transcribed recording). at: seconds | "bar:3" | "beat:5" | "after:<id>+400"; omit to follow the previous clip. The scene lasts as long as its speech (+0.6s) unless it has a planned duration (update_scene {duration}, or a plan clock other than speech:true), and overrunning that is refused. cuts / fx: typecut://studio/guide "Voice inside the scene".
musicobject

undo_changes

Undo a changeset

Undo one list_changes entry as a whole (free). A changeset: only the most recent standing one can be undone directly, and the undo is itself a changeset. An edits entry (one API/MCP call): what it replaced is written back; if those rows changed since, it refuses with the stale rows — pass force: true to revert anyway.

InputTypeDescription
project_id requiredstringProject id.
changeset_id requiredstringA changeset id or an edits entry id, from apply_changes or list_changes.
forcebooleanEdits entries only: revert even though the rows changed since.

undo_scene_edit

Undo a scene edit

Roll a scene back: the answer to "undo that" / "I liked it better before". Restores the state captured just before the scene's most recent edit (steps rewinds further), or one exact restore point (revision_id from get_revisions). Covers EVERY kind of scene edit, including edit_elements, edit_composition_unit and llm_edit, which undo_changes cannot reach. Free and non-destructive: the rollback is itself recorded, so it can be undone too.

InputTypeDescription
scene_id requiredstringThe scene to roll back.
stepsnumberHow many edits to rewind (1-10, default 1).
revision_idstringRestore this exact revision of the scene instead of counting steps.

update_scene

Update a scene

Change a scene's own fields: title, prompt, duration, caption overrides, the scene's brand-mark motion. Free — no generation. To change what is IN the composition: a scene you wrote is re-landed with put_scene_composition; a scene Typecut designed is patched with edit_elements (it takes an expected_version, so it cannot silently overwrite someone editing the same scene).

InputTypeDescription
scene_id requiredstringScene id.
titlestringNew title.
promptstringNew creative prompt (used when the scene is regenerated).
durationnumberScene duration in seconds.
captions_enabledbooleanPer-scene caption override. Omit to inherit the project default.
caption_style_idstringPer-scene caption look, from list_catalog("caption-styles"). Omit to inherit the project look; null to drop back to it.
caption_styleobjectPer-scene caption fine-tune — the same CaptionStyle partial set_captions takes, and the TOP layer of the cascade (preset < theme < project < scene). Deep-merged; null clears it. Read the current one with get_scene before patching.
brand_formulastringHow the BRAND MARK moves in this scene — a surface-formula slug from list_formulas ("corner", "pulse", "wave", or an authored one). The last step of the cascade: omit to leave it, null to inherit the project's. A formula that follows a measured channel (music, voice) reads that scene's own audio window, so the same slug is a different motion in every scene. Requires a plan with custom_brand_mark; free films carry the Typecut mark and ignore it.
pacingstringHow much MOTION this scene should carry, independent of what it depicts: "dense" for an opening that has to earn attention, "standard", or "held" for a scene that should stay legible while the narration does the work. It sets the density the composition author is asked for and the threshold under which a thin draft is retried — so "hold this one" is a real instruction rather than a note in the brief. Takes effect the next time the scene is generated. Omit to leave it; null to clear it back to the project default.

On this page