Communitygithub.com

Monet-AI-Editor/Monet

一個由 AI 驅動的影片編輯助手,提供 CLI `editorctl` 來控制 Monet 編輯器,支援專案管理、時間軸編輯、特效、品牌風格提取等功能。

Monet 是什麼?

Monet 是一個智慧影片編輯器 CLI 工具,專為 AI 代理設計,提供完整的影片編輯控制。它透過 `editorctl` 命令列介面操作,支援 macOS 安裝,並自動將執行檔加入 `PATH`。核心功能包括:專案與時間軸管理、素材庫操作(搜尋、轉錄、嵌入)以及進階編輯(剪輯分割、速度調整、色彩校正等)。特別支援 canvas 模式(Paper.js 向量繪圖、Matter.js 物理模擬、GPT 影像生成)和 Remotion 動畫合成。內建多項強制規則,如輸出檔案命名避免覆蓋、多剪輯音訊處理流程、品牌風格從 URL 自動提取等,確保編輯過程穩定可靠。所有操作透過本地 API(http://localhost:51847)即時同步,適合需要自動化影片編輯流程的開發者和 AI 代理。

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

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

AI 影片編輯器 — 代理控制參考

⚠️ 尋找 editorctl — 強制規定(請先閱讀此項)

editorctl 是 Monet 的命令列工具。始終優先直接嘗試它 — Monet 會將其保留在每個 spawned shell 的 PATH 中,並將 bin 目錄持久化到 ~/.zshrc / ~/.bash_profile,使其能存活於 subshell 和 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. 用該合併後的剪輯取代多剪輯影片軌道,然後再加入音訊。

單一剪輯時間軸:跳過合併步驟。


⚠️ 畫布模式(Canvas Mode)— 強制規則(請先閱讀此項)

當 hook 或 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 橋接(API Bridge): POST http://localhost:51847 — JSON body {"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?{segments}(透過 Whisper)
embed_assetsall?: bool{embedded, total}(透過 text-embedding-3-small)
search_mediaquery, limit?餘弦相似度搜尋(降級為關鍵字搜尋)
search_spokenquery, limit?在轉錄片段內進行子字串搜尋

序列與軌道

命令參數回傳值
list_sequences—所有序列
create_sequencename新序列
activate_sequencesequenceId已啟用的序列
get_tracks—作用中序列的 [{id, name, kind, clipCount}]
add_trackkind: video|audio|caption更新後的序列

剪輯

命令參數回傳值
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_transitionclipId, side: in|out, type, duration?{success}

歷史

命令參數
undo—
redo—

特效類型

類型參數
fade_induration(秒)
fade_outduration(秒)
color_gradebrightness(-1→1)、contrast(0.5→2)、saturation(0→3)
blurradius(像素,預設 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 命令並提取品牌標記,才能撰寫任何畫布/設計程式碼。不要使用假設或記憶的品牌顏色。先 fetch,再設計 — 每次都如此。如果 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) — 在 Matter.js 0.20.0 中,單參數 Runner.run(engine) 會靜默無效
  • 在 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                                          # 在 localhost:3000 即時預覽
npx remotion render remotion/src/index.ts <ID> out.mp4 --props '{"key":"value"}'

內建合成

IDProps
TitleCardtitle(字串)、subtitle?(字串)、backgroundColor、textColor、accentColor — 150 幀 @ 30fps
Slideshowimages(絕對路徑[])、frameDuration(幀)、transitionDuration(幀) — 300 幀 @ 30fps
HtmlInCanvasGlitchtitle、subtitle、glitchIntensity(0–40)、backgroundColor、textColor、accentColor — 180 幀 @ 30fps。透過 <HtmlInCanvas> 實現 RGB 分離故障效果

HTML-in-canvas(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') 已在 ...

[截斷以進行翻譯]

相關技能