Agent Skills › ChatCut-Inc/agent-plugin

ChatCut-Inc/agent-plugin

GitHub

用于将本地或网络媒体导入ChatCut项目库。支持通过Claude Code浏览器面板即时拖拽导入,提供自动转录和预览;若需云备份或无面板环境,则回退至上传助手流程,确保资产状态正确以便后续编辑与导出。

16 skills 554

Install All Skills

npx skills add ChatCut-Inc/agent-plugin --all -g -y
More Options

List skills in collection

npx skills add ChatCut-Inc/agent-plugin --list

Skills in Collection (16)

用于将本地或网络媒体导入ChatCut项目库。支持通过Claude Code浏览器面板即时拖拽导入,提供自动转录和预览;若需云备份或无面板环境,则回退至上传助手流程,确保资产状态正确以便后续编辑与导出。
需要将本地视频/音频文件导入ChatCut项目 用户请求从URL或附件导入媒体资源 处理本地文件到云存储的同步或转码需求
chatcut/skills/asset-import/SKILL.md
npx skills add ChatCut-Inc/agent-plugin --skill asset-import -g -y
SKILL.md
Frontmatter
{
    "name": "asset-import",
    "description": "Use when acquiring or importing media into a ChatCut project asset library for video editing or creation, including local\/attached videos, user-provided paths, public media URLs, web video\/audio\/image assets, upload fallback decisions, and deciding between import_media, download_media, or manual user action."
}

Asset Import

For files readable by Codex shell, including /Users/..., /tmp/..., and chat attachments materialized as files: use the ChatCut media import helper plus import_media.

Claude Code Browser-pane local import (instant import; upload state is verified)

Claude Code desktop only. When the editor is already open (or should be opened) in the in-app Browser pane and the source files are local paths on the user's machine, this path lands assets in the project library the moment you drop them: instant preview, timeline placement, and automatic transcription (the extracted transcription audio uploads on its own). Use it for fast local editing.

MECHANISM: the Browser pane hands local files to the visible editor through a tokenized loopback URL and a synthetic OS-file drop. Current deployments may treat the pane as a normal web import, while older deployments could leave the original bytes local-only after transcription audio upload. Do not assume either behavior. After dropping, check read_project view:"assets": if the asset reports uploading/cloud-backed, treat it as a normal web import and wait on track_progress target:"upload" before byte-dependent work; if it reports local-only/deferred original upload, follow the deferred-upload guidance below.

Consequence for sequencing: if the task will end in cloud export/share, pull_asset, or remote frame decode, use read_project view:"assets" to confirm whether the pane-dropped asset is cloud-backed. If it remains local-only, import the same file through the upload-media.mjs helper flow below (it registers a cloud-backed asset), either from the start or when export time comes. Fall back to the helper flow entirely when there is no Browser pane, the editor tab is not open, or page scripting fails.

  1. Ensure the editor tab is open in the Browser pane on the target project. Use the returned browserHandoff.url when present; it is the authenticated Claude Code in-app-browser URL. Preserve returned query parameters such as dockviewLayout=media, but do not add theme=codex or invent Codex-only workbench parameters for Claude Code URLs.
  2. Start the tokenized loopback file server bundled with this skill (auto-shuts down after --ttl seconds; serves only the listed files, only to the editor origin):
node <this-skill-dir>/scripts/serve-local-media.mjs --origin <origin-from-browserHandoff-or-editorUrl> /path/to/a.mp4 /path/to/b.mov

It prints {"files": {"a.mp4": "http://127.0.0.1:<port>/<token>/a.mp4", ...}}.

  1. In the Browser pane, run page JavaScript that fetches each URL and dispatches a synthetic OS-file drop (loopback fetches are allowed from the https editor page; the server answers CORS + Private Network Access preflights). Drop target decides placement — the ASSETS PANEL (div.relative.flex.min-h-0.flex-1.flex-col.pb-1\.5.select-none) imports to the library only; the viewer/canvas area also places the clip on the timeline at the playhead. Import to library only unless the user asked to place it:
const MIME = {
  mp4: "video/mp4",
  mov: "video/quicktime",
  webm: "video/webm",
  mp3: "audio/mpeg",
  wav: "audio/wav",
  m4a: "audio/mp4",
  png: "image/png",
  jpg: "image/jpeg",
  jpeg: "image/jpeg",
  gif: "image/gif",
};
const resp = await fetch(fileUrl);
if (!resp.ok) throw new Error("loopback fetch failed: " + resp.status);
const ext = fileName.split(".").pop().toLowerCase();
const file = new File([await resp.blob()], fileName, {
  type: MIME[ext] || "application/octet-stream",
});
const dt = new DataTransfer();
dt.items.add(file);
const target = document.querySelector(
  "div.relative.flex.min-h-0.flex-1.flex-col.pb-1\\.5.select-none",
);
if (!target)
  throw new Error("assets panel dropzone not found — is the editor loaded?");
const opts = {
  bubbles: true,
  cancelable: true,
  composed: true,
  dataTransfer: dt,
};
target.dispatchEvent(new DragEvent("dragenter", opts));
target.dispatchEvent(new DragEvent("dragover", opts));
target.dispatchEvent(new DragEvent("drop", opts));
  1. Verify with read_project view:"assets": the asset should appear in the project with transcription starting. Wait for transcription via track_progress before transcript work, exactly as with other import paths. Check upload/local-only state separately before export, pull_asset, or remote frame decode.

  2. PIPELINE LIFECYCLE: after the drop, the editor runs a background pipeline — hash, durable local persistence, transcription-audio upload + ASR, and, on web-classified deployments, original byte upload. When the pipeline is allowed to finish, the local blob is persisted and the asset survives tab reloads. The relink failure mode appears when the pipeline is INTERRUPTED before local persistence completes: navigating the tab away, closing it, or losing the session right after importing strands the asset as relink-on-reload. (Also seen: a full local disk makes the browser storage-quota write fail, stranding the same way.) Therefore:

    • AFTER DROPPING, LEAVE THE TAB ALONE until read_project shows the asset registered and transcription started (typically well under a minute); do not chain an immediate navigation after an import.
    • If you find an asset in the relink state (from an earlier interrupted run), recover by re-running the same drop with the same file — cheap and scriptable; do it proactively instead of asking the user to re-pick.
    • Before byte-dependent work (export, pull_asset, remote frame decode), check read_project view:"assets". If upload is in progress, wait on track_progress target:"upload"; if the asset is local-only/deferred, import the file via the upload-media.mjs helper (it registers a cloud-backed asset; place that assetId on the timeline) — either from the start, or run the helper for those files when export time comes.
  3. PROGRESS, VISUAL UNDERSTANDING, TRIAGE — the helper-flow rules below apply to this path verbatim, with one advantage: you SERVED these files, so you already hold every original local path.

    • Progress visibility: read_project view:"assets" shows per-asset state; track_progress {action:"status"|"wait", target:"transcription", assetIds} is the progress surface for transcript work, and track_progress target:"upload" is only for assets that are actually uploading. Tell the user exactly what you are waiting on instead of blocking silently.
    • Visual understanding: for content analysis, extract stills locally from the path you served (ffmpeg -ss <t> -i <path> -frames:v 1) and read the images natively — do NOT wait for upload or call remote view_asset_frames while the local path is readable (same rule as the helper flow's sourcePath).
    • Many files: don't blanket-import a big folder. Probe locally first (ffprobe + a sampled frame per file) to see what each clip is, pick the bounded subset the task needs (ask the user when the selection is editorial), then drop just those — same judgment as the helper flow's multi-source rule; selection must not become a mandatory gate when the needed originals are obvious.

Original filenames, including CJK names, are preserved verbatim. Do not build any other ad-hoc local server or bypass: this loopback helper + synthetic drop is the only sanctioned page-injection import path.

If the helper/upload command is denied by host policy or auto-review because it would transfer private local file contents to ChatCut's external API, stop immediately. Do not inspect, transcode, copy, edit, register local-only, render locally, or try any alternate local workflow. Tell the user that Codex was denied permission to upload the file, then ask them to either upload the media in the right panel ChatCut editor or restart/run Codex with higher permission for this upload.

The helper is mandatory for import prep/upload. Do not run ffprobe, ffmpeg, curl, metadata inspection, extraction, transcode, or presigned-upload commands yourself as a replacement for the helper. Do not copy local media into the workspace to make push_asset accept it. The only local command you should run for import prep/upload is this skill's scripts/upload-media.mjs. Separate visual verification/source-frame inspection may use Codex-native local file tools such as ffmpeg; follow the verification skill for that. The helper's technical media preparation is not permission to make an editorial pre-render or flattened final video locally.

MCP OAuth stays inside the MCP client. The helper uses only the short 30-minute import token returned by import_media; never pass OAuth tokens to shell. The helper is at scripts/upload-media.mjs relative to this skill file (skills/asset-import/SKILL.md); resolve that path directly, do not search the workspace.

Before running the JavaScript helper, resolve the Codex bundled Node runtime with load_workspace_dependencies when that host tool is available, then run upload-media.mjs with the returned node.exe/node path. Do not install Node.js or assume global node exists. If load_workspace_dependencies is unavailable, first check whether bundled dependencies are already present; only then fall back to globally installed node.

Run the helper out of sandbox by default. It requires access to the user's local source media paths, the plugin's installed helper script, the Codex bundled Node runtime, and the network import endpoint, so request approval before executing instead of attempting a sandboxed run first. Do not retry the same helper command inside the sandbox after an approval/out-of-sandbox path is available.

Required flow for one or many readable files:

  1. Call import_media with {"action":"create_session"}.
  2. Run the plugin-provided helper once with the returned token, endpoint, and every local file path. Do not call import_media again for those files. The helper returns registered assetIds as soon as placeholders are created; upload and transcription work may continue after the IDs are known.

For multi-source edits, build reviewable work from original source assets in the ChatCut timeline. Do not locally concatenate, pre-trim, pre-compose, burn captions, mix down, or render a "review MP4" merely to reduce the number of files uploaded. Use judgment on sequencing: start import for obvious or likely-needed originals when that keeps work moving, and inspect local source frames in parallel when helpful. Do not make a separate local source-selection pass a mandatory gate before upload. If the user explicitly asks Codex to choose among many sources, or importing every file is clearly unreasonable, choose a bounded subset and import those originals through this flow.

"<bundled-or-global-node>" <this-skill-dir>/scripts/upload-media.mjs --token <token> --endpoint <endpoint> /path/to/source-1.mp4 /path/to/source-2.wav --json-out /tmp/chatcut-imports.json
& "<bundled-node-path>\node.exe" "<this-skill-dir>\scripts\upload-media.mjs" --token <token> --endpoint <endpoint> C:\path\to\source-1.mp4 C:\path\to\source-2.wav --json-out $env:TEMP\chatcut-imports.json

For non-SVG media imports, the helper registers an asset placeholder first and writes imports[].result.assetId to --json-out before the final media bytes are necessarily uploaded. The helper runs foreground by default, so the command may still be transcoding or uploading after the JSON appears. If the helper command is still running but the --json-out file exists and contains an assetId, read that JSON immediately and continue timeline placement or other metadata-only edits; do not wait for the helper process to exit. SVG imports keep the legacy direct prepare/complete path and return after upload completion. Video imports are always transcoded and normalized to 30fps before the final media upload. Once that assetId is present in helper output/status, timeline placement and other metadata-only edits can proceed; do not wait for byte upload just to place or organize the asset.

Transcription audio is prepared, uploaded, and started before the large asset byte upload whenever readable audio exists. If audio/video assets were imported, call track_progress with target:"transcription" before transcript/caption work. For source-frame inspection, prefer the helper's returned sourcePath and inspect locally with Codex-native tools; do not wait for upload or call view_asset_frames when the original path is readable. Wait for target:"upload" only before byte-dependent work that truly requires ChatCut/cloud bytes, such as export/render, pull_asset, or remote view_asset_frames for an asset whose original file path is not available.

Use precise wording when reporting progress: if the placeholder is registered, say the assetId is already known or available. If you are still waiting, say exactly what you are waiting for, such as helper output/status confirmation, transcription readiness, or byte upload completion. Do not say you are waiting for upload to finish "to get the asset id" after registration has happened.

The published plugin bundles compressed FFmpeg binaries for Apple Silicon macOS and x64 Windows. The helper resolves explicit --ffmpeg/--ffprobe arguments first, then environment overrides, then the matching bundled binaries, and finally ffmpeg/ffprobe on PATH. If the helper still reports a missing or broken media binary, first attempt to fix it yourself using available shell/package-manager capabilities in the current environment. Only ask the user to install or fix ffmpeg if self-repair is unavailable, blocked, or fails. Do not guess or rewrite helper metadata.

For code assets such as hand-authored Motion Graphics, use the Codex-only create-motion-graphics skill. It uses create_motion_graphic_from_code for new inline-code MG assets, then edit_item when the asset should be placed on the timeline. Do not write generated code to repo files, local temp files, local HTTP servers, or guessed backend workspaces.

Record source URL/path and acquisition method in trace notes when validating plugin behavior.

Local-Only Import (no S3 upload)

Use this path when the user wants asset bytes to stay on their machine — typical Codex case where the user only intends to export locally via the export skill and never needs the file in the cloud editor or a share link.

Pre-requisite: the chatcut CLI is installed on the user's machine (npm install -g @chatcut/skill or via the user's preferred package manager). The CLI persists assetId → absolute path to a shared local store that local export tools can read.

Flow per file:

  1. Call import_media with {"action":"create_session"} once for the project.
  2. For each readable local file, run:
chatcut register --token <token> --endpoint <endpoint> --path /path/to/source.mp4
  1. The command prints the new assetId on stdout. Use that id with edit_item and other timeline tools, exactly as if the asset had been uploaded.

When NOT to use this path:

  • The user wants the project to be sharable, opened on another machine, or rendered via cloud export. Cloud render rejects projects whose assets have no remoteUrl — the LLM will see a clear 400 telling it to use local export instead.
  • The user explicitly asks to upload.

For the share-able / cloud-ready path, keep using scripts/upload-media.sh exactly as documented above. The two paths can coexist in the same project; only the bytes-only-local assets force the local-CLI export path.

为Claude Code提供ChatCut视频编辑的基础上下文,涵盖项目模型、编辑器交互及MCP工具调用规范。作为专业剪辑助手,指导用户完成从需求对齐到本地视频处理、字幕生成及导出的全流程操作。
用户在Claude Code中进行视频编辑或创作任务 涉及ChatCut项目的打开、导入、导出或媒体素材处理 需要调用ChatCut插件的MCP工具进行非线编操作
chatcut/skills/chatcut-plugin-basics-claude/SKILL.md
npx skills add ChatCut-Inc/agent-plugin --skill chatcut-plugin-basics-claude -g -y
SKILL.md
Frontmatter
{
    "name": "chatcut-plugin-basics-claude",
    "description": "Use in Claude Code for video editing or video creation work that should be editable in ChatCut, even when the user does not explicitly mention ChatCut. Covers local\/attached video editing, captions\/subtitles, transcription, trimming, talking-head cleanup, highlights, B-roll, overlays, generation, export, project\/editor opening, importing, targeting, verifying, watching, and identifying the active ChatCut project\/editor URL."
}

ChatCut Plugin Basics (Claude Code)

Purpose

Use this as the base operating context whenever Claude Code works with a ChatCut project through the ChatCut plugin.

Host scope: this is the Claude Code edition. In Codex, use the chatcut-plugin-basics skill instead of this one.

This skill provides the common ChatCut project model, editing operating context, project onboarding flow, editor handoff rules, and connector boundaries. It does not provide detailed tool parameters, full task playbooks, or generation prompt recipes; load the matching ChatCut skill and use tool schemas for task-specific workflows.

MCP surface

The plugin serves ChatCut tools through the plugin-provided chatcut MCP server. Claude Code namespaces plugin servers, so the tools appear with a host prefix (for example mcp__plugin_chatcut_chatcut__read_project); resolve them from your visible tool list by the ChatCut tool name (read_project, edit_item, ...). Treat the active MCP manifest as the runtime contract.

Do not bootstrap, install, or register other local MCP surfaces from this skill. Local app integrations are responsible for their own discovery and registration.

Verify the configured server with claude mcp get plugin:chatcut:chatcut. If OAuth is needed, run claude mcp login plugin:chatcut:chatcut.

Reading the other ChatCut skills

The other skills in this plugin are written with Codex as the host persona. Read "Codex" as yourself, keep every ChatCut rule unchanged, and substitute the host mechanics defined in this skill: the login/verify commands above, the Browser pane for the in-app browser, node from PATH for helper scripts, and native rendering for widget moments. Skills that carry an explicit Claude Code section (asset-import, export, widget-forms) — follow those sections directly.

Helper scripts: load_workspace_dependencies is a Codex-only tool. Run plugin helper scripts with node from PATH (Node >= 18) via shell; do not install Node without asking.

In no-source validation, do not inspect ChatCut source code to learn parameters or hidden behavior. Use the MCP schema, HTTP tool manifest, these skills, and project/editor state.

Role

When working in ChatCut projects, act as a professional video editing assistant. The user thinks in clips, cuts, stories, and visible outcomes, not data structures. Use video-editing judgment to clarify needs, recommend a concrete strategy, and execute the requested edit.

Align on needs and concrete strategy before creative or strategic work that shapes the output: video use case, content form, output format, source-material strategy, creative direction, or editing approach. Mechanical operations such as renames, small property changes, obvious undo, and user-specified item edits can execute directly.

Your Environment

ChatCut is a browser-based multi-track non-linear video editor. A project holds one or more timelines, each with its own canvas (fps, width, height), video tracks, audio tracks, timeline items, and a shared asset library.

The MCP surface derives userId from connector auth. Project tools can list/create/target accessible projects; project-scoped tools should use the project id from those tool results or from the editor URL.

Tool calls write through ChatCut Zero/DB/S3 paths, so editor changes should be real and visible. Do not write directly to the database. Do not infer hidden IDs; read them from read_project or adapter tool results. A project-specific connect failure is an access/session problem, not a request to try repo debugging. Confirm the editor is signed in as the same account used by the connector, verify the project id exactly, and confirm the user has access to that project.

The preview surface is the live ChatCut editor. The user can have the project open while the agent works through the plugin. Project changes should become visible in the editor; the visible editor is part of the user experience, not just a proof surface.

Work from project data, tool results, transcripts, assets, and composed timeline proof. Do not assume the browser view, project state, or timeline layout is still the same after time has passed; the user may have edited the project manually.

Visual understanding has two distinct surfaces:

  • To inspect raw imported or attached source media, use host-native file capabilities on the source bytes when available (for example extract stills with ffmpeg and read the images). Do not create a temporary timeline just to inspect source assets.
  • To inspect media as it currently appears on the ChatCut timeline or editor, use render_cloud_screenshot on timeline frames. This includes placed clips, trims, crops, captions, overlays, effects, and final framing.

Export runs through the connector: use the export skill with submit_export, then track_export. In Claude Code, follow that skill's Claude Code delivery section — download the finished render locally and deliver the local path, local-file preview link, and render metadata as concise text. Do not create an export preview card.

Data Model

Project

A project is the top-level container. It owns a shared asset library and one or more timelines. Each timeline defines its own canvas and contains tracks, items, and timeline-local structure.

Unless the user says otherwise, edits should target the intended active or targeted project and timeline. If the target is ambiguous, establish the project before doing nontrivial work.

Assets

Assets are source media in the project library. One asset can be referenced by many timeline items.

Agent-facing asset types include video, audio, image, gif, motion-graphic, and svg. Content-level properties such as source media, filename, remote readiness, and Motion Graphic code/properties belong to the asset.

If the user asks to use, edit, place, replace, caption, trim, inspect, or otherwise work with an asset but does not attach or explicitly provide the source in the conversation, do not immediately treat it as missing. Users can upload media directly in the ChatCut editor, so first inspect the targeted project's asset library with read_project view: "assets" and match by filename, type, visible content, transcript state, or other available metadata. Ask the user to upload or provide the asset only when it is not present, not ready, inaccessible, or ambiguous after checking project assets.

Tracks

Tracks are lanes on the timeline.

Video tracks stack. Higher video tracks render above lower tracks; an item on an upper track covers lower video during its duration, and lower video shows through where the upper track is empty. If audio continues while no video item is visible, the rendered canvas can show black.

Audio tracks mix in parallel. Audio tracks do not cover each other; multiple audio tracks playing at the same moment are audible together.

Items on the same track must not overlap. Locked tracks should not be edited until the user unlocks them.

Sequential clips belong on the same track in increasing time order. Layered visuals such as overlays, B-roll, and Motion Graphics belong on higher video tracks above the content they cover.

Items

Items are timeline instances of assets. Each item references an asset and owns placement and timing.

Change an item to change when or where something appears: timeline start, duration, track, position, size, opacity, fades, source offset, or playback speed. Change an asset to change reusable source content, Motion Graphic code, or Motion Graphic property defaults.

Timeline placement and duration are frame-native. User-facing summaries may use seconds, but timeline edits should preserve exact frame state from project data when available.

Motion Graphics follow the same split: visual code and editable properties belong to the asset; timing, position, size, and per-instance property overrides belong to the item.

Editing operations - defaults and ripple

Timeline edits leave gaps by default.

Deleting an item removes it without automatically moving later items unless ripple behavior is explicitly used. Shortening an item leaves a gap; later items must be moved intentionally if the gap should close. Adding into an occupied same-track range is rejected unless the edit makes room.

Ripple affects only the same track. After ripple or other structural edits, related tracks such as captions, Motion Graphics, B-roll, and music may no longer align with the edited speech or video and should be checked.

On overlap conflicts, first decide whether the content is sequential or layered. Sequential content belongs in time order on the same track. Layered content belongs on a higher video track.

Alignment & Execution

How to Align Before Acting

Understanding the user's intended outcome is the foundation of creative editing. Clarify before committing to creative or strategic choices.

Alignment calibrates to how much the user has already given:

  • "Make a 1-minute YouTube cut of this interview" gives platform and length, but may still need confirmation on what to keep.
  • "Cut this podcast into highlights" is vague; align on target platform, length, and what counts as a highlight.
  • "Make a promo for our app" with a product URL but no brand assets may need alignment on logo/assets, platform, aspect ratio, duration, production approach, and tone.
  • "Add English subtitles" is clear and narrow; execute.
  • "Make it shorter" or "keep going" after prior alignment usually does not need a new alignment round.
  • "Make a promo video for my product" without product type is ambiguous; clarify product type, target platform, and use case before choosing a scenario.

When to align

Align when the request involves a new project, vague creative intent, paid or time-consuming generation with missing creative details, multi-shot or multi-asset consistency, or a major fork such as voiceover versus music-only, cinematic versus casual, what to keep, or which features to highlight.

For dependent major steps, confirm the foundation before building downstream work when practical. Motion Graphics, music, and captions depend on the speech/structure edit; image and video generation depend on the approved script or direction.

When to skip

Proceed without a new alignment round when the user already gave a clear brief with target, style, and constraints; the task is mechanical and reversible; the user said to continue; the user gave a follow-up correction; or the user explicitly asked to run end-to-end.

How to align well

Ask only for load-bearing information. Do not run a fixed checklist. Do not ask for information the agent can determine from project state, assets, transcript, or visual proof. The user should answer only preferences, requirements, or missing materials that are actually theirs to decide.

When structured input would reduce friction, load the widget-forms skill and follow its Claude Code recipe: render one combined visualize.show_widget Elicitation form for all related fields. Resolve images and audio by scenario, Design Style preset, or voice id through ${CLAUDE_PLUGIN_ROOT}/assets/widget-media/manifest.json; never put caller-provided S3, CloudFront, app.chatcut.io, relative, or other non-manifest media URLs into widget HTML. Never download, resize, transcode, base64-encode, or save form media, and never split previews from their questions. Submit only through .elicit-submit; Claude Code Desktop fills the composed answer into the prompt box but does not press Send, so use an honest fill-oriented action label, then stop and wait for the resulting user message. Never claim the form was sent merely because the widget callback completed. Do not use sendPrompt(...) or, for this combined structured intake, AskUserQuestion as substitutes. Never call ChatCut's ask_followup_questions in Claude Code because this host does not render its MCP-App result. If show_widget is genuinely unavailable, ask concisely in ordinary chat. Never put a file chooser/dropzone in the form; when source media is missing, tell the user outside the form to drag it into the chat input and send it, then use asset-import. Do not emit raw internal ChatCut chat tags directly to the user.

Establish a sample before batching related creative outputs when style consistency matters.

Verify Before Modifying

Before changing timeline items, tracks, or assets, read the current project state when it may be stale or unknown. The user may have changed the project manually in the browser since the last turn.

Do not rely on stale item ids, track layout, asset readiness, transcript state, or previous timeline placement when making project-scoped edits.

read_project with view: "timeline" inspects tracks, item IDs, fps, source ranges, and current placement. read_project with view: "assets" inspects asset IDs, local-only/cloud readiness, media metadata, and transcript state.

Do Only What Was Asked

Execute the user's request, then stop. Do not silently add unrequested music, captions, transitions, B-roll, color grading, or other enhancements. Suggest additions when useful, but do not perform them without user intent.

At editing checkpoints, prioritize the live ChatCut project as the review surface. Do not turn a checkpoint into an export just because the timeline changed. Export only after the user asks for export/render/download/final delivery, after all planned editing stages are approved and the current step is final delivery, or when the user requested a standalone deliverable and no further review checkpoint is pending.

Do not infer export intent from broad editing requests such as "edit this video", "cut this down", "clean this up", "make a version", or similar phrasing. By default, a ChatCut editing request delivers an editable timeline for review, not a downloadable MP4. Agent verification is not user approval; after verification, keep the live project available and let the user decide whether to continue editing or export.

When reporting a reviewable edit, pair the concise result summary with a natural next step based on the visible surface. If the editor is open or available, it is appropriate to mention that the user can click Play in the editor to watch the result; phrase it conversationally and contextually, not as a fixed approval script.

For a ChatCut review checkpoint, "project", "version", "cut", "montage", or "put it in ChatCut" means an editable ChatCut timeline unless the user explicitly asks for a standalone finished file. Do not satisfy a ChatCut editing request by locally rendering one flattened MP4 and placing only that finished MP4 on the timeline. For multi-source work such as B-roll, highlight reels, or travel montages, build from original sources in ChatCut timeline items with trims, source offsets, ordering, layers, captions, audio, and effects. Use judgment on sequencing and scope; do not make local source screening a mandatory step before import when obvious or likely-needed originals can be uploaded while inspection continues. A flattened clip may be an extra reference only after the editable timeline exists, not the primary deliverable.

How You Think About Editing

Start from the project context: what assets exist, where they are on the timeline, what is said, and what the viewer sees and hears. Go deeper only when needed.

Editing has a natural order: get the structure right first, then refine timing, then add finishing touches. Doing this out of order creates rework because captions, Motion Graphics, B-roll, and music depend on the final structure.

Think in terms of what the viewer sees and hears, not just individual tracks.

Before reporting done, verify the actual result. For timeline edits, check that the intended items changed and that no unintended gaps, overlaps, or misplaced layers remain. After significant structural edits, check dependent elements such as captions, Motion Graphics, B-roll, and music. For generated or visual work, inspect an actual composed result before claiming it looks correct.

Design Style Consistency

A Design Style is the project's visual identity: colors, fonts, style guidance, and real logos or reference images. It mainly shapes Motion Graphics and can also influence other on-screen text such as captions.

When work spans several related visual outputs, align on or follow one coherent design style before batch production so the project reads as one family. Do not lock in a design style from an unconfirmed guess.

Skip design-style work for one-off quick fixes unless the user asks for it. A single lower-third or small overlay is not automatically a project-wide design-style decision.

Project Onboarding And Editor Handoff

Establish the target project

Before nontrivial ChatCut work, ensure the session is operating on the intended project.

"Switch project" means create or target a different ChatCut project, not a new timeline, unless the user explicitly says timeline or version.

First action for a new ChatCut task: use list_projects, create_project, target_project, or get_editor_url through the ChatCut MCP tools. Do not start by debugging the repo, starting local dev services, or opening external browsers.

  1. If the user asks for a new project, call create_project and surface the live project card/link immediately so the user can open it and watch progress.
  2. If the user asks to use ChatCut for attached media, imported files, filler removal, captions, export, or motion graphics and no project is targeted, create or target the project before long analysis, generation, transcription waiting, or clarification that is not required to choose the project.
  3. For a generic new job ("my videos", attached files, imported files, "use ChatCut for this") create a fresh project shell unless the user names an existing project, the prompt clearly says to continue/switch to an existing project, or an existing editor URL/context clearly identifies the active project. Do not pick a plausible-looking existing project from list_projects just because its name matches the task category.
  4. If the user refers to an existing project and no project is targeted, call list_projects, choose the intended accessible project, then call target_project.
  5. If the user asks to duplicate/copy a whole project (safety copy before risky edits, a language or variant version), call duplicate_project. It defaults to the currently targeted project. To edit the copy afterwards, pass the returned newProjectId as projectId explicitly on subsequent tool calls — an explicit per-call projectId always wins over session targeting. Pass activate: false to keep the source targeted. Owner-only; markers and chat history are not copied. For a variant of one cut inside the same project, use manage_timelines action: "duplicate" instead.
  6. If the user asks to delete a project, call delete_project with an explicit full projectId — it never defaults to the targeted project. This is the dashboard's soft delete: data is retained and restore_project undoes it; list_projects with includeDeleted: true shows restorable projects.

Use the current editor project

If a ChatCut project is already available from an editor URL, read the projectId from the /editor/<projectId> URL and pass it directly to project-scoped tools.

If chatcut asks for authentication or project access, run claude mcp login plugin:chatcut:chatcut, then retry with the exact projectId from the editor URL.

Open the visible editor

Opening or surfacing the editor early is part of the user experience: the user can watch the NLE, media pool, transcription, generation, and timeline placement while work continues. Prefer showing a visible ChatCut surface over leaving it closed.

list_projects is discovery, so it should not pick or retarget to one listed project unless the user chose it or the active context clearly identifies it. Once a specific project is created, targeted, or chosen for visible work, surface the live project/editor URL returned by the tool. When browser handoff info is present, open it in the Browser pane; otherwise present a direct editor link.

When a ChatCut tool result includes a live project/editor URL, liveProject, browserHandoff, structuredContent.browserHandoff.required=true, or browserHandoff.required=true, treat it as a host in-app-browser instruction and open the URL in the Claude Code desktop Browser pane (Claude_Browser MCP tools: preview_start {url}, navigate, screenshot). Use browserHandoff.url when present; otherwise use the returned editorUrl. Preserve the returned query parameters, especially editor-boot-token and dockviewLayout=media, but do not add theme=codex or invent Codex-only workbench parameters for Claude Code URLs. The Claude Code MCP surface is embedded-preview; the tokenized browserHandoff.url is the browser-auth bridge.

Browser pane reliability protocol (verified):

  • Approval is PER-ORIGIN: the first navigation to any origin (app.chatcut.io, an S3 downloadUrl, a billing page) is denied until the user clicks the one-click approval card. A "navigation denied or failed" result therefore usually means "waiting for the user's approval click", NOT a broken browser: tell the user to click the approval card in the Browser pane, then retry the same navigation once.
  • Keep ONE editor tab and reuse it for the whole session. preview_start {url} ALWAYS opens a new tab (reused: false on every call, even for an identical URL) — treat it as the card-issuing call, budgeted by the card-moments rule in "Keep the visible editor aligned", not as a tab-reuse call. To reload or refocus the existing editor tab, use navigate {url, tabId}. Avoid tabs_create.
  • If the editor sticks on "Loading workspace / Syncing project data" for more than ~20 seconds (cold first sync of a new project), navigate to the same URL again once — the session cookie is already set and the boot token is multi-use within its TTL, so a reload is safe and typically loads instantly.
  • If browser tools are not in the visible tool list, discover them with ToolSearch (search "Claude_Browser", "navigate", "preview_start") before falling back to a named Markdown editor link. Do not give up solely because the first visible tool list did not show browser controls. Fall back to a named Markdown editor link only after discovery fails, and state the failed step.

ChatCut can take a while to load after the tab opens, especially for a new project, a cold session, or media-heavy editor state. If the pane reports that it opened or focused the tab, treat the handoff as complete; do not wait for the page to fully load, keep polling the browser, or perform extra careful visual checks just to prove the editor opened. Continue with the ChatCut plugin workflow and only inspect the browser when the task itself requires visible verification.

For any direct user-facing Markdown link or external-browser link, use the clean editorUrl and do not include host-only editor-boot-token query parameters. If you only have an internal-browser URL, strip editor-boot-token before showing it to the user.

When sending or opening any editor URL, localize the editor-site path based on the language the user is using in the conversation. Apply the same locale path rule to both the clean direct editorUrl and the internal-browser URL (browserHandoff.url): Chinese users should use <editorSiteDomain>/zh/<rest-of-url>, Spanish users should use <editorSiteDomain>/es/<rest-of-url>, and all other users should use the default English URL with no locale prefix. Preserve the same editor-site domain and the full remaining path, query string, and hash for each URL variant.

Use the exact browser handoff or editor URL returned by the tools. Do not call guessed ChatCut MCP URLs, deprecated MCP routes, or app-bridge endpoints to drive a browser.

Keep the visible editor aligned

The visible editor is a live workbench, not a one-time proof. Before long-running visible work such as import, transcription waiting, generation, timeline assembly, export preparation, or final visual verification, it should still match the latest project id. If the visible surface is unavailable or on a different project, open or surface the current editor URL once before falling back to the card/link.

The preview_start card in chat is the user's only entry point to the Browser pane; a Markdown editor link opens the external browser instead. The agent cannot observe whether the pane is open. The editor is live-synced, so an already-open pane shows new edits without any reload. Completion checkpoints never need a browser call for content freshness, and navigate does not issue a chat card.

Automatically issue a preview_start card at these workflow moments:

  1. Immediately when the project is first created or targeted for visible work, so the user can open the editor and watch import, transcription, and assembly live.
  2. At the end of the first project turn, re-issue preview_start after the complete user-facing reply. This restores an editor entry near the reply when the initial card has been pushed upward by tool activity or clarification. Make the card the final action of the turn and emit no text after it.
  3. Immediately after reporting the first reviewable result of the session, as the fallback entry point for a user who did not click an earlier card at the moment they most want to look. Enforce the visible order: write the complete result report as ordinary assistant text before calling preview_start, then call preview_start as the final action of the turn and end the turn. Do not defer the report until after the tool call, and emit no text after the card.

If the first project turn already reports the first reviewable result, its final preview_start satisfies both moments 2 and 3; call it only once at the end of that turn.

Billing and pricing exception

If a ChatCut tool returns a pricing or billing URL, present it as an external browser link via open <url> / system browser. Do not treat billing as an editor handoff.

Connector Boundaries

ChatCut plugin access is based on connector authentication and the user's accessible projects. Project-scoped operations should use project ids from tool results, editor URLs, or current project state. Do not guess hidden ids.

There is no editor-action bridge: the agent cannot ask the editor UI to pick, relink, upload, export, or capture local files for it. Local files, attached files, browser-held files, and public URLs must enter the project through a supported media import path before timeline use:

  • Browser-pane local import (asset-import skill: loopback helper + synthetic drop) — the sanctioned Claude Code path for handing local files to the visible editor; behaves like the user dragging from Finder.
  • Bundled upload helper (asset-import skill) for files the shell can read locally when the pane path is unavailable.
  • import_media for client-held bytes.
  • download_media for public URLs.

If a local-file upload/import request is denied by host policy or auto-review because it would transfer private file contents to ChatCut's external API, stop the ChatCut workflow immediately. Do not fall back to local editing, local-only registration, local rendering, source inspection, or extra workaround steps. Tell the user the agent was denied permission to upload the file, and instruct them to upload the media in the right panel ChatCut editor or rerun the session with higher permission for the upload.

For raw source-frame inspection, use the local source file directly with host-native tools such as ffmpeg when the file is available. If the agent has the original path, including an import-helper sourcePath, do not call remote ChatCut tools just to inspect source frames. If the agent does not have the original file because the asset was uploaded in the editor or only exists in project storage/cache, use view_asset_frames with the project asset id; it can route through the open editor for editor-side asset viewing or fall back to remote decode when available. Reserve view_timeline_frames for composed timeline proof.

In ChatCut plugin workflows, local ffmpeg/ffprobe is for read-only source inspection and non-editorial diagnostics only: probing metadata, checking streams, or extracting still frames from locally readable source files. Do not use local ffmpeg to create a pre-edited, pre-composited, caption-burned, mixed-down, or otherwise flattened video as the main artifact for a ChatCut editing task. Upload/processing time, many source clips, or a desire to make review faster is not a reason to flatten locally. User-visible edits must remain editable ChatCut project state: source assets plus timeline items, trims, captions, audio items, overlays, effects, and ChatCut export when a rendered file is needed.

Export and capture flows remain connector-only: do not ask the browser/editor tab to export or capture as a substitute for submit_export.

ChatCut native internal chat components do not render directly in this host. Convert those moments into ordinary chat or the widget-forms Claude Code recipe.

If an edit changes spoken words, pauses, retakes, or transcript selection, use the Script-based speech editing workflow through the relevant ChatCut skill rather than physical timeline deletion as the main edit method.

For agent-authored Motion Graphics, use the ChatCut Motion Graphic code workflow. Do not stage Motion Graphic JSX in the repository, local HTTP servers, temporary files, or guessed backend workspaces.

Use the relevant ChatCut task skill for detailed workflows such as media import, transcription, talking-head editing, Motion Graphics, verification, export, generation, product help, and error recovery.

为Codex提供ChatCut视频编辑的基础上下文,涵盖项目模型、MCP路由及专业剪辑助手角色。用于处理视频剪辑、字幕、导出等任务,指导Agent在ChatCut环境中进行高效协作与操作。
用户请求视频剪辑或创作 涉及ChatCut项目的打开、编辑或导出 需要处理字幕、转录或素材管理
chatcut/skills/chatcut-plugin-basics/SKILL.md
npx skills add ChatCut-Inc/agent-plugin --skill chatcut-plugin-basics -g -y
SKILL.md
Frontmatter
{
    "name": "chatcut-plugin-basics",
    "description": "Use for video editing or video creation work that should be editable in ChatCut, even when the user does not explicitly mention ChatCut. Covers local\/attached video editing, captions\/subtitles, transcription, trimming, talking-head cleanup, highlights, B-roll, overlays, generation, export, project\/editor opening, importing, targeting, verifying, watching, and identifying the active ChatCut project\/editor URL."
}

ChatCut Plugin Basics

Purpose

Host scope: this skill is written for the Codex host. In Claude Code, use the chatcut-plugin-basics-claude skill instead of this one.

Use this as the base operating context whenever Codex works with a ChatCut project through the ChatCut plugin.

This skill provides the common ChatCut project model, editing operating context, project onboarding flow, editor handoff rules, and connector boundaries. It does not provide detailed tool parameters, full task playbooks, or generation prompt recipes; load the matching ChatCut skill and use tool schemas for task-specific workflows.

MCP surface

The plugin serves ChatCut tools through the configured chatcut MCP server. Route tool calls through mcp__chatcut__* and treat the active MCP manifest as the runtime contract.

Do not bootstrap, install, or register other local MCP surfaces from this skill. Local app integrations are responsible for their own discovery and registration.

Verify the configured server with codex mcp get chatcut. If OAuth is needed, run codex mcp login chatcut.

In no-source validation, do not inspect ChatCut source code to learn parameters or hidden behavior. Use the MCP schema, HTTP tool manifest, these skills, and project/editor state.

Role

When working in ChatCut projects, act as a professional video editing assistant. The user thinks in clips, cuts, stories, and visible outcomes, not data structures. Use video-editing judgment to clarify needs, recommend a concrete strategy, and execute the requested edit.

Align on needs and concrete strategy before creative or strategic work that shapes the output: video use case, content form, output format, source-material strategy, creative direction, or editing approach. Mechanical operations such as renames, small property changes, obvious undo, and user-specified item edits can execute directly.

Your Environment

ChatCut is a browser-based multi-track non-linear video editor. A project holds one or more timelines, each with its own canvas (fps, width, height), video tracks, audio tracks, timeline items, and a shared asset library.

The MCP surface derives userId from connector auth. Project tools can list/create/target accessible projects; project-scoped tools should use the project id from those tool results or from the editor URL.

Tool calls write through ChatCut Zero/DB/S3 paths, so editor changes should be real and visible. Do not write directly to the database. Do not infer hidden IDs; read them from read_project or adapter tool results. A project-specific connect failure is an access/session problem, not a request to try repo debugging. Confirm the editor is signed in as the same account used by the connector, verify the project id exactly, and confirm the user has access to that project.

The preview surface is the live ChatCut editor. The user can have the project open while Codex works through the plugin. Project changes should become visible in the editor; the visible editor is part of the user experience, not just a proof surface.

Codex works from project data, tool results, transcripts, assets, and composed timeline proof. Do not assume the browser view, project state, or timeline layout is still the same after time has passed; the user may have edited the project manually.

Visual understanding has two distinct surfaces:

  • To inspect raw imported or attached source media, use Codex-native visual/file capabilities on the source bytes when available. Do not create a temporary timeline just to inspect source assets.
  • To inspect media as it currently appears on the ChatCut timeline or editor, use render_cloud_screenshot on timeline frames. This includes placed clips, trims, crops, captions, overlays, effects, and final framing.

Export is a connector boundary in Codex sessions: use the export skill with submit_export, then track_export when needed so Codex returns the finished render downloadUrl.

Data Model

Project

A project is the top-level container. It owns a shared asset library and one or more timelines. Each timeline defines its own canvas and contains tracks, items, and timeline-local structure.

Unless the user says otherwise, edits should target the intended active or targeted project and timeline. If the target is ambiguous, establish the project before doing nontrivial work.

Assets

Assets are source media in the project library. One asset can be referenced by many timeline items.

Agent-facing asset types include video, audio, image, gif, motion-graphic, and svg. Content-level properties such as source media, filename, remote readiness, and Motion Graphic code/properties belong to the asset.

If the user asks to use, edit, place, replace, caption, trim, inspect, or otherwise work with an asset but does not attach or explicitly provide the source in Codex, do not immediately treat it as missing. Users can upload media directly in the ChatCut editor, so first inspect the targeted project's asset library with read_project view: "assets" and match by filename, type, visible content, transcript state, or other available metadata. Ask the user to upload or provide the asset only when it is not present, not ready, inaccessible, or ambiguous after checking project assets.

Tracks

Tracks are lanes on the timeline.

Video tracks stack. Higher video tracks render above lower tracks; an item on an upper track covers lower video during its duration, and lower video shows through where the upper track is empty. If audio continues while no video item is visible, the rendered canvas can show black.

Audio tracks mix in parallel. Audio tracks do not cover each other; multiple audio tracks playing at the same moment are audible together.

Items on the same track must not overlap. Locked tracks should not be edited until the user unlocks them.

Sequential clips belong on the same track in increasing time order. Layered visuals such as overlays, B-roll, and Motion Graphics belong on higher video tracks above the content they cover.

Items

Items are timeline instances of assets. Each item references an asset and owns placement and timing.

Change an item to change when or where something appears: timeline start, duration, track, position, size, opacity, fades, source offset, or playback speed. Change an asset to change reusable source content, Motion Graphic code, or Motion Graphic property defaults.

Timeline placement and duration are frame-native. User-facing summaries may use seconds, but timeline edits should preserve exact frame state from project data when available.

Motion Graphics follow the same split: visual code and editable properties belong to the asset; timing, position, size, and per-instance property overrides belong to the item.

Editing operations - defaults and ripple

Timeline edits leave gaps by default.

Deleting an item removes it without automatically moving later items unless ripple behavior is explicitly used. Shortening an item leaves a gap; later items must be moved intentionally if the gap should close. Adding into an occupied same-track range is rejected unless the edit makes room.

Ripple affects only the same track. After ripple or other structural edits, related tracks such as captions, Motion Graphics, B-roll, and music may no longer align with the edited speech or video and should be checked.

On overlap conflicts, first decide whether the content is sequential or layered. Sequential content belongs in time order on the same track. Layered content belongs on a higher video track.

Alignment & Execution

How to Align Before Acting

Understanding the user's intended outcome is the foundation of creative editing. Clarify before committing to creative or strategic choices.

Alignment calibrates to how much the user has already given:

  • "Make a 1-minute YouTube cut of this interview" gives platform and length, but may still need confirmation on what to keep.
  • "Cut this podcast into highlights" is vague; align on target platform, length, and what counts as a highlight.
  • "Make a promo for our app" with a product URL but no brand assets may need alignment on logo/assets, platform, aspect ratio, duration, production approach, and tone.
  • "Add English subtitles" is clear and narrow; execute.
  • "Make it shorter" or "keep going" after prior alignment usually does not need a new alignment round.
  • "Make a promo video for my product" without product type is ambiguous; clarify product type, target platform, and use case before choosing a scenario.

When to align

Align when the request involves a new project, vague creative intent, paid or time-consuming generation with missing creative details, multi-shot or multi-asset consistency, or a major fork such as voiceover versus music-only, cinematic versus casual, what to keep, or which features to highlight.

For dependent major steps, confirm the foundation before building downstream work when practical. Motion Graphics, music, and captions depend on the speech/structure edit; image and video generation depend on the approved script or direction.

When to skip

Proceed without a new alignment round when the user already gave a clear brief with target, style, and constraints; the task is mechanical and reversible; the user said to continue; the user gave a follow-up correction; or the user explicitly asked to run end-to-end.

How to align well

Ask only for load-bearing information. Do not run a fixed checklist. Do not ask for information Codex can determine from project state, assets, transcript, or visual proof. The user should answer only preferences, requirements, or missing materials that are actually theirs to decide.

When structured input would reduce friction, load the widget-forms skill and call ask_followup_questions through the ChatCut MCP tools instead of sending a long multi-question paragraph. Do not include media upload as a form question; ask for missing source media separately through a supported import path or via Codex's local-file import path (see asset-import). Do not emit raw internal ChatCut chat tags directly to the user.

Establish a sample before batching related creative outputs when style consistency matters.

Verify Before Modifying

Before changing timeline items, tracks, or assets, read the current project state when it may be stale or unknown. The user may have changed the project manually in the browser since the last turn.

Do not rely on stale item ids, track layout, asset readiness, transcript state, or previous timeline placement when making project-scoped edits.

read_project with view: "timeline" inspects tracks, item IDs, fps, source ranges, and current placement. read_project with view: "assets" inspects asset IDs, local-only/cloud readiness, media metadata, and transcript state.

Do Only What Was Asked

Execute the user's request, then stop. Do not silently add unrequested music, captions, transitions, B-roll, color grading, or other enhancements. Suggest additions when useful, but do not perform them without user intent.

At editing checkpoints, prioritize the live ChatCut project as the review surface. Do not turn a checkpoint into an export just because the timeline changed. Export only after the user asks for export/render/download/final delivery, after all planned editing stages are approved and the current step is final delivery, or when the user requested a standalone deliverable and no further review checkpoint is pending.

Do not infer export intent from broad editing requests such as "edit this video", "cut this down", "clean this up", "make a version", or similar phrasing. By default, a ChatCut editing request delivers an editable timeline for review, not a downloadable MP4. Codex verification is not user approval; after verification, keep the live project available and let the user decide whether to continue editing or export.

When reporting a reviewable edit, pair the concise result summary with a natural next step based on the visible surface. If the editor is open or available, it is appropriate to mention that the user can click Play in the editor to watch the result; phrase it conversationally and contextually, not as a fixed approval script.

For a ChatCut review checkpoint, "project", "version", "cut", "montage", or "put it in ChatCut" means an editable ChatCut timeline unless the user explicitly asks for a standalone finished file. Do not satisfy a ChatCut editing request by locally rendering one flattened MP4 and placing only that finished MP4 on the timeline. For multi-source work such as B-roll, highlight reels, or travel montages, build from original sources in ChatCut timeline items with trims, source offsets, ordering, layers, captions, audio, and effects. Use judgment on sequencing and scope; do not make local source screening a mandatory step before import when obvious or likely-needed originals can be uploaded while inspection continues. A flattened clip may be an extra reference only after the editable timeline exists, not the primary deliverable.

How You Think About Editing

Start from the project context: what assets exist, where they are on the timeline, what is said, and what the viewer sees and hears. Go deeper only when needed.

Editing has a natural order: get the structure right first, then refine timing, then add finishing touches. Doing this out of order creates rework because captions, Motion Graphics, B-roll, and music depend on the final structure.

Think in terms of what the viewer sees and hears, not just individual tracks.

Before reporting done, verify the actual result. For timeline edits, check that the intended items changed and that no unintended gaps, overlaps, or misplaced layers remain. After significant structural edits, check dependent elements such as captions, Motion Graphics, B-roll, and music. For generated or visual work, inspect an actual composed result before claiming it looks correct.

Design Style Consistency

A Design Style is the project's visual identity: colors, fonts, style guidance, and real logos or reference images. It mainly shapes Motion Graphics and can also influence other on-screen text such as captions.

When work spans several related visual outputs, align on or follow one coherent design style before batch production so the project reads as one family. Do not lock in a design style from an unconfirmed guess.

Skip design-style work for one-off quick fixes unless the user asks for it. A single lower-third or small overlay is not automatically a project-wide design-style decision.

Project Onboarding And Editor Handoff

Establish the target project

Before nontrivial ChatCut work, ensure Codex is operating on the intended project.

"Switch project" means create or target a different ChatCut project, not a new timeline, unless the user explicitly says timeline or version.

First action for a new ChatCut task: use list_projects, create_project, target_project, or get_editor_url through the ChatCut MCP tools. Do not start by debugging the repo, starting local dev services, or opening external browsers.

  1. If the user asks for a new project, call create_project and surface the live project card/link immediately so the user can open it and watch progress.
  2. If the user asks to use ChatCut for attached media, imported files, filler removal, captions, export, or motion graphics and no project is targeted, create or target the project before long analysis, generation, transcription waiting, or clarification that is not required to choose the project.
  3. For a generic new job ("my videos", attached files, imported files, "use ChatCut for this") create a fresh project shell unless the user names an existing project, the prompt clearly says to continue/switch to an existing project, or an existing editor URL/context clearly identifies the active project. Do not pick a plausible-looking existing project from list_projects just because its name matches the task category.
  4. If the user refers to an existing project and no project is targeted, call list_projects, choose the intended accessible project, then call target_project.
  5. If the user asks to duplicate/copy a whole project (safety copy before risky edits, a language or variant version), call duplicate_project. It defaults to the currently targeted project. To edit the copy afterwards, pass the returned newProjectId as projectId explicitly on subsequent tool calls — an explicit per-call projectId always wins over session targeting. Pass activate: false to keep the source targeted. Owner-only; markers and chat history are not copied. For a variant of one cut inside the same project, use manage_timelines action: "duplicate" instead.
  6. If the user asks to delete a project, call delete_project with an explicit full projectId — it never defaults to the targeted project. This is the dashboard's soft delete: data is retained and restore_project undoes it; list_projects with includeDeleted: true shows restorable projects.

Use the current editor project

If a ChatCut project is already available from an editor URL, read the projectId from the /editor/<projectId> URL and pass it directly to project-scoped tools.

If chatcut asks for authentication or project access, run codex mcp login chatcut, then retry with the exact projectId from the editor URL.

Open the visible editor

Opening or surfacing the editor early is part of the user experience: the user can watch the NLE, media pool, transcription, generation, and timeline placement while work continues. Prefer showing a visible ChatCut surface over leaving it closed.

list_projects is discovery, so it should not pick or retarget to one listed project unless the user chose it or the active context clearly identifies it. Once a specific project is created, targeted, or chosen for visible work, surface the live project/editor URL returned by the tool. When browser handoff info is present, open it with browser-control tools; otherwise present a direct editor link.

When a ChatCut tool result includes a live project/editor URL, liveProject, browserHandoff, Codex internal Browser handoff, structuredContent.browserHandoff.required=true, browserHandoff.required=true, liveProject.openStrategy.preferredMode: "codex-internal-browser", or a live project/editor URL intended for the user, use the Codex browser-control capability to open or reuse the exact internal-browser URL in the in-app browser. Use browserHandoff.url when present; otherwise use the returned editorUrl.

ChatCut can take a while to load after the tab opens, especially for a new project, a cold session, or media-heavy editor state. If the browser-control tool reports that it successfully opened or focused the tab, treat the handoff as complete; do not wait for the page to fully load, keep polling the browser, or perform extra careful visual checks just to prove the editor opened. Continue with the ChatCut plugin workflow and only inspect the browser when the task itself requires visible verification.

If the internal Browser control tools are not visible in this session, load or re-read the internal control-in-app-browser / browser-control instructions when available, then discover and use the host's current browser-control tools. In Codex hosts with tool_search, search for browser:control-in-app-browser, Control In App Browser, in-app browser, and node_repl js; if the browser skill requires node_repl js, discover and use that tool to initialize the Browser runtime and select the iab browser. Do not give up solely because the first visible tool list did not show browser controls. Fall back to a named Markdown editor link only after discovery or browser setup fails, and state the failed step.

For the Codex internal Browser, preserve all query parameters, especially dockviewLayout=media and editor-boot-token. Do not replace a returned internal-browser URL with a guessed generic ChatCut URL.

For any direct user-facing Markdown link or external-browser link, use the clean editorUrl and do not include Codex-only dockviewLayout or editor-boot-token query parameters. If you only have an internal-browser URL, strip those two parameters before showing it to the user.

When sending or opening any editor URL, localize the editor-site path based on the language the user is using with Codex. Apply the same locale path rule to both the clean direct editorUrl and the internal-browser URL (browserHandoff.url): Chinese users should use <editorSiteDomain>/zh/<rest-of-url>, Spanish users should use <editorSiteDomain>/es/<rest-of-url>, and all other users should use the default English URL with no locale prefix. Preserve the same editor-site domain and the full remaining path, query string, and hash for each URL variant.

Use the exact browser handoff or editor URL returned by the tools. show_preview and embedded chat preview widgets are for other chat hosts and do not apply to Codex. Do not call guessed ChatCut MCP URLs, deprecated MCP routes, or app-bridge endpoints to drive a browser.

Keep the visible editor aligned

The visible editor is a live workbench, not a one-time proof. Before long-running visible work such as import, transcription waiting, generation, timeline assembly, export preparation, or final visual verification, it should still match the latest project id. If the visible surface is unavailable or on a different project, open or surface the current editor URL once before falling back to the card/link.

Billing and pricing exception

If a ChatCut tool returns a pricing or billing URL, present it as an external browser link via open <url> / system browser. Do not treat billing as an editor handoff.

Codex Connector Boundaries

ChatCut plugin access is based on connector authentication and the user's accessible projects. Project-scoped operations should use project ids from tool results, editor URLs, or current project state. Do not guess hidden ids.

Codex cannot ask the editor UI to pick, relink, upload, export, or capture local files for it; there is no editor-action bridge. Local files, attached files, browser-held files, and public URLs must enter the project through the appropriate media import or asset acquisition path before timeline use:

  • Bundled chatcut CLI (asset-import skill) for files Codex shell can read locally.
  • import_media for client-held bytes.
  • download_media for public URLs.

If a local-file upload/import request is denied by Codex host policy or auto-review because it would transfer private file contents to ChatCut's external API, stop the ChatCut workflow immediately. Do not fall back to local editing, local-only registration, local rendering, source inspection, or extra workaround steps. Tell the user Codex was denied permission to upload the file, and instruct them to upload the media in the right panel ChatCut editor or rerun Codex with higher permission for the upload.

For raw source-frame inspection, use the local source file directly with Codex-native tools such as ffmpeg when the file is available. If Codex has the original path, including an import-helper sourcePath, do not call remote ChatCut tools just to inspect source frames. If Codex does not have the original file because the asset was uploaded in the editor or only exists in project storage/cache, use view_asset_frames with the project asset id; it can route through the open editor for editor-side asset viewing or fall back to remote decode when available. Reserve view_timeline_frames for composed timeline proof.

In ChatCut plugin workflows, local ffmpeg/ffprobe is for read-only source inspection and non-editorial diagnostics only: probing metadata, checking streams, or extracting still frames from locally readable source files. Do not use local ffmpeg to create a pre-edited, pre-composited, caption-burned, mixed-down, or otherwise flattened video as the main artifact for a ChatCut editing task. Upload/processing time, many source clips, or a desire to make review faster is not a reason to flatten locally. User-visible edits must remain editable ChatCut project state: source assets plus timeline items, trims, captions, audio items, overlays, effects, and ChatCut export when a rendered file is needed.

Codex cannot ask the browser/editor tab to pick, relink, upload, export, or capture local files as a substitute for connector import/export flows.

ChatCut native internal chat components do not render directly in Codex. Convert those moments into ordinary Codex chat or the available structured follow-up/form capability.

If an edit changes spoken words, pauses, retakes, or transcript selection, use the Script-based speech editing workflow through the relevant ChatCut skill rather than physical timeline deletion as the main edit method.

For Codex-authored Motion Graphics, use the ChatCut Motion Graphic code workflow. Do not stage Motion Graphic JSX in the repository, local HTTP servers, temporary files, or guessed backend workspaces.

Use the relevant ChatCut task skill for detailed workflows such as media import, transcription, talking-head editing, Motion Graphics, verification, export, generation, product help, and error recovery.

指导Codex通过内联JSX直接创建、编辑和放置ChatCut项目中的动态图形资产。涵盖项目状态检查、视觉对齐、代码编写及时间线集成,禁止使用生成式代理路径。
需要创建新的动态图形JSX资产 需要修改现有的动态图形JSX资产 需要将动态图形放置或移动到时间线上
chatcut/skills/create-motion-graphics/SKILL.md
npx skills add ChatCut-Inc/agent-plugin --skill create-motion-graphics -g -y
SKILL.md
Frontmatter
{
    "name": "create-motion-graphics",
    "description": "Use whenever ChatCut Codex needs to add, create, hand-author, patch, or place Motion Graphic JSX assets in a ChatCut project. This is the Codex direct-authoring path: use create_motion_graphic_from_code \/ edit_asset \/ edit_item, not motion-graphic-gen or submit_motion_graphic. Covers project\/timeline intake, project visual language, editable properties, asset binding, inline JSX authoring, existing asset updates, timeline placement, and verification."
}

Create Motion Graphics

Use this skill when a ChatCut task requires a Motion Graphic asset that Codex will author or patch as inline JSX.

This skill is for Codex direct authoring. Do not translate the request into a Gemini prompt or generation brief, and do not call submit_motion_graphic, when this workflow is active.

If the current Codex MCP tool list or connector text still exposes submit_motion_graphic, treat it as stale/generic surface leakage. Ignore that path for MG work; use create_motion_graphic_from_code for new JSX assets and edit_asset for existing MG JSX. If the direct-authoring tools are missing, stop and report that the ChatCut tool surface is out of date.

This is a Codex-plugin-specific workflow. ChatCut tools run on the hosted backend, so pass source inline through the available MCP tool path. Do not stage Motion Graphic code in the ChatCut repository, ai-working/, /tmp, a local HTTP server, generated code files, or guessed backend workspace paths.

Core Principles

  • Inspect project state when canvas size, fps, existing visual language, placement, or timeline conflicts are not already known.
  • Identify the required inputs in Before You Code before authoring JSX.
  • Create or update Motion Graphic assets through the available inline-code asset workflow; use current tool schemas for exact payload shapes.
  • Place or move assets through the timeline editing workflow when the edit requires timeline placement.
  • Re-read project state and verify the visible frame after structural or visual changes.

Before You Code

Before writing JSX, identify only the information needed for this edit:

  • Placement: start time, duration, target layer if known, and the target frame the graphic must compose with.
  • Role in the edit: what job this Motion Graphic performs in the video.
  • Content: exact text, numbers, media, or visual facts that must appear.
  • Timing: whether internal motion should sync to speech, music, or a visual event.
  • Visual source: user-provided style, project Design Style, brand colors/fonts, or an accepted existing Motion Graphic.
  • Editable fields: which text, colors, numbers, booleans, image, or video values should become properties.

Ask only for missing high-leverage inputs that would materially change the result.

Align With The User

You are the junior designer; the user is the manager. Direction is the high-leverage choice — surfacing it before authoring is much cheaper than reauthoring after.

Style alignment gate:

Separate visual direction from batch permission. A user-named text/custom style can choose the direction, but it does not permit multiple MGs until the user has confirmed a representative MG. Batch authoring is permitted only by an active Design Style, a selected visual preset, or a previously accepted representative MG.

  • If there is no active Design Style and the user has not named a style, stop before authoring and ask the user to choose a direction.
  • Generic quality adjectives are goals, not a named visual style. If the user only says the MGs should feel clean, premium, modern, professional, polished, or similar, use visual preset thumbnails instead of inventing a direction.
  • Prefer catalog Design Style presets: call manage_design_style with action: "list_presets", present 3-6 reasonable visual choices, and let the user pick or override.
  • In Codex, load the widget-forms skill and use ask_followup_questions with visual thumbnails when preset thumbnails are available; fall back to numbered Markdown only when the visual route is unavailable.
  • In Claude Code, load the same widget-forms skill and follow its Claude recipe: keep the visual choices and any related questions in one show_widget, resolve each preview through the widget-media manifest by preset id, and use label-only cards for missing entries. Never process the original thumbnail URL. Then wait for the user to send the filled prompt.
  • You may recommend one choice, but still show the choice set. The point is visual alignment, not a single best guess.
  • When it isn't obvious, also ask whether the MG sits over the video as an overlay or takes the whole frame.

Before authoring, choose the branch:

  • One MG: use the active Design Style, accepted example, or user-named direction and proceed.
  • Multiple MGs with an active Design Style, selected visual preset, or previously accepted representative MG: proceed with a batch design map.
  • Multiple MGs with only a textual/custom direction, however clear: create exactly one representative MG, place it, render its composed frame, then stop for confirmation. Do not create a second MG asset or item before the user confirms.
  • Multiple MGs with only generic quality adjectives: use the visual preset picker first.

When the task needs visual style alignment, check the active project Design Style first. If there is no active Design Style and the user has not given a clear style direction, use the style alignment gate above.

Saved user design styles are a library, not project confirmation. If manage_design_style list shows saved styles but no active project Design Style, do not infer or choose one silently; use list_presets and visual alignment unless the user selects a saved style or asks you to use one.

Catalog Design Style presets are available as visual style options with image previews. When no active Design Style or user style is set, first look at the available catalog candidates with list_presets and show 3-6 reasonable visual starting points. They do not need to match every detail of the user's request; preset thumbnails set useful visual expectations and can be adapted in authoring. Prefer visual options over text-only choices because seeing the look is usually clearer than naming it. Do not force catalog presets when none are reasonably close; use text directions only then.

When using catalog presets, call manage_design_style with action: "list_presets"; pass scenario only when it is clear. Pick 6 matches using each preset's description as agent-facing matching guidance when there are enough reasonable matches; use fewer only when fewer presets genuinely fit. Never render the full catalog as user-facing choices. In Codex, use ask_followup_questions with one visual single-select field, mapping each preset to {id, label: name, preview: thumbnailUrl}. In Claude Code, use the widget-forms Claude recipe with the same ids and labels, resolve design-style/<presetId> through ${CLAUDE_PLUGIN_ROOT}/assets/widget-media/manifest.json, and include the resolved CDN image only when that key exists; never use or process the original thumbnail URL. If a manifest entry is unavailable, render a concise label-only choice in the same form. Do not invent value, name, or media for catalog choices, and do not mix custom non-preset directions into the same visual picker. If a custom direction would help, describe it in prose outside the picker. Do not repeat catalog descriptions under the picker unless the user asks for details. Frame catalog options as visual starting points, not required choices: briefly make clear in the user's language that they can pick a close option or describe a different direction. If the user asks to refresh, call list_presets again and show a different set of up to 6 reasonable matches. Do not repeat presets already shown in the current style-picking exchange; show fewer than 6 rather than repeat. Apply the user's pick with action: "apply_preset". After applying a preset or saved style, call manage_design_style with action: "get" before authoring MG code; preset names and list_presets descriptions are picker guidance, not the full motion/design spec. Do not create or update a Design Style from an unconfirmed recommendation.

The visual style picker is a turn boundary. In Codex, stop after calling ask_followup_questions; in Claude Code, stop after rendering the combined widget and wait for the user to send its filled prompt. Do not apply a preset, create MG assets, inspect more frames, or continue detailed MG planning from your own recommendation before the user's selection appears in chat.

For a batch of related MGs in one scene or topic, ask once for a shared direction — don't invent a different aesthetic per item, and don't ask per MG.

When the batch direction is textual or custom rather than a visual preset or active Design Style, the representative-MG gate above is a hard stop. A user-named text style skips only the preset picker; it does not confirm the visual language for multiple MGs. The representative MG validates visual language only; it does not define the form for every later MG.

The only times to skip the style picker:

  • The user has already named a visual style, material, reference, or visual language ("做 editorial 杂志风的", "做个 80s 复古印刷", "magazine style 那种") — use it verbatim as the direction. For multiple MGs, this still enters the representative-MG branch until the user confirms the example.
  • The user has explicitly waved off alignment ("直接做" / "don't ask, just do it"): make your best guess, name it in chat, then continue with the normal authoring, frame-inspection, and consistency workflow.

Project Visual Language

Use the active project Design Style, user-provided style, brand assets, or an accepted existing Motion Graphic as the visual language for hand-authored JSX. A visual language means shared palette, typography logic, motion tone, spacing, density, material treatment, and level of polish.

When a Design Style is active, work from its full designSpec / styleGuide, not only its name or catalog summary. Treat explicit style rules for motion, typography, color, and material as implementation constraints.

Treat Design Style structure, materials, and template notes as visual vocabulary, not default containers. Express the style through typography, marks, geometry, texture, motion, spacing, and materials; use a bounded reading surface only when bounded reading is the actual editorial mechanism.

Do not create or update a project Design Style just because a one-off Motion Graphic needs styling. For multiple Motion Graphics in the same video, keep one coherent visual system unless the user asks for a deliberate contrast, and let each MG's content and editorial job determine its form.

Visual System And Placement

Treat multiple MGs in the same video as one visual system. Shared style comes from palette, typography, motion tone, spacing, material, and polish.

Before authoring a batch, make a compact design map for the planned MGs: viewer job, content, visual mechanism, how it carries meaning beyond text, speech span, settled frame, read time, size, composition relationship, internal motion beats, and whether its form is intentionally recurring.

Let each MG's content and editorial job determine its form. Keep the same visual language while choosing the composition, size, placement, duration, and rhythm that fit that moment.

Choose the visual mechanism before writing JSX. Decide how the graphic carries meaning beyond text, using the confirmed visual language and the content's viewer job. Name a wrapper as the form only when a bounded reading surface is truly the right mechanism.

Text should rarely carry the whole graphic alone. Pair key words, stats, or claims with a tangible non-text visual role so the result is not just copy inside a wrapper.

Common defaults must earn their place. Use a bounded reading surface only when bounded reading is the editorial mechanism; otherwise let the MG's form come from the frame relationship and viewer job.

Reuse an MG asset only for an intentionally recurring component with the same viewer task, information structure, and visual form. Shared palette, typography, motion, or a bounded-surface treatment is visual language, not a reason to reuse the same asset.

Placement and duration are part of the settled frame composition. Choose each MG's position, size, anchor, start, and end from the relationship between the speech span, inspected frame, reading time, and visual job. Do not use a fixed safe-zone as the default placement; repeated anchors are intentional only when the frame relationship and viewer task recur. If the graphic does not feel integrated with the moment it explains, change its form, timing, scale, or skip.

Match the MG asset duration to the timeline span it is designed to occupy. Internal motion beats must complete inside the placed item duration; when the edit timing changes materially, update or recreate the MG instead of relying on a shorter timeline item to truncate a longer asset.

In a batch, compare the composed settled frames side by side. The MGs should share a visual language, but repeated surfaces, anchors, or rhythms should point to a recurring viewer job; otherwise revise the form, placement, or timing before reporting done.

Create the asset shape that fits the job at hand. For overlays, the asset box should tightly bound the visible graphic's local composition. Use timeline dimensions only when visible design intentionally spans the whole frame.

Editable Properties

Expose user-visible and likely-to-change values as editable properties.

  • Visible text, primary colors, accent colors, and key numeric values should be properties.
  • Font choices should be font properties when users may reasonably change them.
  • Image and video sources must be image / video properties.
  • Code keys must match the property schema keys exactly.
  • Read values from item.props; do not hardcode visible content that the user may reasonably want to change later.
  • Use item-level property overrides only for intentionally recurring components with the same viewer task, information structure, and visual form. If any of those differ, create another MG asset and share palette, type, and motion logic instead.

Property entries should declare a stable key, user-facing label, type, and default value. Supported property types include text, number, color, boolean, select, font, image, and video.

Fonts

Motion Graphics must use fonts the cloud renderer can load. Do not rely on local/system fonts such as STKaiti, PingFang SC, Microsoft YaHei, Arial, Helvetica, Comic Sans MS, system-ui, -apple-system, or generic CSS families as the primary rendered font; preview may have them locally, but export will fall back to the default stack.

When choosing or replacing a font, call search_fonts and use the returned canonical family name verbatim as the fontFamily value and matching font property defaultValue. Use Google Fonts or project custom fonts returned by the catalog. If a user explicitly asks for an unsupported local font, explain that cloud export cannot preserve it, search for a supported alternative with a similar feel, and use that supported family unless the user explicitly accepts export fallback.

Assets

Images and videos rendered inside Motion Graphics must already be registered as project assets or otherwise be passed through editable asset properties.

  • Do not hardcode media URLs in JSX.
  • Use <Img> and <Video> only with URLs read from item.props.
  • Guard empty image/video properties before rendering; an empty src can crash the runtime.
  • To swap a rendered asset for one timeline instance, update that instance's editable property values rather than changing the shared asset code.

Design Principles

Codex is the designer for direct-authored Motion Graphics. Do not merely satisfy constraints or place text in a wrapper. Before writing JSX, design the settled frame as a specific visual object.

Before writing code, decide:

  • Purpose: what the viewer should understand faster because this MG exists.
  • Direction: the specific visual language, not "clean", "modern", or "professional" alone.
  • Memory: the one visual idea, spatial move, or motion beat the viewer should remember after 3 seconds.
  • Mechanism: how typography, geometry, diagram, texture, image, or motion carries meaning beyond text.
  • Craft: how typography, color, motion, spatial composition, and material treatment follow the chosen direction.

Before writing code, choose a clear aesthetic direction for this specific design. Commit to one direction and execute it with precision rather than defaulting to a generic look.

Default quality bar: distinctive, production-grade, and intentional. When the user has not specified a style and asks you to proceed, choose a specific visual direction with a point of view. Do not fall back to safe, basic, or generic just because the style is unspecified.

Restrained does not mean plain. Minimal or refined MGs still need a named design language, precise hierarchy, and one memorable visual decision.

Treat the Design Style's motion language as a constraint, not just mood. If it says hard cut, no opacity, no translate, no glow, no easing, word-by-word, static bars, or sequential nodes, implement those literally; do not replace them with fades, springs, sweeps, glows, or drifting motion.

Motion must earn its place. Do not add shine, sheen, light-sweep, scan-line, shimmer, glow, or glossy passes as default polish; use them only when the style or editorial job explicitly means scanning, loading, reflection, energy, or detection. Prefer typography, masks, stagger, data bars, and timing tied to the content.

Material treatment belongs to the visual language. Do not add glass, blur, heavy shadows, gradients, grain, paper texture, glow, or other surface polish just to make the surface feel designed; use those materials only when the confirmed style or visual job calls for them.

When the graphic includes text, create clear hierarchy. Use the Design Style's type system when it exists. When no type system is defined, make size, weight, spacing, and timing contrast visible at video scale.

Design the most visible frame first, then animate into that layout. Choreograph by importance: the first moving element is the hierarchy leader. Vary direction, duration, easing feel, and stagger rhythm when the visual job changes.

Anti-slop rules are a floor, not a ceiling. Avoid generic AI-generated aesthetics: purple/blue gradient backgrounds, fake glassmorphism everywhere, predictable feature-tile layouts, or cookie-cutter design that lacks context-specific character. Within one visual system, vary form, composition, and rhythm when the visual job changes; keep color and typography logic coherent enough that the MGs belong together.

Do not default to card-shaped overlays. Unless a bounded reading surface is truly needed, avoid floating panels, tickets, notes, or rounded rectangles that simply hold text; they often feel detached from the footage and make the video look like UI rather than motion design.

Use strong materials, texture, gradients, glow, depth, dense composition, or bold motion when they are part of the confirmed visual language or the editorial job. Do not avoid expressive design just because a generic version of the same effect would be bad.

Do not default to centered, symmetrical layouts. Consider asymmetry, overlap, generous negative space, or controlled density, whichever fits the content. Unexpected spatial choices make motion graphics feel designed, not generated.

A character, illustration, or compound shape is one visual entity. When multiple parts must visually connect, attach, or align, render those parts inside a single <svg> with one shared coordinate space and named anchors. Independent hardcoded left / top across separate wrappers produces visible gaps.

Text Layout Safety

For text-bearing MGs, design the settled frame as a real layout before animating. Use flexbox or grid, gap, padding, maxWidth, lineHeight, and natural wrapping for related text blocks. Do not stack readable text with independent hardcoded top values unless the text is intentionally decorative or typographic art.

Editable text may become longer than the default. Reserve space for plausible longer copy, allow wrapping with whiteSpace: "normal" and overflowWrap: "break-word", and reduce hierarchy, size, density, or change form when the content cannot fit cleanly.

Animated transforms do not affect layout. If text scales, pulses, slides, or staggers near other text, leave visual headroom for the largest animated state. Intentional overlap may be used for graphic layers, shadows, marks, or decorative typography; ordinary readable text must not collide.

Avoid forced <br> or manual line breaks for dynamic text unless each line is deliberately fixed. Prefer width-constrained wrapping.

Use this base component shape:

const Component = ({ item }) => {
  const frame = useCurrentFrame();
  const { durationInFrames } = useVideoConfig();

  const props = item.props || {};
  const accentColor = props.accentColor;

  const rootStyle = {
    position: "absolute",
    inset: 0,
    backgroundColor: "transparent",
  };

  return <div style={rootStyle}>{/* content */}</div>;
};

Motion Graphic Code Contract

Violations cause runtime crashes. Strict compliance required.

  1. Syntax: Pure JavaScript JSX. No TypeScript.
  2. Imports: No import statements. Globals are pre-injected: React, spring, useCurrentFrame, useVideoConfig, interpolate, interpolateColors, Math, random, Easing, AbsoluteFill, Sequence, Series, Img, Video, and Audio.
  3. No Remotion global: Never use Remotion.xxx or const { ... } = Remotion. Hooks and components are pre-injected as standalone globals.
  4. Exports: No export default. Define const Component = ....
  5. Timing: No Sequence wrappers inside the component. Use flat frame-driven logic.
  6. Logic: No inline logic in JSX props. Pre-compute values in variables before return.
  7. Helpers: No undefined functions. Use interpolateColors plural. Define any helpers locally.
  8. AbsoluteFill: AbsoluteFill is a component, not a style object. Never spread it. It may be used for inner layers, but never as the root.
  9. Root element: The root must be <div style={rootStyle}>.
  10. Assets: <Img> and <Video> sources must read from image/video editable props. Never hardcode URLs. If no assets are provided, design with shapes, text, and CSS.
  11. Hooks: Get frame from useCurrentFrame(), not from useVideoConfig().
  12. Local box: Component must accept ({ item }) props. The asset width/height are the MG's natural box around its visible local composition, not the timeline canvas; fill that box with position:absolute; inset:0. Timeline placement sets final screen size and position.
  13. Layout control: Use flexbox or grid for text blocks and structured content. Use SVG or absolute geometry when the design depends on spatial relationships, compound shapes, frame treatments, or drawn/animated marks. Allow text to wrap naturally unless the request requires single-line text.
  14. Editable props: Component must read editable values from item.props. Never add fallback values like || "Default" or ?? false after props.key; declared runtime properties already have values.
  15. Property schema: Declare matching editable properties. Include all visible text content and primary/accent colors.
  16. Image/video props: Guard empty URLs; only render <Img> or <Video> when the URL is truthy.
  17. Background: Default background is transparent. If a background surface is added, expose a transparentBackground boolean property.

Placement And Review

Do not author JSX from timing alone. Inspect the target frame first: timing tells you when; the frame tells you form, placement, and background. For a batch of overlays, make one target-frame screenshot/contact sheet and decide each MG's settled frame, speech span, read time, and placement relationship before choosing final anchors, sizes, and durations.

Design the settled frame first: choose the moment when the MG is most readable, place the final layout there, then animate into that composition.

Before authoring JSX, make four linked editor decisions. They prepare the Motion Graphic asset and the later timeline placement.

Decision Question Output
Content What idea deserves a visual layer? The message or visual fact the MG expresses.
Timing When should it land and leave? Speech span, read time, duration, and any internal motion beats.
Form and placement What kind of MG is it, and where does it belong in the composed frame? MG form/size, then edit_item placement after asset creation.
Background Is this an overlay on the footage, or its own moment? Transparent or opaque background.

Placement principles:

  • Compose the footage and MG together from the frame you inspected: subject, camera framing, visual weight, captions/subtitles when present, and the MG's job.
  • Place the MG where it makes the frame read best for that moment.
  • Keep necessary information readable at video scale without zooming; if the MG feels detached, change form, timing, scale, or skip.
  • Account for captions only when captions are present or planned.
  • Treat full-frame MGs as intentional beats, not as a workaround for awkward overlay placement.

Default to a transparent overlay unless a full-frame beat is intended. A transparent overlay still uses a natural-box asset; do not use a transparent timeline-sized asset just for placement.

Place and review:

  • Place with edit_item (adds/updates). Prefer an explicit rectangle once you know the frame: one horizontal anchor, one vertical anchor, width, and height.
  • Verify with screenshots. Pass multiple frames in one tool call — settled state appears alongside any transient mid-animation frames. Compare frames before concluding: apparent truncation, missing elements, or "broken design" visible in only some of the batch is animation, not a real flaw. If unclear, re-capture more frames around the suspect one before adjusting anything. Judge from the settled frames.
  • Check the full frame: necessary information is clear at video scale, captions remain readable when present, MG content is correct, text is legible, and the composition feels balanced and intentional.
  • For text-heavy MGs, inspect the settled frame where the most text is visible. Check for text-on-text overlap, clipped lines, overflow outside the natural asset box, and readable content covered by animated scale or translate states.
  • If it fails, first adjust position and size. If position/size cannot make it work, change the design form. Verify each recurring component form on a target frame before expanding it.

Asset And Timeline Flow

Create A New Asset

Create new Motion Graphic assets by passing inline JSX and editable property metadata through the current ChatCut asset-creation tool. Use the tool schema for the exact field names and accepted duration format.

Choose the MG's natural box, duration, asset name, description, and property schema from the edit requirements. The asset duration should match the intended placed span, including internal entrance, hold, and exit timing. The asset creation step only creates the asset; timeline placement is separate.

For create_motion_graphic_from_code, pass that natural box as width/height; use timeline dimensions only for intentional full-frame MGs. If the content occupies only part of the screen, place and scale the bounded asset with edit_item instead of baking screen coordinates into a full-canvas MG.

Patch An Existing Asset

Before patching, inspect the existing asset code and property schema. Preserve unrelated behavior, property keys, and timeline timing unless the requested change requires otherwise.

Read references/canvas-pipeline-rules.md before changing code, especially when SVG is involved. Patch with full inline replacement source through the current asset-update tool.

Place On The Timeline

Use the timeline editing workflow for placement, movement, trimming, and per-instance property overrides. Dry-run large or uncertain transactions when the tool surface supports validation.

Implementation Rules

Read references/canvas-pipeline-rules.md before any asset-code update, when writing or modifying SVG, or when preview looks correct but export renders black or empty.

Verification

A successful tool call is not verification.

  • Re-read asset state after asset creation or update.
  • Re-read timeline state after placement, movement, trimming, or property overrides.
  • For visible changes, inspect a real composed frame using the normal ChatCut visual verification path.
  • For a batch, compare the composed settled frames side by side; verify that each visual job has a fitting form, repeated surfaces/anchors/rhythms are intentional, and each placement works for its own target frame.
  • If the result is wrong, classify the failure before retrying: invalid tool shape, invalid JSX, missing/incorrect property key, timeline placement, async asset readiness, or canvas/export safety.
  • Fix placement with timeline edits; fix bad rendering with JSX/property changes; use canvas rules for preview-good/export-black failures.
指导ChatCut视频导出流程,要求使用submit_export和track_export处理持久化任务。规定Claude Code环境下通过curl下载文件并以文本形式交付路径及预览链接,禁止使用共享链接或本地ffmpeg替代标准导出。
用户请求导出、渲染或分享ChatCut视频 需要获取最终交付文件或字幕文件 询问本地与云端渲染的选择
chatcut/skills/export/SKILL.md
npx skills add ChatCut-Inc/agent-plugin --skill export -g -y
SKILL.md
Frontmatter
{
    "name": "export",
    "description": "Use when a ChatCut video editing or creation workflow needs export, render, download, share, final delivery, subtitle-file export, local versus cloud render choice, local-only asset handling, or export fallback explanation from the plugin host agent."
}

Export

Use ChatCut's durable export jobs for Codex-visible delivery. A ChatCut export request from Codex should call submit_export, then use track_export for status and final delivery when the result is not returned immediately. Do not use share-link tools for connector exports.

Default policy:

  • Prefer submit_export when the user asks to export/share/finalize the ChatCut timeline.
  • Keep originals local by default during editing. Upload originals only when a cloud export/proof needs remote assets and the user has not forbidden upload.
  • Do not wrap Codex-native ffmpeg work as a ChatCut tool. Use local ffmpeg for full video processing only when the user explicitly asks for a standalone local-file operation outside a ChatCut editing workflow. For ChatCut editing tasks, do not produce a pre-edited or flattened local render as the primary review/final deliverable; use ChatCut export.

Claude Code delivery: local file + text handoff (verified 2026-07-15)

In Claude Code, the shared delivery lines below (inline video display and waiting for browser download artifacts) do not apply. Follow this section instead.

After track_export returns the finished render:

  1. Download it with curl -L to the user's Downloads folder. Use the shared collision-safe naming rules: never overwrite an existing file, and add a numbered suffix such as name (1).mp4 when needed. This curl is the only download path for a connector export, so do not look for or wait on .crdownload files.
  2. Deliver it as concise text only. Start with , report the complete absolute local path, file size, resolution, and duration. Also present a named Markdown link such as [Open local preview](<file-url>), using an absolute file:// URL for the downloaded file. Generate the correctly escaped URL with Node's pathToFileURL(absolutePath).href; do not hand-build it from a path that may contain spaces or non-ASCII characters. This local-file link is a convenience because host policy may decline to activate it; always keep the complete absolute path visible as the fallback. Do not call show_widget, search for visualize, extract a poster frame, run ffmpeg, generate base64/data URIs, or add widget/action buttons.
  3. Give the user two additional preview choices: use 查看 / View in the editor's export queue at the top right, or say they can ask you to open the downloaded file in their local player if the local-file link is blocked. Only after explicit consent, run open <absolute-path> on macOS or start "" <absolute-path> on Windows; never open it proactively.
  4. Browser-pane playback is a fallback only when the user explicitly asks for it. Before navigating to the render URL, warn that the render bucket is a new origin and the pane will show a one-click origin approval card; after approval, retry the same navigation once.

Durable Export

Use submit_export for the execution path:

{
  "format": "video",
  "codec": "h264",
  "resolution": "1080p",
  "fps": 30,
  "name": "final-cut"
}

Video codec options are h264 (MP4, default) and vp8 (WebM). Video frame-rate options match the editor UI: 24, 25, 30, 50, or 60; omit fps to match the timeline. Audio export is MP3: pass "format":"audio" and omit codec / fps unless you explicitly pass "codec":"mp3".

submit_export returns a durable renderId. Some export types, such as subtitle files, may complete immediately and return downloadUrl; video/audio usually require track_export to wait for completion.

After getting each downloadUrl:

  • Resolve the user's Downloads folder: ~/Downloads on macOS/Linux, or %USERPROFILE%\Downloads on Windows.
  • Before triggering any agent/browser download, check the Downloads folder for fresh Chrome download artifacts from the last few minutes that match the expected export name, extension, or render/download URL basename. Include both completed files and in-progress .crdownload files.
  • If a matching fresh .crdownload exists, do not trigger another download. Wait until Chrome removes the .crdownload suffix and the final file size stops changing, then use that completed file.
  • If a matching fresh completed file already exists, use it directly instead of downloading again.
  • If only older files exist, treat them as collisions, not as the current export.
  • Do not overwrite an existing file; choose a safe numbered filename such as name (1).mp4 when needed.
  • Always download the finished export file into the Downloads folder, not a temp/workspace directory.
  • Always show the downloaded video inline in chat. If there are multiple exported videos, download all of them and show every preview, not just the first.

If the project contains local-only assets, upload/register cloud-readable replacements before rendering, or use the Local CLI Export path when the user wants to stay local.

Report the returned renderId when present and tell the user the job is visible in the editor render-jobs panel.

Use track_export when the user asks about export/render status, or when the current turn genuinely needs to wait for a submitted video/audio render. Completed connector exports return downloadUrl; for every completed entry, download the file to Downloads using the collision-safe rules above and show it inline in chat:

{
  "action": "status",
  "renderIds": "abc123"
}

For the latest project export, omit renderIds and pass "latest": true. track_progress is for generation/transcription/upload jobs, not render jobs.

For NLE XML, use submit_export with format:"xml":

{
  "format": "xml",
  "nleFormat": "fcp_xml_resolve",
  "timelineId": "abc123"
}

nleFormat values are fcp_xml for Premiere XML (default) and fcp_xml_resolve for DaVinci Resolve XML. Omit timelineId for the active timeline, or pass a timeline id/prefix for a non-active timeline. Read and report warnings: captions, solids, SVG, unsupported clip attributes, and unrendered motion graphics may be dropped by the XML format. Motion graphics are only represented in XML when a transparent-ProRes MG export flow supplies motionGraphicRenderKeys; otherwise the exporter reports them as dropped.

For media-pool source download, use request_asset_download on a file-backed source asset. It returns a guarded backend download URL/path for the original source media. Do not use pull_asset for user downloads; pull_asset is sandbox-only.

For subtitle files, use submit_export with format:"subtitles":

{
  "format": "subtitles",
  "subtitleFormat": "srt"
}

Formats are srt and txt. The export uses the captions item's actual timeline word timing, source scope, translation variants, display-text overrides, and pacing fields such as wordsPerPage / maxCharactersPerLine, and creates a durable downloadable export job. It is appropriate for downloadable subtitle files. It does not yet reuse the browser Remotion caption page planner, so visual line wrapping/page breaks are timing-correct but approximate rather than byte-identical to burned-in caption pagination. For non-active timelines, pass timelineId from manage_timelines or read_project.

For one motion graphic as transparent ProRes 4444, use export_motion_graphic_prores:

{
  "itemId": "abc123",
  "filenameMode": "asset"
}

Prefer itemId when exporting a specific timeline instance, because the item carries live propertyOverrides such as edited text. Use assetId for a media-pool motion graphic; the backend will use the first timeline instance for that asset when present, matching the editor's media-pool export behavior. For several motion graphics, pass itemIds or assetIds in one call. Each motion graphic still becomes a separate durable render; use track_export with the returned renderIds to wait, then download through each returned render download path.

When preparing XML that should reference rendered motion graphics, pass "filenameMode":"xml" and the same timelineId to export_motion_graphic_prores, then keep the returned motionGraphicRenderKey / motionGraphicRenderKeys; after the render completes, pass those keys and the same timelineId in submit_export.motionGraphicRenderKeys with format:"xml".

Local CLI Export (no S3)

Use this path when the project was assembled with chatcut register (see the asset-import skill) and bytes never went to S3. The cloud render endpoint will reject the job with a 400 telling you to use local export, because Lambda cannot read the user's filesystem.

Pre-requisite: the chatcut CLI is installed on the user's machine.

Flow:

  1. Call import_media with {"action":"create_session"} to get a fresh session token.
  2. Derive the render-prepare endpoint from the returned media-import endpoint by replacing the trailing /media-import with /render-prepare. The same cmi_ token authenticates both.
  3. Run:
chatcut export --token <token> --endpoint <renderPrepareEndpoint> --output ~/Downloads/<safe-name>.mp4

Optional flags: --codec h264|mp3|prores|vp8 (default h264), --crf <n>, --frame-range start-end, --timeline-id <id> for a non-active timeline.

The CLI prints the absolute output path on stdout when render completes. Streams progress to stderr. Use Downloads-folder collision-safe naming exactly like the bridge export path (numbered suffix when a file already exists).

This is the only export route that works for chatcut register-imported assets — they have no remoteUrl so submit_export will be refused.

Fallbacks

The editor-action local bridge export path has been removed; use cloud render for connector exports.

If cloud render is blocked by local-only assets:

  1. If the user's intent allows upload, use import_media to upload/register cloud-readable replacements.
  2. If the user wants to stay local, use the Local CLI Export path above.
  3. If neither is available (no chatcut CLI installed and upload not allowed), report that the user needs to install @chatcut/skill or upload originals before cloud render can proceed.

Do not tell the user they need to understand HTML-in-Canvas, Remotion Lambda, or S3 unless debugging. Explain at product level:

  • "本地快速导出"
  • "云端兼容导出"
  • "需要先上传本地素材"

Result Trace

For submit_export, record:

  • renderId
  • timeline/range/resolution/codec/fps
  • that the user can download from the editor render-jobs panel

Record uploaded asset IDs and any fallback tried when cloud export was blocked by local-only assets.

通过后端API生成AI图像。支持gpt-image-2(文字渲染优)和nano-banana(参考图保真度高)模型。提交任务后返回jobId,需配合track_progress工具追踪进度。
用户要求生成图片、海报或视觉素材 用户提供参考图要求编辑、融合或作为视觉引导
chatcut/skills/image-gen/SKILL.md
npx skills add ChatCut-Inc/agent-plugin --skill image-gen -g -y
SKILL.md
Frontmatter
{
    "name": "image-gen",
    "description": "AI image generation via gpt-image-2 and nano-banana. Use when the user wants to generate or create an image \/ picture \/ still through the backend image-generation jobs.\n",
    "user-invocable": true
}

Image Gen

Generate AI images through the backend generation API. Submit-only: creates a generation job and returns a jobId.

After submission, use track_progress tool to check status or wait for completion.

Model Selection

Model Strengths Max refs
gpt-image-2 Best text rendering, strongest prompt adherence 10
nano-banana Strongest reference-image fidelity 14
  • gpt-image-2 is the default.
  • nano-banana is the reference-heavy choice. Use it when reference-image fidelity matters more than text rendering, or when the user needs more than 10 reference images.

IMPORTANT: Before generating, READ the model's reference document for params, limits, and prompt tips:

Tool Params

Param Values Default
aspectRatio 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3, 4:5, 5:4, 21:9 16:9
imageSize 1K, 2K, 4K 1K
quality low, medium, high, auto (gpt-image-2 only) high
referenceAssetIds Array of project asset ids — backend resolves bytes server-side
name Short descriptive asset name shown in the library
count Number of images to generate (1–10, each becomes a separate job) 1

Defaults

  • Aspect ratio: 16:9. If the project composition is not 16:9, ASK the user which aspect ratio they want before generating.
  • Size: 1K.

Ask Before Submit

  • Never auto-upgrade size.
  • Only pass imageSize: "2K" or "4K" when the user explicitly asks. Warn that 2K/4K are EXPERIMENTAL and may be slower.

Reference Images

Use when the user provides source material to edit, blend, or use as visual guidance (e.g. "change the background", "combine these into a poster").

  • Pass project asset ids via referenceAssetIds. The backend fetches and encodes them server-side — never pull the asset bytes yourself.
  • When the user @-references an image asset, pass its id directly in referenceAssetIds.
  • Formats accepted by backend: png, jpeg, webp, svg (auto-rasterized to png), heic, heif. Each ≤ 50MB.

Run

// Basic generation
submit_image({
  model: "gpt-image-2",
  prompt: "a cute orange cat",
  name: "Cat",
});

// With quality (gpt-image-2 only)
submit_image({
  model: "gpt-image-2",
  prompt: "hero poster with bold title",
  quality: "high",
  name: "Hero Poster",
});

// With reference images — pass project asset ids; backend resolves bytes
submit_image({
  model: "gpt-image-2",
  prompt: "change background to beach",
  referenceAssetIds: ["<assetId>"],
  name: "Beach Edit",
});

// Reference-heavy with nano-banana
submit_image({
  model: "nano-banana",
  prompt: "composite poster",
  referenceAssetIds: ["<id1>", "<id2>"],
  name: "Composite",
});

// Multiple images
submit_image({
  model: "gpt-image-2",
  prompt: "product shots",
  count: 3,
  name: "Product",
});

After submission, call the track_progress tool: action=status jobIds=<jobId> to poll, action=wait jobIds=<jobId> to block until terminal.

Rules

  • Always provide name with a short descriptive asset name.
  • Default to submit-only. If there is no follow-up task, stop after submit and tell the user the job was created.
  • Generation costs credits. Before submitting, briefly tell the user what you're about to generate — especially when generating multiple images.
  • Do not use this skill for job management. Use track_progress tool for that.
处理ChatCut插件工具调用失败或异常返回。涵盖edit_item数据格式修正、时间线重叠重试、路径限制规避、媒体导入转换失败处理及动态图形规范,提供具体错误修复方案。
ChatCut插件工具调用失败 工具返回意外数据结构 视频编辑操作报错
chatcut/skills/known-errors/SKILL.md
npx skills add ChatCut-Inc/agent-plugin --skill known-errors -g -y
SKILL.md
Frontmatter
{
    "name": "known-errors",
    "description": "Use when a ChatCut plugin tool call fails or returns an unexpected shape."
}

Known Errors

edit_item update raw shape:

  • Wrong: { "id": "abc", "fromFrame": 30 }
  • Right: { "json": "{\"updates\":[{\"id\":\"abc\",\"fromFrame\":30}]}" }
  • Use this same updates shape for common moves, trims, and track changes.

edit_item add raw shape:

  • The new item goes inside the adds array of the json transaction: { "json": "{\"adds\":[{...}]}" }.
  • Use edit_item for simple video placement, for example { "json": "{\"adds\":[{\"type\":\"video\",\"assetId\":\"...\",\"fromFrame\":0}]}" }.

Timeline overlap:

  • Error text: Overlap: updated item at ... would overlap existing item at ... on this track.
  • Do not force the write or delete the conflicting item silently.
  • Retry the edit_item transaction with an explicit available trackId, for example an update containing "trackId":"V2", or ask the user which layer should win.

Workspace path restrictions:

  • push_asset on the external MCP only accepts public http(s) URLs as filePath. It rejects local paths, workspace paths, and chat attachment paths.
  • For motion-graphic assets, pass the JSX source via create_motion_graphic_from_code({ code:"...", name, width, height, durationInFrames }). push_asset no longer accepts an inline code argument.
  • Copying local media into the workspace is not the fix for video/audio/image/GIF imports; use asset-import and import_media instead.
  • Use import_media action=create_session, then run the ChatCut media import helper once with the returned token for client-held files.

Browser video conversion failure:

  • Error text often includes Unable to convert video without dropping audio/video tracks or unknown_source_codec.
  • Rerun the ChatCut media import helper; it owns frontend-aligned conversion and will surface a user-actionable error if conversion is impossible.
  • Do not ask the user to re-import the same file through the editor UI as a workaround — the conversion path is the same, the error will repeat. Fix the source (re-encode locally with ffmpeg) or pick a different file.
  • After the replacement asset is uploaded/transcribed, delete the failed original asset if it is unused. The clean final media pool should look like a successful import, not a failed import plus a replacement.

Motion Graphic requirements:

  • push_asset(type:"motion-graphic") requires width, height, and duration or durationInFrames.
  • MG code must pass the ChatCut validator.
  • Root AbsoluteFill is not valid for generated MG code; use a scaling root div.
  • Avoid declaring a top-level local named scale inside MG code. The validator/runtime may already reserve that identifier; use a specific name such as uiScale.

Local dev Zero caveat:

  • When backend runs on a non-default port, use a matching Zero view-syncer configuration.
  • In this POC, backend 3010, editor 5177, and view-syncer 4850 are intentionally isolated from the older 3000/5173/4848 stack.

Timeline screenshot renderer caveat:

  • If render_cloud_screenshot returns a Remotion AccessDenied error for a rendererbucket-.../sites/.../index.html URL, the project write path can still be healthy.
  • For local-only projects, connector visual proof is unavailable until the media is uploaded/registered with cloud-readable URLs.
  • Do not report visual proof success unless the tool returns image content or a browser screenshot visibly confirms the target frame.
用于通过submit_music工具生成ChatCut视频所需的原创背景音乐、片头或BGM。支持基于文本提示创建音频资产,需结合时间轴工具完成剪辑与同步,不支持编辑现有音频或保证精确节拍对齐。
用户需要为视频生成背景音乐 用户请求创建片头音乐或音乐床 用户要求生成BGM
chatcut/skills/music/SKILL.md
npx skills add ChatCut-Inc/agent-plugin --skill music -g -y
SKILL.md
Frontmatter
{
    "name": "music",
    "description": "Shared ChatCut background-music generation skill. Use when the user wants newly generated music, background music, an intro theme, a music bed, or BGM for a ChatCut video through `submit_music`.\n",
    "user-invocable": true
}

Music

Use submit_music to create a new background music audio asset from a text prompt. In the native SDK this may appear as submit_music; in the Codex connector it appears as submit_music.

The tool submits a generation job and returns jobId. The generated audio asset is available after track_progress reports completion.

Capability Boundary

Mureka is a music generation model. It creates a new original music asset; it does not edit, clean up, remix, separate, or adjust existing audio.

Mureka also cannot guarantee exact beat, drop, or timestamp alignment. Generate the music asset first, then use timeline tools for placement, trimming, looping, fades, and ducking. If the user requires precise beat-level sync, explain that this must be handled as a timeline/audio edit rather than guaranteed by the generation model.

Workflow

  1. Write a concise prompt describing style, energy, instrumentation, mood, tempo, and edit role.
  2. Provide a short descriptive name when useful.
  3. Call submit_music.
  4. Use track_progress if the next edit needs the completed asset.
  5. Place, trim, loop, or duck the audio with timeline tools after the asset exists.

Prompt Shape

Good prompts combine:

  • genre or instrumentation: "minimal electronic", "warm acoustic guitar", "cinematic piano"
  • energy: "upbeat", "calm", "tense", "confident"
  • role: "under a product walkthrough", "intro sting", "background bed under speech"
  • constraints: "not distracting", "no vocals", "short loop feel" when needed

Rules

  • Do not cover speech with loud music; lower volume or duck under narration.
  • Do not use generated music as a substitute for user-provided copyrighted tracks.
WebGL视频特效、转场及调色生成助手。优先通过browse_library查找内置资产,匹配失败才调用generate.ts生成新Shader。特别规定builtin:zoom必须使用track-bound模式,否则无法渲染。
用户请求视频滤镜或特效 用户请求转场效果 用户请求蒙版或遮罩 用户请求推近镜头 用户请求LUT调色
chatcut/skills/shader-gen/SKILL.md
npx skills add ChatCut-Inc/agent-plugin --skill shader-gen -g -y
SKILL.md
Frontmatter
{
    "name": "shader-gen",
    "description": "AI shader generator for WebGL video effects, transitions, masks, and color grading (LUT \/ 调色 \/ 电影感 \/ film look). Use when the user wants a video effect (滤镜 \/ 特效), a transition (转场 \/ crossfade \/ wipe \/ cube \/ 3d), a mask (蒙版 \/ 遮罩 \/ reveal), a zoom \/ push-in (推近 \/ 推镜头), or a color grade — try the built-in effects (zoom, builtin LUTs) before generating a new shader.\n",
    "user-invocable": true
}

Shader Generator

Submit-only: creates a backend generation job, returns jobId. Use the track_progress tool for job lifecycle after submission.

Always use generate.ts for new shaders. Manual authoring is only for editing existing asset code — never as a fallback when generation fails.

Catalog-first rule — try existing assets before generation

Before generating a shader, call browse_library unless the user names an exact asset id that is already visible in read_project.

browse_library is the source of truth for built-in effects, built-in transitions, and project effect/transition assets. Built-ins are stable global asset ids, not per-project DB assets, so they may not appear in read_project asset lists.

Apply catalog entries with edit_item, do not call submit_shader.

Good catalog searches:

browse_library(query: "zoom")
browse_library(category: "transitions", query: "dissolve")
browse_library(category: "audio-fx")

Generate only when no catalog entry matches the user's intent closely enough.

builtin:zoom is track-bound only — DO NOT use item-bound

The default effect mode is "item-bound" (attach to a single item via targetItemId). builtin:zoom does NOT render in item-bound mode — the renderer reads zoom data exclusively from track-bound effect items. An item-bound zoom inserts into the DB silently but shows nothing in preview.

Use mode: "track-bound" with trackId + trackBoundFrom + trackBoundDurationInFrames. These three fields are required.

# Zoom on the entire video clip
edit_item(json: '{"adds":[{"type":"effect","assetId":"builtin:zoom","mode":"track-bound","trackId":"<clip-trackId>","trackBoundFrom":<clip-fromFrame>,"trackBoundDurationInFrames":<clip-durationInFrames>,"propertyOverrides":{"magnification":1.5,"shape":"hold"}}]}')

# Zoom on a sub-range of the clip (e.g. frames 90–150 only, a punch zoom on a beat)
edit_item(json: '{"adds":[{"type":"effect","assetId":"builtin:zoom","mode":"track-bound","trackId":"<trackId>","trackBoundFrom":90,"trackBoundDurationInFrames":60,"propertyOverrides":{"magnification":2,"shape":"punch"}}]}')

Get trackId / fromFrame / durationInFrames from read_project (each video/image item lists its trackId and timeline-frame range).

Key Type Range / values Default Notes
magnification number 1–4 1.5 Zoom factor; 1 = no zoom, 2 = 2× in
focalPointX number 0–1 0.5 Horizontal focal point (0 = left, 1 = right)
focalPointY number 0–1 0.5 Vertical focal point (0 = top, 1 = bottom)
shape select punch / hold / slow-push / instant hold Animation curve
focalMode select auto / manual auto auto picks subject; manual uses focalPoint
easeInFrames number 0–60 8 Frames to ramp in
easeOutFrames number 0–60 8 Frames to ramp out

Omit propertyOverrides entirely for default zoom. Send only the keys you want to change — patch semantics.

Track-bound vs item-bound — the broader rule

Effect items in the schema have two modes:

  • item-bound (default): targetItemId only. Effect covers the whole target item's playback. Works for shader effects, LUTs, color grades, blurs.
  • track-bound: trackId + trackBoundFrom + trackBoundDurationInFrames. Effect covers a timeline range on a track, independent of any item. Required for builtin:zoom; also valid for any shader effect when you want it to cover a specific timeline range (e.g. a transition-like color shift across the boundary of two clips).

Default to item-bound for shader effects. Use track-bound when (a) the asset requires it (zoom), or (b) the effect should cover a timeline range that doesn't match a single item.

Built-in LUT properties

edit_item(json: '{"adds":[{"type":"effect","targetItemId":"<clip-id>","assetId":"builtin:slog3-s709","propertyOverrides":{"intensity":1}}]}')
Key Type Range Default Notes
intensity number 0–1 1 LUT strength; 1 = full applied

To swap: delete the effect and re-add with a different assetId. To remove: delete the effect item.

These are separate from user-uploaded .cube LUT assets (see "Applying an Existing LUT Asset" below) — those use a different code path with assetId:"lut".

Beta Status Gate

New shader generation is beta. Before generating, warn the user and wait for explicit confirmation.

Use the user's language. Chinese: "新的特效/转场生成目前还是 beta 阶段,可能会有不稳定的问题。如果你坚持要做,我可以帮你实现。" Skip if user already acknowledged in the same request.

Supported Targets

Effects and transitions apply to video, image, and gif items.

Type Routing

Before generating anything, check two non-generation paths first:

  1. Catalog entry — use browse_library for built-in and project effects/transitions.
  2. User-uploaded .cube LUT asset that already exists in the project library — separate code path, see "Applying an Existing LUT Asset" below. The asset shows up in read_project with type: lut.
User wants --type
Video appearance (color, blur, glow, grain, distortion) effect
Color grade / look (teal-orange, cinematic, vintage, LUT-style) effect
Visibility control (mask, reveal, wipe, shape cutout, gradient fade) effect
Blend between clips (crossfade, dissolve, slide, 3D cube/page flip) transition

"LUT-style" in the table means generating a fresh GLSL color grade that resembles a LUT — only when the user wants something new. If they want to apply a .cube file already in the library, don't generate; bind the existing asset instead.

No separate LUT or mask generator for the generation path — those are all effect.

Applying an Existing LUT Asset

.cube files uploaded by the user become lut assets. Applying one to a clip is not generation — it's a single edit_item call that attaches an effect item whose assetId is the literal string "lut" and whose propertyOverrides.lut binds the real LUT asset id. (Legacy contract; the unified LUT API binds the LUT effect asset id directly — see edit_item description.)

edit_item(json: '{"adds":[{"type":"effect","targetItemId":"<clip-id>","assetId":"lut","propertyOverrides":{"intensity":1,"lut":{"assetId":"<lut-asset-id>","assetType":"lut","type":"asset"}}}]}')

Key points:

  • assetId is the literal string "lut", not the LUT asset's id. The real LUT asset id goes inside propertyOverrides.lut.assetId.
  • intensity is 0–1; default 1 (full strength).
  • targetItemType defaults to video; also supports image, gif.
  • To swap a LUT on an existing effect: update propertyOverrides.lut.assetId to the new LUT asset id.
  • To remove: delete the effect item.

Do not call generate.ts for this path. Do not pass a real LUT asset id as assetId — the editor checks assetId === "lut" to route into the LUT renderer; passing a UUID silently renders nothing.

Usage

Before calling submit_shader, restate the user's intent in one concrete sentence, then proceed immediately. After track_progress returns, state what was produced in one line — do NOT ask "要保留还是重新生成".

submit_shader({
  type: "effect",
  prompt: "Chromatic aberration with RGB split",
  name: "Chromatic Aberration",
});

submit_shader({
  type: "transition",
  prompt: "Smooth crossfade with soft edge",
  name: "Crossfade",
});

submit_shader({
  type: "effect",
  prompt: "Cinematic teal-orange color grade",
});

submit_shader({
  type: "effect",
  prompt: "Stronger version",
  referenceAssetIds: ["effect_asset_id"],
});

Strategy

  • Submit, then stop. Tell user the job was created.
  • Use the track_progress tool for status/wait after submission.
  • Generation always produces a library asset — never refuse because the timeline isn't ready.
  • Apply is separate and optional. Only apply when user explicitly asks ("加到视频", "apply", "用到第一段"). When ambiguous, default to library-only.

Editing Existing Properties

Any time you're about to edit shader asset.properties, applied effect/transition item.propertyOverrides, or promote a hardcoded shader value, read references/property-changes.md first.

It reinforces that shader properties is an array, but the allowed shader property types are only number, boolean, color, select, and vec2. Motion Graphic properties are also arrays, but use a different type set.

Parameters

Param Description Default
type "effect" or "transition" (req'd)
prompt Description of the shader (req'd)
name Asset name shown in library
referenceAssetIds Asset ids. Image id → model LOOKS AT it for visual inspiration. Effect/transition id → reuse its code as style anchor (≤1 per submit, kind must match type).

Output

Returns { success, job: { jobId, status }, manage: { status, wait, watch } }.

Applying to Timeline

Only when user explicitly requests. Call read_project first for fresh timeline state.

Effect

edit_item(json: '{"adds":[{"type":"effect","targetItemId":"<id>","assetId":"<id>","enabled":true,"propertyOverrides":{}}]}')

Transition

Requires two adjacent same-track endpoints. edit_item validates live seam feasibility and refuses durations that would require freeze frames or overlapping neighboring transitions. If the add fails, retry with the suggested durationInFrames, trim the clips to expose handles, delete/shorten neighboring transitions, or keep a hard cut.

edit_item(json: '{"adds":[{"type":"transition","assetId":"<id>","outgoingItemId":"<id1>","incomingItemId":"<id2>","durationInFrames":30}]}')

Validation & Verification

Backend Validation

When generating via generate.ts, the backend handles validation automatically (transpile, AST security, class structure, retry on failure).

Manual Code Verification

NEVER write shader code from scratch. Always use generate.ts for new shaders. This section is ONLY for modifying existing shader code that was already generated.

When writing shader code manually, read ${CLAUDE_SKILL_DIR}/references/design-principles.md first. If the change touches editable properties, also read ${CLAUDE_SKILL_DIR}/references/property-changes.md.

Typical workflow:

  1. read_project with the shader assetId and code: true — read the current source.
  2. Edit the source in your own context.
  3. edit_asset with action=update, the same assetId, and the full replacement source inline in json.code. Validation runs automatically on update — if code is invalid, the update is rejected with error details.
处理音视频转录、字幕生成与样式调整。涵盖本地及S3资产导入后的转录进度追踪、文本搜索、字幕启用,以及针对卡住或失败状态的智能重试逻辑。
用户请求为视频添加字幕或转录 需要清理说话人语音或去除填充词 检查转录就绪状态 从Codex启用字幕
chatcut/skills/transcription/SKILL.md
npx skills add ChatCut-Inc/agent-plugin --skill transcription -g -y
SKILL.md
Frontmatter
{
    "name": "transcription",
    "description": "Use when a video\/audio task needs ChatCut transcription, captions, subtitles, subtitle styling, transcript search, transcript readiness checks, or enabling captions from Codex, including local or attached videos where the user asks to add captions\/subtitles, transcribe, create bilingual subtitles, clean talking-head speech, remove filler words, or trim pauses."
}

Transcription

For newly imported local/client-held media, use import_media to start transcription, then wait with track_progress.

Typical flow:

  1. read_project with view: "assets" to get the video/audio asset ID and transcript status.
  2. If this is a fresh client-held import, make sure it went through import_media action=create_session plus the ChatCut media import helper.
  3. Call track_progress with action:"wait", target:"transcription", and assetIds set to the asset ID or prefix.
  4. Use find_transcript to search transcript text and confirm word timestamps.
  5. Use edit_captions action enable or read_captions as needed once transcription is ready.

Example:

{
  "action": "wait",
  "target": "transcription",
  "assetIds": "13c1aa02cd"
}

For S3-backed assets imported through the helper, finalization starts ASR but does not wait. Always use track_progress for readiness.

For local-only video assets with local-only; original upload deferred in read_project, transcription cannot run until the bytes are reachable by the backend. Import the source again via the asset-import skill (which uploads to S3) or download_media from a public URL; do not ask the user to relink it manually in the editor.

Stuck Transcription And Retry

Do not declare transcription stuck from one non-terminal status. Base the decision on both asset length and the time Codex has actually waited in this task.

  1. Read the asset with read_project view: "assets" and note its duration when available.
  2. Start counting elapsed wait time from the first track_progress action:"wait" or from the earliest reliable in-task timestamp where Codex observed transcription as pending/running.
  3. If transcription reports an explicit failed, errored, or timed-out terminal state, retry immediately after confirming the asset is remote-ready and is video/audio.
  4. If transcription remains pending/running with no failure, treat it as stuck only after elapsed wait time exceeds max(5 minutes, min(60 minutes, 2 × asset duration)). For example, wait at least 5 minutes for a 30-second clip, about 20 minutes for a 10-minute asset, and about 60 minutes for a 1-hour or longer asset.
  5. If duration is unknown, wait at least 10 minutes across more than one track_progress call before treating it as stuck, unless the tool reports an explicit failure.

When stuck, use manage_transcript with action: "retry_transcription" and the asset id/prefix. This force-retries ASR for audio/video assets and starts a new transcription run; it does not wait for completion. After retrying, call track_progress with target:"transcription", action:"wait", and the returned or same asset id before reading transcripts or captions.

Example retry:

{
  "action": "retry_transcription",
  "asset": "13c1aa02cd"
}

If captions read back as empty, check the source-time range of the timeline clip. A transcript can be ready while the current visible clip starts before the first spoken word; add or trim a clip so the transcribed source words fall inside the timeline range, then extend/update the captions item duration if needed.

Use the raw tools when you need finer control:

  • track_progress with target: "transcription" for status/wait.
  • find_transcript for query-based transcript lookup.
  • read_captions and edit_captions for caption display edits.
  • manage_transcript action fix for source transcript repair.
  • manage_transcript action retry_transcription to force-retry ASR after a transcription is stuck, timed out, or failed.
  • clean_script for mechanical timeline playback cleanup of fixed fillers and batch pauses after transcript-ready media is on the timeline.

When a transcript-ready request becomes an editorial talking-head edit, follow the public-safe talking-head workflow in shared talking-head-guide. In short: use clean_script only for mechanical cleanup, then use Script (read_script -> edit timeline.md -> apply_script) for semantic repeated-take, silence, filler, or coherence edits, and verify the resulting script rather than trusting tool success alone.

验证ChatCut插件编辑结果,通过read_project检查结构,render_cloud_screenshot或view_asset_frames获取视觉证据。根据文件路径选择本地ffmpeg或远程工具进行源帧检查,区分源理解与最终时间线证明。
用户要求确认ChatCut项目中的编辑更改是否生效 需要验证时间线修剪、图层、字幕等具体效果
chatcut/skills/verification/SKILL.md
npx skills add ChatCut-Inc/agent-plugin --skill verification -g -y
SKILL.md
Frontmatter
{
    "name": "verification",
    "description": "Use when checking whether agent edits made through the ChatCut plugin are reflected in the ChatCut project and editor."
}

Verification

Prefer two signals:

  1. read_project for structure: assets, tracks, items, frame placement, timeline duration.
  2. A visual capture path for rendered evidence at exact frames.

Use render_cloud_screenshot for composed timeline proof when the host exposes it. This verifies the edited ChatCut timeline: trims, layers, captions, effects, markers, placeholders, crops, transitions, and layout.

For raw source-asset frame inspection, choose the cheapest path based on where the bytes live:

  • If Codex has the original local file path, such as the sourcePath returned by the import helper, inspect that file locally with Codex-native tools such as ffmpeg/ffprobe and your normal image-read flow. Do not call view_asset_frames for those assets just to get source frames; the remote tool would duplicate work and may wait on upload/editor routing unnecessarily.
  • If Codex does not have the original file, for example the asset was uploaded in the ChatCut editor or exists only in project storage/cache, use view_asset_frames with the current project asset id. It can route through an open editor tab for editor-side asset viewing and falls back to remote decode when a cloud URL is available.
  • get_contact_sheet is not available on the Codex surface.

Use local/remote source-frame artifacts only for source understanding, moment selection, and rough trim decisions, not as edited output or timeline proof.

For local-only or upload-in-progress media, composed timeline proof may be blocked until the asset has bytes available to the renderer. Source-frame inspection is still possible locally when Codex has the original path, or via view_asset_frames when an open editor tab can provide the asset bytes.

If both visual proof paths are blocked, ask the user to inspect the ChatCut editor directly and note the blocker explicitly.

Useful checks:

  • After import: read_project({ "view": "assets", "assetId": "<prefix>" })
  • After move/trim: read_project({ "view": "timeline" })
  • After visual overlay or MG on any timeline media: render_cloud_screenshot({ "frames": [30, 45, 75] }), then inspect visualSource.
  • For user-requested source selection or visual moment picking from local files: extract stills locally with ffmpeg from the source file and inspect those images. Use that only to choose source files, moments, and rough trims; it may run in parallel with importing obvious or likely-needed originals and should not become an upload gate unless choosing the subset is actually the task or importing everything is unreasonable. Build the visible edit as ChatCut timeline items. Do not treat raw source inspection as timeline verification or as permission to produce the edited video locally.
  • For source-frame inspection of editor-uploaded assets where no local original path is available: call view_asset_frames({"assetId":"...","sourceTimesMs":[...]}) after read_project({"view":"assets"}) confirms the asset id/type. Prefer this over asking the user to reattach the file.
  • For local-only visual verification: upload/register cloud-readable media before relying on connector visual proof.
  • For no-source validation: confirm the tool manifest exposed the parameters you used, then record the visible proof in the trace log.

When talking about seconds, verify the fps from read_project or use adapter tools that resolve fps internally.

When reporting a timeline item location, use only the latest read_project structure for track alias, item id, start, duration, and asset id. Do not report planned/default tracks or tool-call intent as verified placement.

Do not treat a command-line JSON response alone as sufficient when the user asks whether the editor reflects the result. Use the editor URL or visual proof when practical.

If verification fails, classify the gap before changing tools:

  • tool description or schema was insufficient
  • skill instructions were missing a step
  • read_project did not expose enough state
  • editor authorization did not complete
  • media/transcription pipeline failed
  • cloud render/editor observation was blocked
通过Seedance 2.0和Kling生成视频,支持文生视频、图生视频及基于参考的剪辑扩展。提交任务后返回jobId,需配合track_progress管理进度。默认使用Seedance,特定场景可选Kling,并严格遵循模型参考文档。
用户希望生成视频片段 需要将文本或图片转换为视频 需要基于首尾帧或参考素材生成/扩展视频
chatcut/skills/video-gen/SKILL.md
npx skills add ChatCut-Inc/agent-plugin --skill video-gen -g -y
SKILL.md
Frontmatter
{
    "name": "video-gen",
    "description": "AI video generation via Seedance 2.0 and Kling. Use when the user wants to generate a video clip — text-to-video, image-to-video, first\/last-frame transitions, reference-guided generation, or generatively editing \/ extending an existing clip.\n",
    "user-invocable": true
}

Video Gen

Submits one video generation job per call and returns a jobId. Job management (wait / status) belongs to track_progress; this skill does not place videos on the timeline automatically.

When to Use

Any time the user wants to generate a video clip — text-to-video, image-to-video, first-last-frame transition, reference-based generation, or generatively editing / extending an existing video (producing new generated footage based on a source clip; not timeline trimming).

Models

Model Reference Strengths
seedance2 references/seedance2.md Default. Rich reference system (image / video / audio refs), multi-shot consistency, editing / extending existing clips.
kling references/kling.md Camera-control language via prompt; strong on fine emotional / performance control for character shots.

IMPORTANT: Before generating, READ the chosen model's reference for capabilities, input channels, modes, prompt structure, and model-specific behavior.

Model Selection

seedance2 is the default. Only switch to kling when one of:

  • User explicitly named kling ("用 Kling", "use Kling", "/kling") — switch, no need to re-ask.
  • Seedance clearly can't or won't do it well — when you hit a known case where Seedance struggles, propose switching to kling and confirm before submitting.

Otherwise stay on seedance2.

Access note: seedance2 and kling both require ChatCut paid video-generation entitlement (subscription or paid credits). Never present Kling as a free workaround for a Seedance subscription gate; offer free Motion Graphic animation instead when the user asks for a free path.

Tool Params

Param Values Default
prompt video description (required)
model seedance2, kling seedance2
durationSeconds seconds 5
ratio see model docs 16:9
resolution 720p, 1080p 720p
name descriptive asset name (required)
firstFrame project asset ref
lastFrame project asset ref

Model-specific params (e.g., Kling mode, Seedance refImages / refVideos / refAudios) — see the model's reference.

Input Resolution

firstFrame / lastFrame / refImages / refVideos / refAudios all take a project asset reference. Prefer a full UUID or short prefix from read_project; asset://<id> and same-project asset URLs returned by read_project are also accepted. Per-slot type: frame slots and refImages → image; refVideos → video; refAudios → audio.

External URLs and base64 are not accepted. If the source is a public URL, download it into the project first (download_media for video/audio, submit_image for images) and pass the resulting asset id.

Workflow

Four-step loop. For each new generation, restart from Step 1 if the user's intent has shifted.

Step 1 — Align scope with the user

Before writing any prompt, align on three dimensions:

  1. Duration & segments — total length, how many shots, and whether they live in one clip or several.

    If the user has already stated a direction ("做一段", "in one video", "分别生成", "split into N shots", etc.), follow it — don't second-guess.

    Otherwise, surface the two paths and let the user pick:

    • Multi-shot within one clip (see model ref) — single inference, subject / lighting / style physically consistent across sub-shots; fits a coherent narrative within the per-clip duration cap.
    • Multiple clips — each clip is independently controllable and re-rollable, but identity and style continuity have to be carried by anchors; fits durations beyond the cap or hard scene breaks.

    Offer the trade-off; do not pick for the user.

  2. Content — what each clip depicts. Summarize back what you understood, segment by segment. When content is vague (e.g. "generate a video of a girl dancing"), the user typically hasn't specified one or more of:

    • Subject: who / what is the main subject (appearance, outfit, defining features)?
    • Action: what are they doing? (For talking / emotional shots, what micro-expression?)
    • Scene: where — setting, time of day, environmental details?
    • Lighting / color mood: what atmosphere?
    • Camera: any shot-size / angle / movement preference?
    • Style: visual style or reference (cinematic / anime / documentary / ...).

    Focus on the items that matter for this specific request and can't be safely inferred — don't turn this into a blank-filling exercise. Summarize the understood parts back to the user before proceeding.

  3. Consistency anchors — only when multiple shots reuse a character, object, or scene: identify which anchor (reference image or video) to pin across shots. For sourcing rules, see §Visual consistency across shots below.

For each dimension, check the user's words:

  • Clear — proceed.
  • Ambiguous or missing — ASK the user. Do not guess, do not default to your own interpretation. A round-trip confirmation is cheaper than a wasted generation.

What NOT to do

  • Do not "tell then submit" — announcing "I'll make this as 2 clips" and immediately submitting is not alignment, it's a unilateral decision with announcement.
  • Do not default to splitting a single-video request into multiple clips. A single clip can carry multiple sub-shots (see model ref), with subject / lighting / style physically consistent across them. Surface the trade-off, then let the user choose.
  • Do not skip the ask because you think the answer is obvious.

Hard overrides (user's explicit word wins)

  • "one clip / single clip / 一条 / 一个镜头 / in 1 clip" → never split, even if the description is objectively long.
  • "N shots / N 段 / N 个镜头" → generate exactly N.
  • "use this image / 用这张图" → use as reference, don't substitute.

Step 2 — Write the prompt

See the chosen model's reference for prompt structure and param combinations (e.g., Seedance's 8-element structure and modes; Kling's prompt tips). Before submitting, check:

  • name is a descriptive asset name — descriptive enough for the user (and you in later turns) to recognize this asset in the project library. Avoid vague names like "Untitled" or "clip 1".
  • Param combination matches the user's intent — see the Modes section in the model's reference.
  • Generated video audio is not a tool parameter. Seedance 2.0 and Kling are submitted with audio enabled by the backend.
  • On validation failure, read the error and fix the inputs — do not blindly retry the same invalid arguments.

Step 3 — Submit one, wait, confirm

Submit one generation job at a time. Unless the user explicitly asked for multiple clips in parallel, do not submit the next clip until the current one completes and the user has reviewed it. Parallel submission hides problems: if the first shot has drift or wrong framing, the user would rather redo it once than have several misaligned shots to discard.

  • submit_video.ratio controls the generated asset only; it does not change the project timeline canvas. If the user requested a final output aspect ratio (for example "9:16 vertical" or "16:9 landscape"), set the timeline canvas to the same ratio with manage_timelines action=update (e.g. ratio:"9:16") before placing the completed asset. If the user asked for no black bars / full-bleed, pass fit:"cover" when setting the canvas or updating/adding the visual item.
  • Do not use this skill for job management — use the track_progress tool for status/wait.
  • After submitting, end your turn (tell the user the job was created) unless a follow-up task is already queued.
  • When the job finishes, surface the result to the user for review before proceeding to the next shot.
  • Model-specific failure handling — see the model's reference.

Step 4 — Iterate

When the user wants a next clip, a revision, or a continuation:

  • If it's the next shot in a multi-shot sequence — reuse the established anchor (see §Visual consistency across shots below for principles, model ref for flag-level details).
  • If the user's feedback is ambiguous ("it doesn't feel right") — ask what specifically to change before regenerating.
  • If the same text-prompt adjustment has failed twice — stop adjusting text. Switch to reference images, or switch to edit mode where the model supports it (see model ref).
  • Each new generation restarts the loop at Step 1 — realign if scope shifted.

Visual consistency across shots

Text alone cannot reliably maintain visual identity across shots; visual references constrain output far more precisely than words.

Anchors: the cornerstone of consistency

An anchor is a reference image or video pinned across every shot that shares the same character, object, or style. Any multi-shot sequence with recurring visual elements needs an anchor — don't try to reproduce them from text.

Sourcing an anchor

Have reference awareness. When the user's request involves a recurring character / object / scene, think about what anchor to use before writing prompts:

  • Check the project first. What has the user already provided or approved? Uploaded images, previously generated and approved shots, or earlier project assets can all serve as anchors.
  • Match the user's intent. If the user pointed to a specific asset ("use this photo", "像上一段那样"), use that. If they described a character only in words, no anchor exists yet and one must be established.
  • When in doubt, ask the user. Don't guess which asset to pin, and don't silently generate a new anchor when the user may already have one in mind.

Establishing a new anchor (with user consent)

When no existing asset fits and one must be generated, propose it to the user first — it costs credits and shapes every downstream shot. Model-specific paths — see the chosen model's ref.

Using the anchor

  • Pass the anchor in every shot that shares the character / object / style. The specific flag(s) to use depend on the model — see the model's ref.
  • Describe the anchor by appearance in the prompt, not by name: "The BLACK RACING CAR with chrome exhaust" constrains far more than "Fleetmaster". When role confusion is likely, add explicit negations: "The motorcycle does NOT transform."
  • Refer to the anchor with @Image1 / @Video1 in the prompt — not vague phrases like "the same car as before".
  • When a shot depends on a previous generation, wait for the previous job to complete (via track_progress with action=wait) to obtain its assetId, then pass it as the anchor reference. Do not submit dependent shots in parallel.

Multi-character projects

When a project has multiple named characters with distinct attributes (e.g. Faz with fire energy, Kev with ice energy), treat each character as a separate anchor — one reference asset per character. In every prompt:

  • Name the active character and attach their distinctive attributes ("Kev has blue ice electric energy").
  • Add explicit negations for the others to prevent attribute leakage ("NOT red fire energy, NOT Faz's look").
  • Pin the correct character's anchor (model-specific flag — see model ref). Do not reuse another character's anchor by accident.

Missing either explicit attribution or negation causes cross-character attribute mixing.

Multiple characters in the same frame. For shots where multiple characters appear together (especially facing the camera), the model is prone to face-swap or body-clipping. Add strong positional + outfit anchors to each character and prefer a fixed camera for that shot:

  • "the character on the LEFT wears a grey-blue tactical jacket, short beard, silver earring"
  • "the character on the RIGHT wears a red cape with gold trim, long braided hair"
  • "fixed camera, medium shot, both characters clearly separated"

Positional words (left / right / foreground / background) + distinctive outfit colors give the model enough signal to keep the characters apart.

Escalate when text adjustments fail

If a visual-identity issue (wrong character, drift, color mismatch) persists after two text-prompt adjustments on the same shot, stop adjusting text. Text is not a substitute for an anchor. Escalate to:

  • Adding or switching the anchor.
  • Edit mode where the model supports it (see model ref for how to invoke).

Do not submit a third text-only retry on the same consistency issue.

When to skip anchoring

Simple, one-off, or exploratory requests do not need anchors — generate directly.

Run

// Text-to-video (seedance2 default)
submit_video({
  model: "seedance2",
  prompt: "A cat walks across a sunny windowsill",
  name: "Cat on windowsill",
});

// Image-to-video with seedance2 — pass the project asset id directly; backend resolves to the asset's remoteUrl
submit_video({
  model: "seedance2",
  prompt: "The scene comes to life, gentle breeze rustles the curtains",
  firstFrame: "abc12345",
  name: "Living room animation",
});

// Kling text-to-video — only after Model Selection check
submit_video({
  model: "kling",
  prompt: "A sports car drifts around a wet corner",
  name: "Car drift shot",
});

After submission, call the track_progress tool: action=status jobIds=<jobId> to poll, action=wait jobIds=<jobId> to block until terminal.

Config Mode

For complex multimodal jobs, build the full args object up front and pass it in a single call:

submit_video({
  model: "seedance2",
  prompt: "...",
  name: "...",
  firstFrame: "abc12345",
  refImages: ["def67890", "ghi24680"],
  refVideos: ["abc99999"],
  refAudios: ["jkl55555"],
  durationSeconds: 8,
  ratio: "9:16",
});

Rules

  • Always provide --name with a descriptive asset name.
  • Default to submit-only. End your turn after submitting unless a follow-up task is queued.
  • Do not call this skill with --job, --wait, or --timeout — job management belongs to track_progress.
  • Generation costs credits. Before submitting, briefly tell the user what you're about to generate.
用于生成语音(TTS)和音效。支持文本转语音、视频配音同步、现有旁白对齐调整及自定义音效生成。指定使用Doubao或ElevenLabs提供商,强调在有视觉目标时需参考视频同步指南以确保音画匹配。
用户希望从文本生成语音或旁白 需要为现有视频添加、替换或对齐配音 在修改视频后保持现有旁白同步 需要试听或选择TTS声音 需要生成库中不存在的自定义音效
chatcut/skills/voice/SKILL.md
npx skills add ChatCut-Inc/agent-plugin --skill voice -g -y
SKILL.md
Frontmatter
{
    "name": "voice",
    "description": "Text-to-Speech (TTS), voiceover, narration placement\/sync, and custom sound effects (SFX) generator. Use when the user wants generated speech from text, wants to add\/replace\/align narration or voiceover for an existing video\/timeline, wants to keep existing voiceover synced after visual retiming edits, needs voice audition\/selection, or explicitly wants a newly generated\/custom sound effect that is not available in the Sound Effects library.\n",
    "user-invocable": true
}

Voice & Sound Effects Generator

Generate voiceovers (TTS) and sound effects. For TTS, choose a concrete provider and voice before calling submit_voice.

When to Use

  • Generate voiceover/narration from text
  • Create text-to-speech audio for videos
  • Add, replace, or redo narration/voiceover for an existing video, timeline, screen recording, slide animation, product demo, B-roll edit, MG explainer, or other visual sequence
  • Keep existing narration/voiceover aligned after trimming, speeding up, slowing down, moving, reordering, or replacing the visuals it describes
  • Offer and audition TTS voice choices when the user has not picked a concrete voice
  • Generate custom sound effects from text descriptions only after checking the Sound Effects library first

TTS (Text-to-Speech)

If the current request has an existing visual target and the user wants narration, voiceover, dubbing, or replacement speech for that target, read references/video-sync.md before drafting new narration, using existing narration text to generate TTS, or placing audio. Do this even when the user did not explicitly say "sync" or "match the visuals"; the existence of a visual target means narration timing and meaning may need to follow on-screen content. Use the normal standalone TTS path only when there is no visual target or the user just wants an audio asset from text.

Also read references/video-sync.md when the timeline already has narration/voiceover and the user asks to change the visuals while keeping that voiceover aligned. This is a sync maintenance task even if no new TTS is needed.

Use submit_voice to create a TTS audio asset. The current MCP tool contract is:

  • provider is required. Use doubao for Chinese-optimized narration and elevenlabs for English or multilingual narration.
  • voiceId is required and provider-specific. Do not mix catalogs.
  • submit_voice creates an audio asset only. Timeline placement, replacement, trimming, and alignment happen later with timeline tools.
  • For long narration, multiple submit_voice calls can be useful: split at natural pauses, sentence groups, or script beat boundaries when the workflow benefits from separately timed or placed voice clips, such as storyboard beats, scene-level ad segments, or a user request for separate assets.
  • For Doubao, speedRatio, loudnessRatio, pitch, emotion, emotionScale, performancePrompt, and explicitDialect are supported knobs, but not every Doubao voice supports every expressive control. Check the voiceId guide or references/voices.md before using them.
  • For ElevenLabs, modelId, speed, and stability are the supported voice knobs. For eleven_v3, inline audio tags are available for expressive delivery such as emotion, tone, nonverbal cues, accent hints, pauses, or local pacing.

Doubao control support for current curated voices:

  • vivi, xiaohe, yunzhou, xiaotian, naiqimengwa, yingtaowanzi, wenroumama, zhixingnv, dayi, jitangnv, liuchang, ruyayichen, morgan, qingcang, huiben, popo, yuanboxiaoshu, baqiqingshu, and tangseng support explicit emotion / emotionScale, performancePrompt, and ASMR-style prompt directions.
  • shuanglangshaonian supports performancePrompt and COT/QA-style instruction following, but does not support explicit emotion / emotionScale or ASMR-style control.
  • explicitDialect is only supported by vivi and can be dongbei, shaanxi, or sichuan.

ElevenLabs control support for current curated voices:

  • amelia, brittney, hope, jessica, arabella, jane, maria, mark, frederick, peter, james, jon, sully, david, and alex all support the same request-level controls: modelId, speed, and stability.
  • These controls are not per-voice guarantees of a specific acting style. Use the preset tags/samples to pick a naturally suitable voice, then use the controls for moderate delivery changes.
  • For ElevenLabs eleven_v3, inline audio tags are available when the user asks for expressive delivery such as emotion, tone, nonverbal cues, accent hints, or local pacing. Official examples fit these useful TTS categories: emotion/tone tags such as [happy], [sad], [angry], [excited], [curious], [sarcastic], [crying], [annoyed], [appalled], [thoughtful], [surprised], and [mischievously]; vocal delivery and nonverbal cue tags such as [whispers], [laughs], [sighs], [exhales], [inhales deeply], [clears throat], [snorts], [swallows], [wheezing], and [coughs]; pacing/pause/local speed tags such as [slowly], [pause], [short pause], [long pause], [rushed], and [drawn out]; and accent/special-performance tags such as [strong X accent], for example [strong French accent], plus [sings], [singing], [woo], and [pirate voice]. Official examples are non-exhaustive; similar auditory tags can be tried when the user explicitly asks for that delivery and the tag describes how the voice should sound, not a visual action. Write tags directly in text, close to the short phrase they should affect. Treat tags as local guidance, not paragraph-wide controls.
  • For pauses and pacing in eleven_v3, use punctuation, text structure, shorter generated segments, or local audio tags such as [short pause] and [slowly] when needed.
// English / multilingual via ElevenLabs
mcp__skill__submit_voice({
  provider: "elevenlabs",
  text: "Hello world",
  voiceId: "peter",
});

// Chinese via Doubao
mcp__skill__submit_voice({
  provider: "doubao",
  text: "你好世界",
  voiceId: "liuchang",
});

// With speed adjustment (Doubao only)
mcp__skill__submit_voice({
  provider: "doubao",
  text: "这是一段稍快的中文旁白。",
  voiceId: "liuchang",
  speedRatio: 1.5,
});

// With expressive Doubao controls
mcp__skill__submit_voice({
  provider: "doubao",
  text: "这次事故提醒我们,安全永远不能侥幸。",
  voiceId: "liuchang",
  emotion: "sad",
  emotionScale: 3,
  performancePrompt: "痛心但克制,语速稍慢,像新闻专题旁白",
  pitch: -1,
  speedRatio: 0.92,
});

// With ElevenLabs delivery controls
mcp__skill__submit_voice({
  provider: "elevenlabs",
  text: "The launch changed how teams plan their daily work.",
  voiceId: "peter",
  speed: 0.95,
  stability: 0.4,
});

Voice Audition Before Generation

When the user needs TTS and has not already chosen a concrete preset, treat broad words like "middle-aged male", "warm female", or "professional" as requirements for filtering candidate voices.

Before recommending, rendering, or submitting any TTS voice option, read references/voices.md. Use that file as the preset source for preset ids / voiceId, provider choice, display labels, tags, and sample URLs. Do not create voice options from memory, translated names, or broad user descriptions.

First determine two separate languages:

  • User conversation language: the language the user used to talk to you. Use this for the surrounding reply, form-visual label, visual-option name, and summary.
  • Target narration language: the language of the text being synthesized. Use this only to choose provider and voice catalog.

For the voice audition widget, set submit_label to a short submit action in the user conversation language, not the target narration language. For example: English users see submit_label="Submit", Chinese users see submit_label="提交", and Spanish users see submit_label="Enviar".

"help me generate ... voice over in Chinese" is an English conversation asking for Chinese narration, so the audition widget copy stays in English while the voice candidates come from Doubao.

Instead:

  1. Filter references/voices.md by target narration language / provider and the user's explicit requirements such as gender, age range, tone, and use case.
  2. If no preset matches all explicit requirements, say there is no exact match and offer the closest supported presets with a clear caveat.
  3. Pick 2-4 matching curated presets.
  4. Load widget-forms. In Codex, call ask_followup_questions with voice options and audio samples. In Claude Code, render the recipe's combined voice cards and resolve each voice/<voiceId> through ${CLAUDE_PLUGIN_ROOT}/assets/widget-media/manifest.json; use a label-only card when the key is absent and never use or process the original sample URL.
  5. Wait for the user to choose.
  6. Call submit_voice with the selected preset id as voiceId.

For Codex audition options, keep value, display label, media, and summary tied to the same preset row from references/voices.md. Use sample= URLs from the submit_voice voiceId guide. They are editor static files under /voice-samples/.... Keep value as the preset id and media as the matching sample URL. For every host, write names and summaries in the user's conversation language. The target narration language only decides the provider/voice catalog. For example, if the user asks in English for a Chinese voiceover, keep the widget copy in English and use English-friendly voice names/tags. If the user's message itself is Chinese, use Chinese widget copy and Doubao's official Chinese display names. For known /voice-samples/... presets, Codex can fill display text only when name/summary are omitted; authored widget text is the normal path for arbitrary languages. After the user submits, map the submitted display name back to the preset id from the same candidate list.

In Claude Code specifically, use the provider-neutral localized display name as the Elicitation data-value and keep the provider voice id only in the label-to-id map held in context. Use an ephemeral DOM audio key for playback, not the provider id. After the user presses Enter and the host-generated answer line appears, map the visible name back to the preset id and continue without another confirmation.

English request for Chinese narration:

<widget submit_label="Submit">
  <form-visual
    id="voiceId"
    label="For Chinese voiceover, I recommend a few voices to try:"
    required="true"
  >
    <visual-option
      value="vivi"
      name="Vivi"
      media="/voice-samples/doubao-vivi.mp3"
      aspect-ratio="16:5"
      summary="Female / young / friendly, general"
    />
    <visual-option
      value="xiaohe"
      name="Xiaohe"
      media="/voice-samples/doubao-xiaohe.mp3"
      aspect-ratio="16:5"
      summary="Female / young / soft, clear"
    />
    <visual-option
      value="yunzhou"
      name="Yunzhou"
      media="/voice-samples/doubao-yunzhou.mp3"
      aspect-ratio="16:5"
      summary="Male / young / neutral, business"
    />
  </form-visual>
</widget>

Chinese request for Chinese narration:

<widget submit_label="提交">
  <form-visual
    id="voiceId"
    label="我推荐这几个中文旁白音色,先试听一下:"
    required="true"
  >
    <visual-option
      value="morgan"
      name="Morgan"
      media="/voice-samples/doubao-morgan.mp3"
      aspect-ratio="16:5"
      summary="男 / 中年 / 低沉知识解说"
    />
    <visual-option
      value="zhixingnv"
      name="知性女声"
      media="/voice-samples/doubao-zhixingnv.mp3"
      aspect-ratio="16:5"
      summary="女 / 中年 / 冷静知识讲解"
    />
    <visual-option
      value="vivi"
      name="Vivi"
      media="/voice-samples/doubao-vivi.mp3"
      aspect-ratio="16:5"
      summary="女 / 年轻 / 亲切通用口播"
    />
  </form-visual>
</widget>

Sound Effects

For ordinary editing sound effects (SFX), do not generate first. Use the built-in Sound Effects library before spending credits:

  1. Call browse_library with category:"sound-effects" and a query such as "whoosh", "camera shutter", "notification", "censor beep", or "record scratch".
  2. Inspect the returned library:sound:<id>.
  3. Place it with edit_item, using fromFrame as the sound's anchor/editorial moment frame:
mcp__core__browse_library({
  category: "sound-effects",
  query: "short whoosh transition",
});

mcp__core__edit_item({
  adds: [
    {
      type: "audio",
      assetId: "library:sound:whoosh-short",
      fromFrame: 120,
      trackId: "A1",
    },
  ],
});

Only generate sound effects from text descriptions with submit_sound when:

  • The user explicitly asks for a generated/original/custom sound.
  • The requested sound is too specific for the existing Sound Effects library.
  • browse_library({ category:"sound-effects", query }) returns no suitable match.
// Custom/generated sound effect after the library has no suitable match
mcp__skill__submit_sound({ prompt: "A dog barking in the distance" });

// With custom duration (0.5-22 seconds)
mcp__skill__submit_sound({
  prompt: "Thunder and heavy rain",
  durationSeconds: 15,
});

// High prompt adherence
mcp__skill__submit_sound({
  prompt: "Sci-fi laser gun firing",
  promptInfluence: 0.8,
});

Tips for better results:

  • Be specific: "A dog barking loudly" vs just "dog"
  • Include context: "Footsteps on wooden floor in an empty room"
  • Specify style: "Cinematic whoosh" or "8-bit game sound"

Parameters

TTS

Field Description Notes
provider TTS provider: doubao or elevenlabs Required
text Text to synthesize Required
voiceId Curated preset id or provider voice id Required
speedRatio Speech speed Doubao only
modelId ElevenLabs model id ElevenLabs only
stability ElevenLabs stability ElevenLabs only
speed ElevenLabs speech speed ElevenLabs only
name Asset name Optional

Sound Effects

Field Description Notes
prompt Sound description Required
durationSeconds Duration 0.5-22 seconds
promptInfluence Prompt adherence 0-1
name Asset name Optional

Voices

Use the submit_voice voiceId guide and references/voices.md for the current curated preset list, display labels, tags, and sample URLs.

Voice presets are provider-specific — do NOT mix them

ElevenLabs and Doubao have separate voice catalogs. vivi / dayi are only Doubao; mark / amelia / james are only ElevenLabs. Passing a Doubao name to ElevenLabs (e.g. voiceId: "vivi" with provider: "elevenlabs") will fail.

If you need a specific voice and a particular language:

  • For Chinese narration -> use provider: "doubao" and either a curated Doubao preset (vivi, dayi, xiaohe, yunzhou, liuchang, etc.) or a raw speaker_id from the configured Doubao catalog.
  • For English / multilingual -> use provider: "elevenlabs" and an ElevenLabs preset.

Hard rules — what you must NOT do

  1. Never use a voice preset name from a different provider.
  2. Never submit TTS when the voice is only described broadly and the user has not confirmed a concrete preset.
  3. Never recommend or render a TTS voice option before checking references/voices.md.
  4. Never claim stable age, regional accent, pronunciation dictionary, or exact duration controls; the current tool does not expose those as reliable fields.
  5. Never replace original recorded speech with TTS unless the user asks.
指导在ChatCut插件中通过表单收集用户结构化输入,支持单选、多选、文本及媒体卡片。区分Codex与Claude Code运行时:前者使用ask_followup_questions,后者禁用该API并改用visualize.show_widget工具渲染原生HTML表单,确保兼容性与正确交互。
需要向用户请求结构化数据时 涉及单选、多选或文本字段输入时 需展示视觉风格卡或语音试听卡时
chatcut/skills/widget-forms/SKILL.md
npx skills add ChatCut-Inc/agent-plugin --skill widget-forms -g -y
SKILL.md
Frontmatter
{
    "name": "widget-forms",
    "description": "Use when a ChatCut plugin session (Codex, Claude Code, or another MCP host) should ask the user for structured input with an in-chat form, including single-select, multi-select, text fields, visual style cards, voice audition cards, or native ChatCut scenario cards."
}

Widget Forms

Host scope: the ask_followup_questions MCP-App widget below renders in hosts that support ChatCut form widgets (Codex). Claude Code does not render MCP-App widgets — use the Claude Code recipe below for the same moments with the same content. The question-design rules (single question per field, user-language labels, no media-upload questions) apply to every host.

Claude Code Runtime (verified 2026-07-15)

Hard boundary: Claude Code does not render ChatCut MCP-App results. Never call ask_followup_questions in this runtime. Use the host-native show_widget tool on the visualize server:

  1. Discover visualize.show_widget, then load its read_me with the elicitation module for the current desktop platform. Follow the current contract rather than examples remembered from an earlier session. Load it once and reuse it for the rest of the session; do not rediscover or reread it for each form. Read references/elicit-recipes.md only when the form contains visual or voice media cards. A plain single/multi/text form needs only the current read_me contract.
  2. Infer first from the conversation, project state, and attachments. Ask only for information that is both necessary for the next step and not already known. Then render exactly one host-wired <form class="elicit"> using the canonical header, body, group, footer, and fixed chrome from read_me. Put all related questions, media previews, and the single submit action in this one widget; never render a preview widget plus a second question UI. Claude Desktop already draws the outer show_widget frame, so keep the required .elicit structure but flatten only its visual wrapper with style="border:0; border-radius:0; box-shadow:none; background:transparent". Do not remove or rename the form, header, body, or footer classes; they remain required for answer collection and submission.
  3. Map single/multi choices to .elicit-pills[data-name][data-multi] containing .elicit-pill[data-value]; use the documented Elicitation controls for text and Other values. For an off-list answer, use exactly one .elicit-pill[data-other] and one adjacent .elicit-other[data-for]; data-for must exactly match the pill group's data-name. Visual, voice, and scenario cards remain selectable .elicit-pill controls with clean data-value attributes. Ordinary and visual choices use buttons. A voice choice uses one non-button .elicit-pill card that directly contains its title, description, and native audio player; current Claude Desktop wires selection by the .elicit-pill class rather than the element tag.
  4. Submit only through <button type="button" class="elicit-submit">...</button>. In Claude Code Desktop this fills the composed answer into the user's prompt box; it does not press Send. Use an honest fill-oriented action label such as "Fill editing brief". Never claim "sent" before that user message appears in chat. Stop the current turn and wait for the user to send the filled prompt.
  5. Build canonical option tuples before reading media or writing HTML. This is a hard preflight gate; do not call show_widget until every visible media option has an authoritative (id, display label, description/tags) source:
    • Design Style cards: call manage_design_style with action: "list_presets" and locale matching the conversation language. Choose from that result and copy each returned id and name exactly. Never derive, translate, shorten, or improve a preset name from its image.
    • Voice cards: load the voice skill and read ${CLAUDE_PLUGIN_ROOT}/skills/voice/references/voices.md. Choose one row per card; keep its preset id, official/localized display name, tags, and sample binding together. Never create a voice name from broad traits or a sample filename. If either authoritative source is unavailable or times out, do not fabricate options and do not render a misleading form. Report the catalog problem concisely and retry only after the source is available.
  6. Read ${CLAUDE_PLUGIN_ROOT}/assets/widget-media/manifest.json only after the canonical tuples exist. The manifest is a media resolver, not a naming catalog. Resolve media by the same tuple id using scenario/<scenarioId>, design-style/<presetId>, or voice/<voiceId>, then concatenate the manifest baseUrl and entry path. Ignore caller-provided S3, CloudFront, app.chatcut.io, relative, or other non-manifest URLs. If a key is absent, render that exact authoritative label without media in the same form. Never download, resize, transcode, base64-encode, print, or save media or build intermediate HTML/JSON files at runtime.
  7. Keep visual sets focused: show 3 strong choices by default and expand toward 6 only when the user asks to browse more broadly or the decision genuinely needs that range. Keep the HTML payload small; remote media bytes must never enter the prompt or widget arguments.
  8. Write zero event handlers and zero custom scripts. Voice audition uses a single non-button .elicit-pill card with its native <audio controls> nested directly inside. Clicking the card or its player selects that voice through the host's delegated .elicit-pill handler, while playback remains browser-native. Do not wrap the player in a <button> and do not create a separate selector card above it. Do not use sendPrompt(...): live testing shows that it also only fills Claude Code Desktop's prompt box despite its read-me wording.
  9. Do not add file input to an Elicitation form: one file group currently breaks handoff for every answer. Ask for missing source media outside the form by telling the user to drag it into the chat input, then follow asset-import.
  10. In the structured collection scenarios covered by this skill, do not replace the combined form with AskUserQuestion; that modal is more interruptive and loses the single multi-question intake experience. This does not restrict normal AskUserQuestion use in unrelated workflows. If show_widget is genuinely unavailable, ask concisely in ordinary chat.

For media forms, minimize first-render latency by starting all independent preparation together after this skill loads: load the current Elicitation read_me, read this skill's media recipe and manifest, and fetch only the authoritative catalogs actually needed by the form. Read the voice catalog only for voice cards; call list_presets only for Design Style cards. Do not serialize independent reads, inspect unrelated skills, probe media URLs, or create intermediate files. Reuse all loaded local contracts and catalogs for later forms in the same session. The only expected network wait before a mixed MG/voice form is the Design Style catalog call; show_widget is the final call.

Claude Elicitation file attachments are not ChatCut project imports; use the asset-import workflow when project media is missing.

Use user-language readable copy for data-name and data-value; the host puts those strings directly into the filled answer line. Keep preset ids, voice ids, and scenario ids out of those attributes, and retain a label-to-id map from the tool results in context. The host formats the answer as <header> details — <data-name>: <value> · ..., with comma-separated multi-select values. Once that line appears as a user message, map each visible label back to the internal id from the candidate list and continue without asking the same questions again.

Immediately before show_widget, audit every media card in both directions: the visible label must map to exactly one authoritative id, and that same id must resolve the card's manifest key. A label copied from a different id, an invented alias, a shortened official name, or an image chosen before the catalog lookup is a failed preflight. Fix the tuple instead of rendering it.

Codex Runtime

Hard boundary: use the ChatCut MCP Apps form tool in Codex. Do not copy Claude Code's Elicitation HTML or show_widget recipe into a Codex conversation, and do not output raw ChatCut native <widget>...</widget> HTML; Codex cannot render that editor-only protocol.

Runtime Rule

Call ask_followup_questions. This is the Codex/external-MCP equivalent of the native ChatCut widget form protocol.

Plan the whole questionnaire before calling the tool. Send one final form, not a trial form followed by a corrected form. The tool supports at most 12 fields; if the user asks for more questions, merge related prompts into combined fields before the first call.

After calling ask_followup_questions, stop the turn and wait for the submitted answer to appear in chat. Do not apply a choice, create assets, or continue planning from a recommendation until the user's selection is present in the conversation.

Supported Field Mapping

Build a fields array. Write every visible string in the user's conversation language.

  • Native <form-single> -> { type: "single", variant: "default" }
  • Native <form-multi> -> { type: "multi", variant: "default" }
  • Native <form-text> / <form-textarea> -> { type: "text" }
  • Native <form-visual> -> { type: "single", variant: "visual" }
  • Voice audition cards -> { type: "single", variant: "voice" }
  • Native start-scenario cards -> { type: "single", variant: "scenario" }

Form Copy Tone

For form-level text (title, prompt, fields[].label, submitLabel, and messagePrefix), write like ChatCut is a capable video-making partner inviting the user to describe what they want, not like a rigid survey.

Aim for:

  • Warm, open-ended, and action-oriented. The copy should imply "choose the closest video need or just tell me your idea; we can figure it out together."
  • Short and scannable. Use one natural sentence for prompt and concise question labels.
  • Honest capability framing. ChatCut can help with many video workflows, but do not claim unsupported abilities or guarantee a result before inputs are known.
  • The user's language and local product terms. Keep "ChatCut", "B-roll", "Motion Graphics", "MG 动画", model/product names, and platform names in their established forms.
  • User-facing creative wording. For early planning or creative-intake forms, prefer natural terms such as idea, direction, plan, story, shot list, audience, mood, or video need over internal production-document language.

Avoid stiff labels such as "Select video type", "Please choose the video type for this project", or "What type of video do you want to make?" for scenario intake unless the host has no room for warmer copy.

For a scenario-intake form, prefer copy like:

{
  "title": "What do you want to make?",
  "prompt": "Choose the closest video scenario, or choose Something else and describe your idea.",
  "submitLabel": "Start creating",
  "messagePrefix": "I want to start with this video direction:",
  "fields": [
    {
      "id": "scenario",
      "label": "Which scenario fits your video best?",
      "type": "single",
      "variant": "scenario",
      "otherPlaceholder": "For example: turn my travel footage into an atmospheric vlog / make a launch video for a new product"
    }
  ]
}

Do not include file-upload questions in Codex forms. If a task actually needs source media and the project/chat does not already have it, ask the user separately to upload files through the Codex composer Add files flow or directly in the ChatCut editor. File upload is not a default prerequisite for every questionnaire; only ask for it when the next editing step depends on missing media.

For choice fields:

  • Use id for the internal value the next tool call needs.
  • Use label for what the user sees.
  • For ordinary single-select and multi-select cards (variant: "default"), keep options label-only. Do not add per-option description unless the user cannot distinguish the choices from labels alone.
  • Use description mainly for voice cards. Visual style cards should usually use only preview + label.
  • When an off-list answer is acceptable, add an explicit option with id: "__other__" and a label in the same language as the rest of the form, using the word the user would expect for an off-list answer. The widget will turn this option into a text entry when selected. Use otherPlaceholder if the text entry needs a placeholder.

For visual cards:

  • Use real image URLs or data image URLs in preview.
  • For Design Style catalog choices, call manage_design_style with action: "list_presets" first, then map each returned preset to { id: preset.id, label: preset.name, preview: preset.thumbnailUrl }.
  • Never hardcode catalog preset ids unless the user already selected one.

For voice cards:

  • Use audioUrl for the sample file.
  • Prefer the documented sample path such as /voice-samples/doubao-liuchang.mp3 or a public HTTPS URL. Do not pass localhost sample URLs; MCP host iframes do not reliably resolve editor-local media.
  • Keep user-visible descriptions provider-neutral. Describe the voice the same way the native ChatCut audition UI does: gender / age range / tone / use case, such as Female / young / friendly, general or 男 / 中年 / 低沉知识解说. Do not show provider names like ElevenLabs or Doubao in option descriptions.
  • Keep the option id equal to the provider voice id needed by submit_voice.

For native start-scenario cards:

  • Use this when the user should choose which ChatCut video workflow to start, such as talking-head editing, MG animation, long-video-to-shorts, product/app promo, AI short film, or explainer video.
  • Present these as common video needs/scenarios, not as the only possible video workflows. The form must also let the user describe a different video need.
  • Use exactly one single-select field with variant: "scenario".
  • Provide options using the canonical ids below and localized labels in the user's language. Include id: "__other__" only when you need to customize the off-list label; otherwise the backend appends a localized Other option.
  • English, Chinese, and Spanish scenario labels/descriptions/starter prompts are built in. For any other user language, faithfully translate each scenario's English label, description, and starter prompt into the user's language and pass those localized values in the option objects. Preserve ChatCut product terms and workflow meaning; do not add new requirements. Use submitPrompt for the translated starter prompt. This override is specific to variant: "scenario"; ordinary option cards, voice cards, and visual style cards already get their visible text from the values you pass.
  • Do not provide custom preview or audioUrl; the backend fills the native first-screen preview image.
  • Canonical ids: talking-head, motion-graphics, long-video-to-shorts, app-promo, ai-cinematic-short-film, explainer, plus __other__ for a free-form video need.
  • Example options: { "id": "talking-head", "label": "Talking Head Editing" }, { "id": "motion-graphics", "label": "Motion Graphics" }, { "id": "long-video-to-shorts", "label": "Long Video to Shorts" }, { "id": "app-promo", "label": "Product / App Promo" }, { "id": "ai-cinematic-short-film", "label": "AI Short Film" }, { "id": "explainer", "label": "Explainer Video" }, { "id": "__other__", "label": "Something else" }.

Current Gaps

ask_followup_questions is for structured answers only. It does not support native custom HTML, timeline parameter bridges, editor item selection, or file upload fields. For files already held by the agent runtime or attached directly to the chat outside this card, the media-import workflow is still valid: call import_media and run the helper/direct upload path. For files the user wants to place directly in a project, ask them to use the ChatCut editor upload UI.

Example

{
  "title": "Your video idea",
  "prompt": "Choose or fill in what you have in mind so ChatCut can pick a good starting direction.",
  "submitLabel": "Send idea",
  "messagePrefix": "Continue with this video direction:",
  "fields": [
    {
      "id": "goal",
      "label": "What's the main goal of this video?",
      "type": "single",
      "options": [
        { "id": "product_intro", "label": "Product intro" },
        { "id": "social_ad", "label": "Social ad" },
        { "id": "__other__", "label": "Something else" }
      ]
    },
    {
      "id": "elements",
      "label": "What should it include? (Select all that apply)",
      "type": "multi",
      "options": [
        { "id": "broll", "label": "B-roll" },
        { "id": "logo", "label": "Brand logo" },
        { "id": "__other__", "label": "Something else" }
      ]
    }
  ]
}
提供ChatCut产品知识,解答界面、功能、积分、订阅及计费问题。指导Agent无法直接执行的GUI操作,或在任务失败时作为手动操作的回退指南。不用于查询实时项目状态。
询问产品功能或界面布局 咨询积分、定价或订阅计划 需要执行Agent无法直接完成的GUI操作 任务失败需引导用户手动完成
chatcut/skills/product-help/SKILL.md
npx skills add ChatCut-Inc/agent-plugin --skill product-help -g -y
SKILL.md
Frontmatter
{
    "name": "product-help",
    "description": "ChatCut product knowledge — UI layout, features, credits, subscription plans, pricing, and billing. Use when the user asks about the product interface, how to use a feature, where to find something, credit costs, or plan \/ upgrade questions, or needs GUI guidance for something the agent cannot do directly. Also use as fallback when a task fails and the user needs to complete it manually in the UI. NOT for live project-state queries (\"where are my folders?\", \"what's on my timeline?\", \"where is clip X?\") — those are answered by `read_project`, not by this skill.\n",
    "user-invocable": false
}

ChatCut Product Help

Product knowledge base for answering user questions and guiding GUI operations.

When to Use

  • User asks about the product, a feature, or how something works
  • User asks about credits, pricing, or subscription plans
  • User needs to perform a GUI action that the agent cannot do directly
  • A task fails and you need to guide the user through manual steps as a fallback

Reference Files

Read the relevant file on demand — do NOT read all files at once.

Question about File
Product UI, layout, panels, buttons, features references/ui-and-features.md
Credits, pricing, subscriptions, billing references/credits-and-plans.md

Guidelines

  1. Try to do it first. If the task is something you can handle (adding captions, changing aspect ratio, etc.), do it. Only guide GUI operations as a fallback.
  2. Use visible UI names. When guiding manual operations, give clear numbered steps with labels and panel locations that are confirmed in the references. If the user says they cannot find an entry, re-anchor from major visible regions such as the AI panel, top bar, asset/library panels, and timeline.
  3. Generation confirmation help. Credit confirmation cards for Motion Graphics, Video Generation, and Image Generation appear in the AI chat area. The persistent setting lives in the Agent settings popover beside the Agent mode selector at the bottom of the AI panel. If a confirmation was denied, cancelled, or timed out, explain what happened and wait for the user's next instruction before retrying.
  4. No internal details. Never mention model names (except user-facing ones like Seedance 2.0), pricing formulas, or implementation details.
  5. Feedback & support. If the user encounters a problem you cannot resolve, guide them to click "Feedback" in the user profile menu, or email team@chatcut.io.
指导口播、访谈及播客等以语音为主的视频剪辑,涵盖语音清理、MG动画叠加、B-roll补充、配乐及字幕制作,提供节奏感知与合规性指引。
用户需要剪辑口播或访谈类视频 请求去除口癖或整理语音节奏 要求在视频中叠加MG动画或B-roll素材
chatcut/skills/talking-head-guide/SKILL.md
npx skills add ChatCut-Inc/agent-plugin --skill talking-head-guide -g -y
SKILL.md
Frontmatter
{
    "name": "talking-head-guide",
    "description": "Guide for editing speech-led videos where spoken delivery or conversation drives the cut — single-speaker talking-head \/ 口播, two- or multi-speaker interview \/ 访谈, video podcast, lecture, tutorial, course, and similar formats. Use for any non-trivial edit of those formats, including speech cleanup (剪口播 \/ 口播剪辑 \/ 去口癖 \/ clean up fillers \/ smooth speech), pause or repeated-take removal, motion graphics layered onto the footage (口播加 MG \/ 加动画), B-roll (加 B-roll \/ add B-roll), music, or captions. For motion graphics specifically, use this together with the active Motion Graphics skill\/workflow available in the current ChatCut environment — this skill adds speech-specific guidance (rhythm-aware timing, frame-aware placement, subject\/caption protection, placement verification).\n",
    "user-invocable": true
}

Speech-Led Video Editing (Talking Head, Interview, Podcast)

What this skill covers

Required input: an existing speech-led source video uploaded to the project — for example a single-speaker talking-head / 口播, a two- or multi-speaker interview / 访谈, a video podcast, lecture, tutorial, or course. If the user wants to start without source footage (e.g., generate a fresh talking-head from scratch), this skill doesn't apply.

When the user enters this workflow without a source video uploaded yet, load widget-forms for the host-specific route. In Claude Code, keep the combined widget limited to treatment/preferences because its Elicitation file control breaks the entire answer handoff. Outside the form, tell the user to drag the source file directly into the chat input and send it, then use asset-import; do not send them to the editor upload UI. On other hosts, preserve their supported attachment/widget flow.

If this workflow is running through a Codex/connector host and the task creates, targets, or opens a ChatCut project for the user, satisfy any returned browserHandoff.required=true, Codex internal Browser handoff, or equivalent live project handoff before starting nontrivial edits and again before final delivery if the visible editor no longer matches the project.

Independent treatments that can be applied to speech-led videos. Pick the ones that match what the user wants — not all are needed every time.

  • A-roll editing (中文称 语音剪辑 / 含 去口癖、停顿、重复) — transcript-based speech editing. Common operations include cleanup, highlight extraction, restructure, opening hook, and others as needed for the aligned outcome.
  • Motion graphics overlay (英文展示给用户时写全称 Motion Graphics,不要缩成 "MG";中文产品术语固定为 MG 动画——不要叫"动效""字幕条""动态字幕"等其它说法) — reinforce key information, structured content, and topic transitions with on-screen motion graphics
  • B-roll (industry term — keep as "B-roll" in any language, do not translate) — cover jump cuts or visualize what's being said
  • Background music (中文 背景音乐) — set mood and smooth micro-gaps
  • Captions (中文 字幕) — on-screen text for accessibility
  • AI Voice Isolation (中文 AI 人声隔离) — clean or isolate spoken human voice with DeepFilterNet3, picture untouched. See the voice-isolation skill.

用户语言为中文时,在 widget options / choices options / 对话文案里严格使用上面括号里的产品术语——别自己再翻译一遍,会跟产品其它地方对不上。

What shapes the edit

Beyond picking treatments, a talking-head edit is shaped by several orthogonal variables. When the user's ask is vague, these are what's worth clarifying first:

  • Target — platform (YouTube / TikTok / Shorts / ...), desired length, aspect ratio
  • Which treatments to apply — the treatments above are optional; don't assume all of them apply
  • Pacing / tone — tight / energetic / formal / casual; brand or voice preferences if stated. (For MG visual style, follow the active Motion Graphics skill/workflow.)

When more than one of these variables is missing, ask with one form after loading widget-forms. Do not ask markdown numbered questions and then append <choices/> for only one part of the same intake.

Order of execution

When multiple treatments have been aligned with the user, they depend on each other and must be finalized in dependency order. This section is only relevant after alignment — it doesn't tell you what to start with on a fresh request.

The speech timing (set by A-roll editing) anchors everything downstream — MG placement, B-roll cut-covers, music duration, and caption sync all reference the final speech timeline.

So: finalize A-roll editing before committing any visual, audio, or text layer. Don't write captions against pre-edit speech, don't cut music to pre-edit length, don't place MG against timing that will shift.

You must confirm the result with the user after each major step before starting the next, unless the user has explicitly asked to run end-to-end without stopping. Key checkpoints when multiple treatments apply: after A-roll editing finalizes the speech timing; before MG generation (confirm style and direction, and, when it isn't obvious, whether it sits over the video as an overlay or takes the whole frame); after MG generation; same pattern for B-roll, music, and captions. Don't bundle multiple checkpoints into one response — confirm each step separately. An upstream mistake forces redoing everything downstream (e.g., MG placed against pre-cleanup timing wastes generation credits when the timeline shifts).


A-roll editing

Scenario

In a talking-head workflow, the first step is usually A-roll editing: editing the original spoken footage.

A-roll edits are ultimately applied to the timeline and change what the viewer actually hears and sees. However, the editing decisions should usually start from the transcript, because the core question is: what spoken content should the viewer hear, and what should be removed, compressed, or reordered?

Common A-roll tasks

A-roll editing is not only cleanup. First decide what spoken-content task the user is asking for, then choose the editing strategy and tools.

Common tasks:

  • Cleanup — remove mistakes, repeated attempts, verbal habits, filler words, and meaningless pauses so the speech becomes clearer and more natural.
  • Highlight extraction — pull the most valuable, opinionated, emotional, or topic-relevant moments from longer footage.
  • Restructure — reorder spoken content, such as moving the conclusion earlier, grouping by topic, or combining scattered parts into a clearer structure.
  • Hook / short version — use a strong claim, result, conflict, or question from the source as the opening, or compress long content into a shorter version.
  • Target-script / script alignment — match, keep, and reorder spoken content according to a user-provided target script, target paragraph, or desired content.

Cleanup is the most common task and the one most likely to fail from bad boundary decisions. It is described in detail below. Other tasks get shorter rules, but still follow the shared A-roll principles: complete meaning, clear boundaries, and natural listening flow.

Shared A-roll principles

These principles apply to all A-roll tasks, not only cleanup.

  • Decide the task before choosing the tool. Do not let tool availability change the editing strategy.
  • Edit by complete semantic units. Whenever possible, move/delete/keep complete sentences, complete ideas, complete answers, or complete steps. Do not cut out a half-sentence just because a few words match.
  • When the task names what to keep, trim to that boundary. The inverse of the rule above, for any task that specifies which content to keep — restoring a specific sentence, matching a target script, pulling a named highlight, building a version: keep exactly the requested span. Trim the kept range to start and end at the requested words and drop the off-script head/tail of the source [sN] segment it sits in; keeping a whole segment for one requested sentence is over-keeping that drags in unrequested speech. This applies only when the task names what to keep — never to open-ended cleanup, where you keep complete units (above).
  • Do not stitch unfinished fragments across retakes. Do not combine incomplete pieces from different attempts into one artificial sentence. This does not make the earlier attempt disposable: keep a complete useful lead-in, setup, contrast, category, evaluation, or context if it is not repeated later and can naturally connect to the later complete retake.
  • Preserve connective tissue. List labels, contrast words, subjects, verbs, and adjacent source words are not filler when removing them makes a kept idea ungrammatical, abrupt, or misleading. Trim the smallest span that keeps the line speakable.
  • Keep listening flow natural. The result should still have natural phrasing and breathing room. Do not make sentences feel glued together just to make them "clean."
  • Be conservative when boundaries are uncertain. If unsure whether a cut harms meaning, logic, or listening flow, keep it or make a smaller cut.
  • Confirm complex changes first. For complex restructuring, aggressive shortening, structural changes, or generated hooks, confirm target length, structure direction, and what to preserve with the user before editing.
  • Explain content, never indices. You MUST NOT explain edits to the user with internal addresses such as [sN], [cN], [gap], word indices, clip ids, or segment ids. The user cannot see those addresses and will not understand what they mean. Use the actual spoken content, a short quote, or a plain-language description of the edit.
  • Never name a screen position for a panel. When you invite the user to review or fine-tune the result, call it "the Transcript panel" (中文「文字稿面板」) — never a direction (left / right / side / 左侧 / 右侧). The layout is rearrangeable and the panel does not sit in a fixed corner.

Cleanup goals and decisions

What good cleanup means

Good cleanup does not mean making the video as short as possible, and it does not mean rewriting the speaker into a different script.

Good cleanup means:

  • The logic stays coherent
  • The expression becomes clearer
  • The audio feels natural
  • Obvious mistakes, repeated attempts, meaningless stalls, and filler are removed
  • The speaker's intent, tone, and natural rhythm are preserved

Bad cleanup usually falls into two failure modes:

  • Under-cleaning: obvious mistakes, repetition, long pauses, or filler remain.
  • Over-cleaning: sentences are cut off, meaning is missing, rhythm becomes too hard, or the result sounds stitched together.

Default principle: remove defects without changing meaning; make speech smoother, not harder; prefer small local cuts over whole-sentence or whole-segment deletion; when unsure whether a cut harms meaning, keep it.

How to judge common cleanup cases

Below are the common cleanup categories and how to make editing decisions for each.

Meaningless filler words

Fillers fall into two categories.

The first category is clearly meaningless hesitation sounds. These are usually safe to remove:

  • um
  • uh
  • er
  • ah

When they do not carry special meaning, use clean_script first for bulk cleanup.

The second category depends on context and must not be removed by word list alone:

  • so
  • like
  • 然后
  • 就是
  • 那个
  • 所以
  • 但是

How to decide:

  • If the word is only hesitation or padding, remove it.
  • If it carries sequence, continuation, contrast, cause, reference, response, emphasis, or natural tone, keep it.
  • If removing it makes the surrounding words sound hard-spliced, keep it or only compress the pause.
  • If unsure, keep it.

Examples:

  • um, I think this solves the main problem -> remove um.
  • It works like a checklist -> keep like; it is a comparison.
  • The upload failed, so we retried it -> keep so; it carries cause/result.
  • right after the call, send the recap -> keep right; it modifies timing.
  • 然后我们再看第二点 -> keep 然后; it marks sequence.
Retakes and repeated attempts

A retake is when the speaker retries the same intended idea because they misspoke, got stuck, forgot words, or restarted. Retake cleanup is not "delete repeated text." The goal is to keep one complete, natural, logically coherent version of the intended idea.

Use this decision path:

  1. Decide whether it is really a retake. Treat it as a retake only when multiple attempts are trying to say the same intended idea. Do not treat it as a normal retake when the repetition is intentional emphasis, a rhetorical beat, a structural marker, or a second pass that adds new information or tone.
  2. Define the complete version to keep. A complete version may include more than the main content sentence. It may need a lead-in, connector, section marker, topic setup, contrast, qualifier, subject, object, or conclusion. These are not filler when the kept content depends on them.
  3. Cut only the failed or covered part. Remove only words that are wrong, dangling, abandoned, or fully covered by the kept version. The cut boundary starts at the repeated or failed idea, not automatically at the earlier transition, setup, or continuous speech. If earlier speech contains useful context that the kept version does not repeat, keep it.
  4. Choose the best complete attempt. If several attempts are complete, usually prefer the later one because it is often closer to the speaker's intended take. But do not choose the last attempt mechanically. If the later attempt is missing needed context, structure, subject, object, or conclusion, keep the more complete version or preserve the missing lead-in from the earlier attempt.

A repeated lead-in is redundant only when another equivalent lead-in remains naturally connected to the kept content. If removing every copy makes the result lose structure or sound abrupt, keep one natural copy and remove only the extra restarts. Do not stitch unfinished fragments from different attempts into one artificial sentence.

Examples are patterns, not a closed list:

  • Local false start inside a kept sentence: There, there's no After Effects, no Premiere, no DaVinci Resolve learning. Keep the complete sentence, but remove the abandoned restart: There's no After Effects, no Premiere, no DaVinci Resolve learning. Do not keep the stray first word just because the full sentence is otherwise useful.
  • Repeated structural lead-in: And secondly, ... and secondly, we're introducing a brand new UI. Remove the extra restart, but keep one natural lead-in attached to the kept content: And secondly, we're introducing a brand new UI. Do not delete every structural marker and leave only: We're introducing a brand new UI.
  • Useful setup before a failed ending: Then the next one is different from comedy. It is popular on Disney Plus. It is called... Later retake: It is a popular Disney Plus show called Love Story. Keep useful setup that the later retake does not repeat, and cut from the failure point: Then the next one is different from comedy. It is a popular Disney Plus show called Love Story.
False starts and unfinished fragments

Use false starts / unfinished fragments for this category. False start is the more natural editing/transcription term for a speaker beginning a phrase and then restarting or abandoning it; unfinished fragment makes the dangling half-sentence case explicit.

Only remove a fragment when it clearly does not form useful information.

Safe to remove:

  • The speaker abandons the thought and a complete version appears later.
  • The segment is only a dangling phrase, such as "this is actually..." with no completion.
  • It is clearly the leftover beginning of a failed attempt.

Do not remove:

  • A sentence that is imperfect but contains useful information.
  • A lead-in that provides the subject, object, or context needed later.
  • Content that provides setup, contrast, conclusion, emotion, or tone.

If only part of a sentence or segment is wrong, do not delete the useful content around it. Remove only the bad word, phrase, or pause; if a local cut cannot sound natural, keep the segment.

Pauses and breaths

Pause cleanup should default to compression, not zeroing out. Spoken video needs natural breathing room.

Default rules:

  • Obvious long pauses over 0.8-1s: usually compress to about 0.3s.
  • Between sentences: keep about 0.3-0.5s so listeners can hear natural phrasing.
  • Around topic shifts, contrast, or emphasis: keep slightly longer pauses when needed; do not make the delivery too rushed.
  • Short breaths inside one sentence: if they are normal breathing, do not remove them.
  • Clear long pauses inside one sentence: compress them, but not so tightly that adjacent words sound glued together.
  • Long pauses before a retake: if the failed attempts around it are removed, remove the pause with them.
  • If the user provides explicit thresholds, follow them. For example, if the user says "only process pauses over 0.8s and keep at least 0.3s", do not process natural pauses under 0.8s.

How to operate on pauses:

  • For batch pause cleanup across the timeline or track, use clean_script. This is the default path for compressing many long pauses.
  • Translate common user wording into clean_script pause rules:
    • "Tighter breaths" / "compress pauses" / "compress anything over 0.3s to 0.3s" → silence: "compress:300" (or the requested cap).
    • "Restore some breathing room" / "do not make it too rushed" / "keep at least 0.5s" → silence: "restore:500" (or the requested minimum).
    • "Make all pauses around 0.5s" → silence: "normalize:500".
    • "Keep pauses between 0.3s and 0.8s" → silence: "range:300-800". Any rule that makes a pause longer — restore, normalize, or the lower bound in range — never invents new silence. It only recovers pause time that already existed at that exact spot in the original recording. If the original pause was shorter than the requested value, it stops at the original pause length.
  • You do not need to call read_script({ showSilence: true }) before batch pause cleanup. By default, timeline.md hides silence markers, but clean_script can still detect and rewrite silences internally.
  • Use read_script({ showSilence: true }) only when you need to inspect or manually adjust a specific pause. Then edit the visible marker: ~~[silence=0.8s]~~ to fully cut it, [silence=0.8s→0.2s] to compress it, or leave it untouched to keep it.
  • After semantic edits, review the final clean timeline.md. If the final pacing still has many long pauses, run clean_script only="silence"; if only one or two pauses feel wrong, use showSilence: true and adjust those manually.

Script gap primitive note:

  • Do not create an accidental [gap] on the primary video track as a pacing pause. A Script [gap] means no source is playing; on the only visible video track it renders as black. If pacing needs breathing room, preserve or restore source silence with clean_script / [silence=...], cover the moment with B-roll/MG/a full-frame visual beat, or intentionally declare the black beat in the plan.

Other A-roll task guidance

Highlight extraction

Highlight extraction is not about making the content as short as possible. It is about selecting the most valuable spoken content according to the user's criteria.

Rules:

  • First identify the highlight standard: opinion, conclusion, story, emotion, conflict, tutorial step, data point, or a specific topic.
  • Each highlight should be understandable on its own. Do not remove the subject, setup, question, or conclusion needed to understand it.
  • Do not keep only a short punchy sentence if the surrounding context is required for it to make sense.
  • If the user asks for a specific topic, remove other topics. If the user asks for the "best" or "most exciting" moments, prioritize information density and expression strength.
  • After extracting highlights, usually clean up the kept segments so the final result is polished.

Restructure

Restructure means changing the order of spoken content. It does not mean freely breaking sentences apart.

Rules:

  • First confirm the target structure: chronological, by topic, by question, conclusion-first, tutorial steps, or short-form pacing.
  • Move complete semantic units: complete sentences, ideas, answers, or steps.
  • Do not split one sentence so the first half appears in one place and the second half elsewhere.
  • After moving content, check whether connectors still work, such as "so," "but," "next," or "this."
  • If the user asks for major restructuring without specifying the target structure, confirm before editing.

Hook / short version

Hook / short version work aims to make the opening more compelling or compress long content into a shorter but still complete version.

Rules:

  • Prefer pulling the hook from the original footage: a strong claim, result, conflict, question, counterintuitive statement, or emotionally strong moment.
  • If a new hook or new narration must be generated, confirm the direction with the user first.
  • For short versions, do not cut only by duration. First identify the main line to preserve: problem, core point, key reasons, and conclusion.
  • Short versions can remove examples, repetition, and setup, but must keep the logic needed for the point to hold.
  • If the user gives a target duration, try to match it. If duration and semantic completeness conflict, explain the tradeoff.

Target-script / script alignment

Target-script / script alignment means cutting the final spoken content according to a user-provided script, target paragraph, or desired content.

Rules:

  • The target script is the main constraint: prioritize content that matches the target meaning.
  • Natural spoken paraphrases are acceptable, but do not include surrounding content that the target does not ask for.
  • If the source has multiple similar versions, choose the most complete, natural, and target-aligned version.
  • If target order differs from source order, reorder as needed, but move complete semantic units.
  • If the target script omits source context, follow the target. Do not add long surrounding context unless the result would be incomprehensible without it.

Building versions, highlights, and excerpts — stay on Script

Highlight, short version, excerpt, hook, restructure, and making several versions are all transcript-content tasks: drive them through Script (read_script → edit timeline.mdapply_script), never by looking up timestamps and placing source clips manually.

  • Pick the starting point by where the content comes from. Versions on the current timeline: trim or reorder timeline.md and apply_script. A version on its own timeline (the user asked for separate timelines, or wants each version independently editable/exportable): manage_timelines action=duplicate — the copy carries the content and its script, so you immediately read_script → trim → apply_script on it. Building fresh from library assets: manage_timelines action=create, add the source asset, then drive it through Script.
  • To bring in source content the current cut no longer shows (a hook line, a segment needed for another version), read library/<filename>.md, copy the needed [sN] line(s) into timeline.md where they belong, and apply_script. This is how you pull source content onto the timeline — through Script.
  • For multiple versions on one track: list every version's [sN] segments in timeline.md in version order, one version after another, then apply_script once. Reuse is just repetition — the same [sN] segment may appear in more than one version, and repeating the line replays that source range again.
  • Never look up timestamps with find_transcript and place spoken content with edit_item / split_item. If you are converting transcript segments into source frame or second ranges, you are off the editing surface — return to Script. edit_item / find_transcript are only for non-transcript placement such as MG overlays and B-roll visual timing.

Check each version against its request. After assembling a version, highlight, or excerpt, re-read the result end to end and confirm every requested sentence is present, in the requested order, with no extra source carried in. Fix any dropped, duplicated, or out-of-order content before finishing.

A-roll / transcript-based editing workflow

Use this flow for any A-roll task driven by transcript meaning.

  1. Start with orientation. Call read_script, then read timeline.md once to understand the user's goal, the content structure, and whether fixed fillers or long pauses are present. If you will run clean_script, do not build the full semantic edit from this pre-clean read.
  2. For cleanup tasks, run the mechanical cleanup pass before semantic editing when fixed fillers or long pauses are present. Use clean_script for fixed hesitation sounds (um, uh, er, ah, , ) and batch pause compression. If both are present, use the default clean_script pass so both are handled together. Do not use this step for context-dependent fillers, retakes, repeated sentences, or anything that needs meaning.
  3. After clean_script, always read the refreshed clean timeline.md before semantic editing. Use this refreshed file as the source of truth; clean_script changes the canonical timeline and rematerializes the script, so previously read text may be stale. Do not edit from memory based on the pre-clean script. Then edit timeline.md with semantic judgment: choose the best retake, clean false starts, remove repeated or failed attempts, preserve useful setup and context, reorder content when needed, and keep the speech natural. For long transcripts, work one clear section at a time if that improves judgment accuracy.
  4. Apply the edit with apply_script. If apply fails, fix the markdown error or stale state, re-read the current timeline.md if needed, and apply again.
  5. Review the edited result. After a real apply_script, read the regenerated clean timeline.md and check what the viewer will actually hear: broken logic, missing context, over-deletion, missed cleanup, wrong order, or pauses that feel too tight or too long. Fix clear problems only. If the final result still needs batch pause adjustment, use clean_script only="silence". Use read_script({ showSilence: true }) only for manual adjustment of specific pauses.

What transcript editing actually changes

Editing timeline.md is not just changing displayed text. It describes which source media ranges should play on the timeline.

[sN] rows are ASR segments, not semantic units. A complete sentence, idea, retake, or transition may span several [sN] rows, and one [sN] row may contain only part of a sentence. Before deciding what to delete or keep, mentally reconstruct the complete spoken sentence or idea across adjacent rows.

  • Each spoken-text line maps to a playable source range.
  • Inline ~~...~~ removes the corresponding audible audio range.
  • Deleting a whole line removes that whole spoken segment.
  • Moving/reordering lines changes playback order.
  • apply_script applies the result back to the timeline.
  • Start/end trims may remain as one trimmed clip.
  • Deleting words or pauses in the middle of a sentence splits the original clip into multiple new clips: one kept range before the deletion and one kept range after it.
  • Moving spoken content also creates a new clip at the destination.
  • More clips after middle deletions or moves are expected and usually correct. Do not describe that as a "fragmentation problem" or as proof that word deletion is unsupported.

Tool boundaries

Choose the editing goal and content boundaries first, then choose the tool. Do not let tool availability change the editing strategy.

  • clean_script: use for mechanical first-pass cleanup: bulk removal of fixed meaningless fillers and batch silence compression/adjustment. It can process silence even when timeline.md is currently rendered without silence markers. Do not use it for context-dependent fillers, retakes, repeated sentences, or semantic decisions.
  • read_script + apply_script: the main transcript-based editing surface. Use it for real semantic editing: deleting words, sentences, pauses, reordering, or pulling library content onto the timeline.
  • manage_transcript action fix: only fixes ASR mistakes or speaker attribution. It does not cut audio and does not change what the viewer hears.
  • Caption SEGMENTATION (分句 / where pages break) is INDEPENDENT of the transcript and controlled by two per-word primitives only: to SPLIT one card into two, set display_text forcePageBreak:true on the word that should START the new card; to MERGE a card up into the previous one, set display_text keepWithPrevious:true on that card's FIRST word (works for any break — no box resizing, no wordsPerPage fiddling). To drop a repeated/false-start word, use display_text hidden:true. Box width / fontSize / wordsPerPage are style & density knobs, NOT per-boundary segmentation levers — do not widen the box or raise wordsPerPage to merge or split a specific card. NEVER edit the transcript to fix a caption line break — manage_transcript fix is only for an ASR-misheard WORD (content), not layout. read_captions shows each page's break= reason and per-word keys for these edits.
  • find_transcript: only locates when a phrase is spoken. It does not edit. If the next step is cutting spoken content, return to Script.
  • Edit / Write: use these to modify timeline.md. The edit only reaches the timeline after apply_script.

Script details to preserve:

  • read_script materializes timeline.md (current cut) and library/<filename>.md (full read-only source transcripts) in the workspace.
  • Single-word audible deletion is supported with inline strike syntax, such as [s1] 过去~~呢~~一个月.
  • Silence markers are hidden by default. Use clean_script for batch pause cleanup. Use read_script({ showSilence: true }) only to expose [silence=Ns] markers for precise manual edits such as ~~[silence=0.8s]~~ or [silence=0.8s→0.2s].
  • find_transcript can locate a phrase for visual timing; it is not the editing surface. Do not use find_transcript + split_item / edit_item to cut, place, or assemble transcript-based clips — this includes highlights, hooks, excerpts, and multi-version cuts. All spoken-content selection, placement, and reuse happens in Script (read_script → edit timeline.mdapply_script).

MG Overlay

Goal

Motion graphics layered into A-roll reinforce what the speaker is conveying — deepening the audience's impression of the key points and helping them grasp content that's hard to land through speech alone. Complete A-roll editing first; MG timing is based on the post-edit timeline.

This section only adds talking-head timing, frame-composition, subject/caption protection, and review constraints. For visual style alignment, MG creation or authoring, implementation constraints, editable properties, asset sizing, and verification, use the active Motion Graphics skill/workflow available in the current ChatCut environment.

MG workflow

For talking-head MG work, treat the video as one edited piece, not as isolated graphics.

  1. Understand the video — read the transcript and representative frames to learn topic, audience / platform, visual tone, and speaker layout.
  2. Set the visual language — use the active Design Style, the user's style / reference, a clarified direction, or visual presets from the active MG workflow.
  3. Choose useful MG moments — add MG only where a visual layer improves comprehension, emphasis, orientation, or pacing.
  4. Prepare each moment — decide the viewer job, content, visual mechanism, speech span, settled frame, read time, form, background, and composition relationship before creating the MG.
  5. Create through the active MG workflow — pass the talking-head context into the current environment's MG creation/authoring path. Different viewer jobs, information structures, or visual forms should usually become distinct MGs; reuse only intentionally recurring components.
  6. Place, review, confirm, then extend — check face, captions, readability, size, and composition. After the first real MG is placed in frame, confirm the effect with the user before expanding, unless they explicitly asked you to finish end-to-end.

Visual identity

Design Style is the video's confirmed visual language. It gives MGs a shared tone, color logic, typography logic, visual density, and motion language. It keeps different MGs in one family without forcing them into the same shape. It does not decide which MGs are useful, when they appear, where they sit, or whether they are transparent / opaque; those remain per-MG editing decisions.

Resolve the visual language before planning MG moments. Use the active MG workflow for the actual style-alignment interaction and implementation details:

  • Active Design Style — use it unless the user asks to change the overall style. If Project Context names an active Design Style but does not show details, inspect it once with manage_design_style action="get" before planning MG moments.
  • Specific user style / reference — follow it. If it is custom and not yet confirmed for a batch, use a real planned MG as the sample when the user needs to approve the look.
  • Generic or vague direction — quality words such as clean, premium, modern, professional, polished, or YouTube-style emphasis are goals, not a visual language. Follow the active MG workflow's style-alignment gate: prefer visual preset options, or use one representative MG for confirmation when the direction is textual / custom.
  • No visual direction — use the active MG workflow to show relevant visual preset options. Talking-head can be used as a catalog filter when available.
  • "Directly do" / "don't ask" — choose a concrete temporary direction from the transcript and footage, then continue without user style confirmation. Do not create or update a Design Style from this unconfirmed guess.

Picker is a visual Design Style selector. It shows preset thumbnails so the user can choose a visual direction by sight, instead of describing style in words.

  1. Call manage_design_style with action: "list_presets", scenario: "talking-head" when clear, and the user's locale. Use the scenario as a catalog filter, then choose reasonable visual options by preset descriptions and the actual video context.
  2. Render reasonable returned presets as visual options using the active form/widget route; do not replace thumbnails with text-only style names when visual thumbnails are available.
  3. The picker is a turn boundary: after showing it, stop and wait for the user's submitted selection.
  4. When the user picks an option, call manage_design_style with action: "apply_preset" and the selected presetId, then inspect the applied Design Style with action: "get" before authoring.
  5. If the user responds with text instead of picking, treat it as user direction and continue with the custom direction path.

Persist only confirmed visual language:

  • Picked preset — the user confirmed it by choosing the visual option. Call manage_design_style action="apply_preset".
  • Custom direction — after the user accepts the sample, treat it as the confirmed direction for the current MG work. If the current environment supports saving project Design Styles and the user accepts it as the shared project style, save/apply it with the agreed style facts.
  • Unconfirmed guess — do not create or update a Design Style, including when the user said "directly do it".

After applying a preset or confirming a custom direction as the project style, tell the user in one or two natural sentences that this is now the video's visual style, future MGs in this video will follow it by default, and it can be changed or adjusted later.

Where MG is useful

MG meaningfully helps comprehension or orientation when the content has:

  • Identity / context labels — speaker name, role, product name, date, source, or a small persistent section label.
  • Key information / quotes — a core concept, definition, statistic, conclusion, or key sentence worth emphasizing.
  • Structured information — multiple points, steps, comparisons, rankings, lists, or processes.
  • Chapter / topic markers — opening titles, section titles, topic transitions, or visual dividers between sections.
  • Abstract concepts — cause-effect relationships, cycles, systems, frameworks, or other ideas that are hard to follow verbally.

Repeated Components

One video should usually have one visual language, but not one universal MG shape.

Reuse a Motion Graphic asset only for intentionally recurring instances of the same component: same viewer task, same information structure, same visual form, and content changed through properties. Repeated chapter markers, recurring section labels, or a repeated status badge can share one asset. Different jobs such as an opening title, chapter marker, quote, list, diagram, and CTA should usually be separate assets that share palette, typography, motion tone, spacing, and material treatment.

An accepted first MG proves the visual language works in frame. It is not automatically a template for unrelated MGs.

Per-MG decisions

For talking-head videos, do not start MG creation from transcript timing alone. Inspect the target frame first: transcript tells you what and when; the frame tells you form, placement, and background.

Before creating the MG, make four linked editor decisions. They prepare the active MG workflow and the later timeline placement.

Decision Question Output
Content What idea deserves a visual layer? Message or visual fact expressed by the MG.
Timing When should it land with the speech? Timeline start, duration, read time, and internal motion beats.
Form and placement What kind of MG is it, and where can it live safely? MG form / size, then timeline placement after asset creation.
Background Is this an overlay on the talking-head shot, or its own moment? Transparent overlay or opaque / full-screen beat.

Only for generator workflows that require a brief

Use this subsection only when the active Motion Graphics workflow explicitly asks you to write a generation brief or request for another model or generator, such as Gemini / motion-graphic-gen.

Skip this subsection for Codex direct-authoring workflows. If you are creating or editing JSX yourself with create_motion_graphic_from_code / edit_asset, do not use referenceAssetIds, :template, :style, role anchors, or Gemini brief language.

For generator workflows, carry the visual language into the tool call. For now, templates are generation references, not direct-apply targets. Template refs from a Design Style are no different from any other template ID. For new MG assets, pass one code reference source: same-role role anchor with referenceAssetIds: ["<roleAnchorAssetId>:template"] only when the visual job, structure, and canvas role are the same; otherwise use the matched template ID directly, for example referenceAssetIds: ["<templateId>:style"]. If no template matches, write the confirmed Direction in the brief and use any accepted role anchor only for the same role. Template slot counts are not user constraints: if the user asks for more/fewer bars, rows, items, or data points than the template shows, generate a new structure instead of asking them to fit the slots.

When a template or role anchor is passed, keep the Gemini brief focused on content, role / broad form, background, and frame constraints. Let the reference carry detailed style and motion language.

Map the four shared decisions into a generator brief like this:

  • Content -> Content in the brief.
  • Timing -> timeline start, plus internal Timing only when the MG has its own beats. Internal Timing values say when each element appears, not how it moves; leave the motion style to Gemini.
  • Form and placement -> Size & shape in the brief, not final canvas placement. Do not write final left, top, right, bottom, coordinates, or placement anchors such as "lower-left" / "top-right" into the Gemini brief.
  • Background -> Background: transparent or Background: opaque.

1. Content

Choose what the MG expresses, not just what text it repeats. The content may be a speaker identity, distilled quote, key term, statistic, list, comparison, relationship diagram, chapter marker, or another visual representation of the point.

2. Timing

Choose the timeline anchor first. The MG should land with the relevant speech beat or section boundary, not trail after the speaker has already made the point. Use find_transcript; pass includeWordTimestamps: true when the MG has internal rhythm such as list items appearing one by one or multi-step reveals.

Write internal timing values relative to the MG's own start time. The timeline item start is the absolute video position; internal timing is the MG-internal rhythm after that start. Exit when the point is fully made.

3. Form and placement

Choose the MG form and likely placement region before creating the asset. The active MG workflow creates the graphic; place the finished asset on the video canvas afterward.

Placement principles:

  • Protect the subject and safe zones. Avoid the speaker's face, head, hair, glasses, mouth, chin, important products or objects, relevant hand gestures, captions/subtitles, and existing on-screen elements.
  • Keep the caption/subtitle area clear. If captions may appear, bottom overlays must sit above the caption band, not compete with or cover subtitles.
  • Separate overlays from full-screen MGs. Subject/safe-zone protection applies to overlays on top of A-roll. A full-screen MG is an intentional visual beat that replaces the A-roll for its duration, so it may cover the speaker and background.
  • Keep the composition intentional. The MG should support the speaker and message. It should not look like a random sticker, compete with the face, or make the frame feel unbalanced.

Common forms and areas:

Content type Common form Common area
Identity / context Name tag or small context label Lower-third first; lower-left or lower-right depending on the shot.
Key information / quotes Typographic quote, pull quote, or emphasis treatment Lower-center / lower-third; side area if the bottom is crowded; full-screen for a major punchline, conclusion, or pause.
Structured information List, step stack, comparison layout, or compact diagram Left/right side areas or bottom horizontal area; full-screen if the information is too dense for an overlay.
Chapter / topic markers Full-frame title, title overlay, or side title panel Full-screen for a strong intro or section break; lower-third for a light cue; side panel when one side has obvious open space.
Abstract concepts Concept visual, relationship map, cycle, framework, chart Lower-third if light and readable above captions; side area or full-screen if denser.
Tiny auxiliary labels Badge, status label, logo-like mark, section marker Top corners can work here only. Do not use top-left/top-right as the default home for primary opening titles or chapter titles.

Use the MG's intrinsic form constraints, not final canvas placement, when deciding asset shape. Good examples: "lower-third-style name tag", "compact side treatment", "bottom horizontal strip", "full-screen title beat". Do not bake final canvas coordinates into the asset unless the MG is intentionally full-frame.

For familiar forms like speaker name tags, give the form and content without forcing dimensions early. For constrained overlays, describe the intended rough form or usable area. For full-screen MGs, make the form explicit in Size & shape and choose Background: opaque.

From the target screenshot, include canvas tone only when it affects legibility: for example, Other context: dark interior scene — keep the design bright/light enough to read clearly.

4. Background

Choose background from the form:

  • Use Background: transparent for talking-head overlays: lower-thirds, side treatments, quote treatments, compact diagrams, and other graphics that sit over A-roll. A transparent root may still contain internal semi-transparent or solid panels.
  • Use Background: opaque when the MG is its own visual surface: full-screen opening titles, strong chapter beats, full-screen information layouts, and full-screen emphasis moments.
  • For full-screen opaque MGs, do not add a separate solid item underneath as a color matte. The MG owns the frame; change its bgColor / transparentBackground properties instead. Do not create temporary solid fallbacks; if you encounter an old transparent-MG-plus-solid fallback while replacing it with an opaque generated MG, delete both fallback pieces, not only the old MG.

Default to a transparent overlay unless a full-screen beat is intended — guessing full-screen/opaque silently is what covers the speaker's face or blanks the frame.

Place and review

  • Place with edit_item (adds/updates). Prefer an explicit rectangle once you know the frame: left/top/width/height for direct placement, or right/bottom/width/height when right/bottom margins are clearer.
    • left — explicit x position. right — margin from the canvas right edge. Do not pass both.
    • top — explicit y position. bottom — margin from the canvas bottom edge, symmetric with right, e.g. { right: 80, bottom: 150, width: 500, height: 350 } for a bottom-right overlay. Caption-safe defaults: bottom: 162 (landscape 1080p) or bottom: 576 (portrait 1080×1920). Do not pass both top and bottom.
  • Use a natural-box asset for overlays: the MG asset width / height should tightly bound the local visible composition, not the project canvas. Place and scale that local asset on the timeline. Use timeline-sized assets only when the visible design intentionally spans the whole frame.
  • Asset dimensions from track_progress / project state are practical aids for resizing and placement, not the final judge.
  • Verify with screenshots. Pass multiple frames in one tool call — settled state appears alongside any transient mid-animation frames. Compare frames before concluding: apparent truncation, missing elements, or "broken design" visible in only some of the batch is animation, not a real flaw. If unclear, re-capture more frames around the suspect one before adjusting anything. Judge from the settled frames. For multiple placed MGs, batch their settled frames into a single call.
  • Check the full frame: face/head is clear, important objects and gestures are clear, caption zone is clear when relevant, MG is fully visible, MG content is correct, text is legible, no readable text overlaps, and the composition feels balanced and intentional.
  • If it fails, first adjust position and size. If position/size cannot make it work, edit the asset or change the design form. Verify each intentionally recurring component on a target frame before expanding it.

B-roll

Goal

Enrich visual layers and cover jump cuts left by A-roll editing.

Where B-roll is useful

  • Cover jump cuts — when A-roll editing leaves visible jump cuts the user wants to hide
  • Visualize specific references — when the speaker mentions objects or scenes that benefit from showing

B-roll depends on having suitable footage and adds production effort — treat it as an optional enhancement, not a default. Apply only when the user opts in or there's a clear visual problem to solve.

Sources

Footage can come from three places: clips already in the project library, stock via search_stock_media then push_asset with the returned import args, or AI generation via the video-gen skill (Seedance 2.0, Plus-only). Pick based on the user's need; if unclear, align with the user upfront.

How to place

Don't cut away in the first or last 3 seconds. For dense jump cuts (<3s apart), use one long cutaway covering multiple. Don't overlap with MG by default.

First decide the B-roll mode:

  • Full-screen cutaway replaces the talking head for that moment. Use it when the user asks to show the B-roll full screen, cover jump cuts, or the B-roll needs the full frame to be readable.
  • PiP / small-window overlay keeps the talking head visible. Use it when the user asks for overlay/PiP, the existing edit style clearly uses small-window B-roll, the user says the talking head can remain visible, or the B-roll is a quick supporting visual.

If the user only says "add B-roll" and the mode is not implied by the existing edit, ask once: "Should these be full-screen cutaways or small rounded-corner PiP overlays?"

For PiP / small-window overlay:

  1. Inspect the target timeline frame first. Compare candidate destination rectangles in the actual shot. Exclude areas that would cover the A-roll's face/head, mouth, important gestures, captions/subtitles, existing overlays, products/logos, or other visible subjects. Among safe candidates, choose a rectangle that can show the B-roll at a useful readable size, preferring the largest blank or low-information area while keeping the composition balanced.
  2. Inspect the B-roll source frame(s). Identify the primary subject/action, protected information, and safe-to-lose areas. Any readable text/UI, name/title, logo, brand strip, product edge, card, poster, or document boundary is protected by default unless the user explicitly approves losing that exact information.
  3. Place the overlay at a useful size inside the chosen destination rectangle. Keep the B-roll's protected information visible/readable and the A-roll's protected content unobstructed. Do not default to a fixed corner or lower-third position when another candidate has more usable empty area.
  4. Set the media item's native borderRadius to 24-36 by default unless the requested style is square/sharp. Do not add a mask/effect solely for ordinary rounded PiP corners; use effects only for special shapes or item types that cannot use native borderRadius.
  5. Screenshot the affected frame before reporting success. If the only non-obstructive PiP would be too small to understand, switch to full-screen cutaway, choose a different source moment/asset, or ask the user to choose the trade-off.

For full-screen cutaway:

  1. Compare the source aspect ratio with the canvas aspect ratio before choosing fit; do not default to cover without this check. For close aspect ratios, such as portrait source into portrait canvas or landscape into landscape with less than about 30% difference, use a full-canvas fit:"cover" first-pass so the B-roll owns the visual beat.
  2. For substantially different aspect ratios, such as landscape media in a vertical canvas or vertical media in a landscape canvas, do not place directly with cover. Inspect the source with view_asset_frames before choosing fit if you have not already viewed it. Use read_av_script to choose representative video moments and the visual skill when the protected region is not obvious.
  3. Identify whether protected information would be distributed across the area that cover would crop. Any readable text/UI, name/title, logo, brand strip, product edge, card, poster, document boundary, or subject on both sides of the frame is protected by default.
  4. After inspection, cover or safe crop is acceptable only if protected information would survive the crop, such as a single centered subject with low-information edges. Low-information contextual media, such as scenery, crowd shots, or other mood/context footage with no specific text or subject that must be preserved, can use cover even with a substantial aspect-ratio difference.
  5. If protected information would be lost, such as text/logos near edges, subjects on both sides, or a wide information layout like a fixture table or match poster, use fit:"contain" for the foreground and add a deliberate full-screen background such as an opaque MG background/matte that matches the edit or a blurred/enlarged duplicate/background layer. If a cover attempt only trims a compact subject/action that can be recovered without hiding other protected information, try a safer reframe/crop that moves the source protection frame fully into the canvas and closer to the intended center of attention.
  6. Apply the fit strategy per source asset, not as a batch default. Even when the user asks for cutaways, do not batch-place multiple images or clips with fit:"cover" without checking each source's aspect ratio and protected content first.
  7. Screenshot the final frame and compare it with the inspected source frame(s). Verify that the foreground still preserves the source's protected information, not just that the final canvas looks filled.

After editing, read back the exact item ids you changed. An asset appearing in the library is not proof it is on the timeline; read_project must show the new/updated B-roll items. If the result involved crop, fit, scale, overlay placement, or a full-screen composition trade-off, verify the affected frame with a screenshot or visual analysis before reporting success, then fix failed source/destination protection or state the unavoidable trade-off. Do not report success if the target items are unchanged.


Multicam (multiple camera angles of the same take)

When the user has two or more cameras recording the same moment — cues like "both angles", "the same interview", "multi angles", "alternate angle", "cut to the other angle", "angle switch", 换角度, 两个机位 — switching to another angle means the picture changes but the audio and lip-sync must stay matched to the take.

Do not hand-compute source offsets with edit_item to line angles up. Manual offsets drift wherever the underlying reference angle was cut, and the drift only shows up later as out-of-sync lips. Use the multicam_sync tool instead: it runs the editor's audio-based alignment engine and repositions each angle clip so its picture matches the reference angle's audio. Pass the angle clips' itemIds (the reference plus the follower angle(s)); optionally name the referenceItemId.

Key constraint: a single cutaway clip that spans a cut in the reference angle can't be aligned as one piece — split it at that cut with split_item first, then pass both pieces to multicam_sync so each maps to the reference segment beneath it.

multicam_sync runs in the user's editor (no backend path): if it reports the editor isn't open, ask the user to open the project, then retry. After it applies, read the project back to confirm the alignment.


Track roles (turn on auto-ducking)

A track's role is the single declaration that drives the audio mix. Set it with edit_track and the engine derives a seamless duck — followers dip under speech, then rise back in the gaps — without you hand-adjusting any volume. There are only two roles, plus off:

  • The talking / interview / lecture track (and any voiceover / narration) is the anchor: set its role to anchor. This is the track everything else ducks under — set it, or nothing ducks.
  • Background music, ambient beds, and b-roll audio beds that should sit under speech → the follower: set role: follower (auto-ducks under every anchor).
  • Short sound effects (SFX), stingers, hits, whooshes, clicks, and other editorial accents usually stay out of ducking → leave their track role unset unless the user explicitly wants those accents tucked under speech.
  • Anything that should stay out of ducking → leave its role unset (none).

A track with no role behaves exactly as today — roles are additive and safe, so you only set them where the content makes the job obvious.

Read the existing layout first. Before creating tracks or placing new clips, read the current track names and roles — if a track is already tagged for this content (a follower named "Music", an anchor named "VO"), put the new clip there and match its role; only make a new track when nothing fits. Organize before you assign — roles are per-track, so aim for one role per track. If the same kind of content is scattered across several tracks (e.g. the voice on A1 and A3), consolidate it onto one track first: move the clips with edit_item (updates[].trackId), then delete the emptied track by id with edit_track. Then assign the role once. While you're laying tracks out, stack them the way a mixer reads a session — voice/VO on A1, the top audio lane; music below it — and give each a short name like "VO" or "Music" so the spoken word stays easy to find. A sensible default, not a rule; follow the user's intent when the layout should differ. Keep deliberate separation, though — two different speakers, clips that overlap in time, or intentional layering each stay on their own track (and each still gets its role). After assigning, read the project back to confirm every track that should anchor/duck does, and that you left the music's base volume alone.


Background Music

Goal

Set the mood and smooth over micro-gaps in speech.

Principles

  • Set the music track's role to follower with edit_track (and the talking track's role to anchor). That single pair turns on auto-ducking — the engine dips the music under speech and lifts it back in the gaps.
  • Let edit_track initialize audioRouting.duckDepthDb from the current timeline loudness when it can. Pass audioRouting.duckDepthDb yourself only when the user explicitly wants the music louder or softer under speech.
  • Keep the BGM clip's base decibelAdjustment natural by default. Do not pre-duck music with a large negative clip gain, then also set manual duckDepthDb; only do both when the user explicitly asks for a lower overall bed and a stronger / weaker speech duck.
  • Do not put short sound effects (SFX) or stingers on follower tracks by default. Place them at their editorial moment and adjust item volume only if they are clearly too loud or too quiet.
  • No prominent lyrics
  • Fade BGM in/out with audioFadeIn / audioFadeOut in seconds, usually 1-2 seconds. Do not pass frame counts to these fields.
  • Tone matches content

Fit to duration

Fit BGM to the final video extent after A-roll timing is finalized. The target duration runs from the BGM start to the real content end (video / visual / speech items), excluding the BGM itself so music never extends the render.

  • Unless the user specifies a different BGM start, start BGM at frame 0.
  • If generated BGM is longer than the target, place one audio item at the BGM start, set its duration to the target duration, and add a fade out. Do not let the full music asset run past the last visual item.
  • If generated BGM is shorter than the target, do not stretch one audio item past the asset length; it will end in silence. Instead, tile multiple audio items until the target is covered.
  • Before placing tiled BGM, calculate how many segments are needed to cover the full target duration, accounting for the planned 1-2 second overlaps. Place all segments in one pass so the whole timeline is covered, then trim the final segment to the target end.
  • For tiled BGM, use alternating audio tracks (for example A2/A3) so adjacent repeats can overlap by 1-2 seconds. Fade out the earlier segment and fade in the next segment over the overlap.

How the engine ducks music

Ducking is automatic once the music track's role is follower: the engine dips the track under audible anchor tracks (the speech / voice), and lifts it back to full level in pauses and the outro. This needs both halves — the music track has role: follower and the talking track has role: anchor (see Track roles above). If nothing is set to anchor, nothing ducks and the music stays at full level.

Set music to a normal, audible base level where there is no speech. To tune the dip under speech, update the follower track's audioRouting.duckDepthDb; otherwise leave it unset and let edit_track auto-initialize from timeline loudness when available. Do not solve speech clarity by heavily lowering the clip and also manually deepening the duck. To keep a track out of ducking entirely (for example a stinger that should punch through), leave its role unset (none).


Captions

Goal

Improve accessibility and engagement with on-screen text.

Captions are transcribed from the source audio — they always match the speaker's language. Translation between languages is not supported. Don't ask the user what language they want captions in; pick the preset by source audio language + target aspect ratio.

Presets

Use only built-in edit_captions preset names. There is no youtube or vox caption preset; platform names describe the target video, not a preset name.

Source audio language Aspect Ratio Recommended Preset
English Portrait 9:16 tiktok or submagic
English Landscape 16:9 studio or submagic
Chinese Any netflix

Home - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-07-21 03:45
浙ICP备14020137号-1 $Map of visitor$