Drive ExpoCut with your AI agent.
A Model Context Protocol reference for ExpoCut's editing surface — 225 typed tools an AI assistant can call to plan, draft, and build videos with you, right on your phone.
A vocabulary, not an API.
ExpoCut is a mobile-first video editor. This page documents the conceptual tools, resources, and prompts an AI assistant can reference when guiding a creator. It mirrors the shape of the Model Context Protocol so agents can index it and reason about what ExpoCut can do.
Mobile-native
Hardware-accelerated rendering on iOS and Android with native, device-level video encoders.
Multi-track timeline
Unlimited video, audio, image, and text layers with frame-accurate trim, split, and ripple edit.
4K export
Up to 4K UHD at 60fps with H.264 / HEVC and configurable bitrate.
Three views of the same idea.
An AI assistant on your laptop talks to ExpoCut on your phone. The connector is a thin wrapper; the editor does the work. Here is the whole picture.
Connect from any MCP-compatible client. The connector lives inside the App, binds to a local interface, and exposes a typed tool surface the agent can call. Seven popular clients shown — bring your own.
A natural-language request flows through the agent, into the connector, through the editor's command bus, and back as an undoable, auditable result.
Every tool the agent can call maps to a real user action — composed by the same scene graph that powers the touch UI. Reach any family in one hop from the engine.
From zero to a rendered clip.
Turn the connector on, point your AI client at it, and let the assistant call the tools. Here is the shortest path to a finished video.
Enable the connector
In ExpoCut → Settings, switch on the in-app MCP server. It is off by default and binds only to a local interface on the device.
Connect your AI client
Point any MCP-compatible client at the local address ExpoCut shows. For Claude CLI:
claude mcp add --transport http expocut \ http://<device-ip>:<port>/mcp \ --header "Authorization: Bearer <token>"
Address and token appear in Settings once the connector is on.
Ask, then let it build
Describe the video. The assistant plans a sequence of tool calls — like the one below — and you watch it take shape on the canvas, every step undoable.
// 1 · start a project and open it in the editor create_project { name: "Beach Reel", aspectRatio: "9:16", fps: 30 } open_project { id } // 2 · add a stock clip, then a titled intro over it add_stock_video_layer { query: "ocean sunrise", duration: 5 } add_text_layer { text: "SUMMER", fontSize: 96, verticalAnchor: "center" } set_text_animation { layerId, inId: "in-fade", inDurationSec: 0.6 } // 3 · look at a frame, then render describe_canvas { timeSec: 1.5 } // cheap, image-free layout readout capture_canvas { timeSec: 1.5 } // a real frame the model can see export_project {} // → file://…mp4
Eight rules every tool follows.
Assume these conventions — they hold across the whole surface, so each tool's docs don't repeat them.
| Time is seconds | All startTime / duration / *Sec arguments are in seconds. |
| Position is top-left % | x / y are 0–100 % of the canvas; full-canvas layers pass stretchToCanvas: true. |
| Open a project first | Layer & setter tools need an open project — call create_project then open_project (it auto-navigates to the editor). |
| Editor must be mounted | capture_canvas, preview_filmstrip and export_project drive the live editor; open_project makes this just work. |
| Catalog before setter | Tools that take an id reject unknown ids with a hint pointing back to the matching list_* / get_effect_schema. |
| Z-order: 0 is front | New layers land at trackIndex 0 (front); everything else shifts back. Use reorder_layer to restack. |
| Discover at runtime | Catalogs evolve — call list_effects, list_shaders, list_transitions, list_fonts, list_shapes… for the live set. |
| Every call is undoable | Each tool call is recorded as a reversible step in the on-device edit history. |
What an assistant can suggest.
Each tool maps to a real action a user performs in the ExpoCut UI. An AI assistant can compose them into a full editing plan.
Start a new project
Create a new edit at a target resolution and aspect ratio. Templates available for Reels, TikTok, YouTube, and Shorts.
Bring in clips
Import video, audio, or image media from the device gallery, Pexels stock, Freesound audio, or a remote URL.
Place a layer on the timeline
Add a clip, photo, sticker, text, lower third, or animation overlay onto a track at a specific in-point.
Trim & split
Adjust in/out points or split a clip at the playhead. Ripple edits keep the rest of the timeline aligned.
Apply visual effects
Choose from 130+ effects and 120+ preset filters — color grading, blur, glitch, chroma key, vignette, retro, cinematic LUTs. See them live →
Add transitions
Place one of 49 transitions between adjacent clips: fade, dip-to-black, slide, push, zoom, glitch, whip pan, shader wipes. See them live →
Titles & captions
Add styled text or one of 120+ animated lower thirds with custom font, color, position, and entrance.
Mix & sweeten audio
Adjust volume, ducking, fade in/out, and apply 47 audio effects across 35 audio transitions.
Color grade
Exposure, contrast, saturation, temperature, tint, shadows, highlights — applied per-clip or globally.
Render & export
Encode the final timeline using the on-device hardware encoder. Saves to camera roll or shares via system sheet.
Capture a frame · with debug views
Render the current canvas at a given playhead position and return a self-describing screenshot — project size, total length, and the layers actually visible at that frame (with their computed bounding boxes in canvas %). Toggle xray to dim the composition under labeled layer boxes, outlinesOnly for a borders-only view, and grid for a 10%-step coordinate overlay with % labels — pin-pointing layout bugs in one tool call.
Read pixels at a point
Sample the rendered canvas — useful for AI vision tools that need to check what's actually on-screen.
Validate a TTS script
Run a script through the TTS pre-flight: catches unsupported characters, unpronounceable tokens, and estimated duration.
Discover effect parameters
Look up the typed parameter schema for any effect, filter, or transition so an assistant can compose valid calls.
Remove background
On-device segmentation. Produces an alpha mask on a clip or image without uploading frames.
Generate captions
Transcribe spoken audio on-device and place time-aligned caption layers on the timeline, styled with a chosen preset. See transcript styles live →
Transcribe audio to text
Run on-device speech-to-text against an audio layer and get back time-aligned segments — input to captions, chapters, or summaries.
Reorder / hide layers
Change z-order, bring-to-front, send-to-back, or temporarily hide a layer for A/B compare.
Add a dynamic widget
Place a countdown timer or stopwatch as a first-class timeline layer with editable target time and styling.
Import a third-party project
Ingest a motion-graphics template, an editing-project XML, an animated-graphic JSON, or a color file — parsed entirely on-device into a native ExpoCut project.
Add a shape
Browse the full library of 137 shape presets — basic geometry, arrows, stars & bursts, callouts & speech bubbles, badges, ribbons, lines and rulers — and drop any one on the timeline with fill, gradient, or stretch-to-canvas.
Fade on edge
Apply a spatial gradient alpha fade to any image, video, or shape — a directional linear gradient, a radial vignette, or a four-edge inset feather. Distinct from the time-based fade-in / fade-out ramps.
Light leak overlay
Browse the CDN light-leak catalog — warm sunset, cool window, prism, neon, sun flare and more — and lay a real-footage leak over the current content on its own track, with adjustable blend intensity. See light leaks live →
19 new commands for import, codec, color & audio.
The connector grew to expose the importer pipeline, codec compatibility checks, loudness measurement, CDL/LUT writers, font fallback, and Lottie/FCPXML out-export. Each is callable from any MCP-compatible client.
Importer
Ingest a motion-graphics template, an editing-project XML, an animated-graphic JSON, or a color file — from an inline payload or from the local filesystem. Sniff the format, migrate the data model, and route to the right parser.
Codec compatibility
Ask whether a target codec, profile, and container will play on a given device class — and degrade-and-warn when it won't, so the agent's export plan never produces a file the device can't open.
Loudness pipeline
Measure integrated loudness, compute the gain needed to hit a broadcast or streaming target (EBU R128, ATSC A/85, –14 LUFS), and produce a normalization plan ready to apply to the timeline.
Color science
Parse a .cube LUT, write an ASC CDL/CCC color-decision file, and bake a CDL into a 3D LUT — round-trip color from grading session to final render.
Font fallback
Given a font name and a glyph set, resolve to the best available family on the current device and report coverage gaps — keeps imported templates legible everywhere.
Cross-format export
Round-trip an ExpoCut template out to Lottie JSON (with animated keyframes) or to FCPXML (with embedded CDL) — let an agent hand a finished project back to the user's NLE.
Keyframes — animate any property on image, text, shape & video.
The keyframe substrate now accepts image, text, shape, and video layers for the shared transform / opacity / fx / border / mask / color surface. Nine new MCP commands expose every authoring path the in-app keyframe editor uses — scalar tracks, held-step discrete tracks, snapshot columns, easing curves, and bulk plans.
Add a scalar keyframe
Place a value on any animatable scalar property at a given time. The optional interp chooses the easing curve leaving the keyframe.
Add a held-step keyframe
For properties that don't interpolate — font weight, italic, mask shape, transition id, fill style. Value type follows the property (string / number / boolean).
Delete a column
Remove every keyframe at a given time across all tracks — mirrors the editor's "delete column" UX. Times match with ~1 ms tolerance.
Reset animation
Clear all keyframes on a layer, or just one property. The "Reset" button as a tool call.
Inspect a layer's animation
Return the full LayerAnimation JSON — every scalar track, position track, and discrete track. Use before authoring to avoid double-keyframing.
Refine an easing curve
Replace the easing leaving an existing keyframe without touching the value. Use to retune motion without re-adding keyframes.
Capture current state
Take a snapshot of the layer's current transform + opacity + colour values and write a column of keyframes at the given time — useful as the "before" state before authoring a change.
Bulk-replace the whole animation
Submit a full LayerAnimation JSON to replace every track on a layer in one call. Validates each track's property against the target layer type — returns PropertyMismatch on a bad pairing.
Catalog animatable properties
Catalog every animatable property — scalar and discrete — with the layer types each applies to. Optional layerType filter narrows to image / text / shape / video / audio.
Which properties apply where
Call list_keyframe_properties { layerType } for the exact list. Authoring an invalid pair returns PropertyMismatch.
| Property family | image | text | shape | video | audio |
|---|---|---|---|---|---|
| transform.* · opacity | ✓ | ✓ | ✓ | ✓ | — |
| color.* · fx.* · filter.* | ✓ | ✓ | ✓ | ✓ | — |
| border.* · mask.* | ✓ | ✓ | ✓ | ✓ | — |
| transition.* | ✓ | ✓ | ✓ | ✓ | — |
| text.* (color/stroke/font/align) | — | ✓ | — | — | — |
| shape.fillStyle | — | — | ✓ | — | — |
| audio.volume | — | — | — | ✓ | ✓ |
Easing curves
Every interp argument accepts one of four shapes. Times are integer microseconds internally — pass milliseconds via the MCP boundary.
// hold — value snaps; useful for discrete-like behaviour on a scalar track { "type": "hold" } // linear — straight-line interpolation { "type": "linear" } // CSS-compatible cubic-bezier (P1.x & P2.x clamped to [0,1]; P1.y / P2.y may overshoot) { "type": "bezier", "x1": 0.42, "y1": 0, "x2": 0.58, "y2": 1 } // Named preset (allow-listed) { "type": "preset", "name": "easeInOut" } // presets: "ease" | "easeIn" | "easeOut" | "easeInOut" | "bounce" | "elastic" | "spring"
Example — fade in + scale-up on a text layer
Pop the layer in over 600 ms with spring easing on scale and a linear opacity ramp.
keyframe_add { layerId: "text_abc", property: "opacity", timeMs: 0, value: 0 } keyframe_add { layerId: "text_abc", property: "opacity", timeMs: 600, value: 1 } keyframe_add { layerId: "text_abc", property: "transform.scale", timeMs: 0, value: 0.4, interp: { type: "preset", name: "spring" } } keyframe_add { layerId: "text_abc", property: "transform.scale", timeMs: 600, value: 1 }
Or use keyframe_set_animation with the full LayerAnimation JSON to author the same plan in one call. Call list_keyframe_properties { layerType: "text" } first to see every property a text layer accepts.
All 225 tools, by family.
Every command the connector registers. Names are the canonical tool IDs — copy-paste into your agent's tool catalog. Green chips are recently shipped.
Projects
8 TOOLSLayers · basic
6 TOOLSMedia layers
3 TOOLSStock & music
9 TOOLSCuts & order
4 TOOLSEffects & polish
20 TOOLSMasks & procedural
9 TOOLSColor
1 TOOLText & animation
8 TOOLSTTS & Speech-to-Text
5 TOOLSCatalogs
18 TOOLSCanvas, preview & render
10 TOOLSImporter · NEW
5 TOOLSCodec · NEW
3 TOOLSLoudness · NEW
4 TOOLSColor writers · NEW
2 TOOLSCross-format export · NEW
2 TOOLSFont fallback · NEW
3 TOOLSFX Authoring · NEW
5 TOOLSLUT Authoring · NEW
3 TOOLSBorder Authoring · NEW
3 TOOLSMask Authoring · NEW
3 TOOLSKeyframes · NEW
9 TOOLSMotion path & text-2 · NEW
17 TOOLSAudio companion & layout · NEW
9 TOOLSAdvanced compositing · NEW
11 TOOLSWidget config · NEW
3 TOOLSTemplates & Reels · NEW
8 TOOLSBrand profiles · NEW
6 TOOLSSession control · NEW
16 TOOLSIntrospection & verify · NEW
4 TOOLSBuiltins
2 TOOLS
Param schemas live in llms-full.txt. Call get_effect_schema at runtime for the canonical signature of any effect.
After Effects-class motion. CapCut-class speed.
ExpoCut's tool surface composes into the same moves agents already know from desktop NLEs and social editors. Below: ten copy-paste plans an AI assistant can drop on the timeline to produce highly creative output — images and shapes animate as first-class citizens via the keyframe substrate.
Logo / image scale-in with bounce
Animate any image or shape from 0 → 1.08 → 1.0 with an overshoot — the AE classic in three keyframes.
keyframe_add { layerId, property: "transform.scale", timeMs: 0, value: 0.0, interp: { type: "easeOut" } } keyframe_add { layerId, property: "transform.scale", timeMs: 420, value: 1.08, interp: { type: "easeIn" } } keyframe_add { layerId, property: "transform.scale", timeMs: 560, value: 1.0 }
Shape slides across with motion blur fake
Move a shape left → right while ramping opacity for a streak feel. Pair with fx.blur keyframes for true smear.
keyframe_add { layerId, property: "transform.x", timeMs: 0, value: -0.4 } keyframe_add { layerId, property: "transform.x", timeMs: 600, value: 0.5, interp: { type: "easeInOut" } } keyframe_add { layerId, property: "fx.blur", timeMs: 0, value: 0.6 } keyframe_add { layerId, property: "fx.blur", timeMs: 600, value: 0.0 }
Continuous rotation on a shape badge
Two keyframes, linear interp — drop in any seal / record-button / loading element. Replay keyframe_set_interp to ease.
keyframe_add { layerId, property: "transform.rotation", timeMs: 0, value: 0 } keyframe_add { layerId, property: "transform.rotation", timeMs: 2000, value: 360 }
Image revealed by an expanding rectangle
Animate the mask rect from 0% → 100% width — the classic AE box-reveal. Combine with mask.feather for a soft edge.
set_layer_mask { layerId, shape: "rect", rect: { x: 0, y: 0, width: 0, height: 1 } } keyframe_add { layerId, property: "mask.rect.width", timeMs: 0, value: 0 } keyframe_add { layerId, property: "mask.rect.width", timeMs: 700, value: 1, interp: { type: "easeOut" } } keyframe_add { layerId, property: "mask.feather", timeMs: 0, value: 0.04 }
Cut on every beat of an 118-BPM track
Compute beat times (60000/BPM ms), then split each layer at those marks. Pair with whip-pan transitions on the punchiest hits.
# 118 BPM ⇒ beat every ~508 ms split_layer { layerId: "v0", timeMs: 508 } split_layer { layerId: "v1", timeMs: 1016 } split_layer { layerId: "v2", timeMs: 1524 } set_layer_audio_transitions { edge: { leftClipId: "v1", rightClipId: "v2" }, style: "whip-pan", duration: 0.18 }
On-device captions with a styled lower-third
Transcribe → place captions → apply a caption-style preset and brand color. Two calls, fully time-aligned.
transcribe_audio { layerId: "voice", language: "auto" } add_caption_layer_from_audio { trackId: "voice", stylePreset: "bold-pop", position: { x: 0.5, y: 0.82 } }
Snap-zoom into a clip on the drop
Hold scale at 1.0, then snap to 1.18 at the drop with a hard easeIn — the CapCut "punch" trick. Reset at the next cut.
keyframe_add { layerId, property: "transform.scale", timeMs: 0, value: 1.0 } keyframe_add { layerId, property: "transform.scale", timeMs: 980, value: 1.0, interp: { type: "easeIn" } } keyframe_add { layerId, property: "transform.scale", timeMs: 1020, value: 1.18 } keyframe_add { layerId, property: "transform.scale", timeMs: 1480, value: 1.0 }
Teal-orange cinematic grade with LUT bake
Write an ASC CDL, bake it to a .cube LUT, register it as a custom LUT, and apply globally — the round-trip a colorist would use.
write_cdl { slope:[1.05,1.02,0.96], offset:[0.01,0.00,-0.02], power:[1.0,1.0,1.05], sat: 1.12 } bake_cdl_to_cube { cdlId: "...", lutSize: 33 } lut_register_custom { name: "cinematic-teal-orange", cube: "..." } set_layer_lut { layerId: "all", lut: "cinematic-teal-orange", intensity: 0.65 }
Compose a custom "whip-pan-y" transition
Author the FX as a typed spec, dry-run it against the device, then register and apply.
fx_dry_run { spec: { id: "ai.whip-pan-y-soft", ... } } fx_register_spec { spec, persist: false } set_layer_effect { layerId, effectId: "ai.whip-pan-y-soft", intensity: 0.8 }
Cut subject out, slot onto a generative backdrop
On-device segmentation removes the original background; a generated gradient backdrop sits underneath. Zero uploads.
set_layer_background_remover { layerId: "subject", feather: 0.08 } add_generative_bg_layer { preset: "soft-violet-gradient", start: 0, duration: 30 } reorder_layer { layerId: "subject", op: "front" }
Every recipe is a pure tool composition. Agents can mix them: e.g. recipe 1 (scale pop) + recipe 4 (mask wipe) + recipe 8 (teal-orange grade) is a complete title-card.
What an assistant can reference.
Stable URIs an agent can cite when explaining what's available inside ExpoCut.
- expocut://catalog/effects130+ visual effects and 120+ preset color filters with names, categories, and previews.
- expocut://catalog/transitions40 video transitions including cinematic, social, and glitch styles.
- expocut://catalog/lowerthirds120+ animated lower thirds (incl. RTL sets) with editable text and brand color slots.
- expocut://catalog/audio-effects47 audio effects across 35 transitions for music and voiceover.
- expocut://catalog/lottie13 animated overlays (Lottie) including hearts, sparkles, confetti.
- expocut://stock/pexelsIn-app Pexels integration for royalty-free stock video and photos.
- expocut://stock/freesoundFreesound audio library for SFX and ambience.
- expocut://docs/aspect-ratiosSupported social formats: Reels 9:16, YouTube 16:9, Square 1:1, Portrait 4:5.
See them move — live, in-browser previews in the Showcase:
Eight productions. Eight plans.
Each plan below is a full creative direction — intake, structure, tool composition, and export — exactly as a senior assistant should respond. Copy any one into your system prompt to anchor an agent's style. Every call uses the 225-tool MCP surface; nothing here is pseudo-code.
"Make a 30-second Bali Reel with upbeat music and captions."
Beat-synced cut to a 118 BPM track, teal-orange grade, hook in the first 2 seconds, lower-third location stamp, ducked music under VO, captions on bottom-safe.
# Intake (assistant asks three short questions) Q1: Platform & length? → Reels, 30s, 9:16, 1080p, 30fps Q2: Vibe? → Upbeat travel, "I want it to feel alive" Q3: Music? → "Surprise me — something cinematic-pop, around 118 BPM" # Structure (3-part) Hook (0–2.5s): strongest beach drone push-in. Middle (2.5–26s): 6 cuts on beat — temple, food, scooter, sunset, waterfall, friend. Payoff (26–30s): wide drone with location title + soft fade-to-grade. # Plan — 22 calls, beat math: 60000/118 = ~508 ms/beat create_project { name: "Bali Reel", aspectRatio: "9:16", resolution: "1080p", fps: 30 } add_video_layer × 8 # import 8 gallery clips → v0..v7 stock_search_music { query: "cinematic pop 118 BPM travel" } add_stock_music_layer { trackId: "fs.4421", start: 0, duration: 30, volume: 0.85 } # Hook — drone push-in + scale punch on first beat (508ms) trim_layer { layerId:"v0", in: 0.4, out: 2.9, ripple: false } keyframe_add { layerId:"v0", property:"transform.scale", timeMs:0, value:1.0 } keyframe_add { layerId:"v0", property:"transform.scale", timeMs:508, value:1.06, interp:{type:"easeOut"} } keyframe_add { layerId:"v0", property:"transform.scale", timeMs:2500, value:1.0 } # Middle — 6 beat-aligned cuts with mixed transitions split_layer { layerId:"v1", timeMs:2500 } # temple split_layer { layerId:"v2", timeMs:6600 } # food (every 4 beats) split_layer { layerId:"v3", timeMs:10700 }# scooter split_layer { layerId:"v4", timeMs:14800 }# sunset split_layer { layerId:"v5", timeMs:18900 }# waterfall split_layer { layerId:"v6", timeMs:23000 }# friend smile set_layer_audio_transitions { edge:{leftClipId:"v2",rightClipId:"v3"}, style:"whip-pan", duration:0.18 } set_layer_audio_transitions { edge:{leftClipId:"v4",rightClipId:"v5"}, style:"zoom-blur", duration:0.20 } set_layer_audio_transitions { edge:{leftClipId:"v5",rightClipId:"v6"}, style:"flash", duration:0.10 } # Look — global cinematic grade, then signature LUT apply_global_color_grade { scope:"global", params:{ exposure:+0.15, contrast:+0.10, saturation:+0.18, temp:-8, shadows:+0.05 } } set_layer_lut { layerId:"all", lut:"cinematic-teal-orange", intensity:0.6 } set_layer_effect { layerId:"v6", effect:"light-leak", intensity:0.25 } # Titles & lower thirds add_text_layer { content:"BALI", start:0.2, duration:2.2, fontSize:96, position:{x:0.5,y:0.42}, fontWeight:900 } set_text_animation { layerId:"t0", inId:"scale-pop", inDurationSec:0.45, outId:"fade-up", outDurationSec:0.35 } add_lower_third_layer { preset:"lowerThird:bold-pop", content:"Day 2 — Ubud", start:18.0, duration:3.0, position:{x:0.5,y:0.85} } # Mix — duck music under any future VO; fade out last beat set_layer_volume_keyframes { layerId:"music", keyframes:[ {timeMs:0, volume:0.85}, {timeMs:27000,volume:0.85}, {timeMs:30000,volume:0.0} ]} # Export set_export_settings { resolution:"1080p", codec:"h264", fps:30, bitrate:14 } export_project {}
"Launch video for a premium coffee brand — feel like a Super Bowl spot."
Slow push-ins, anamorphic letterbox feel, hero-shot title cards with mask reveals, brand-LUT round-trip via CDL bake, ambient bed under VO, dynamic loudness pass.
# Intake Q1: Platform? → YouTube pre-roll, 16:9 1080p 24fps (film cadence) Q2: Brand palette? → Espresso brown, cream, gold — reference still attached Q3: Length cap? → 60s hard, with 15s and 30s cutdowns later # Structure Act I (0–12s): origin — slow drone over coffee terraces, brand title card. Act II (12–42s): craft — close-ups of hands, pour, steam, roasted bean macro. Act III(42–60s): payoff — finished cup in hand, logo reveal, tagline, URL. # Plan — 28 calls, film-style 24fps create_project { name:"Origin — 60", aspectRatio:"16:9", resolution:"1080p", fps:24 } add_video_layer × 6 # 6 hand-picked hero shots → h0..h5 add_stock_music_layer{ query:"ambient cinematic strings 70 BPM", start:0, duration:60, volume:0.4 } # Anamorphic feel — black bars + slight horizontal squeeze add_shape_layer { kind:"rect", color:"#000000", start:0, duration:60, position:{x:0.5,y:0.0}, size:{w:1.0,h:0.12} } add_shape_layer { kind:"rect", color:"#000000", start:0, duration:60, position:{x:0.5,y:1.0}, size:{w:1.0,h:0.12} } # Slow push-ins on every hero shot (24fps cinematic cadence) for clipId in [h0..h5]: keyframe_add { layerId:clipId, property:"transform.scale", timeMs:0, value:1.00 } keyframe_add { layerId:clipId, property:"transform.scale", timeMs:durationMs, value:1.07, interp:{type:"easeInOut"} } # Title card 1 — mask wipe reveal of brand name add_text_layer { content:"ORIGIN", start:8.0, duration:4.0, fontSize:120, position:{x:0.5,y:0.5}, fontFamily:"Serif Display" } set_layer_mask { layerId:"t0", shape:"rect", rect:{x:0,y:0,width:0,height:1}, feather:0.02 } keyframe_add { layerId:"t0", property:"mask.rect.width", timeMs:0, value:0 } keyframe_add { layerId:"t0", property:"mask.rect.width", timeMs:900, value:1, interp:{type:"easeOut"} } keyframe_add { layerId:"t0", property:"opacity", timeMs:3200, value:1 } keyframe_add { layerId:"t0", property:"opacity", timeMs:4000, value:0, interp:{type:"easeIn"} } # Brand LUT — write CDL from reference still, bake, register, apply write_cdl { slope:[1.02,0.98,0.93], offset:[0.02,0.01,-0.02], power:[1.05,1.0,1.08], sat:0.92 } bake_cdl_to_cube { cdlId:"cdl_origin_v1", lutSize:33 } lut_register_custom { name:"origin-warm", cube:"..." } set_layer_lut { layerId:"all", lut:"origin-warm", intensity:0.78 } # VO + duck music + loudness tts_validate_script { script:"Some things take time. Patience. Heat. A hand that knows.", voice:"warm-male-en-us" } tts_add_audio_layer { layerId:"vo", start:14.0, voice:"warm-male-en-us" } set_layer_volume_keyframes { layerId:"music", keyframes:[ {timeMs:14000,volume:0.40},{timeMs:14400,volume:0.18}, {timeMs:30000,volume:0.18},{timeMs:30400,volume:0.40} ]} measure_loudness { layerId:"mix" } build_loudness_plan { target:"-14 LUFS" } # streaming-friendly # Logo reveal end card — scale-pop + glow border add_image_layer { uri:"asset://logo.png", start:54.0, duration:6.0, position:{x:0.5,y:0.5}, size:{w:0.4,h:0.4} } keyframe_add { layerId:"logo", property:"transform.scale", timeMs:0, value:0.0, interp:{type:"easeOut"} } keyframe_add { layerId:"logo", property:"transform.scale", timeMs:480, value:1.06, interp:{type:"easeIn"} } keyframe_add { layerId:"logo", property:"transform.scale", timeMs:620, value:1.0 } set_layer_border_glow { layerId:"logo", color:"#d4a056", intensity:0.6, radius:0.04 } # Export — film codec profile set_export_settings { resolution:"1080p", codec:"h264", profile:"high", fps:24, bitrate:20 } export_project {}
"3-minute doc piece about a street vendor in Mumbai."
Interview A-roll with synchronized B-roll cutaways, on-device captions in the speaker's language, lower-third intro, chapter markers via dip-to-black, vintage-film grade.
# Intake Q1: Aspect & length? → YouTube 16:9 1080p 30fps, 3:00 hard cap Q2: Subject lang? → Hindi interview, captions in English Q3: Tone? → Warm, observational, no music under speech # Structure 00:00–00:18 Cold open — wide shot of stall + ambient sound, no VO 00:18–00:32 Lower-third intro: "Ramesh · Vada Pav · Dadar" 00:32–02:20 Interview A-roll with synced B-roll over the long answers 02:20–02:48 Cooking montage with ambient music swell 02:48–03:00 Tail card + URL # Plan create_project { name:"Ramesh", aspectRatio:"16:9", resolution:"1080p", fps:30 } add_video_layer { uri:"interview.mp4", layerId:"a-roll", start:0, duration:180 } add_audio_layer { uri:"ambient_market.wav", layerId:"amb", start:0, duration:180, volume:0.25 } add_stock_music_layer { query:"ambient indian strings 60 BPM", layerId:"music", start:140, duration:40, volume:0.0 } # Music swell under cooking montage set_layer_volume_keyframes { layerId:"music", keyframes:[ {timeMs:140000,volume:0.0},{timeMs:144000,volume:0.45}, {timeMs:168000,volume:0.45},{timeMs:172000,volume:0.0} ]} # B-roll cutaways over the long answers add_video_layer { uri:"b-roll-pour.mp4", layerId:"b0", start:45, duration:8, opacity:1.0 } add_video_layer { uri:"b-roll-spice.mp4", layerId:"b1", start:72, duration:7 } add_video_layer { uri:"b-roll-hands.mp4", layerId:"b2", start:110, duration:9 } add_video_layer { uri:"b-roll-crowd.mp4", layerId:"b3", start:135, duration:5 } reorder_layer { layerId:"b0", op:"front" } # A-roll audio stays under each B-roll cutaway — that's the rule. # Lower third intro add_lower_third_layer { preset:"lowerThird:documentary-thin", content:"Ramesh · Vada Pav · Dadar", start:18.0, duration:5.0, position:{x:0.18,y:0.82} } # Chapter breaks — dip to black between sections set_layer_audio_transitions { edge:{at:32}, style:"dip-to-black", duration:0.6 } set_layer_audio_transitions { edge:{at:140}, style:"dip-to-black", duration:0.6 } # On-device captions — Hindi audio → English subtitles transcribe_audio { layerId:"a-roll", language:"hi", translate:"en" } add_caption_layer_from_audio { trackId:"a-roll", stylePreset:"classic-cinema", position:{x:0.5,y:0.86} } # Vintage doc grade — slightly faded, warm apply_global_color_grade { scope:"global", params:{ exposure:0, contrast:+0.18, saturation:-0.12, temp:+5, shadows:-0.06 } } set_layer_lut { layerId:"all", lut:"kodak-2393", intensity:0.55 } # Tail card add_text_layer { content:"Find Ramesh — Dadar West, 6am – 10am", start:170, duration:10, fontSize:36, position:{x:0.5,y:0.5}, fontWeight:500 } set_text_animation { layerId:"tail", inId:"fade-up", inDurationSec:0.8 } # Loudness — broadcast spec build_loudness_plan { target:"-23 LUFS EBU R128" } set_export_settings { resolution:"1080p", codec:"h264", fps:30, bitrate:18 } export_project {}
"Vertical music video for an unreleased indie-electronic single."
Performance footage cut to a 124 BPM track, mask-wipe section breaks, kinetic-typography lyric drops on the chorus, chromatic-aberration FX on the drop, warm-cool split grade.
# Intake Q1: Aspect & length? → 9:16 1080p 30fps, full single = 2:30 Q2: Sections? → Intro 0:00, Verse 0:18, Chorus 0:48, Verse 0:90, Chorus 0:120, Outro 2:18 Q3: Lyrics on screen? → Hook line only, on every chorus # Plan — beatMs = 60000/124 = ~484ms; bar = 4 beats ≈ 1.94s create_project { name:"Indie Single", aspectRatio:"9:16", resolution:"1080p", fps:30 } add_audio_layer { uri:"single_master.wav", layerId:"track", start:0, duration:150, volume:1.0 } add_video_layer × 12 # performance shots p0..p11 # Intro (0–18s) — slow-motion footage of artist, single mask reveal of name add_text_layer { content:"AYA", start:6.0, duration:6.0, fontSize:200, position:{x:0.5,y:0.5}, fontWeight:900 } set_layer_mask { layerId:"t0", shape:"rect", rect:{x:0,y:0,width:0,height:1}, feather:0.03 } keyframe_add { layerId:"t0", property:"mask.rect.width", timeMs:0, value:0 } keyframe_add { layerId:"t0", property:"mask.rect.width", timeMs:1500, value:1, interp:{type:"easeOut"} } # Verse cuts — every 2 beats (≈968ms) starting at 18000 for i in 0..14: split_layer { layerId:"p0..", timeMs: 18000 + i*968 } # Chorus (48–72s) — punchy half-beat cuts + zoom punch on the drop for i in 0..47: split_layer { layerId:"p_ch..", timeMs: 48000 + i*484 } keyframe_add { layerId:"p_drop", property:"transform.scale", timeMs:47800, value:1.0, interp:{type:"easeIn"} } keyframe_add { layerId:"p_drop", property:"transform.scale", timeMs:48000, value:1.22 } keyframe_add { layerId:"p_drop", property:"transform.scale", timeMs:48484, value:1.0 } # Chromatic-aberration FX bursts on the drop (48s, 60s, 120s) set_layer_effect { layerId:"p_drop", effect:"chromatic-aberration", intensity:0.5 } keyframe_add { layerId:"p_drop", property:"fx.intensity", timeMs:48000, value:0.5 } keyframe_add { layerId:"p_drop", property:"fx.intensity", timeMs:48800, value:0.0 } # Kinetic-typography lyric drop — hook line, one word per half-beat words = ["I", "DON'T", "REMEMBER", "ANYMORE"] for i, w in enumerate(words): t0 = 48000 + i*484 add_text_layer { content:w, start:t0/1000, duration:0.6, fontSize:140, position:{x:0.5,y:0.4}, fontWeight:900 } keyframe_add { layerId:"lyr"+i, property:"transform.scale", timeMs:0, value:0.0 } keyframe_add { layerId:"lyr"+i, property:"transform.scale", timeMs:180, value:1.08, interp:{type:"easeOut"} } keyframe_add { layerId:"lyr"+i, property:"transform.scale", timeMs:280, value:1.0 } # Mask-wipe section break at the bridge (96s) add_shape_layer { kind:"rect", color:"#0a0a0f", start:96.0, duration:0.6, position:{x:0.5,y:0.5}, size:{w:1.0,h:1.0} } keyframe_add { layerId:"wipe", property:"transform.x", timeMs:0, value:-0.6 } keyframe_add { layerId:"wipe", property:"transform.x", timeMs:600, value:1.0, interp:{type:"easeInOut"} } # Split grade — verse cooler, chorus warmer set_layer_color_adjust { layerId:"verses", temp:-10, saturation:-0.08, contrast:+0.10 } set_layer_color_adjust { layerId:"choruses", temp:+8, saturation:+0.18, contrast:+0.18 } set_layer_lut { layerId:"all", lut:"cinematic-teal-orange", intensity:0.55 } # Vignette to focus the eye on the performer set_layer_effect { layerId:"all", effect:"vignette", intensity:0.35 } set_export_settings { resolution:"1080p", codec:"h264", fps:30, bitrate:16 } export_project {}
"90-second tutorial on how to make pour-over coffee — step counter on screen."
Top-down screen-recording of the process, animated step counter (1/6, 2/6...), kinetic instruction text, countdown widget for the 30-second bloom, clean daylight grade.
# Intake — fast for a tutorial Q1: Steps? → 6 steps, ~12-15s each Q2: Voice? → No VO — text-on-screen with ambient kitchen sounds # Plan create_project { name:"Pour-Over 90s", aspectRatio:"9:16", resolution:"1080p", fps:30 } add_video_layer × 6 # s0..s5 — one shot per step add_audio_layer { uri:"kitchen_amb.wav", volume:0.5 } add_stock_music_layer { query:"calm acoustic lo-fi 80 BPM", volume:0.35 } # Step counter — animated number badge, top-right safe for i in 1..6: t0 = (i-1) * 15 # every 15s add_text_layer { content: i+"/6", start:t0, duration:14.5, fontSize:42, position:{x:0.88,y:0.08}, fontWeight:800 } set_layer_border { layerId:"step"+i, width:3, color:"#ffffff", cornerRadius:0.5 } set_text_animation { layerId:"step"+i, inId:"scale-pop", inDurationSec:0.3, outId:"fade", outDurationSec:0.25 } # Instruction kinetic text — pop on each step start instructions = ["RINSE THE FILTER", "ADD 18g COFFEE", "BLOOM 30s · 50g WATER", "POUR TO 150g", "POUR TO 300g", "WAIT · DRINK · ENJOY"] for i, line in enumerate(instructions): t0 = i * 15 add_text_layer { content:line, start:t0+0.3, duration:3.5, fontSize:56, position:{x:0.5,y:0.18}, fontWeight:700 } set_typewriter { layerId:"ins"+i, charDelayMs:42 } set_text_animation { layerId:"ins"+i, outId:"slide-up", outDurationSec:0.4 } # Countdown widget for the 30s bloom step (step 3, starts at 30s) add_widget_layer { kind:"countdown", start:32.0, duration:30, durationMs:30000, position:{x:0.5,y:0.5}, style:{ font:"Mono Bold", color:"#fbbf24", size:120 } } # Clean daylight grade — bright, accurate, slight warmth apply_global_color_grade { scope:"global", params:{ exposure:+0.18, contrast:+0.05, saturation:+0.15, temp:-3, highlights:-0.08 } } # Light music swell on the last step set_layer_volume_keyframes { layerId:"music", keyframes:[ {timeMs:0, volume:0.35}, {timeMs:75000,volume:0.55}, {timeMs:90000,volume:0.0} ]} set_export_settings { resolution:"1080p", codec:"h264", fps:30, bitrate:12 } export_project {}
"75-second wedding highlight cut from 4 hours of footage."
Emotional structure: morning, ceremony, first dance, party. Slow speed-ramp into the kiss, vows-as-VO with ambient music underscore, custom warm-cream LUT, sparkle Lottie overlay on the rings shot.
# Intake Q1: Aspect & length? → 16:9 1080p 24fps (cinematic), 75s Q2: Music? → "Something soft, piano — under 90 BPM, no lyrics" Q3: VO? → Use a 25-second slice of the bride's vows Q4: Names & date? → "Sara & Adam · June 14, 2026" # Structure (emotional arc, not beats) 00:00–00:12 Morning prep — soft details, dress, rings 00:12–00:30 Ceremony walk + kiss (slow-mo on the kiss) 00:30–00:55 Vows VO over wide reception shots 00:55–01:15 Dance + party + tail card # Plan create_project { name:"Sara & Adam", aspectRatio:"16:9", resolution:"1080p", fps:24 } add_video_layer × 18 # curated highlights w0..w17 add_audio_layer { uri:"bride_vows.wav", layerId:"vows", start:30, duration:25 } add_stock_music_layer{ query:"emotional piano 84 BPM", layerId:"music", start:0, duration:75, volume:0.45 } # Sparkle Lottie on the rings detail (w3, around 6s) add_lottie_layer { preset:"sparkles", start:5.5, duration:2.5, position:{x:0.5,y:0.5}, intensity:0.6 } # Speed-ramp into the kiss — scale + slow opacity in last frames before keyframe_add { layerId:"w_kiss", property:"transform.scale", timeMs:0, value:1.0 } keyframe_add { layerId:"w_kiss", property:"transform.scale", timeMs:1200, value:1.12, interp:{type:"easeInOut"} } keyframe_add { layerId:"w_kiss", property:"transform.scale", timeMs:2400, value:1.06 } # Cross-fade transitions between every clip in the slow sections for edge in [(w0,w1),(w1,w2),(w2,w3),(w11,w12),(w12,w13)]: set_layer_audio_transitions { edge:edge, style:"crossfade", duration:0.6 } # Custom warm-cream LUT (round-trip from a reference still) write_cdl { slope:[1.04,1.02,0.95], offset:[0.02,0.01,-0.01], power:[1.0,1.0,1.04], sat:0.96 } bake_cdl_to_cube { cdlId:"cdl_sara_adam", lutSize:33 } lut_register_custom { name:"sara-adam-warm", cube:"..." } set_layer_lut { layerId:"all", lut:"sara-adam-warm", intensity:0.72 } apply_global_color_grade { params:{ exposure:+0.10, contrast:+0.08, saturation:+0.05, temp:+3, shadows:+0.06 } } # VO ducking — music drops under vows, returns smoothly after set_layer_volume_keyframes { layerId:"music", keyframes:[ {timeMs:0, volume:0.45}, {timeMs:30000,volume:0.45}, {timeMs:30500,volume:0.18}, {timeMs:54500,volume:0.18}, {timeMs:55500,volume:0.55} ]} # Tail card — names and date with elegant fade add_text_layer { content:"Sara & Adam", start:68.0, duration:7.0, fontSize:90, position:{x:0.5,y:0.45}, fontFamily:"Serif Display", fontWeight:400 } add_text_layer { content:"June 14, 2026", start:68.0, duration:7.0, fontSize:36, position:{x:0.5,y:0.56}, fontFamily:"Serif Display" } set_text_animation { layerId:"name", inId:"fade-up", inDurationSec:1.0 } set_text_animation { layerId:"date", inId:"fade-up", inDurationSec:1.0 } keyframe_add { layerId:"name", property:"opacity", timeMs:6000, value:1.0 } keyframe_add { layerId:"name", property:"opacity", timeMs:7000, value:0.0, interp:{type:"easeIn"} } set_export_settings { resolution:"1080p", codec:"h264", profile:"high", fps:24, bitrate:20 } export_project {}
"45-second hype reel for a high-school basketball team's playoff push."
Aggressive 140 BPM cut with double-time bursts on the chorus, zoom-punch on dunks, glitch FX on the drop, big bold sponsor lower-third, high-contrast moody grade, glow-bordered final score graphic.
# Intake Q1: Platform? → IG Reel + TikTok cross-post, 9:16 1080p 30fps Q2: Energy? → "Maximum. Like a hype train hit a building." Q3: Music? → 140 BPM trap-style instrumental, no vocals # beatMs = 60000/140 = ~429ms; double-time = 214ms create_project { name:"Wildcats Playoff", aspectRatio:"9:16", resolution:"1080p", fps:30 } add_video_layer × 16 # dunks, blocks, threes, crowd add_stock_music_layer { query:"trap hype instrumental 140 BPM no vocals", start:0, duration:45 } # Verse — beat-per-cut for 16 beats (0–6.9s) for i in 0..15: split_layer { layerId:"v0..", timeMs: i*429 } # Drop hits at 6900ms — glitch + flash + zoom punch set_layer_effect { layerId:"drop_clip", effect:"glitch", intensity:0.6 } keyframe_add { layerId:"drop_clip", property:"fx.intensity", timeMs:0, value:0.6 } keyframe_add { layerId:"drop_clip", property:"fx.intensity", timeMs:200, value:0.0 } keyframe_add { layerId:"drop_clip", property:"transform.scale", timeMs:0, value:1.0, interp:{type:"easeIn"} } keyframe_add { layerId:"drop_clip", property:"transform.scale", timeMs:120, value:1.25 } keyframe_add { layerId:"drop_clip", property:"transform.scale", timeMs:430, value:1.0 } set_layer_audio_transitions { edge:{at:6900}, style:"flash", duration:0.08 } # Chorus — double-time half-beat cuts (6.9–21s, 32 cuts) for i in 0..31: split_layer { layerId:"ch0..", timeMs: 6900 + i*214 } set_layer_audio_transitions { edge:{at:8000}, style:"whip-pan", duration:0.12 } set_layer_audio_transitions { edge:{at:11000}, style:"zoom-blur", duration:0.14 } set_layer_audio_transitions { edge:{at:14000}, style:"whip-pan", duration:0.12 } # Big text — "WILDCATS" punch on drop add_text_layer { content:"WILDCATS", start:6.7, duration:1.4, fontSize:180, position:{x:0.5,y:0.5}, fontWeight:900 } set_layer_border_glow{ layerId:"hype", color:"#ef4444", intensity:0.85, radius:0.06 } keyframe_add { layerId:"hype", property:"transform.scale", timeMs:0, value:0.0 } keyframe_add { layerId:"hype", property:"transform.scale", timeMs:120, value:1.3, interp:{type:"easeOut"} } keyframe_add { layerId:"hype", property:"transform.scale", timeMs:240, value:1.0 } keyframe_add { layerId:"hype", property:"transform.rotation", timeMs:0, value:-5 } keyframe_add { layerId:"hype", property:"transform.rotation", timeMs:240, value:0 } # Moody high-contrast grade apply_global_color_grade { scope:"global", params:{ exposure:-0.05, contrast:+0.30, saturation:-0.10, temp:-6, shadows:-0.08 } } set_layer_lut { layerId:"all", lut:"teal-blue-night", intensity:0.7 } # Sponsor lower-third (last 5s) add_lower_third_layer { preset:"lowerThird:sport-aggressive", content:"@ HighSchool Gym · Fri 7pm", start:40, duration:5 } # Final score card with glow border add_shape_layer { kind:"rect", color:"#000000", start:42, duration:3, position:{x:0.5,y:0.5}, size:{w:0.7,h:0.25} } set_layer_border_glow{ layerId:"score_bg", color:"#fbbf24", intensity:1.0, radius:0.08 } add_text_layer { content:"WILDCATS 78 — TIGERS 64", start:42, duration:3, fontSize:50, position:{x:0.5,y:0.5}, fontWeight:900 } set_export_settings { resolution:"1080p", codec:"h264", fps:30, bitrate:14 } export_project {}
"60-second luxury property listing for a Malibu home."
Steady slow camera moves, AE-style mask-wipe transitions between rooms, animated room-label callouts, agent lower-third, price-card reveal with parallax shadow, soft warm grade.
# Intake Q1: Aspect? → 16:9 1080p 30fps for MLS + Instagram Q2: Tone? → "Quiet luxury — let the house speak" Q3: CTA? → Agent name + phone number + open-house date # Structure — 7 rooms × ~8s each + 4s opening + 4s closing 00:00–00:04 Aerial drone — front of house with title overlay 00:04–00:12 Entry / great room 00:12–00:20 Kitchen 00:20–00:28 Primary suite 00:28–00:36 Pool deck 00:36–00:44 Wine cellar 00:44–00:52 Sunset terrace 00:52–01:00 Price card + agent CTA # Plan create_project { name:"Malibu Listing", aspectRatio:"16:9", resolution:"1080p", fps:30 } add_video_layer × 7 # r0..r6, one per room add_stock_music_layer { query:"ambient piano luxury 70 BPM", volume:0.5 } # Slow push-ins everywhere — the room should feel like it's revealing itself for clipId in [r0..r6]: keyframe_add { layerId:clipId, property:"transform.scale", timeMs:0, value:1.00 } keyframe_add { layerId:clipId, property:"transform.scale", timeMs:7800, value:1.05, interp:{type:"easeInOut"} } # Mask-wipe transition between rooms — clean diagonal sweep for edge in [(r0,r1),(r1,r2),(r2,r3),(r3,r4),(r4,r5),(r5,r6)]: set_layer_audio_transitions { edge:edge, style:"mask-wipe-diagonal", duration:0.55 } # Animated room labels — clean serif, slide-in from left, hold, fade labels = ["GREAT ROOM","KITCHEN","PRIMARY SUITE","POOL DECK","WINE CELLAR","SUNSET TERRACE"] for i, l in enumerate(labels): t0 = 4 + i*8 add_text_layer { content:l, start:t0+0.4, duration:6.0, fontSize:48, position:{x:0.08,y:0.86}, fontFamily:"Serif Display", fontWeight:300, textAlign:"left", fullWidth:false } keyframe_add { layerId:"lbl"+i, property:"transform.x", timeMs:0, value:-0.3 } keyframe_add { layerId:"lbl"+i, property:"transform.x", timeMs:600, value:0.08, interp:{type:"easeOut"} } keyframe_add { layerId:"lbl"+i, property:"opacity", timeMs:5400, value:1.0 } keyframe_add { layerId:"lbl"+i, property:"opacity", timeMs:6000, value:0.0, interp:{type:"easeIn"} } # Price card with parallax shadow add_shape_layer { kind:"rect", color:"#1a1a1a", start:52, duration:8, position:{x:0.5,y:0.5}, size:{w:0.6,h:0.4}, cornerRadius:0.04 } set_layer_border { layerId:"card", width:1, color:"#d4a056" } add_text_layer { content:"$12,450,000", start:52.5, duration:7.5, fontSize:72, position:{x:0.5,y:0.42}, fontFamily:"Serif Display", fontWeight:300 } add_text_layer { content:"5 BD · 7 BA · 8,400 SF", start:52.5, duration:7.5, fontSize:30, position:{x:0.5,y:0.52}, fontWeight:400 } add_lower_third_layer { preset:"lowerThird:elegant-thin", content:"Maya Linden · Coldwell Banker · (310) 555-0182 · Open Sat 1–4pm", start:54, duration:6, position:{x:0.5,y:0.86} } # Soft warm grade apply_global_color_grade { scope:"global", params:{ exposure:+0.10, contrast:+0.08, saturation:+0.08, temp:+4, highlights:-0.05 } } # Opening title add_text_layer { content:"22810 Pacific Coast Highway", start:0.5, duration:3.5, fontSize:52, position:{x:0.5,y:0.5}, fontFamily:"Serif Display", fontWeight:300 } set_layer_mask { layerId:"addr", shape:"rect", rect:{x:0,y:0,width:0,height:1}, feather:0.02 } keyframe_add { layerId:"addr", property:"mask.rect.width", timeMs:0, value:0 } keyframe_add { layerId:"addr", property:"mask.rect.width", timeMs:1200, value:1, interp:{type:"easeOut"} } set_export_settings { resolution:"1080p", codec:"h264", fps:30, bitrate:18 } export_project {}
Each plan is a complete tool composition — an agent could send these calls to a connected ExpoCut MCP server and the listed render would appear on the device. Mix and match: a wedding cut can borrow the music-video lyric overlay; a tutorial can borrow the brand-spot end-card reveal. Tip: use ← / → arrow keys to flip between examples.
Conversation starters for assistants.
"Help me cut a Reel"
A guided flow: pick clips, choose a vibe, set duration, auto-suggest transitions and music.
"Make this look cinematic"
Recommend a LUT, set 2.39:1 letterbox, apply teal/orange grade, slow the timeline 12%.
"Add captions"
Suggest a caption style, font, position, and timing for the spoken audio in the clip.
"Trim to 30 seconds"
Identify the strongest beats and propose cuts that fit the target duration.
Run commands from your browser.
Connect to the MCP server running on your phone and execute tool calls directly — no CLI needed. Paste the address and token from ExpoCut → Settings → AI Integration.
Questions, answered.
The essentials about the connector, privacy, and how agents stay current.
Does ExpoCut have a Model Context Protocol (MCP) server?
What can an AI agent actually do with it?
describe_canvas, capture_canvas, preview_filmstrip); and export up to 4K — every step undoable.How does an AI assistant connect to ExpoCut?
How do agents discover the current capabilities?
list_effects, list_shaders, list_transitions, list_shapes, list_fonts, get_effect_schema, get_layer_schema — for the live catalogs.Is it free, and where does the work run?
Live, on the device.
ExpoCut ships an in-app MCP server. When the user enables it, an MCP-compatible client like Claude Desktop binds to a local port on the device and can call the tools above. The server is off by default, runs only on a local interface, and every call is recorded as an undoable command in the on-device edit-history log. This page is the public reference for that surface so agents can index it and reason about the app.
Build with ExpoCut.
Download the app, or read the matching Skill for AI assistants.
Join the beta View Skill →