Subtítulos y superposiciones para reel
Toma un reel 9:16 ya cortado (normalmente 2160x3840 a 30fps, por ejemplo la salida de talking-head-edit) y le añade
subtítulos y superposiciones. Todo se basa en un único edit.json (páginas de subtítulos y superposiciones, en fotogramas) que ambos
motores de renderizado leen, por lo que las versiones de HyperFrames y Remotion coinciden fotograma a fotograma.
SK=~/.claude/skills/reel-captions-overlays
PY=$($SK/scripts/find_python.sh) # faster-whisper large-v3 + opencv ($REELKIT_PYTHON, el .venv del repo, o python3)
AUDIO_PY=~/.cache/reel-audio/venv/bin/python # etapa de música (scripts/setup_audio.sh la crea)
ANA_PY=~/.cache/reel-audio/analysis-venv/bin/python # análisis de estilo de referencia (scripts/setup_audio.sh --analysis)
Herramienta por defecto: HyperFrames (Apache-2.0, fijado en [email protected]). Remotion (4.0.539) se mantiene como una compilación
de paridad. Remotion es gratuito para individuos y empresas de hasta 3 personas; una empresa más grande necesita una Licencia Comercial de pago
para uso comercial (remotion.pro/license). HyperFrames no tiene esa condición de licencia.
Flujo de trabajo
- Configuración (primera pasada).
$SK/scripts/new_reel.sh <reel.mp4> <directorio-de-trabajo>Esto transcribe con marcas de tiempo por palabra (large-v3), detecta cajas de rostros cada 0.5s (faces_src.json) y cortes de escena (cuts.txt), copiaoverlays.example.jsona<directorio-de-trabajo>/overlays.json, y luego se detiene. - Rellenar
overlays.json. Leewords_raw.jsonprimero.corrections: corrige nombres de marca por secuencia de tokens, por ejemplo["Ackme"]→"Acme",["re","-motion,"]→"Remotion,",["Acme","Voice."]→"Acme Voice.". Unir pares de marca en un solo token los mantiene en una página de subtítulos. Mantén las líneas en idiomas extranjeros exactamente como se pronuncian (por ejemplo "Même voix, autre langue.").sansWindows: segundos[inicio,fin]de cortes de B-roll, tomas completas y tramos de promptDemo. Los subtítulos allí cambian al sans grueso (mismo carril del 75%).overlays: consulta la especificación de estilo a continuación y el Plan de gráficos. Los tiempos están en segundos, tomados de las marcas de tiempo de las palabras.sponsored: truepara un reel patrocinado o de marca. Activa la regla de ritmo de demostración (Reels patrocinados más abajo) y la advertencia de verificación.
- Construir ambos proyectos.
$SK/scripts/new_reel.sh <reel.mp4> <directorio-de-trabajo> <directorio-de-trabajo>/overlays.json - Revisar antes de renderizar.
cd <directorio-de-trabajo>/hyperframes && npx [email protected] snapshot --at 2.5,20,30 --no-end(onpx remotion still Reel x.png --frame=N --scale=0.5enremotion/). - Renderizar. Estos necesitan Chrome, así que ejecútalos fuera del sandbox de Bash (
dangerouslyDisableSandbox). Dentro de él, Chrome falla en las búsquedas de puertos Mach.<directorio-de-trabajo>/hyperframes/render.sh <salida>_captions_hyperframes.mp4renderiza un diseño de 1080x1920 sobremuestreado a 2160x3840 con CRF 16 y faststart.<directorio-de-trabajo>/remotion/render.sh <salida>_captions_remotion.mp4hace lo mismo con--scale=2, CRF 16, AAC 192k y faststart, luego ejecutascripts/repair_remotion.py(consulta Problemas conocidos).
- Verificar.
$PY -I $SK/scripts/verify.py <reel.mp4> <salida.mp4> <directorio-de-trabajo>/edit.json <directorio-de-trabajo>/faces_src.json <directorio-de-trabajo>/qc <etiqueta>(termina con código 1 e imprime FALLO si fallan los fotogramas, los fotogramas corruptos, la legibilidad, los bordes de las tarjetas o la oferta de CTA; tarda unos 9 minutos en un reel 4K de 60s)- Comprueba que el recuento de fotogramas y la duración coinciden con la fuente.
- Escanea cada fotograma en busca de corrupción (un fotograma de video incorrecto o mosaicos negros).
corrupt_framesdebe ser 0. - Verifica 5 páginas de subtítulos: la banda debe estar vacía 1 fotograma antes de que comience una página y llena 2 fotogramas después.
- Mide el cambio de píxeles de la caja del rostro debajo de cada superposición. Debería ser aproximadamente 0, excepto en la toma completa y las tarjetas de promptDemo, que cubren el rostro a propósito (se excluyen de las comprobaciones de rostro, fotograma corrupto y legibilidad).
- Enumera
demo_beats(superposiciones de promptDemo, o cualquier superposición con"demo": true). Cuandoedit.jsontengasponsored: truey haya menos de 2, imprime una ADVERTENCIA y la añade awarnings(no es un fallo grave; corrige el reel o explica por qué en el informe). - Separador ANTES/DESPUÉS (v7, advertencia). Para cada par de filas de antes -> después de promptDemo, informa
before_after: las palabras que comparten ambos clips, el salto en la edición y el silencio medido en el renderizado, y si la edición tiene la banda de cambio y el SFX de cambio (build_editba). Un par que repite palabras sin todo esto (salto >= 400 ms, banda, SFX) imprime una ADVERTENCIA: una línea repetida sin separador se lee como un error de edición (consulta promptDemo). - Oferta de CTA (v7, comprobación estricta). Un
ctacon unaofferdebe ser completamente visible >= 2.5 s, con un tamaño >= 40px (13+ px en un teléfono de 360px), y realmente dibujado (cambio de píxel en su banda).<etiqueta>_offer_mobile.jpglo muestra a tamaño de teléfono; míralo. Un reel patrocinado cuyo CTA no tieneofferrecibe una ADVERTENCIA. - Legibilidad a tamaño de teléfono: reduce 8 páginas de subtítulos a 360px de ancho y mide el grosor del trazo, la altura del texto y
el halo de contorno (luminancia del glifo menos el anillo a su alrededor). Mínimos: trazo >= 4.0px, altura >= 28px, halo >= 130.
legibility_okdebe ser verdadero.<etiqueta>_mobile.jpgmuestra los recortes; míralo. - Escribe una hoja de contactos con una imagen fija en medio de cada superposición, y una hoja de recortes sincronizados. Ábrelas ambas antes de informar.
- Música + SFX (etapa por defecto; omítela con
--no-musicoMUSIC=0). Rellena<directorio-de-trabajo>/music_plan.json(copiado desdemusic_plan.example.jsonen la primera pasada; usa el preajuste de estilo por defectosteady-funk-bed; consulta Diseño de música y sonido más abajo), luego$SK/scripts/music_stage.sh <salida_hyperframes.mp4> <directorio-de-trabajo> <salida>_music.mp4Esto mezcla la base y los SFX debajo de la voz, lo multiplexa en la imagen con una copia del flujo de video (sin recodificar) y el audio recortado a la duración del video, crea la copia para teléfono<salida>_music_mobile.mp4(MOBILE_OUT=para ponerla en otro lugar) y ejecutamusic_verify.py, incluyendo la comprobación de estilo contra el preajuste del plan. Debe imprimir APROBADO. Se niega a sobrescribir una salida existente (FORCE=1para permitirlo). También falla si alguna frase tiene un volumen de voz inferior a 6 dB sobre la música debajo de ella (voice_over_musicen el informe,--min-voice-over-music): lo que importa es si cada línea se puede escuchar bien. La base es un groove constante sin ducking a unos 13 dB por debajo de la voz, por lo que una frase tranquila puede hundirse en ella incluso cuando el promedio de la sección pasa. Corrige un fallo aguas arriba, con la nivelación del habla de talking-head-edit o la ganancia por segmento, no bajando toda la base. Un reel de entrevista típico que pasa midió un mínimo de 11.2 dB y una mediana de 14.1 dB. Abre<directorio-de-trabajo>/qc/music_sections.png. La primera ejecución crea~/.cache/reel-audio/venv(scripts/setup_audio.sh). - Copia para teléfono (para enviar, cuando se omitió la etapa de música):
ffmpeg -i <salida.mp4> -vf scale=720:1280:flags=lanczos -c:v libx264 -preset slow -crf 22 -maxrate 2800k -bufsize 5600k -pix_fmt yuv420p -c:a copy -movflags +faststart <salida>_mobile.mp4(unos 14-19 MB para 60s, por debajo del límite de 25 MB). Copia el audio masterizado, nunca lo recodifiques: una segunda codificación AAC a 128k elevó el pico real de un reel de -1.3 a -0.7 dBTP.
Especificación de estilo (del reel de referencia)
Todos los tamaños a continuación están en el espacio de diseño 1080x1920 (renderizado a 2x). El CSS compartido es templates/style.css.
- Subtítulos (v2: los subtítulos v1 eran líneas blancas finas, difíciles de leer en un teléfono. Más gruesos, más grandes, con contorno es el valor por defecto).
- Una palabra por página, ocasionalmente dos: una palabra funcional corta se une a su vecina, y los pares de marca están pegados.
- El texto mantiene mayúsculas y puntuación tal como se pronuncian ("contenido.", "Entonces"). Nunca lo pongas en mayúsculas. Sin resaltado por palabra: con 1-2 palabras por página solo añade ruido.
- Fuente: DM Serif Display (incluida, fijada en
@fontsource/[email protected], OFL) a 136px, blanca. Nunca vuelvas a una serifa fina como Instrument Serif regular para subtítulos. Instrument Serif se queda para títulos de tarjetas sobre papel o rojo. - Contorno: una copia trazada de la palabra (
::beforecondata-t,-webkit-text-stroke: 6px, por lo que 3px fuera del glifo) en color casi negro al 86%, pintada detrás del relleno para que nunca adelgace las letras. Sombra: 0 0 3px, 0 5px 12px y 0 14px 34px, todo oscuro. - Ajuste:
build_edit.pyestablecefspor página a partir detemplates/fonts/caption_metrics.jsonpara que una página nunca exceda 820px (por ejemplo "automáticamente." a 127px). Regenera las métricas conscripts/caption_metrics.pysi la fuente cambia. - Ubicación: un carril centrado al 75% de la altura (y=1440), debajo de las manos del hablante y el micrófono y por encima de la interfaz de usuario del 20% inferior. Baja a barbilla + 6% (limitado al 76%) solo en primeros planos. En una configuración de escritorio típica, las manos están en 55-72%, por lo que un carril "debajo de la barbilla" (60%) se sitúa sobre las manos.
- Animación: un pop de 4 fotogramas (escala 0.86→1, y 14→0, fundido) que comienza un fotograma antes, para que la palabra sea visible en su primer fotograma.
- Las páginas comienzan exactamente en el fotograma de inicio de la palabra y se mantienen hasta la página siguiente, o hasta el final de la palabra + 0.2s si hay una pausa.
- Subtítulos de B-roll y tomas completas: Inter 900 a 120px con tracking -0.03em, mismo contorno y el mismo carril del 75%.
- Tarjeta de título (
titleCard, para la frase gancho)- Un cuadro rojo ladrillo
#B23A2E, de 810px de ancho (75%), con su parte superior en y=190. - Línea superior: Anton EN MAYÚSCULAS a 118px. Debajo, un subtítulo blanco en Instrument Serif a 62px.
- Su parte inferior está aproximadamente al 23% de la altura del fotograma. Esto es deliberadamente más alto que la referencia (borde superior 22-28%), porque el rostro comienza aproximadamente al 26%.
- Un cuadro rojo ladrillo
- CTA (
cta)- Un "Comentar" en itálica serif blanca (82px) sobre un cuadro rojo con la palabra clave en Anton (196px, p. ej. "GUÍA"). Misma banda superior que la tarjeta de título.
- El cuadro aparece en 3 fotogramas después del remate.
- Línea de oferta (
offer, reels patrocinados, v7): la oferta de la marca debajo de la barbilla en una tarjeta de papel, p. ej. "Usa mi enlace para una PRUEBA GRATUITA de 14 días." Usa el texto de la propia marca.\nestablece el salto de línea, y las palabras EN MAYÚSCULAS ("GRATIS") reciben un cuadro blanco sobre rojo. "Comentar / PALABRA" sigue siendo el elemento principal; la oferta es la línea de apoyo.build_edit.pyderivaofferF(a partir deofferAt, por defecto el inicio del CTA + 10 fotogramas),offerY(barbilla + 3% de--facessobre la ventana de CTA, mantenido entre 55-60% de la altura, por encima de la tinta del subtítulo a aproximadamente 1385px) yofferFs(Inter ajustado a 720px, máximo 46px; advierte por debajo de 40px). La tarjeta tiene 780px de ancho (x 150-930, clara de la interfaz de usuario del lado derecho) e inclinada -1.5°. - La oferta debe estar completamente en pantalla >= 2.5 s. Si el reel termina demasiado pronto después de que el hablante dice el CTA, mantén el
último fotograma:
$SK/scripts/hold_end.sh <reel.mp4> <fotogramas> <reel_hold.mp4>copia el flujo del corte, añade N copias codificadas de su último fotograma con silencio digital, y comprueba que el habla se decodifica de manera idéntica a la muestra. Elige N para que el reel termine justo antes de un tiempo de música (tiempo k = k * 60 / bpm concue_at0), establece elenddel CTA y elendde la sección del plan de música a la nueva duración, y ejecuta build_edit con el nuevo--frames. La base suena durante la retención y corta con el último fotograma (ejemplo: 32 fotogramas, terminando a 68.2 s, justo antes del tiempo 125 de una base de 110 BPM a 68.207 s; oferta completamente visible 3.2 s).
- Toma completa (
takeover, para una mención de herramienta o producto, mantenida 1.5-3s)- Un fotograma completo rojo oscuro
#8E1F17con una cuadrícula sutil de color rojo más claro de 8x14. - Una píldora de búsqueda redondeada blanca (lupa a la izquierda; micrófono y lente a la derecha) cuya consulta en negrita itálica se escribe en 14 fotogramas.
- Debajo, una tarjeta redondeada blanca con el nombre de la herramienta (serif 128px), una descripción de una línea, una forma de onda roja y 2-3 chips.
- Nunca falsifiques una interfaz de usuario de producto real. Usa la tarjeta neutra solo con texto. La voz continúa debajo.
- Un fotograma completo rojo oscuro
- Tarjeta flotante (
floatCard, para una estadística, un consejo o una etiqueta;kickeropcional,width)- Una tarjeta de papel
#FBF7F1, de 470px de ancho, con su parte superior en y=200, en el lado izquierdo o derecho. Rotada ±3-4° con una sombra profunda. - El contenido es un kicker opcional + un número grande en Anton + una etiqueta serif + una línea en versalitas, o una variante de bandera:
flag: "es"(kicker + bandera CSS + palabra) oflag: "us-es"(kicker "Misma voz, diferente idioma" + bandera de EE. UU. → bandera de ES + palabra). - Las banderas emoji se dibujan en CSS, por lo que nunca dependen de una fuente emoji.
- Una tarjeta de papel
- Lista de pasos (
steps): una tarjeta de papel en la parte superior (y 150) con un kicker rojo y filas numeradas (DM Serif 54px). Cada elemento tiene su propio tiempoaty aparece cuando el hablante lo dice; el número actual es rojo, las filas anteriores se atenúan. Úsala cuando el hablante diga "tres pasos", "primero... luego". - División antes vs. después (
split): dos paneles inclinados uno al lado del otro en la parte superior, oscuro "Forma antigua" (tachado) y rojo "Forma nueva". El nuevo panel...