/edicion — edición con motion graphics + XML para Premiere
Entrada: un video crudo (o una carpeta con el crudo + material de apoyo: clips de kling/IA, PNG, música, SFX).
Salida en la carpeta del video: <NOMBRE>_EDIT/ con <NOMBRE>_v1_premiere.xml, Assets/{MG,Subtitulos,SFX,Envato}, LEEME.md. No se renderiza vista previa MP4 (el usuario lo pidió para ganar velocidad): la revisión visual se hace con las hojas de contacto del paso 5.
Hablarle al usuario en español rioplatense (voseo). Avisarle brevemente el avance entre pasos largos.
Rutas: SK = la carpeta de esta skill, donde está este SKILL.md (Claude Code: ~/.claude/skills/edicion; Codex: ~/.codex/skills/edicion) · scripts en $SK/scripts · motor en $SK/engine/engine.html · catálogo en $SK/reference/escenas.md · ejemplo en $SK/reference/ejemplo_jobs.js.
Workdir del proyecto: <carpeta>/<NOMBRE>_EDIT/.work (persistente, permite hacer v2 en otra sesión).
Correr Python siempre con python3 -I (Windows: py -3 -I). Pasar rutas con espacios entre comillas. Funciona en macOS y Windows: en PowerShell usar rutas con \, $env:VAR en vez de VAR=... y los flags de los scripts (ej. --t=end-0.4) en vez de variables de entorno.
0 · Preparación
- Cronómetro: apenas se sabe el nombre, crear el workdir y correr
python3 -I $SK/scripts/timing.py start "<work>". Los scripts anotan solos cuánto tarda cada paso. - Dependencias:
python3 -I $SK/scripts/doctor.py(Windows:py -3 -I $SK\scripts\doctor.py). Si algo sale con ✗, correr el comando que indica (en general el instalador:bash $SK/scripts/install.shen Mac,powershell -ExecutionPolicy Bypass -File $SK\scripts\install.ps1en Windows) y volver a chequear. - Inventario de la carpeta:
ffprobede cada video (duración, fps, rotación,nb_frames), tamaño de los PNG, duración de los audios. El crudo suele ser 1920×1080 con rotación 90 (= vertical 1080×1920, 30 fps). - Mirar el material de apoyo:
ffmpeg -vf "fps=2,scale=150:-1,tile=10x2"→ mirar la imagen. Identificar qué ilustra cada clip/foto (gancho, chiste, metáfora). Si hay escenas, detectar cortes conscdet. - Mirar un cuadro del crudo (color de ropa → colores de subtítulos, ver escenas.md).
1 · Transcribir
python3 -I $SK/scripts/transcribe.py "<crudo>" "<work>" → lista de frases con tiempos.
Whisper alucina sobre ruido ("Gracias", "Gracias por ver el video", "Suscríbete al canal", "CC por…"): verificar esas zonas y cualquier duda con
python3 -I $SK/scripts/check.py "<work>" 21.9-26.3 ... (habla ≈ −5…−25 dB; ruido ≈ −48…−70 dB).
2 · Decidir el guion (criterio editorial)
- Sacar frases repetidas, falsos arranques, tomas incompletas y tropiezos. Ante varias tomas de lo mismo, quedarse con la última completa.
- Corregir el texto para subtítulos (voseo: "querés", "tenés", "dejá"; "método IDEAS"; nombres propios).
- CTA: si grabó varias alternativas, usar por defecto "mandame un mensaje(ito)" (fue la elección explícita del usuario). Las demás se listan en el LEEME con su timecode del crudo. Si hay una lista de CTAs que no se repiten (opciones distintas, sin la misma intro), se pueden dejar todas como OPCIÓN 01/02… En la respuesta final decir cuál elegiste.
- Escribir
<work>/segs.json: lista de segmentos lógicos (cada uno = idea que comparte un gráfico), cada uno con frases[a, b, "texto"]tomadas de las frases de transcribe/check.
3 · Corte AJUSTADO (obligatorio)
python3 -I $SK/scripts/tighten.py "<work>" recorta cada frase sobre la energía real de la voz y corta pausas internas ≥ 0,25 s (lecturas, miradas al costado, respiraciones). El usuario pidió explícitamente cortes sin silencios: no dejar pausas.
Crear <work>/config.json (abajo) y correr python3 -I $SK/scripts/edl.py "<work>" → imprime la duración y los tiempos por segmento y re-transcribe el corte: confirmar que no falte ni sobre ninguna palabra. Si falta un arranque, revisar con check.py y ajustar segs.json.
{ "name": "SIGN_SPINNER", "version": 1, "fps": 30, "tail": 1.2,
"src": "/abs/crudo.mp4", "edit_dir": "/abs/carpeta/SIGN_SPINNER_EDIT",
"caption_colors": {"act":"var(--hot)","kwAct":"var(--lime)","kw":"#FFB08A"},
"keywords": ["pacientes","scroll","correctas"],
"broll": { "kl": {"path":"/abs/kling.mp4","frames":97,"rate":24,"w":1080,"h":1916},
"s1": {"path":"/abs/foto.png","still":true,"w":941,"h":1672} },
"music": {"path":"/abs/musica.wav"},
"face": {"top": 0.22},
"markers": [["HOOK",0],["CTA · Mandame un mensaje",17]] }
tail = segundos extra al final (cara a cámara) para que se lea el último gráfico.
face.top = altura (0–1) de la parte de arriba de la cabeza en el cuadro (mirarlo en el frame del paso 0.4): limita el zoom máximo para no cortarla. music lo completa envato.py use (o una ruta de la carpeta del video). Opcionales: sfx_max (máximo de SFX en toda la edición, default 5), sound_design: "manual", max_zoom.
4 · Diseñar los motion graphics → <work>/jobs.js
Basarse en reference/ejemplo_jobs.js y reference/escenas.md. Estilo fijo (al usuario le encantó, no cambiarlo): tarjetas crema con kicker mono y punto naranja, títulos Bricolage condensados en mayúsculas, resaltados naranja, ✓ lima, pantallas completas con grano y wipe en capas.
Reglas:
- Límites del usuario (obligatorios): 3 pantallas completas (
fs) y como máximo 3 motion graphics superpuestos (ov/ov2: tarjetas, listas, sellos, stickers…) en toda la edición. Lo demás lo cuentan los subtítulos, los reencuadres y el b-roll. Elegir los 3 MG para las ideas que más ganan viéndose (una lista que se arma, un dato, el CTA), no para repetir lo que ya se dice. - Subtítulos vs. MG: los subtítulos corren todo el tiempo, pero desaparecen solos mientras hay un MG (ov, ov2 o fs) para no competir; vuelven apenas el MG sale. No hace falta hacer nada: lo resuelve render.js. Por eso cada MG tiene que contar por sí mismo lo que se dice en ese tramo, y conviene que no dure más que la idea (2–5 s).
- Sincronizar cada MG con la palabra que lo dispara (
W(seg,'palabra')). - Pantallas completas (fs) que tapan la cara en los 3 remates más fuertes, de 1 a 3 s, repartidas. Fondos alternados ink / naranja / crema.
- Gancho fuerte en los primeros 2 s: texto grande arriba y, si hay un clip de apoyo divertido o visual, que entre en el gancho (con sticker y flecha o HUD) y la música fuerte.
- B-roll: primero el de la carpeta (clips de kling/IA, fotos), donde ilustra lo que se dice (metáforas: ruedita de hámster, cartel, rayos X). Fotos fijas con Ken Burns
[100,112]. Además, 3 momentos de Envato (paso 4a). Encima del b-roll, solo sticker/HUD/sello. - Audio extra de la carpeta del video (cámara, pasos, etc.) con
X(). - SFX: automáticos (paso 4b). No hace falta poner el último parámetro de
J()salvo para cambiar el sonido. - Usar escenas nuevas cuando la metáfora lo pida (agregarlas a engine.html siguiendo escenas.md). No reusar textos fijos de otras escenas que no apliquen (ej.
hookdice MARKETING DESDE CERO). - Pista
ov2solo si una tarjeta debe ir encima de otro overlay (ej. tracker).
4a · B-roll semántico + música de Envato
El MCP de Envato solo busca (no descarga ni licencia). envato.py lo llama por HTTP, así que funciona igual en Claude y en Codex aunque el MCP no esté configurado.
- Elegir 3 momentos del guion donde una imagen real suma: una situación concreta (paciente en consulta, alguien scrolleando), una metáfora visual o un dato que se entiende mejor visto. Repartidos (primer tercio, medio, antes del CTA), de 1,5–3,5 s, nunca durante una pantalla completa ni en el CTA final, y en tramos donde la tarjeta de ese momento pueda ser un sticker/HUD o no haya tarjeta.
- Buscar (términos concretos en inglés, describiendo la imagen, no la palabra del guion):
python3 -I $SK/scripts/envato.py search "<work>" video "<términos>" --vertical [--sub Medical]. Si hay pocos resultados, repetir sin--vertical(los horizontales se recortan al centro). Mirar la hoja<work>/envato/<búsqueda>.jpg(fila n = candidato #n) y elegir: auténtico (no pose de stock), sujeto centrado que entre en 9:16, luz y color parecidos al crudo, sin texto, que amplíe lo que se dice en vez de repetirlo. - Usar:
python3 -I $SK/scripts/envato.py use "<work>" <clave> <búsqueda>#<n>(registra la vista previa enconfig.broll) y ubicarlo en jobs.js conB('<clave>', seg_origen, inicio, dur). - Música:
python3 -I $SK/scripts/envato.py search "<work>" music "<estilo en inglés>" --mood <mood> --tempo "<tempo>" [--genre <género>](siempre instrumental). Elegir por el tono del video y por el perfil de energía que imprime (parejo, sin caídas largas; para videos enérgicosUpbeat (110-140 BPM), para videos cálidosMedium (90-110 BPM)), yenvato.py use "<work>" music <búsqueda>#<n>. Si el usuario dejó música en la carpeta, usar esa ("music": {"path": ...}). El volumen se arma solo en el XML: fuerte en el gancho, baja bajo la voz y sube en el cierre (hook_gain0.3 ·bed_gain0.08 ·outro_gain0.22 ·offset= segundo de la canción donde arranca, para entrar en una parte con energía). - Licenciar y descargar: mientras tanto el XML usa las vistas previas con marca de agua (prefijo
PREVIEW_). Si el agente tiene un navegador con la sesión de Envato iniciada: mostrar la lista (envato.py report "<work>") y pedir confirmación una sola vez; después, en cada link: Download → licenciar para un proyecto con el nombre del video → descargar el original (video en la mayor resolución vertical/HD; música en WAV). Si no hay navegador o no hay sesión, darle al usuario la tabla de links para que lo haga. Luegopython3 -I $SK/scripts/envato.py collect "<work>"(busca en~/Downloads, descomprime, copia aAssets/Envatoy reemplaza las vistas previas) y volver a correrbuild_xml.py. Nunca usar material de otros bancos ni saltear la búsqueda.
4b · Diseño sonoro (automático, con la librería de la skill)
Todos los SFX viven en $SK/assets/sfx/<categoría>/<id>.wav, normalizados a −16 LUFS, y están descritos en catalog.json (duración, volumen por categoría y anchor = el golpe o arranque que cae justo en el evento). Ver la lista completa: python3 -I $SK/scripts/sfx_import.py --list. Al armar el XML se copian a Assets/SFX solo los que se usaron.
| Categoría | Cuándo |
|---|---|
whoosh | Entrada de pantallas completas, wipes, cambios fuertes de tarjeta |
build | Antes de un corte o remate (reverse-whoosh; riser ≈ 6 s, solo por id para el remate más grande) |
pop | Aparición de tarjetas, stickers, ítems de lista |
click | Interfaces: búsqueda, DM, botón seguir, tildar |
ding | ✓ check, acierto, idea, dato positivo |
error | ✗, tachar, mito, lo que está mal (game-over es una voz robótica: usar con humor) |
hit | Remates, sellos, fs de impacto (bass-drop solo por id, máximo 1 por video) |
glitch · poof | Algo que falla, se rompe o desaparece |
zoom · bounce · wind | Punch-in o lupa · rebote con humor · aparición mágica |
foley · splash · car | Literales: solo si lo que se dice o se ve coincide (escribir, cierre, estirar, inodoro, agua, autos) |
Regla del usuario: como máximo 5 efectos en TODA la edición, elegidos con sutileza. Más que eso queda brusco.
Automático (por defecto): se juntan los momentos candidatos (entrada de cada gráfico y sus momentos internos: ✓ → ding, sello/remate → hit, buscador/DM/seguir → click, pantalla completa → whoosh, corte a b-roll → whoosh) y se eligen solo los 5 más importantes: remates y pantallas completas > el gancho > el CTA > el corte a b-roll > tarjetas > detalles internos, separados al menos ~6 s entre sí (≥ 3 s en videos cortos). Volúmenes bajos (≈ −11 a −14 dB respecto de la voz). Las variantes se alternan.
Al revisar el plan, preguntarse en cada uno si suma; si no, sacarlo (J(..., null)). Menos es mejor: 3 bien puestos valen más que 5.
Manual (pisa al automático para ese gráfico; cuenta para el máximo de 5):
- Categoría o id puntual:
J(..., 'pop')·J(..., 'bass-drop')·J(..., null)= sin sonido. - Sonido suelto en un segundo de la línea de tiempo:
S('splash', W(4,'agua'))·S('car-pass-2', t, {gain:.25, dur:3}). Los literales (foley,splash,car) nunca son automáticos: ponerlos conS()solo cuando suman al chiste o la metáfora.node render.js --planlista todos los SFX (los automáticos marcados(auto)). Para sumar sonidos nuevos:python3 -I $SK/scripts/sfx_import.py <archivo> --id <id> --cat <categoría> [--anchor peak|onset] [--max 4] --desc "..."(recorta, normaliza y lo registra).
4c · Reencuadres y zooms (automáticos según el discurso)
render.js decide la escala de cada clip de V1 y la escribe en framing.json; el XML la aplica con keyframes:
snap(zoom rápido 100→118 %) en el gancho ·punch(124 %) en las frases de énfasis: con!, con palabra clave en un clip corto, o bajo un sello/bigword (máx. uno cada 6 s) ·push(acercamiento lento) en preguntas y en el CTA ·tight(114 %) /wide(100→103 %) alternados para disimular los jump cuts (siempre ≥ 8 % de diferencia entre clips seguidos) · los clips tapados por fs o b-roll quedan enwide.- El zoom máximo sale de
config.face.top(no corta la cabeza); default 124 %. - Para forzar un encuadre:
F(seg, 'punch')oF.clip(i, 'wide')en jobs.js.
5 · Dirección creativa, prueba y render
node $SK/scripts/render.js "<work>" --plan(lista los gráficos, SFX y encuadres con tiempos; detecta palabras no encontradas).- Dirección creativa:
node $SK/scripts/director.js "<work>"→ informe (direction.md) + línea de tiempo (timeline.png, mirarla). Revisa que nada compita: más de 3 MG o de 3 pantallas completas, subtítulos visibles debajo de un MG, dos tarjetas a la vez, tarjetas tapando el b-roll, b-roll solapado sin fade, SFX muy seguidos, palabras clave sin resaltar, gancho sin música fuerte. Corregir en jobs.js según el informe y volver a hablar con el usuario si hay que cambiar el guion o los MG. - Hojas de contacto:
node $SK/scripts/preview.js "<work>" --frames(pngs de cada ~3 s) y mira las hojas:contact.pdfdel compaginado ygatling.pngcon todo junto. Tambiénnode $SK/scripts/preview.js "<work>" --labels→labels.png(cada frame con categoría, tiempo y nombre para revisión de sync). - Revisar sync: cada MG entra exacto en su palabra y no se corta antes de la siguiente idea. Los subtítulos coinciden con el texto del guion. Los SFX caen justo con el evento. Los b-roll y las pantallas completas duran lo justo y no tapan el texto clave.
- Comprobación final: correr
node $SK/scripts/sanity.js "<work>"(verifica duración, assets encontrados, MG únicos, subtítulos completos, SFX dentro del máximo, cumplimiento de los límites del usuario). - Armar XML:
python3 -I $SK/scripts/build_xml.py "<work>"(genera el XML para Premiere con todos los assets enlazados en la timeline). El XML no escribe pistas de video adicionales en los segmentos de b-roll (aíslan la cara del crudo).
6 · LEEME.md
Grabar en <NAME>_EDIT/LEEME.md (en español):
- Video:
<NAME>, duración del corte ≈m:ss. Fecha. Duración de la edición (del paso 0 al final): mostrarla conpython3 -I $SK/scripts/timing.py report "<work>". - Cómo se repartieron los 3 MG y las 3 pantallas completas (qué va en cada uno, o
(slots libres)). - Si sobran MG o pantallas completas, listar los que se eligieron luego del análisis.
- Si se usó más de 1 CTA: OPCIÓN 01, OPCIÓN 02… y timecodes a continuación.
- B-roll usado: clip/foto de la carpeta + 3 de Envato + cualquier otro.
- Música de Envato: título, autor, link a la preview (para licenciar).
- SFX usados (máx. 5).
- Enlaces de Envato para licenciar (solo si no se descargaron automáticamente).
- Enlace a la carpeta
Assets/(relativo). - Instrucciones en Premiere: arrastrar el XML a la ventana de proyecto (o Archivo > Importar > XML). Reemplazar los archivos
PREVIEW_con los originales descargados en Assets/Envato. Reemplazar la fuente Bricolage Grotesque si no está instalada. Si los subtítulos no se ven: abrir la pista de subtítulos (ventana de subtítulos) y asegurarse de que esté activa.
7 · Informar al usuario
- "Editado en m:ss. XML para Premiere en …/EDIT. Revisá las hojas de contacto en … que ya se armaron."
- Si hay algo que revisar: "Te pido que veas X (ej. el final del b-roll se siente apurado). Si te parece bien, decime y lo ajusto."
- Importante: si algún paso requiere volver a correr, asegurarse de que los archivos intermedios sean consistentes (no copiar XML viejos sobre nuevos). Si se hicieron correcciones, correr
build_xml.pyde nuevo.
Notas adicionales
- Si el usuario pide un cambio manual (ej. "cambiá la tarjeta 2 por una lista"), el flujo es: ajustar jobs.js → correr
render.js --plan→director.js→preview.js --frames→build_xml.py. Nunca tocar el XML a mano. - Toda la interacción en español rioplatense.
- Los scripts de timing y sanity son idempotentes; se pueden correr varias veces.
- Para depurar sync:
node $SK/scripts/preview.js "<work>" --labelsy despuéspython3 -I $SK/scripts/check.py "<work>" ...con los rangos dudosos.