KI-Videoeditor – Agenten-Steuerungsreferenz
⚠️ editorctl FINDEN – ZWINGEND (zuerst lesen)
editorctl ist das Monet-CLI. Versuche es immer zuerst direkt – Monet stellt es für jede Shell auf den PATH und persistiert das Bin-Verzeichnis in ~/.zshrc / ~/.bash_profile, sodass es Subshells und PATH-überschreibende Wrapper überlebt. Wenn command -v editorctl nichts zurückgibt, falle in dieser Reihenfolge zurück:
"$HOME/Library/Application Support/Monet/bin/editorctl"– macOS-Installation (die meisten Benutzer)node /Applications/Monet.app/Contents/Resources/app.asar.unpacked/out/cli/cli/editorctl.js …node ./out/cli/cli/editorctl.js …– Entwicklungsbaum
Gib niemals nach dem ersten "Befehl nicht gefunden" auf. Bevorzuge editorctl gegenüber rohem curl localhost:51847 – es zeigt immer die aktuelle Befehlsoberfläche und Argumentformen an.
⚠️ AUSGABEDATEINAMENSGEBUNG – ZWINGEND (zuerst lesen)
Verwende niemals einen Dateinamen beim Bearbeiten oder Neugenerieren eines Videos oder Bildes wieder. Der Asset-Cache speichert die vorherige Datei unter dem Pfad, sodass das Schreiben auf denselben Namen stillschweigend veraltete Inhalte anzeigt. Jede Bearbeitung/Neugenerierung muss einen neuen, eindeutigen Dateinamen erzeugen (z. B. clip_v1.mp4, clip_v2.mp4 oder einen Zeitstempel-Suffix). Dies gilt für alle Videorenderings, Bildgenerierungen, Canvas-Exporte und Miniaturansichten. Wenn ein Zielpfad bereits existiert, hänge _v2, _v3, … an – überschreibe nicht.
⚠️ AUDIO AUF MEHRFACH-CLIP-ZEITACHSEN – ZWINGEND
Wenn Audio zu einer Zeitachse mit mehr als einem Videoclip hinzugefügt wird, wird das Audio an jeder Clip-Grenze unterbrochen. Erforderlicher Ablauf:
- Teile dem Benutzer mit: "Damit das Audio nicht zwischen den Clips unterbrochen wird, fasse ich zunächst alle Videoclips zu einem kombinierten Video zusammen und füge dann das Audio hinzu. Einverstanden?"
- Warte auf Bestätigung – führe keine automatische Zusammenführung durch.
- Verkette alle Clips zu einer einzigen neuen Datei (eindeutiger Dateiname gemäß obiger Regel).
- Ersetze die Mehrfach-Clip-Videospur durch den zusammengeführten Clip und füge dann das Audio hinzu.
Bei Einzelclip-Zeitachsen: Überspringe die Zusammenführung.
⚠️ CANVAS-MODUS – ZWINGENDE REGELN (zuerst lesen)
Wenn activeView=canvas vom Hook oder durch editorctl get-state gemeldet wird:
Es gibt GENAU 3 Canvas-Optionen. Andere existieren nicht.
- Paper.js – Code-Zeichnung mit Vektorgrafiken (
canvas-run-paperjs) - Matter.js – Physik und Animation (
canvas-run-matterjs) - GPT image 2 – KI-generiertes Bild (
generate-image+canvas-add-image)
ENTFERNT – Biete diese NICHT unter irgendeinem Namen an:
Designmodus– entferntBearbeitbare Ebenen– entferntFigma-ähnliches Layout– entferntKnotenbasiertes Design– entferntDirektes Canvas-Design– entfernt
Wenn der Benutzer im Canvas-Modus nach etwas Visuellem fragt, präsentiere NUR diese drei Optionen mit diesen EXAKTEN Bezeichnungen. Kopiere sie wörtlich. Erfinde keine vierte Option oder formuliere Option 1 als designbezogen um.
API-Brücke: 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") # → vollständige Befehlsliste
Befehle
Projekt / Einstellungen
| Befehl | Argumente | Rückgabe |
|---|---|---|
get_project | — | Vollständiges Projekt-JSON |
get_settings | — | Modell- + Anbieterkonfiguration |
Assets
| Befehl | Argumente | Rückgabe |
|---|---|---|
list_assets | — | [{id, name, path, type, duration, semantic}] |
get_asset | assetId | Einzelnes Asset mit semantischer + Transkription |
import_files | paths: string[] | Importierte Asset-Datensätze |
transcribe_asset | assetId, language? | {segments} via Whisper |
embed_assets | all?: bool | {embedded, total} via text-embedding-3-small |
search_media | query, limit? | Kosinus-Ähnlichkeitssuche (Fallback auf Schlüsselwort) |
search_spoken | query, limit? | Substring-Suche in transkribierten Segmenten |
Sequenzen & Spuren
| Befehl | Argumente | Rückgabe |
|---|---|---|
list_sequences | — | Alle Sequenzen |
create_sequence | name | Neue Sequenz |
activate_sequence | sequenceId | Aktivierte Sequenz |
get_tracks | — | [{id, name, kind, clipCount}] für aktive Sequenz |
add_track | `kind: video | audio |
Clips
| Befehl | Argumente | Rückgabe |
|---|---|---|
list_clips | sequenceId? | Alle Clips sortiert nach startTime, mit trackKind |
add_clip | assetId, trackId, startTime, duration?, inPoint? | {clipId, clip} |
remove_clip | clipId | {success} |
move_clip | clipId, startTime | {success} |
trim_clip | clipId, inPoint?, duration?, startTime? | Aktualisierter Clip |
split_clip | clipId, time | Aktualisierte Sequenz |
duplicate_clip | clipId, offsetSeconds? | {clipId, clip} |
update_clip_label | clipId, label | {success} |
Effekte & Eigenschaften
| Befehl | Argumente | Rückgabe |
|---|---|---|
list_effects | — | Verfügbare Effekte + Parameterdokumentation |
add_effect | clipId, effectType, parameters | Aktualisiertes Projekt |
remove_effect | clipId, effectId | Aktualisiertes Projekt |
set_speed | clipId, speed | Aktualisiertes Projekt (0,1–10× Wiedergabe) |
set_volume | clipId, volume | Aktualisiertes Projekt (0–4, 1=normal) |
set_transition | `clipId, side: in | out, type, duration?` |
Verlauf
| Befehl | Argumente |
|---|---|
undo | — |
redo | — |
Effekttypen
| Typ | Parameter |
|---|---|
fade_in | duration (Sek.) |
fade_out | duration (Sek.) |
color_grade | brightness (-1→1), contrast (0,5→2), saturation (0→3) |
blur | radius (px, Standard 5) |
sharpen | amount (0→3, Standard 1) |
Übergangstypen
crossfade · dip_to_black · wipe · slide
Wichtige Konzepte
inPoint= Position in der Quelldatei, an der die Clip-Wiedergabe beginntstartTime= Position auf der Zeitleiste, an der der Clip platziert wirdduration= Wie lange der Clip abgespielt wird (kann kürzer als die Quelle sein)- Jede Mutation sendet sofort
project:updated→ UI spiegelt Änderungen live wider - Effekte werden in Echtzeit (CSS) und beim Export via FFmpeg gerendert
Sicherheitsregeln für die Bearbeitung
- Behandle Lücken in der Zeitleiste als Fehler, es sei denn, der Benutzer wünscht ausdrücklich eine Pause, einen Takt oder eine schwarze Lücke.
- Überprüfe nach dem Erstellen einer Sequenz oder dem Verschieben von Clips die Kontinuität mit
list_clips(sequenceId)und stelle sicher, dass jeder Clip genau dort beginnt, wo der vorherige endet, wenn die Bearbeitung durchgehend sein soll. - Gehe nicht davon aus, dass
create_sequenceoderactivate_sequenceallein ausreichen. Überprüfe die aktive Sequenz immer anschließend mitlist_sequencesoderget_project. - Wenn ein gesprochener Highlight-Cut erstellt wird, verschiebe Video, Audio, Untertitel und Marker gemeinsam. Hinterlasse keine Untertitel oder Marker auf alten Zeitpunkten, nachdem der Schnitt gestrafft wurde.
- Wenn die Wiedergabe zwischen Clips anzuhalten scheint, überprüfe zuerst die Zeitleiste auf leere Lücken, bevor du annimmst, dass der Vorschauplayer defekt ist.
- Bevorzuge exakte Zielstartzeiten gegenüber kumulativem Offset-Rechnen, wenn ein Schnitt gestrafft wird. Berechne die beabsichtigte
startTimejedes Clips neu aus dem Schnittplan.
Markenästhetik aus einer URL
ZWINGEND – KEINE AUSNAHMEN: Wenn die Nachricht des Benutzers eine URL oder Domain enthält, MUSST du die untenstehenden Fetch-Befehle ausführen und Markentoken extrahieren, bevor du Canvas-/Designcode schreibst. Verwende keine angenommenen oder auswendig gelernten Markenfarben. Zuerst holen, dann designen – jedes Mal. Wenn der Fetch fehlschlägt, bitte den Benutzer, die Hex-Werte einzufügen; falle niemals auf Raten zurück.
curl -sL "<url>" | grep -Eo '(#[0-9a-fA-F]{3,8}|font-family:[^";}]+|font-size:[^";}]+|border-radius:[^";}]+)' | sort -u | head -60
Extrahiere: Hintergrundfarben, Oberflächenfarben, Primär-/Akzentfarben, Textfarben, Schriftfamilien, Schriftgrößen/-gewichte, Rahmenradien, Abstände und Box-Shadows. Finde auch das Logo – es ist die ultimative Quelle für Markenfarben und visuellen Ton. Hardcode diese exakten Werte – rate niemals, wenn eine echte URL verfügbar ist.
# Logo finden
curl -sL "<url>" | grep -Eo '(src|href)="[^"]*logo[^"]*"' | head -10
curl -sL "<url>" | grep 'og:image'
Canvas – Matter.js Physik-Frames
Verwende canvas_run_matterjs, um eine live-interaktive Physikszene auf dem Canvas zu platzieren.
MCP-Werkzeuge
| Werkzeug | Argumente |
|---|---|
canvas_run_matterjs | id? (Frame-ID zum Aktualisieren), name?, script (JS-String), width?, height? |
canvas_add_frame | name, width, height, mode: 'matterjs' |
canvas_matterjs_scene | style (balls/stacks/pendulum/bridge/ragdoll), gravity?, count?, colors? |
canvas_frames | — → {frames: [{id, name, mode, width, height}]} |
Skriptmuster – wähle EINES aus
Muster A – In sich geschlossen (reichhaltige UIs, benutzerdefiniertes 2D-Zeichnen, rAF-Schleife)
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'); // ← immer dies verwenden; nie ein neues erstellen
canvas.width = W; canvas.height = H;
const ctx = canvas.getContext('2d');
// ... Bodies hinzufügen, Maus einrichten ...
function loop() {
Engine.update(engine, 1000/60);
ctx.fillStyle = '#121212'; ctx.fillRect(0, 0, W, H);
// mit ctx zeichnen
requestAnimationFrame(loop);
}
loop();
Muster B – Nur Bodies (Template verwaltet Engine/Render/Runner)
// engine, render, width, height und alle Matter-Variablen sind bereits deklariert – deklariere sie NICHT neu
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 und Render.run werden nach diesem Skript automatisch aufgerufen – rufe sie hier nicht auf
Kritische Regeln
Runner.runbenötigt zwei Argumente:Runner.run(Runner.create(), engine)–Runner.run(engine)mit einem Argument tut in Matter.js 0.20.0 stillschweigend nichts- Nie
element: document.bodyinRender.create– erzeugt ein unsichtbares zweites Canvas; verwende stattdessencanvas: document.querySelector('canvas') - Nie
const engineoderlet enginein Muster B deklarieren – das Template hat bereitsvar engine; die Neudeklaration mitconst/letverursacht einen SyntaxError, der das Canvas stillschweigend leert - Nie
Render.run/Runner.runin Muster B aufrufen – das Template macht dies nach der Ausführung deines Skripts; der doppelte Aufruf führt zu doppelter Geschwindigkeit oder defektem Rendering - Nie Matter-Variablen in Muster B importieren oder neu deklarieren –
Engine,Bodies,Composite, etc. sind bereits destructuring-entpackt;const { Engine } = Matterwird einen SyntaxError auslösen
Muster B verfügbare Globals
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-Videokomposition
Verwende Remotion, um animierte Video-Assets (Titelkarten, Lower Thirds, Diashows, Bewegungsgrafiken) zu generieren und direkt in die Zeitleiste zu importieren.
MCP-Werkzeuge
| Werkzeug | Argumente | Rückgabe |
|---|---|---|
video_editor_list_remotion_compositions | — | Liste der Kompositions-IDs |
video_editor_render_remotion | compositionId, outputFilename?, props?, durationInFrames?, fps? | {outputPath, assetId} |
CLI
npm run remotion:studio # Live-Vorschau unter localhost:3000
npx remotion render remotion/src/index.ts <ID> out.mp4 --props '{"key":"value"}'
Integrierte Kompositionen
| ID | Props |
|---|---|
TitleCard | title (str), subtitle? (str), backgroundColor, textColor, accentColor – 150 Frames @ 30fps |
Slideshow | images (abs path[]), frameDuration (frames), transitionDuration (frames) – 300 Frames @ 30fps |
HtmlInCanvasGlitch | title, subtitle, glitchIntensity (0–40), backgroundColor, textColor, accentColor – 180 Frames @ 30fps. RGB-Split-Glitch via <HtmlInCanvas> |
HTML-im-Canvas (Remotion ≥ 4.0.455)
⚠️ Namenskonflikt – zuerst lesen. Remotion
<HtmlInCanvas>(dieser Abschnitt) erzeugt eine Videodatei für die Zeitleiste. Monet-Canvas-HTML-Frames (canvas-add-frame ... html,canvas_update_frame) erzeugen eine Live-HTML-Szene im Canvas-Tab-Artboard. Unterschiedliche Systeme. Wähle nach Ziel: Zeitleiste → Remotion; Canvas-Tab → Monet-HTML-Frame. Mische die beiden niemals in einer Aufgabe.
Verwende <HtmlInCanvas>, um einen DOM-Unterbaum in ein <canvas> zu zeichnen und mit Canvas 2D / WebGL / WebGPU nachzubearbeiten. Am besten geeignet für Glitch-, Lupen-, CRT-, Displacement-, Farbton-Dreheffekte.
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() // <-- immer erneut anwenden
}
<HtmlInCanvas width={1920} height={1080} onPaint={onPaint}>
<YourDomTree />
</HtmlInCanvas>
Regeln:
- Immer den Rückgabewert von
drawElementImageaufelement.style.transformanwenden, damit Layout/Input korrekt bleiben. - Nie
<HtmlInCanvas>in ein anderes verschachteln – Chrome zeichnet nur das äußere und Remotion wirft einen Fehler. Führe Effekte in einem einzigenonPaintzusammen. Config.setChromiumOpenGlRenderer('angle')ist bereits inpackage.jsongesetzt.