Editor de Video AI — Referencia de Control del Agente
⚠️ ENCONTRAR editorctl — OBLIGATORIO (lee esto primero)
editorctl es la CLI de Monet. Inténtala directamente primero — Monet la mantiene en el PATH para cada shell que inicia y persiste el directorio bin en ~/.zshrc / ~/.bash_profile, por lo que sobrevive a sub-shells y envoltorios que reescriben el PATH. Si command -v editorctl no devuelve nada, recurre en orden:
"$HOME/Library/Application Support/Monet/bin/editorctl"— instalación en macOS (la mayoría de usuarios)node /Applications/Monet.app/Contents/Resources/app.asar.unpacked/out/cli/cli/editorctl.js …node ./out/cli/cli/editorctl.js …— árbol de desarrollo
Nunca te rindas después del primer "comando no encontrado". Prefiere editorctl sobre curl localhost:51847 sin formato — siempre expone la superficie de comando actual y las formas de los argumentos.
⚠️ NOMBRADO DE ARCHIVOS DE SALIDA — OBLIGATORIO (lee esto primero)
Nunca reutilices un nombre de archivo al editar o regenerar un video o imagen. La caché de activos retiene el archivo anterior por ruta, por lo que escribir en el mismo nombre muestra contenido obsoleto de forma silenciosa. Cada edición/regeneración debe producir un nuevo nombre de archivo único (por ejemplo, clip_v1.mp4, clip_v2.mp4, o un sufijo de marca de tiempo). Se aplica a todas las representaciones de video, generaciones de imágenes, exportaciones de lienzo y miniaturas. Si una ruta de destino ya existe, añade _v2, _v3, … — no sobrescribas.
⚠️ AUDIO EN LÍNEAS DE TIEMPO DE MÚLTIPLES CLIPS — OBLIGATORIO
Al añadir audio a una línea de tiempo con más de un clip de video, el audio se corta en cada límite de clip. Flujo requerido:
- Informa al usuario: "Para evitar que el audio se corte entre clips, primero fusionaré todos los clips de video en un solo video combinado y luego añadiré el audio. ¿Procedo?"
- Espera la confirmación — no combines automáticamente.
- Concatena todos los clips en un solo archivo nuevo (nombre único según la regla anterior).
- Reemplaza la pista de video de múltiples clips con ese clip combinado, luego añade el audio.
Líneas de tiempo de un solo clip: omite la fusión.
⚠️ MODO LIENZO — REGLAS OBLIGATORIAS (lee esto primero)
Cuando activeView=canvas es reportado por el hook o editorctl get-state:
Hay EXACTAMENTE 3 opciones de lienzo. No existen otras.
- Paper.js — dibujo con código y gráficos vectoriales (
canvas-run-paperjs) - Matter.js — física y animación (
canvas-run-matterjs) - GPT image 2 — imagen generada por IA (
generate-image+canvas-add-image)
ELIMINADAS — NO ofrezcas estas bajo ningún nombre:
Modo de diseño— eliminadoCapas editables— eliminadoDiseño tipo Figma— eliminadoDiseño basado en nodos— eliminadoDiseño directo en lienzo— eliminado
Cuando el usuario pida algo visual en modo lienzo, presenta SOLO estas tres opciones usando estas ETIQUETAS EXACTAS. Cópialas textualmente. No inventes una cuarta opción ni reformules la opción 1 como algo relacionado con diseño.
Puente API: POST http://localhost:51847 — Cuerpo JSON {"command":"<nombre>","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") # → lista completa de comandos
Comandos
Proyecto / Configuración
| Comando | Argumentos | Devuelve |
|---|---|---|
get_project | — | JSON completo del proyecto |
get_settings | — | Configuración del modelo + proveedor |
Activos
| Comando | Argumentos | Devuelve |
|---|---|---|
list_assets | — | [{id, name, path, type, duration, semantic}] |
get_asset | assetId | Activo individual con semántica + transcripción |
import_files | paths: string[] | Registros de activos importados |
transcribe_asset | assetId, language? | {segments} mediante Whisper |
embed_assets | all?: bool | {embedded, total} mediante text-embedding-3-small |
search_media | query, limit? | Búsqueda por similitud de coseno (recurre a palabras clave) |
search_spoken | query, limit? | Búsqueda de subcadenas en segmentos transcritos |
Secuencias y Pistas
| Comando | Argumentos | Devuelve |
|---|---|---|
list_sequences | — | Todas las secuencias |
create_sequence | name | Nueva secuencia |
activate_sequence | sequenceId | Secuencia activada |
get_tracks | — | [{id, name, kind, clipCount}] para la secuencia activa |
add_track | `kind: video | audio |
Clips
| Comando | Argumentos | Devuelve |
|---|---|---|
list_clips | sequenceId? | Todos los clips ordenados por startTime, con 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? | Clip actualizado |
split_clip | clipId, time | Secuencia actualizada |
duplicate_clip | clipId, offsetSeconds? | {clipId, clip} |
update_clip_label | clipId, label | {success} |
Efectos y Propiedades
| Comando | Argumentos | Devuelve |
|---|---|---|
list_effects | — | Efectos disponibles + documentación de parámetros |
add_effect | clipId, effectType, parameters | Proyecto actualizado |
remove_effect | clipId, effectId | Proyecto actualizado |
set_speed | clipId, speed | Proyecto actualizado (reproducción 0.1–10×) |
set_volume | clipId, volume | Proyecto actualizado (0–4, 1=normal) |
set_transition | `clipId, side: in | out, type, duration?` |
Historial
| Comando | Argumentos |
|---|---|
undo | — |
redo | — |
Tipos de Efecto
| Tipo | Parámetros |
|---|---|
fade_in | duration (seg) |
fade_out | duration (seg) |
color_grade | brightness (-1→1), contrast (0.5→2), saturation (0→3) |
blur | radius (px, por defecto 5) |
sharpen | amount (0→3, por defecto 1) |
Tipos de Transición
crossfade · dip_to_black · wipe · slide
Conceptos Clave
inPoint= posición en el archivo fuente donde comienza la reproducción del clipstartTime= posición en la línea de tiempo donde se coloca el clipduration= cuánto tiempo se reproduce el clip (puede ser más corto que el origen)- Cada mutación envía instantáneamente
project:updated→ la interfaz refleja los cambios en vivo - Los efectos se previsualizan en tiempo real (CSS) y se aplican mediante FFmpeg en la exportación
Reglas de Seguridad de Edición
- Trata los espacios vacíos en la línea de tiempo como un error a menos que el usuario solicite explícitamente una pausa, un tiempo o un espacio negro.
- Después de crear una secuencia o mover clips, verifica la continuidad con
list_clips(sequenceId)y comprueba que cada clip comience exactamente cuando termina el clip anterior si la edición debe ser continua. - No asumas que
create_sequenceoactivate_sequencees suficiente por sí solo. Siempre verifica la secuencia activa después conlist_sequencesoget_project. - Al construir un corte destacado con voz, mueve video, audio, subtítulos y marcadores juntos. No dejes subtítulos o marcadores en tiempos antiguos después de ajustar la edición.
- Si la reproducción parece detenerse entre clips, inspecciona primero la línea de tiempo en busca de espacios vacíos antes de asumir que el reproductor de vista previa está roto.
- Prefiere tiempos de inicio exactos sobre cálculos de desplazamiento acumulativos al ajustar un corte. Recalcula el
startTimeprevisto de cada clip a partir del plan de corte.
Estética de Marca desde una URL
OBLIGATORIO — SIN EXCEPCIONES: Si el mensaje del usuario contiene alguna URL o dominio, DEBES ejecutar los comandos de obtención a continuación y extraer los tokens de marca antes de escribir cualquier código de lienzo/diseño. No uses colores de marca asumidos o memorizados. Obtén primero, diseña después — cada vez. Si la obtención falla, pide al usuario que pegue los valores hexadecimales; nunca recurras a adivinanzas.
curl -sL "<url>" | grep -Eo '(#[0-9a-fA-F]{3,8}|font-family:[^";}]+|font-size:[^";}]+|border-radius:[^";}]+)' | sort -u | head -60
Extrae: colores de fondo, colores de superficie, colores primarios/de acento, colores de texto, familias de fuentes, tamaños/pesos de fuente, radios de borde, espaciado y sombras de caja. También encuentra el logotipo — es la verdad fundamental para los colores de marca y el tono visual. Codifica esos valores exactos — nunca adivines cuando hay una URL real disponible.
# Encontrar logotipo
curl -sL "<url>" | grep -Eo '(src|href)="[^"]*logo[^"]*"' | head -10
curl -sL "<url>" | grep 'og:image'
Lienzo — Marcos de Física Matter.js
Usa canvas_run_matterjs para colocar una escena de física interactiva en vivo en el lienzo.
Herramientas MCP
| Herramienta | Argumentos |
|---|---|
canvas_run_matterjs | id? (id del marco a actualizar), name?, script (cadena JS), 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}]} |
Patrones de script — elige UNO
Patrón A — Autónomo (interfaces enriquecidas, dibujo 2D personalizado, bucle 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'); // ← usa siempre este; nunca crees uno nuevo
canvas.width = W; canvas.height = H;
const ctx = canvas.getContext('2d');
// ... agrega cuerpos, configura mouse ...
function loop() {
Engine.update(engine, 1000/60);
ctx.fillStyle = '#121212'; ctx.fillRect(0, 0, W, H);
// dibuja con ctx
requestAnimationFrame(loop);
}
loop();
Patrón B — Solo cuerpos (la plantilla gestiona engine/render/runner)
// engine, render, width, height y todas las variables de Matter ya están declaradas — NO las redeclares
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 y Render.run se llaman automáticamente después de que este script se ejecute — no los llames aquí
Reglas críticas
Runner.runnecesita dos argumentos:Runner.run(Runner.create(), engine)—Runner.run(engine)con un solo argumento no hace nada en Matter.js 0.20.0- Nunca
element: document.bodyenRender.create— genera un segundo canvas invisible; usacanvas: document.querySelector('canvas')en su lugar - Nunca declares
const engineolet engineen el Patrón B — la plantilla ya tienevar engine; redeclarar conconst/letcausa un SyntaxError que deja el lienzo en blanco silenciosamente - Nunca llames a
Render.run/Runner.runen el Patrón B — la plantilla lo hace después de que tu script se ejecuta; llamarlos dos veces causa velocidad duplicada o renderizado roto - Nunca importes o redeclares variables de Matter en el Patrón B —
Engine,Bodies,Composite, etc. ya están desestructurados;const { Engine } = Matterdará un SyntaxError
Variables globales disponibles en el Patrón B
engine · render · width · height · Engine · Render · Runner · Bodies · Composite · World · Body · Events · Constraint · Mouse · MouseConstraint
CLI
editorctl canvas-add-frame "Nombre" 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 — Composición de Video con React
Usa Remotion para generar activos de video animados (tarjetas de título, tercios inferiores, presentaciones de diapositivas, gráficos en movimiento) e importarlos directamente a la línea de tiempo.
Herramientas MCP
| Herramienta | Argumentos | Devuelve |
|---|---|---|
video_editor_list_remotion_compositions | — | Lista de IDs de composición |
video_editor_render_remotion | compositionId, outputFilename?, props?, durationInFrames?, fps? | {outputPath, assetId} |
CLI
npm run remotion:studio # vista previa en vivo en localhost:3000
npx remotion render remotion/src/index.ts <ID> out.mp4 --props '{"key":"value"}'
Composiciones incorporadas
| ID | Props |
|---|---|
TitleCard | title (str), subtitle? (str), backgroundColor, textColor, accentColor — 150 fotogramas @ 30fps |
Slideshow | images (abs path[]), frameDuration (fotogramas), transitionDuration (fotogramas) — 300 fotogramas @ 30fps |
HtmlInCanvasGlitch | title, subtitle, glitchIntensity (0–40), backgroundColor, textColor, accentColor — 180 fotogramas @ 30fps. Glitch de división RGB mediante <HtmlInCanvas> |
HTML en canvas (Remotion ≥ 4.0.455)
⚠️ Colisión de nombres — lee primero. El
<HtmlInCanvas>de Remotion (esta sección) produce un archivo de video para la línea de tiempo. Los marcos HTML de Monet canvas (canvas-add-frame ... html,canvas_update_frame) producen una escena HTML en vivo en el tablero de la pestaña de lienzo. Sistemas diferentes. Elige por destino: línea de tiempo → Remotion; pestaña de lienzo → marco HTML de Monet. Nunca mezcles los dos en una misma tarea.
Usa <HtmlInCanvas> para dibujar un subárbol DOM en un <canvas> y posprocesarlo con Canvas 2D / WebGL / WebGPU. Ideal para glitch, lupa, CRT, desplazamiento, efectos de matiz.
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() // <-- siempre reaplica
}
<HtmlInCanvas width={1920} height={1080} onPaint={onPaint}>
<YourDomTree />
</HtmlInCanvas>
Reglas:
- Siempre reaplica el valor devuelto por
drawElementImageaelement.style.transformpara que el diseño y la entrada sigan siendo correctos. - Nunca anides
<HtmlInCanvas>dentro de otro — Chrome solo pinta el exterior y Remotion lanza un error. Combina los efectos en un soloonPaint. Config.setChromiumOpenGlRenderer('angle')ya está configurado en
… [truncado para la traducción]