Nuevo video: de la toma al máster
Antes de empezar: harness.config.json → configured: true (de lo contrario, skill setup), bash video/scripts/doctor.sh sin MISSING. Lee brand-kit.md, editing-taste.md, «Perfil de estilo» en exemplars.md, anti-patterns.md, delivery-specs.md. El estilo del video proviene únicamente del perfil del usuario: si hay póster, tarjetas, stickers, b-roll, sonido, cuánta gráfica, qué ritmo. Lo que no esté en el perfil, pregúntalo, no lo decidas tú. El punto de partida del código es el actual video/src/.
Si video/public/footage.mp4 ya existe de un video anterior y no está archivado en edits/ — primero archívalo (paso 11), luego comienza.
1. Inspección de la toma
ffprobe -v error -show_entries format=duration:stream=width,height,r_frame_rate:stream_side_data=rotation -of default=nw=1 takes/1.MOV
Mira la orientación por rotation, no por width (el iPhone escribe vertical como 1920x1080 + flag). Mira 3–4 fotogramas (ffmpeg -ss N -i … -frames:v 1 out/peek-N.jpg). No estabilices, si se grabó con trípode — vidstab añadirá vibración. Solo si es claramente a mano: estabiliza el ORIGINAL (vidstabdetect=shakiness=6:accuracy=15 → vidstabtransform=smoothing=25:optzoom=1:interpol=bicubic, -c:a copy; necesita ffmpeg con libvidstab) y luego trabaja con él.
2. Tomas duplicadas y falsos inicios — ANTES del corte
cd video && python3 scripts/chunks.py ../takes/1.MOV
Una transcripción completa esconde las repeticiones, pero el espectador las nota enseguida. Encuentra: fragmentos adyacentes con la misma frase (toma duplicada — deja la ÚLTIMA), fragmentos de 1–2 palabras que el siguiente fragmento comienza de nuevo (falso inicio). Muestra al usuario la lista de lo que vas a cortar, con códigos de tiempo — y obtén un «sí». Los límites están dentro de las pausas.
3. Corte
cp public/captions.json out/captions.backup.json 2>/dev/null # cut.py sobrescribe la transcripción
DROP="12.40-15.80" python3 scripts/cut.py ../takes/1.MOV
El ritmo se toma de cut en el perfil (ajustado según referencias). El script imprime DURATION, los fotogramas de los cortes y una verificación de «corte en plena palabra». Si hay pocos cortes para el ritmo que desea el usuario, pasa argumentos por debajo del perfil, por ejemplo … 0.4 0.2 (pausa ~0.35 / 0.2); si hay muchos, por encima. Sin cortes en absoluto — habitación ruidosa: QUIET=-46. Hablante rápido/ritmo lento — SPEED=1.1. Corte en plena palabra — desplaza DROP o los parámetros, no lo dejes así.
4. Máscara — ejecútala INMEDIATAMENTE (si style.poster.enabled)
TITLE_OUT = primer corte de la salida de cut.py (el póster aparece ahí), normalmente 4–7 s. La máscara es la parte más larga (~8 s/fotograma en CPU, 2 workers ≈ 6 fotogramas/min), ejecútala en segundo plano y escribe código mientras:
python3 scripts/matte.py <TITLE_OUT> 2 > out/matte.log 2>&1 # en segundo plano (run_in_background)
No renderices fotogramas mientras se ejecuta, lo ralentizan. Espera a que termine mediante ps -axo command | grep "[m]atte.py", no con pgrep. El script omite fotogramas ya listos — tras reiniciar, simplemente ejecútalo de nuevo.
5. Transcripción
Abre public/captions.json (w, s, e en segundos, em):
- corrige los errores auditivos: nombres, marcas, términos, anglicismos; acrónimos como se escriben (
AI,ROI); whisper suele poner «Gracias por ver» / «Thank you.» en el silencio de la cola — elimínalo; em: 2(sistyle.captions.highlightessizeoboth) y"accent": 1(si escoloroboth) — según el SIGNIFICADO, en la cantidad y en las palabras descritas en el perfil (brand-kit.md§2, §4). Si no está descrito, pregunta qué palabras destacar.
6. Lista de beats
Tú mismo o con el subagente script-beats (para videos largos) escribe video/SCRIPT.md:
- póster — solo si
style.poster.enabled: líneas con las palabras y el tono del usuario, acento y kicker como en el perfil; - tarjetas — si
style.cardsno esnone, con la densidad deediting-taste.md§3 (número →count; paso →num+head; enumeración →head+linesorowcon iconos en las palabras);from= primera palabra de la frase + 4 fotogramas; - stickers
FLOATS— solo sistyle.stickers: subtítulo de una palabra, pictograma compacto (ART_NAMES); - tarjeta
pain: true— solo si el usuario quiere «así no».
Antes del código, muestra al usuario la lista de beats de forma breve (qué y dónde aparece) — es su video, sus decisiones.
7. Código
src/Composition.tsx:DURATION,TITLE_OUT,KICKER,TITLE,BEATS,FLOATS;Captions from= inicio de la segunda frase, si hay póster, si no 0.src/ui/Footage.tsx: tablaBEATSestrictamente según los cortes de cut.py, a plena potencia (primer plano 1.16–1.21×, normal 1.06–1.09×) —style.motion.punchlo suavizará o desactivará. Dónde poner primer plano — segúnediting-taste.md§4; después del primer plano — vuelve a abrir más, de lo contrario el primer plano se «pega»; si hay póster, en el primer corte.- Nuevo componente — solo si ni una tarjeta, ni un sticker, ni
Photo/Clip/Tagpueden expresarlo (entonces —scene-builder). - B-roll de Higgsfield — si está conectado y el perfil lo desea (
brand-kit.md§5): muéstralo mediante<Clip>(recorta y silencia previamente:ffmpeg -an -t <seg>), verifica el texto/las caras/las manos en los fotogramas de generación antes de insertarlo. Primero pregunta al usuario y menciona el precio. - Sonido — solo si
style.sfx: los roles faltantes (card,count,end) — mediante subagenteaudio-agentsegún la descripción del perfil. npm run lint— limpio.
8. Fotogramas para aprobación (después de la máscara)
Renderiza un fotograma por cada tarjeta y sticker en el momento completamente ensamblado, el póster en la mitad de su vida (la última línea se lee sobre el cabello), varias frases de subtítulos, el ÚLTIMO fotograma:
npx remotion still MyComp out/key/f<N>.png --frame=<N> --scale=0.5 --timeout=120000
Combínalos en una lista de 4 por fila con subtítulos-números (PIL; fuente con cirílico, por ejemplo /System/Library/Fonts/Supplemental/Arial Bold.ttf), muéstrasela al usuario (SendUserFile). El máster — solo después de su «ok». La lista — minutos, el máster — 10–20 minutos.
Comprueba tú mismo antes de mostrar: el texto clave fuera del 15% inferior / 8% superior; nada se superpone; el sticker no se cruza con la tarjeta; el último fotograma no está vacío ni cortado; todo como en el perfil del usuario y nada más.
9. Máster
npm run master # en segundo plano; espera el proceso, no la aparición del archivo
El script comprueba los recortes, cuenta los fotogramas y genera out/preview.mp4. Verifica el volumen: ffmpeg -i out/final-master.mp4 -af ebur128 -f null - 2>&1 | grep -A3 Summary ≈ objetivo de audio.lufs. Envía al usuario la vista previa.
Corrección después del máster («corta esta frase») — corta el propio máster (ffmpeg trim+concat en silencio), no re-cortes la toma ni lo renderices todo de nuevo; indica el ETA de antemano. Verifica el empalme: corta 6 s alrededor y ejecuta whisper — deben coincidir exactamente las dos frases necesarias.
10. Portada
Pregunta qué portada se necesita, si no se indica en el perfil: fotograma con título (Cover), póster del video (PosterCover) o propia. Elige el fotograma junto con el usuario: propón 3–4 fotogramas nítidos con ojos abiertos (ffmpeg -ss <seg> -i takes/1.MOV -frames:v 1 -q:v 2 out/cover-N.jpg).
- Fotograma seleccionado →
public/cover-bg.jpg. rembg i -m birefnet-portrait public/cover-bg.jpg out/cover-matte.pngpython3 scripts/cover-sticker.py public/cover-bg.jpg out/cover-matte.png public/cover-cutout.png 20- En
Root.tsx→CoverdefaultProps.lines: título con las palabras del usuario,accent/em— como él quiera. Los tamaños se ajustan solos — no modifiques los tamaños de fuente. npx remotion still Cover out/cover.png --timeout=120000— muéstra.
Alternativa: PosterCover — póster del video como portada (fotograma + su recorte en poster-bg.jpg / poster-cutout.png).
11. Archivo
edits/<N>/ (en la raíz, no en video/): Composition.tsx, Footage.tsx, captions.json, SCRIPT.md, cover.png, final-master.mp4, preview.mp4. Si el usuario lo desea — luego el skill publish.