Communitygithub.com

Monet-AI-Editor/Monet

`editorctl` は Monet CLI です。常に直接試してください — Monet は生成するすべてのシェルで PATH に保持し、bin ディレクトリを `~/.zshrc` / `~/.bash_profile` に永続化するため、サブシェルや PATH を書き換えるラッパーでも機能します。**`command -v editorctl` が何も返さない場合**は、以下の順序でフォールバックしてください。

Monet とは?

Monet-AI-Editor/Monet は、AI ビデオエディタのエージェント制御を提供するスキルです。`editorctl` という CLI ツールを中心に、プロジェクト管理、アセット操作、シーケンス編集、エフェクト適用、キャンバスモード、Remotion を使った動画合成など、映像制作の全工程をコードベースで操作できます。このスキルは、Claude Code などの AI エージェントが Monet アプリケーションと連携し、ユーザーの指示に基づいて自動的にビデオ編集タスクを実行するためのものです。主な機能として、ファイルの出力名の重複を防ぐ命名規則、複数クリップタイムラインへの音声追加時のマージフロー、キャンバスモードでの 3 種類のオプション(Paper.js / Matter.js / GPT image 2)の提示、ブランドカラーの自動抽出、Matter.js を使った物理アニメーション、Remotion を使った React ベースの動画合成などが含まれます。API は `POST http://localhost:51847` 経由の JSON-RPC スタイルで、`editorctl` が常に最新のコマンドサーフェスを提供します。

対応~Claude Code~Codex CLI~Cursor
npx skills add Monet-AI-Editor/Monet

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

AI ビデオエディタ — エージェント制御リファレンス

⚠️ editorctl の検索 — 必須(最初に読むこと)

editorctl は Monet CLI です。常に直接試してください — Monet は生成するすべてのシェルで PATH に保持し、bin ディレクトリを ~/.zshrc / ~/.bash_profile に永続化するため、サブシェルや 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」で諦めないでください。curl localhost:51847 の代わりに editorctl を優先してください。常に現在のコマンドサーフェスと引数の形状を公開します。

⚠️ 出力ファイルの命名 — 必須(最初に読むこと)

ビデオや画像を編集・再生成する際に、ファイル名を再利用しないでください。 アセットキャッシュはパスで前のファイルを保持するため、同じ名前で書き込むと古いコンテンツが静かに表示されます。編集・再生成のたびに新しい一意のファイル名(例:clip_v1.mp4、clip_v2.mp4、またはタイムスタンプのサフィックス)を生成する必要があります。すべてのビデオレンダリング、画像生成、キャンバスエクスポート、サムネイルに適用されます。ターゲットパスがすでに存在する場合は、_v2、_v3、… を追加してください — 上書きしないでください。

⚠️ マルチクリップタイムラインでのオーディオ — 必須

複数のビデオクリップがあるタイムラインにオーディオを追加する場合、オーディオはクリップ境界ごとに途切れます。必要なフロー:

  1. ユーザーに伝える:「クリップ間でオーディオが途切れないように、最初にすべてのビデオクリップを1つの結合ビデオにマージしてから、オーディオを追加します。続行してもよろしいですか?」
  2. 確認を待つ — 自動マージしないでください。
  3. すべてのクリップを連結して、1つの新しいファイル(上記のルールに従って一意のファイル名)を作成します。
  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 スタイルのレイアウト — 削除
  • ノードベースのデザイン — 削除
  • 直接キャンバスデザイン — 削除

ユーザーがキャンバスモードで視覚的なものを求めた場合、これら3つのオプションのみを、これらの正確なラベルで提示してください。そのままコピーしてください。4つ目のオプションを考案したり、オプション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?: booltext-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 またはドメインが含まれている場合、キャンバス/デザインコードを書く前に、以下のフェッチコマンドを実行し、ブランドトークンを抽出する必要があります。想定または記憶したブランドカラーを使用しないでください。毎回、まずフェッチし、次にデザインしてください。フェッチが失敗した場合は、ユーザーに HEX 値を貼り付けるように依頼してください。推測にフォールバックしないでください。

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 には2つの引数が必要: Runner.run(Runner.create(), engine) — 単一引数の Runner.run(engine) は Matter.js 0.20.0 では静かに何もしません
  • Render.create で element: document.body を使用しない — 見えない2つ目のキャンバスが生成されます。代わりに canvas: document.querySelector('canvas') を使用してください
  • パターン B で const engine や let engine を宣言しない — テンプレートはすでに var engine を持っています。const/let で再宣言すると SyntaxError が発生し、キャンバスが静かに空白になります
  • パターン B で Render.run / Runner.run を呼び出さない — テンプレートはスクリプトの実行後にこれを実行します。2回呼び出すと、2倍の速度またはレンダリングの破損を引き起こします
  • パターン 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 フレーム。1つのタスクで両方を混在させないでください。

<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 はエラーをスローします。エフェクトを1つの onPaint にマージしてください。
  • Config.setChromiumOpenGlRenderer('angle') はすでに設定されています。

関連スキル