Editor de Vídeo AI — Referência de Controle do Agente
⚠️ ENCONTRANDO editorctl — OBRIGATÓRIO (leia isto primeiro)
editorctl é a CLI do Monet. Sempre tente usá-la diretamente primeiro — o Monet mantém o comando no PATH para cada shell que inicia e persiste o diretório bin em ~/.zshrc / ~/.bash_profile, sobrevivendo a sub-shells e wrappers que reescrevem o PATH. Se command -v editorctl não retornar nada, use as alternativas na ordem:
"$HOME/Library/Application Support/Monet/bin/editorctl"— instalação macOS (mais comum)node /Applications/Monet.app/Contents/Resources/app.asar.unpacked/out/cli/cli/editorctl.js …node ./out/cli/cli/editorctl.js …— árvore de desenvolvimento
Nunca desista após o primeiro "comando não encontrado". Prefira editorctl em vez de curl localhost:51847 bruto — ele sempre expõe a superfície de comandos atual e as formas dos argumentos.
⚠️ NOMEAÇÃO DE ARQUIVOS DE SAÍDA — OBRIGATÓRIO (leia isto primeiro)
Nunca reutilize um nome de arquivo ao editar ou regenerar um vídeo ou imagem. O cache de assets mantém o arquivo anterior pelo caminho, então escrever no mesmo nome exibe silenciosamente conteúdo desatualizado. Cada edição/regeneração deve produzir um novo nome de arquivo único (ex.: clip_v1.mp4, clip_v2.mp4, ou um sufixo de timestamp). Aplica-se a todas as renderizações de vídeo, gerações de imagem, exportações de canvas e miniaturas. Se um caminho de destino já existir, anexe _v2, _v3, … — não sobrescreva.
⚠️ ÁUDIO EM TIMELINES COM MÚLTIPLOS CLIPES — OBRIGATÓRIO
Ao adicionar áudio a uma timeline com mais de um clipe de vídeo, o áudio é cortado em cada limite de clipe. Fluxo obrigatório:
- Informe ao usuário: "Para evitar que o áudio seja cortado entre os clipes, vou mesclar todos os clipes de vídeo em um único vídeo combinado primeiro, e depois adicionar o áudio. Posso prosseguir?"
- Aguarde a confirmação — não faça a mesclagem automaticamente.
- Concatene todos os clipes em um único novo arquivo (nome único conforme a regra acima).
- Substitua a trilha de vídeo com múltiplos clipes pelo clipe mesclado e, em seguida, adicione o áudio.
Timelines com um único clipe: pule a mesclagem.
⚠️ MODO CANVAS — REGRAS OBRIGATÓRIAS (leia isto primeiro)
Quando activeView=canvas for informado pelo hook ou por editorctl get-state:
Existem EXATAMENTE 3 opções de canvas. Nenhuma outra existe.
- Paper.js — desenho com código e gráficos vetoriais (
canvas-run-paperjs) - Matter.js — física e animação (
canvas-run-matterjs) - GPT image 2 — imagem gerada por IA (
generate-image+canvas-add-image)
REMOVIDO — NÃO ofereça estes sob nenhum nome:
Modo design— removidoCamadas editáveis— removidoLayout estilo Figma— removidoDesign baseado em nós— removidoDesign direto no canvas— removido
Quando o usuário pedir algo visual no modo canvas, apresente APENAS estas três opções usando estes RÓTULOS EXATOS. Copie-os literalmente. Não invente uma quarta opção nem reformule a opção 1 como algo relacionado a design.
API Bridge: POST http://localhost:51847 — corpo JSON {"command":"<nome>","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
Projeto / Configurações
| Comando | Argumentos | Retorno |
|---|---|---|
get_project | — | JSON completo do projeto |
get_settings | — | Configuração de modelo + provedor |
Assets
| Comando | Argumentos | Retorno |
|---|---|---|
list_assets | — | [{id, name, path, type, duration, semantic}] |
get_asset | assetId | Asset único com semântica + transcrição |
import_files | paths: string[] | Registros de assets importados |
transcribe_asset | assetId, language? | {segments} via Whisper |
embed_assets | all?: bool | {embedded, total} via text-embedding-3-small |
search_media | query, limit? | Busca por similaridade de cosseno (fallback para palavra-chave) |
search_spoken | query, limit? | Busca por substring em segmentos transcritos |
Sequências e Trilhas
| Comando | Argumentos | Retorno |
|---|---|---|
list_sequences | — | Todas as sequências |
create_sequence | name | Nova sequência |
activate_sequence | sequenceId | Sequência ativada |
get_tracks | — | [{id, name, kind, clipCount}] da sequência ativa |
add_track | `kind: video | audio |
Clipes
| Comando | Argumentos | Retorno |
|---|---|---|
list_clips | sequenceId? | Todos os clipes ordenados por startTime, com 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? | Clipe atualizado |
split_clip | clipId, time | Sequência atualizada |
duplicate_clip | clipId, offsetSeconds? | {clipId, clip} |
update_clip_label | clipId, label | {success} |
Efeitos e Propriedades
| Comando | Argumentos | Retorno |
|---|---|---|
list_effects | — | Efeitos disponíveis + documentação dos parâmetros |
add_effect | clipId, effectType, parameters | Projeto atualizado |
remove_effect | clipId, effectId | Projeto atualizado |
set_speed | clipId, speed | Projeto atualizado (reprodução 0,1–10×) |
set_volume | clipId, volume | Projeto atualizado (0–4, 1=normal) |
set_transition | `clipId, side: in | out, type, duration?` |
Histórico
| Comando | Argumentos |
|---|---|
undo | — |
redo | — |
Tipos de Efeitos
| 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, padrão 5) |
sharpen | amount (0→3, padrão 1) |
Tipos de Transição
crossfade · dip_to_black · wipe · slide
Conceitos Chave
inPoint= posição no arquivo fonte onde a reprodução do clipe começastartTime= posição na timeline onde o clipe é colocadoduration= duração da reprodução do clipe (pode ser menor que a fonte)- Cada mutação envia instantaneamente
project:updated→ a UI reflete as alterações ao vivo - Efeitos são pré-visualizados em tempo real (CSS) e renderizados via FFmpeg na exportação
Regras de Segurança de Edição
- Trate lacunas na timeline como um bug, a menos que o usuário peça explicitamente por uma pausa, batida ou espaço preto.
- Após criar uma sequência ou mover clipes, verifique a continuidade com
list_clips(sequenceId)e confirme que cada clipe começa exatamente onde o anterior termina, se a edição pretende ser contínua. - Não assuma que
create_sequenceouactivate_sequencesão suficientes por si só. Sempre verifique a sequência ativa depois comlist_sequencesouget_project. - Ao criar um corte de destaques falados, mova vídeo, áudio, legendas e marcadores juntos. Não deixe legendas ou marcadores em temporizações antigas após apertar a edição.
- Se a reprodução parecer parar entre clipes, inspecione primeiro a timeline em busca de lacunas vazias antes de assumir que o player de pré-visualização está quebrado.
- Prefira posições iniciais exatas em vez de matemática de deslocamento cumulativo ao apertar um corte. Recalcule o
startTimepretendido de cada clipe a partir do plano de corte.
Estética de Marca a partir de uma URL
OBRIGATÓRIO — SEM EXCEÇÕES: Se a mensagem do usuário contiver qualquer URL ou domínio, você DEVE executar os comandos de busca abaixo e extrair os tokens visuais da marca antes de escrever qualquer código de canvas/design. Não use cores de marca assumidas ou memorizadas. Busque primeiro, desenhe depois — todas as vezes. Se a busca falhar, peça ao usuário para colar os valores hexadecimais; nunca recorra a palpites.
curl -sL "<url>" | grep -Eo '(#[0-9a-fA-F]{3,8}|font-family:[^;"]+|font-size:[^;"]+|border-radius:[^;"]+)' | sort -u | head -60
Extraia: cores de fundo, cores de superfície, cores primárias/de destaque, cores de texto, famílias de fontes, tamanhos/pesos de fonte, raios de borda, espaçamento e sombras de caixa. Encontre também o logotipo — ele é a verdade fundamental para as cores da marca e tom visual. Codifique esses valores exatos — nunca adivinhe quando uma URL real estiver disponível.
# Encontrar logotipo
curl -sL "<url>" | grep -Eo '(src|href)="[^"]*logo[^"]*"' | head -10
curl -sL "<url>" | grep 'og:image'
Canvas — Frames de Física Matter.js
Use canvas_run_matterjs para colocar uma cena de física interativa ao vivo no canvas.
Ferramentas MCP
| Ferramenta | Argumentos |
|---|---|
canvas_run_matterjs | id? (id do frame para atualizar), name?, script (string 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}]} |
Padrões de script — escolha UM
Padrão A — Autossuficiente (UIs ricas, desenho 2D personalizado, loop 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'); // ← sempre use este; nunca crie um novo
canvas.width = W; canvas.height = H;
const ctx = canvas.getContext('2d');
// ... adicione corpos, configure mouse ...
function loop() {
Engine.update(engine, 1000/60);
ctx.fillStyle = '#121212'; ctx.fillRect(0, 0, W, H);
// desenhe com ctx
requestAnimationFrame(loop);
}
loop();
Padrão B — Apenas corpos (o template gerencia engine/render/runner)
// engine, render, width, height e todas as variáveis Matter já estão declaradas — NÃO as redeclare
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 e Render.run são chamados automaticamente após este script — não os chame aqui
Regras críticas
Runner.runprecisa de dois argumentos:Runner.run(Runner.create(), engine)—Runner.run(engine)com um argumento não faz nada silenciosamente no Matter.js 0.20.0- Nunca use
element: document.bodyemRender.create— cria um segundo canvas invisível; usecanvas: document.querySelector('canvas') - Nunca declare
const engineoulet engineno Padrão B — o template já temvar engine; redeclarar comconst/letcausa um SyntaxError que silencia o canvas - Nunca chame
Render.run/Runner.runno Padrão B — o template faz isso após seu script ser executado; chamá-los duas vezes causa renderização em velocidade dobrada ou quebrada - Nunca importe ou redeclare variáveis Matter no Padrão B —
Engine,Bodies,Composite, etc. já estão desestruturados;const { Engine } = Mattercausará SyntaxError
Globais disponíveis no Padrão B
engine · render · width · height · Engine · Render · Runner · Bodies · Composite · World · Body · Events · Constraint · Mouse · MouseConstraint
CLI
editorctl canvas-add-frame "Nome" 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 — Composição de Vídeo em React
Use Remotion para gerar assets de vídeo animados (cards de título, terços inferiores, slideshows, gráficos em movimento) e importá-los diretamente para a timeline.
Ferramentas MCP
| Ferramenta | Argumentos | Retorno |
|---|---|---|
video_editor_list_remotion_compositions | — | Lista de IDs de composição |
video_editor_render_remotion | compositionId, outputFilename?, props?, durationInFrames?, fps? | {outputPath, assetId} |
CLI
npm run remotion:studio # pré-visualização ao vivo em localhost:3000
npx remotion render remotion/src/index.ts <ID> out.mp4 --props '{"key":"value"}'
Composições integradas
| ID | Props |
|---|---|
TitleCard | title (str), subtitle? (str), backgroundColor, textColor, accentColor — 150 frames @ 30fps |
Slideshow | images (caminhos absolutos[]), frameDuration (frames), transitionDuration (frames) — 300 frames @ 30fps |
HtmlInCanvasGlitch | title, subtitle, glitchIntensity (0–40), backgroundColor, textColor, accentColor — 180 frames @ 30fps. Efeito glitch com separação RGB via <HtmlInCanvas> |
HTML no canvas (Remotion ≥ 4.0.455)
⚠️ Conflito de nomenclatura — leia primeiro. O
<HtmlInCanvas>do Remotion (esta seção) produz um arquivo de vídeo para a timeline. Frames HTML do canvas Monet (canvas-add-frame ... html,canvas_update_frame) produzem uma cena HTML ao vivo na prancheta da aba canvas. Sistemas diferentes. Escolha pelo destino: timeline → Remotion; aba canvas → frame HTML do Monet. Nunca misture os dois em uma única tarefa.
Use <HtmlInCanvas> para desenhar uma subárvore DOM em um <canvas> e pós-processar com Canvas 2D / WebGL / WebGPU. Melhor para efeitos de glitch, lupa, CRT, deslocamento, 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() // <-- sempre reaplique
}
<HtmlInCanvas width={1920} height={1080} onPaint={onPaint}>
<YourDomTree />
</HtmlInCanvas>
Regras:
- Sempre reaplique o valor de retorno de
drawElementImageaelement.style.transformpara que layout/input permaneçam corretos. - Nunca aninhe
<HtmlInCanvas>dentro de outro — o Chrome renderiza apenas o externo e o Remotion lança erro. Mescle efeitos em um únicoonPaint. Config.setChromiumOpenGlRenderer('angle')já está definido em
…
[truncado para tradução]