Communitygithub.com

Monet-AI-Editor/Monet

`editorctl` 是 Monet CLI。始终优先直接尝试它——Monet 会将其保留在每个 shell 的 `PATH` 中,并将 bin 目录持久化到 `~/.zshrc` / `~/.bash_profile`,以确保它在子 shell 和重写 PATH 的包装器中仍可用。**如果 `command -v editorctl` 无返回**,则按顺序回退:

Monet 是什么?

Monet 是一个 AI 驱动的视频编辑器代理控制工具,专为开发者和 AI 代理设计,通过命令行界面 (CLI) 或 HTTP API 桥接实现自动化视频编辑。该技能的核心是 `editorctl` CLI 工具,它提供了一套丰富的命令,用于管理项目、资产、序列、轨道、剪辑、特效和历史操作。主要特点包括:强制性的输出文件命名规则以避免缓存冲突,多剪辑时间线上的音频处理流程,以及精确的三种 Canvas 模式(Paper.js、Matter.js 和 GPT image 2),用于创建矢量图形、物理动画或 AI 生成的图像。它还集成了 Remotion,用于生成更复杂的 React 视频合成(如标题卡、幻灯片),并提供了从 URL 提取品牌设计令牌的机制。其工作模式主要基于对本地端口 51847 的 HTTP POST 请求(JSON 格式),或直接使用 `editorctl` 命令。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add Monet-AI-Editor/Monet

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

AI 视频编辑器 — 代理控制参考

⚠️ 查找 editorctl — 强制阅读(请先阅读此节)

editorctl 是 Monet CLI。始终优先直接尝试它——Monet 会将其保留在每个 shell 的 PATH 中,并将 bin 目录持久化到 ~/.zshrc / ~/.bash_profile,以确保它在子 shell 和重写 PATH 的包装器中仍可用。如果 command -v editorctl 无返回,则按顺序回退:

  1. "$HOME/Library/Application Support/Monet/bin/editorctl" — macOS 安装(大多数用户)
  2. node /Applications/Monet.app/Contents/Resources/app.asar.unpacked/out/cli/cli/editorctl.js …
  3. node ./out/cli/cli/editorctl.js … — 开发树

永远不要在第一次出现 "command not found" 后就放弃。优先使用 editorctl 而不是原始的 curl localhost:51847——它始终暴露当前的命令表面和参数形状。

⚠️ 输出文件命名 — 强制阅读(请先阅读此节)

在编辑或重新生成视频或图像时,切勿重复使用文件名。 资产缓存会按路径保留之前的文件,因此写入相同名称会静默显示陈旧的内容。每次编辑/重新生成都必须产生一个新的唯一文件名(例如 clip_v1.mp4、clip_v2.mp4,或时间戳后缀)。适用于所有视频渲染、图像生成、画布导出和缩略图。如果目标路径已存在,请附加 _v2、_v3 … — 不要覆盖。

⚠️ 多剪辑时间线上的音频 — 强制阅读

当向包含多个视频剪辑的时间线添加音频时,音频会在每个剪辑边界处中断。必需流程:

  1. 告诉用户:"为了避免音频在剪辑之间中断,我会先将所有视频剪辑合并为一个组合视频,然后再添加音频。可以继续吗?"
  2. 等待确认——不要自动合并。
  3. 将所有剪辑连接成一个新的单一文件(根据上述规则使用唯一文件名)。
  4. 用该合并后的剪辑替换多剪辑视频轨道,然后添加音频。

单剪辑时间线:跳过合并。


⚠️ 画布模式 — 强制规则(请先阅读此节)

当钩子或 editorctl get-state 报告 activeView=canvas 时:

恰好有 3 个画布选项。不存在其他选项。

  1. Paper.js — 使用矢量图形进行代码绘图 (canvas-run-paperjs)
  2. Matter.js — 物理和动画 (canvas-run-matterjs)
  3. GPT image 2 — AI 生成的图像 (generate-image + canvas-add-image)

已移除——不要以任何名称提供这些选项:

  • 设计模式 — 已移除
  • 可编辑图层 — 已移除
  • 类 Figma 布局 — 已移除
  • 基于节点的设计 — 已移除
  • 直接画布设计 — 已移除

当用户在画布模式下要求视觉内容时,仅提供这三个选项,并使用这些确切的标签。逐字复制它们。不要发明第四个选项,也不要将选项 1 重新表述为与设计相关的任何内容。


API 桥接: POST http://localhost:51847 — JSON 主体 {"command":"<name>","args":{...}}

import urllib.request, json

def call(command, **args):
    data = json.dumps({"command": command, "args": args}).encode()
    req = urllib.request.Request(
        "http://localhost:51847", data=data,
        headers={"Content-Type": "application/json"}, method="POST"
    )
    return json.loads(urllib.request.urlopen(req).read())["result"]

call("ping")   # → {"status":"ok","version":"1.0.0","port":51847}
call("help")   # → 完整命令列表

命令

项目/设置

命令参数返回
get_project—完整项目 JSON
get_settings—模型 + 提供者配置

资产

命令参数返回
list_assets—[{id, name, path, type, duration, semantic}]
get_assetassetId单个资产及其语义和转录
import_filespaths: string[]已导入的资产记录
transcribe_assetassetId, language?通过 Whisper 的 {segments}
embed_assetsall?: bool通过 text-embedding-3-small 的 {embedded, total}
search_mediaquery, limit?余弦相似度搜索(回退到关键词)
search_spokenquery, limit?在转录片段内进行子串搜索

序列和轨道

命令参数返回
list_sequences—所有序列
create_sequencename新序列
activate_sequencesequenceId已激活的序列
get_tracks—活动序列的 [{id, name, kind, clipCount}]
add_track`kind: videoaudio

剪辑

命令参数返回
list_clipssequenceId?按 startTime 排序的所有剪辑,含 trackKind
add_clipassetId, trackId, startTime, duration?, inPoint?{clipId, clip}
remove_clipclipId{success}
move_clipclipId, startTime{success}
trim_clipclipId, inPoint?, duration?, startTime?更新后的剪辑
split_clipclipId, time更新后的序列
duplicate_clipclipId, offsetSeconds?{clipId, clip}
update_clip_labelclipId, label{success}

效果和属性

命令参数返回
list_effects—可用效果 + 参数文档
add_effectclipId, effectType, parameters更新后的项目
remove_effectclipId, effectId更新后的项目
set_speedclipId, speed更新后的项目 (0.1–10× 播放速度)
set_volumeclipId, volume更新后的项目 (0–4, 1=正常)
set_transition`clipId, side: inout, type, duration?`

历史

命令参数
undo—
redo—

效果类型

类型参数
fade_induration (秒)
fade_outduration (秒)
color_gradebrightness (-1→1), contrast (0.5→2), saturation (0→3)
blurradius (px, 默认为 5)
sharpenamount (0→3, 默认为 1)

过渡类型

crossfade · dip_to_black · wipe · slide


关键概念

  • inPoint = 源文件中剪辑开始播放的位置
  • startTime = 时间线上放置剪辑的位置
  • duration = 剪辑播放的时长(可以短于源文件)
  • 每次修改都会立即推送 project:updated → UI 实时反映更改
  • 效果实时预览 (CSS) 并在导出时通过 FFmpeg 烘焙

编辑安全规则

  • 除非用户明确要求暂停、节拍或黑屏间隙,否则将时间线间隙视为错误。
  • 创建序列或移动剪辑后,使用 list_clips(sequenceId) 验证连续性,并检查每个剪辑是否恰好在前一个剪辑结束时开始(如果编辑意图是连续的)。
  • 不要假设 create_sequence 或 activate_sequence 本身已足够。之后始终使用 list_sequences 或 get_project 验证活动序列。
  • 在构建语音精彩片段剪辑时,同时移动视频、音频、字幕和标记。在收紧编辑后,不要将字幕或标记留在旧的时序上。
  • 如果播放似乎在剪辑之间停止,请先检查时间线是否存在空白间隙,然后再假设预览播放器损坏。
  • 在收紧剪辑时,优先使用精确的目标起始时间,而不是累积偏移计算。根据剪辑计划重新计算每个剪辑的预期 startTime。

从 URL 获取品牌美学

强制——无例外:如果用户的消息包含任何 URL 或域名,在编写任何画布/设计代码之前,您必须运行下面的 fetch 命令并提取品牌标记。不要使用假设或记忆的品牌颜色。每次都先获取,后设计。如果获取失败,请用户粘贴十六进制值;切勿回退到猜测。

curl -sL "<url>" | grep -Eo '(#[0-9a-fA-F]{3,8}|font-family:[^";}]+|font-size:[^";}]+|border-radius:[^";}]+)' | sort -u | head -60

提取:背景颜色、表面颜色、主色/强调色、文本颜色、字体系列、字体大小/粗细、边框半径、间距和盒阴影。还要找到徽标——它是品牌颜色和视觉基调和真实依据。硬编码这些确切的数值——当有真实 URL 可用时,切勿猜测。

# 查找徽标
curl -sL "<url>" | grep -Eo '(src|href)="[^"]*logo[^"]*"' | head -10
curl -sL "<url>" | grep 'og:image'

画布 — Matter.js 物理帧

使用 canvas_run_matterjs 将一个实时交互式物理场景放置在画布上。

MCP 工具

工具参数
canvas_run_matterjsid? (要更新的帧 id), name?, script (JS 字符串), width?, height?
canvas_add_framename, width, height, mode: 'matterjs'
canvas_matterjs_scenestyle (balls/stacks/pendulum/bridge/ragdoll), gravity?, count?, colors?
canvas_frames— → {frames: [{id, name, mode, width, height}]}

脚本模式——选择一种

模式 A — 自包含(丰富 UI、自定义 2D 绘制、rAF 循环)

const { Engine, Bodies, Composite, Mouse, MouseConstraint, Events } = Matter;
const W = 390, H = 844;
const engine = Engine.create({ gravity: { y: 1.5 } });
const canvas = document.querySelector('canvas'); // ← 始终使用此方法;切勿创建新的
canvas.width = W; canvas.height = H;
const ctx = canvas.getContext('2d');
// ... 添加物体,设置鼠标 ...
function loop() {
  Engine.update(engine, 1000/60);
  ctx.fillStyle = '#121212'; ctx.fillRect(0, 0, W, H);
  // 使用 ctx 绘制
  requestAnimationFrame(loop);
}
loop();

模式 B — 仅物体(模板管理 engine/render/runner)

// engine, render, width, height, 和所有 Matter 变量已声明——请勿重新声明
var ground = Bodies.rectangle(width/2, height+25, width, 50, { isStatic: true, render: { fillStyle: '#334155' } });
var ball = Bodies.circle(width/2, 50, 30, { restitution: 0.8, render: { fillStyle: '#5b82f7' } });
Composite.add(engine.world, [ground, ball]);
engine.gravity.y = 1;
// Runner.run 和 Render.run 在此脚本运行后自动调用——请勿在此处调用它们

关键规则

  • Runner.run 需要两个参数:Runner.run(Runner.create(), engine) — 单个参数 Runner.run(engine) 在 Matter.js 0.20.0 中静默无效
  • 切勿在 Render.create 中使用 element: document.body — 会生成一个不可见的第二个画布;应使用 canvas: document.querySelector('canvas') 代替
  • 在模式 B 中切勿声明 const engine 或 let engine — 模板已有 var engine;使用 const/let 重新声明会导致 SyntaxError,从而静默地使画布空白
  • 在模式 B 中切勿调用 Render.run / Runner.run — 模板会在您的脚本运行后执行此操作;调用两次会导致双倍速度或渲染损坏
  • 在模式 B 中切勿导入或重新声明 Matter 变量 — Engine, Bodies, Composite 等已解构;const { Engine } = Matter 会导致 SyntaxError

模式 B 可用全局变量

engine · render · width · height · Engine · Render · Runner · Bodies · Composite · World · Body · Events · Constraint · Mouse · MouseConstraint

CLI

editorctl canvas-add-frame "Name" 390 844 matterjs        # matterjs|paperjs|html
editorctl canvas-run-matterjs <frameId> "$(cat script.js)"
editorctl canvas-run-paperjs  <frameId> "$(cat script.js)"
editorctl canvas-run-html     <frameId> "$(cat scene.html)"
editorctl canvas-frames
editorctl canvas-done

Remotion — React 视频合成

使用 Remotion 生成动画视频资产(标题卡、下三分之一、幻灯片、动态图形)并直接导入到时间线。

MCP 工具

工具参数返回
video_editor_list_remotion_compositions—合成 ID 列表
video_editor_render_remotioncompositionId, outputFilename?, props?, durationInFrames?, fps?{outputPath, assetId}

CLI

npm run remotion:studio                                          # 本地预览 at localhost:3000
npx remotion render remotion/src/index.ts <ID> out.mp4 --props '{"key":"value"}'

内置合成

ID参数
TitleCardtitle (str), subtitle? (str), backgroundColor, textColor, accentColor — 150 帧 @ 30fps
Slideshowimages (abs path[]), frameDuration (帧数), transitionDuration (帧数) — 300 帧 @ 30fps
HtmlInCanvasGlitchtitle, subtitle, glitchIntensity (0–40), backgroundColor, textColor, accentColor — 180 帧 @ 30fps。通过 <HtmlInCanvas> 实现 RGB 分离故障效果

画布中的 HTML (Remotion ≥ 4.0.455)

⚠️ 命名冲突——请先阅读。 Remotion <HtmlInCanvas>(本节)为时间线生成一个视频文件。Monet 画布 HTML 帧(canvas-add-frame ... html, canvas_update_frame)在画布选项卡的画板中生成一个实时 HTML 场景。不同的系统。根据目的地选择:时间线 → Remotion;画布选项卡 → Monet HTML 帧。切勿在一个任务中混合使用两者。

使用 <HtmlInCanvas> 将 DOM 子树绘制到 <canvas> 中,并使用 Canvas 2D / WebGL / WebGPU 进行后处理。最适合故障效果、放大镜、CRT、位移、色相旋转等效果。

import { HtmlInCanvas, type HtmlInCanvasOnPaint } from 'remotion'

const onPaint: HtmlInCanvasOnPaint = ({ canvas, element, elementImage }) => {
  const ctx = canvas.getContext('2d')!
  ctx.reset()
  ctx.filter = 'blur(8px)'
  const transform = ctx.drawElementImage(elementImage, 0, 0)
  element.style.transform = transform.toString() // <-- 始终重新应用
}

<HtmlInCanvas width={1920} height={1080} onPaint={onPaint}>
  <YourDomTree />
</HtmlInCanvas>

规则:

  • 始终将 drawElementImage 的返回值重新应用到 element.style.transform,以便布局/输入保持正确。
  • 切勿将 <HtmlInCanvas> 嵌套在另一个内部——Chrome 仅绘制外部的,并且 Remotion 会抛出错误。将所有效果合并到一个 onPaint 中。
  • Config.setChromiumOpenGlRenderer('angle') 已在 ... 中设置

[文档已截断以供翻译]

相关技能