Communitygithub.com

Monet-AI-Editor/Monet

`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:

O que é Monet?

Este skill capacita agentes de IA (como Claude Code, Cursor, Codex) a controlar o Monet, um editor de vídeo profissional baseado em canvas, através de uma interface de linha de comando (`editorctl`) e uma API REST local. O Monet permite criar, editar e manipular projetos de vídeo completos: gerenciar assets e transcrições, montar sequências com clipes e trilhas, aplicar efeitos e transições, controlar a reprodução e exportar resultados. Além disso, o skill oferece três modos de canvas (Paper.js para desenho vetorial, Matter.js para física e animações, e geração de imagens via GPT image 2) e integração com Remotion para criar composições animadas em React. É essencial seguir regras rígidas de nomeação de arquivos para evitar problemas de cache visual, mesclar áudio corretamente em timelines com múltiplos clipes, e extrair tokens visuais de marcas a partir de URLs fornecidas pelo usuário.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add Monet-AI-Editor/Monet

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

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:

  1. "$HOME/Library/Application Support/Monet/bin/editorctl" — instalação macOS (mais comum)
  2. node /Applications/Monet.app/Contents/Resources/app.asar.unpacked/out/cli/cli/editorctl.js …
  3. 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:

  1. 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?"
  2. Aguarde a confirmação — não faça a mesclagem automaticamente.
  3. Concatene todos os clipes em um único novo arquivo (nome único conforme a regra acima).
  4. 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.

  1. Paper.js — desenho com código e gráficos vetoriais (canvas-run-paperjs)
  2. Matter.js — física e animação (canvas-run-matterjs)
  3. GPT image 2 — imagem gerada por IA (generate-image + canvas-add-image)

REMOVIDO — NÃO ofereça estes sob nenhum nome:

  • Modo design — removido
  • Camadas editáveis — removido
  • Layout estilo Figma — removido
  • Design baseado em nós — removido
  • Design 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

ComandoArgumentosRetorno
get_project—JSON completo do projeto
get_settings—Configuração de modelo + provedor

Assets

ComandoArgumentosRetorno
list_assets—[{id, name, path, type, duration, semantic}]
get_assetassetIdAsset único com semântica + transcrição
import_filespaths: string[]Registros de assets importados
transcribe_assetassetId, language?{segments} via Whisper
embed_assetsall?: bool{embedded, total} via text-embedding-3-small
search_mediaquery, limit?Busca por similaridade de cosseno (fallback para palavra-chave)
search_spokenquery, limit?Busca por substring em segmentos transcritos

Sequências e Trilhas

ComandoArgumentosRetorno
list_sequences—Todas as sequências
create_sequencenameNova sequência
activate_sequencesequenceIdSequência ativada
get_tracks—[{id, name, kind, clipCount}] da sequência ativa
add_track`kind: videoaudio

Clipes

ComandoArgumentosRetorno
list_clipssequenceId?Todos os clipes ordenados por startTime, com trackKind
add_clipassetId, trackId, startTime, duration?, inPoint?{clipId, clip}
remove_clipclipId{success}
move_clipclipId, startTime{success}
trim_clipclipId, inPoint?, duration?, startTime?Clipe atualizado
split_clipclipId, timeSequência atualizada
duplicate_clipclipId, offsetSeconds?{clipId, clip}
update_clip_labelclipId, label{success}

Efeitos e Propriedades

ComandoArgumentosRetorno
list_effects—Efeitos disponíveis + documentação dos parâmetros
add_effectclipId, effectType, parametersProjeto atualizado
remove_effectclipId, effectIdProjeto atualizado
set_speedclipId, speedProjeto atualizado (reprodução 0,1–10×)
set_volumeclipId, volumeProjeto atualizado (0–4, 1=normal)
set_transition`clipId, side: inout, type, duration?`

Histórico

ComandoArgumentos
undo—
redo—

Tipos de Efeitos

TipoParâmetros
fade_induration (seg)
fade_outduration (seg)
color_gradebrightness (-1→1), contrast (0,5→2), saturation (0→3)
blurradius (px, padrão 5)
sharpenamount (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ça
  • startTime = posição na timeline onde o clipe é colocado
  • duration = 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_sequence ou activate_sequence são suficientes por si só. Sempre verifique a sequência ativa depois com list_sequences ou get_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 startTime pretendido 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

FerramentaArgumentos
canvas_run_matterjsid? (id do frame para atualizar), name?, script (string 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}]}

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.run precisa 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.body em Render.create — cria um segundo canvas invisível; use canvas: document.querySelector('canvas')
  • Nunca declare const engine ou let engine no Padrão B — o template já tem var engine; redeclarar com const/let causa um SyntaxError que silencia o canvas
  • Nunca chame Render.run / Runner.run no 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 } = Matter causará 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

FerramentaArgumentosRetorno
video_editor_list_remotion_compositions—Lista de IDs de composição
video_editor_render_remotioncompositionId, 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

IDProps
TitleCardtitle (str), subtitle? (str), backgroundColor, textColor, accentColor — 150 frames @ 30fps
Slideshowimages (caminhos absolutos[]), frameDuration (frames), transitionDuration (frames) — 300 frames @ 30fps
HtmlInCanvasGlitchtitle, 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 drawElementImage a element.style.transform para 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 único onPaint.
  • Config.setChromiumOpenGlRenderer('angle') já está definido em

…

[truncado para tradução]

Habilidades Relacionadas