Edición de Shorts — Corta el Footage en un Short Listo para Publicar
Eres el técnico de sala de edición. Alguien te entrega footage real — una toma a cámara, una grabación de pantalla, una voz en off, algo de b-roll — y lo conviertes en un short vertical listo para publicar: silencios eliminados, cortes rápidos, subtítulos quemados palabra por palabra, movimiento sincronizado con el ritmo, exportado conforme a especificaciones. Codificas píxeles y tiempos. No escribes las palabras ni eliges el gancho.
El rigor es un archivo comprobable: un MP4 H.264 1080x1920 con subtítulos quemados que ffprobe confirma, más los artefactos intermedios (una lista de cortes, un .ass/.srt, una rejilla de beats). Si no puedes ejecutar ffprobe sobre el resultado y ver las especificaciones, no has terminado.
Alcance: tres habilidades tocan "un vídeo vertical" — conoce tu lugar
| La petición | Va a | Artefacto |
|---|---|---|
| Escribir el guion, gancho, beats, texto de subtítulos en pantalla, hoja de decisiones de edición | ../video-shorts/SKILL.md | un script .md |
| Cortar/subtitular/exportar footage real, independiente de herramienta | aquí | .mp4 editado + archivos de subtítulos/cortes |
Construir un proyecto de composición Remotion React (<TransitionSeries>, render headless) | ../remotion-video/SKILL.md | un proyecto .tsx |
Enrutamiento de una línea: footage de entrada → cortado, subtitulado, exportado → esta habilidad. Palabras o un plan → video-shorts. Un codebase React → remotion-video. Eres la única de las tres que es portable entre herramientas.
Elige tu ruta primero
No empieces a cortar antes de haber elegido la herramienta. La elección depende de quién la ejecuta y si debe ser reproducible.
| Situación | Ruta | Por qué |
|---|---|---|
| Reproducible / batch / CI / "haz esto a 40 clips" | ffmpeg + WhisperX | scripteable, determinista, sin GUI — misma entrada, misma salida |
| El repositorio ya es un proyecto Remotion | @remotion/captions | reutiliza el grafo de composición existente; no invoques externamente |
| Un humano pule un vídeo manualmente | Ruta CapCut | lo más rápido para un solo pase práctico con subtítulos automáticos + marcadores de beat automáticos |
El resto de esta habilidad es el pipeline ffmpeg + WhisperX (la ruta reproducible), con las rutas Remotion y CapCut indicadas cuando divergen. Los bloques largos de comandos están en references/ffmpeg-pipeline.md; el detalle de subtítulos está en references/captions.md.
El pipeline reproducible, en orden
Esta es la columna vertebral. Ejecútalo de arriba a abajo; cada paso alimenta al siguiente.
1. Extraer una pista de audio limpia mono a 16 kHz para transcripción.
ffmpeg -i in.mp4 -vn -ac 1 -ar 16000 a.wav
Por qué mono 16 kHz: eso es lo que esperan los modelos Whisper; alimentar estéreo 48 kHz pierde tiempo y no cambia nada en la precisión.
2. Transcripción con marcas de tiempo por palabra. Las marcas de tiempo por segmento no son suficientes — los subtítulos palabra por palabra necesitan temporización por palabra.
whisperx a.wav --model large-v3 --output_format json --highlight_words True
WhisperX (v3.8.5) ejecuta faster-whisper más alineación forzada wav2vec2, dando una temporización por palabra precisa a menos de 100 ms — el mínimo para el resaltado karaoke. faster-whisper solo con word_timestamps=True funciona (~10% de sobrecarga) pero se desvía más en los límites de las palabras. Por qué alineación forzada: las marcas de palabra nativas de Whisper son interpoladas y tiemblan; la alineación forzada fija cada palabra al audio. Ver references/captions.md para la instalación y la forma del JSON.
3. Detectar silencio, luego cortar video Y audio juntos. Este es el paso que la gente hace mal.
# Pase 1: encontrar los rangos de silencio (umbral de habla)
ffmpeg -i in.mp4 -af silencedetect=noise=-25dB:d=0.3 -f null - 2> silence.log
silenceremove solo es un filtro solo de audio y desincroniza el video — nunca lo uses como un solo comando. Analiza las líneas silence_start / silence_end de silence.log, inviértelas en rangos de conservación y construye un filtro select + aselect (o un gráfico trim+concat) que elimine los mismos rangos de ambos flujos. Umbrales: habla noise=-25dB:d=0.3; bases musicales noise=-40dB:d=1. El fragmento de generación de filtros está en references/ffmpeg-pipeline.md.
4. Construir la rejilla de beats (solo si estás cortando con música).
python -c "import librosa; y,sr=librosa.load('music.wav'); \
_,b=librosa.beat.beat_track(y=y,sr=sr,units='time'); print(*b,sep='\n')" > beats.txt
beats.txt es una lista de tiempos de beat en segundos. CapCut coloca estos marcadores en la forma de onda automáticamente; librosa (o aubio) te da la misma rejilla en un script.
5. Ajustar los puntos de corte y keyframes de zoom al beat más cercano. Redondea cada tiempo de corte a su valor más cercano en beats.txt. Un zoom-punch en el beat se percibe como energía; ver Sincronización con el beat más abajo para CUÁNDO NO hacerlo.
6. Quemar los subtítulos karaoke .ass.
ffmpeg -i tightened.mp4 -vf "ass=captions.ass" -c:a copy captioned.mp4
El .ass lleva la temporización \k por palabra construida a partir de las marcas de tiempo por palabra del paso 2 y los márgenes de zona segura. El detalle de generación y la plantilla están en Subtítulos karaoke más abajo.
7. Exportar el master de plataforma (ver Especificaciones de exportación).
Subtítulos karaoke
Los subtítulos palabra por palabra son la apariencia característica. Constrúyelos a partir de las marcas de tiempo por palabra, no de las marcas de tiempo por segmento.
- Temporización. El resaltado en pantalla de cada palabra proviene de su inicio/fin de alineación forzada. En
.ass, la etiqueta\k<centisegundos>avanza el relleno karaoke por palabra. Palabra por palabra a partir de la temporización de segmento tiembla y coloca el resaltado en la palabra equivocada — usa siempre las marcas por palabra del paso 2. - Legibilidad sin sonido. Negrita grande sans, contorno/trazo grueso, sombra opcional opaca. La gente ve en silencio: si no es legible de un vistazo en un teléfono, ha fallado. Mantén un máximo de ≤ 2 líneas / ~6 palabras en pantalla a la vez.
- Zona segura — la menos obvia. Coloca los subtítulos en la banda central vertical, no en la parte inferior. La UI de la plataforma (iconos del carril derecho, subtítulos/CTA/perfil inferiores) cubre la parte inferior ~15–20% y el borde derecho. Mantén los subtítulos y el texto clave dentro del ~80% central del fotograma
1080x1920. Los subtítulos quemados en la parte inferior quedan ocultos detrás de los botones de TikTok — esta es la causa #1 de "mis subtítulos están rotos".
Bloque de estilo .ass mínimo (plantilla completa en references/captions.md):
[V4+ Styles]
Style: Karaoke,Montserrat,64,&H00FFFFFF,&H0000FFFF,&H00000000,&H64000000,-1,0,0,0,100,100,0,0,1,5,2,5,80,80,640,1
MarginV (el 640 final) eleva la línea a la banda central; el Outline (5) grueso la mantiene legible sobre cualquier fondo.
Ruta Remotion: si estás dentro de un proyecto Remotion, usa @remotion/captions — createTikTokStyleCaptions({ captions, combineTokensWithinMilliseconds }) pagina los tokens. Bajo (200–500 ms) = aparición palabra por palabra; alto (1200–2000 ms) = frases paginadas. durationMs de página se añadió en v4.0.261. Ruta CapCut: Texto → Subtítulos automáticos → Generar, luego cambiar estilo.
Sincronización con el beat
Una rejilla de beats (paso 4) es una lista de segundos. Ajusta tus puntos de corte y keyframes de zoom al beat más cercano para que el movimiento caiga sobre la música.
- Malo → Bueno. Cortar a mitad de palabra para que un corte caiga exactamente en un beat se percibe como un error → desplaza el corte al beat más cercano que también respete el límite del habla. Honra las palabras primero, el beat segundo.
- CUÁNDO NO cortar al beat. Un video explicativo de una persona hablando donde las palabras son el valor: la claridad supera al ritmo. Cortar al beat a una persona a mitad de frase corta su presentación. Reserva la sincronización con el beat para montajes de b-roll, transiciones y segmentos guiados por música.
- Las transiciones se mantienen baratas y rápidas. El corte directo es el predeterminado. Whip-pan o zoom-punch solo en un beat. Evita crossfades de 1 segundo en un short de 30 segundos — matan el ritmo; un short vive de cortes directos rápidos.
Especificaciones de exportación
El master vertical universal — un archivo que se reproduce limpio en las tres plataformas:
ffmpeg -i captioned.mp4 \
-vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2,setsar=1" \
-c:v libx264 -profile:v high -pix_fmt yuv420p -r 30 \
-c:a aac -b:a 192k -ar 48000 -ac 2 \
-movflags +faststart out.mp4
yuv420p (reproducción amplia), +faststart (la transmisión web comienza antes de la descarga completa), AAC-LC 48 kHz. Usa 30 fps; sube a 60 fps para Shorts de alto movimiento.
| Plataforma | Bitrate de video | Notas |
|---|---|---|
| TikTok | ~2,000–4,000 kbps | el más ligero de las tres |
| Instagram Reels | ~3,500–4,500 kbps | |
| YouTube Shorts (1080p) | ~8,000–15,000 kbps | hasta ~53,000 para 4K/60 |
Un único 1080x1920 H.264 MP4 @30 fps con menos de ~250 MB es seguro en todas partes. Verifica antes de enviar:
ffprobe -v error -select_streams v:0 \
-show_entries stream=width,height,codec_name,avg_frame_rate out.mp4
Espera width=1080 height=1920 codec_name=h264. Las banderas de codificación completas por plataforma y las aserciones ffprobe están en references/ffmpeg-pipeline.md.
Anti-patrones
| Malo | Por qué se rompe | Bueno |
|---|---|---|
silenceremove como filtro único | Es solo de audio; el video sigue reproduciéndose → desincronización audio/video | silencedetect → invertir rangos → select+aselect cortan ambos flujos |
| Subtítulos de palabras a partir de marcas de tiempo de segmento | El resaltado tiembla y cae en la palabra equivocada | Marcas por palabra de alineación forzada (WhisperX / word_timestamps) |
| Subtítulos quemados en la parte inferior 15–20% | La UI de la plataforma (botones, CTA, perfil) los cubre | Colocar en la banda central vertical, ~80% central |
| Una exportación reutilizada para cada plataforma | Por encima/por debajo del objetivo de bitrate en algún lugar | Bitrate por plataforma, o el master universal seguro |
| Crossfades de 1 segundo en un short de 30 segundos | Mata el ritmo; se percibe lento | Cortes directos; whip/zoom solo en un beat |
| Cortar al beat a una persona hablando a mitad de frase | Corta la presentación; se pierde claridad | Sincronizar al beat solo b-roll/montaje; honrar límites del habla |
| Volver a ejecutar la codificación para "verificar las especificaciones" | Pierde minutos; el archivo ya existe | ffprobe sobre la salida; verifica, no vuelvas a renderizar |
| Escribir el texto del subtítulo o el gancho aquí | Eso es el guion, no el corte | Enrutar a ../video-shorts/SKILL.md; tú solo lo quemas |
ffmpeg sobrescribiendo la fuente en el lugar | Una mala bandera y el original se pierde | Siempre escribir a un nuevo archivo; mantener in.mp4 intacto |
Verificar y referencias
bash scripts/verify.sh <output.mp4>— ejecutaffprobey afirmawidth=1080,height=1920(9:16), códec de videoh264, códec de audioaac, fps en{30, 60}, y que exista un archivo de subtítulos.srt/.asshermano y no esté vacío. Sinffprobefalla a una comprobación de ruta/extensión. Solo lectura; sale 0 en un destino vacío/limpio para que nunca falle falsamente. El juicio de "¿se siente en el beat?" no es mecánico — eso vive en la evaluación de capacidad.references/ffmpeg-pipeline.md— la detección de silencio completa → inversión de rango de conservación → generación de filtroselect/aselectque corta video+audio juntos, el enfoque concat/trim, banderas de codificación por plataforma, asercionesffprobey solución de problemas de desincronización/desviación de audio/faststart.references/captions.md— instalación y ejecución de WhisperX, la forma del JSON de marcas de tiempo por palabra, la plantilla.asskaraoke completa con márgenes de zona segura, el fragmentocreateTikTokStyleCaptions()de Remotion con guía decombineTokensWithinMilliseconds, y la compensación faster-whisper vs WhisperX.