Communitygithub.com

Qsnh/video-make

Crea videos narrados con explicaciones, tutoriales o promocionales a partir de código (B站横向 tutorial, 抖音/小红书/视频号 vertical short video) — TTS con voz AI, subtítulos, renderizado fotograma a fotograma de animaciones HTML a MP4, portada de video, marcas de tiempo de capítulos, textos de publicación; también cuando TTS pronuncia mal términos, los subtítulos se desincronizan con la voz, la renderización de fotogramas se rompe o la portada se recorta.

¿Qué es video-make?

Esta habilidad te permite crear videos narrados profesionalmente (explicaciones, tutoriales, promociones) completamente desde código, siguiendo un flujo de trabajo sistemático que garantiza sincronización perfecta entre audio y animaciones. Es especialmente útil para contenido educativo y promocional en plataformas como Bilibili, TikTok y WeChat Video, manejando formatos horizontal y vertical. El proceso central es: texto finalizado → TTS por oración → verificación ASR → línea de tiempo → animación HTML → captura de fotogramas → composición con ffmpeg. La línea de tiempo se deriva del audio real, no de valores fijos, lo que permite reajustes sin romper la sincronización. La habilidad incluye herramientas para generar guiones, locuciones con TTS (MiMo), corrección de pronunciación, subtítulos alineados, portadas adaptadas a diferentes plataformas y textos de publicación. También maneja edge cases como términos técnicos mal pronunciados, desincronización de subtítulos, fallos de renderizado y recortes de portada, asegurando un resultado consistente y listo para publicar.

Compatible con~Claude Code✓Codex CLI~Cursor
npx skills add https://github.com/Qsnh/video-make-skill/tree/HEAD/skills/video-make

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Cómo hacer videos con voz en off mediante código

Resumen

Un video = texto finalizado → TTS por oración → verificación ASR → línea de tiempo → animación HTML → captura fotograma a fotograma → composición con ffmpeg.

Principio fundamental: la línea de tiempo proviene del audio. Primero se graba cada frase, se verifica, se mide el tiempo real de inicio y fin de cada segmento de subtítulo, y luego se colocan todas las animaciones en esos tiempos. Las animaciones no tienen segundos fijos; si cambia la locución, solo se vuelve a ejecutar la línea de tiempo. La renderización consiste en capturar fotogramas de la página con __seek(t), el resultado es determinista y reproducible.

Adecuado para: explicaciones/tutoriales (2–5 minutos), videos promocionales de productos (20–40 segundos), videos educativos con subtítulos y capítulos. No adecuado para: edición con personas reales, videos que requieren material grabado real, videos musicales puros.

Flujo de trabajo

Cada paso tiene un punto de control; no pasar al siguiente si el anterior no se ha superado.

#PasoResultadoPunto de controlReferencia
0InicializaciónDirectorio de trabajobash scripts/init.sh <dir> exitosoabajo
1Elección del tema, verificación, textoscript.md, audio/make_script.pyHechos verificados (experimentos primero); el usuario acepta explícitamente el texto antes de empezar la locuciónreferences/script.md
2Locuciónaudio/raw/NN.wav → audio/clips/NN.wav (1.3x)Cada frase pasa ASR; las problemáticas se regrabarreferences/voice.md
3Línea de tiempobuild/narration.wav, build/timeline.jsonLa segmentación de subtítulos coincide con la vozreferences/timeline.md
4MaterialCapturas de interfaz real, salida de terminal realCoherente con la locución; usar example.com para dominios de ejemploreferences/capture.md
5Composicióncomp/index.htmlRevisar cada composición de fotogramasreferences/composition.md
6Renderizacióndist/video.mp4Duración = línea de tiempo, sonoridad -14 LUFSreferences/render.md
7Portada, textodist/cover-bili.png, dist/cover-douyin.png, dist/copy.txtPortada dentro del área de recorte segura de cada plataformareferences/publish.md
8Entrega, limpiezaEnviar al usuario; archivar fuentesEl usuario confirma que ha guardado antes de limpiarabajo

Inicialización

bash scripts/init.sh ~/work/<proyecto>/video-<número-episodio> copia template/ como directorio de trabajo, copia scripts/ a tools/, e instala playwright-core. La plantilla es una demo de 30 segundos que funciona directamente; antes de empezar, reemplaza estos contenidos de ejemplo:

  • script.md, audio/make_script.py: texto del episodio actual; los capítulos solo se definen una vez en CHAPTERS de make_script.py, y las pausas entre capítulos, la barra de capítulo y las marcas de tiempo se derivan de ahí.
  • audio/direction.txt: [Escena] de la instrucción del director de TTS.
  • asr-prompt.txt: glosario de términos del episodio actual (escritura estándar, con pronunciación si es necesario).
  • Las escenas y animaciones de comp/index.html, y el contenido de las portadas en comp/cover-*.html.

Comandos comunes

Ejecutar en el directorio de trabajo:

ComandoFunción
python3 audio/make_script.pyGenera audio/script.json y audio/lines.json
python3 tools/tts.py audio/lines.json audio/rawLocución por oración; reutiliza audio existente según el texto; volver a ejecutar tras cambiar el texto
bash tools/speed.sh audio/raw audio/clips 1.3Cambia velocidad sin cambiar tono
python3 tools/asr.py audio/clips --enReconocimiento por oración: plain / con sugerencias de términos / modo inglés
python3 tools/takes.py 3,7 3Graba 3 tomas de las oraciones 3 y 7, y las puntúa
python3 tools/takes.py audio/var.json 2Graba 2 tomas de cada variante de la misma oración
python3 tools/tts.py audio/lines.json audio/raw --adopt 3 audio/takes/03-0-1.raw.wavAdopta una toma específica
python3 tools/build_audio.py audio/clips build audio/script.jsonUne la locución y genera la línea de tiempo
python3 tools/align_chunks.py audio/clips build/timeline.json audio/script.jsonAlinea los segmentos de subtítulos con la pronunciación real
node tools/render.mjs --timeline=build/timeline.json --stills=2,8.5,20Captura fotogramas clave en build/stills (limpia antes cada vez)
bash tools/contact.sh build/stills build/sheetsCrea collage 2x2; revisa con Read
bash tools/render-par.sh build/timeline.json build/narration.wav dist/video.mp4 8Renderiza y mezcla el video completo con 8 procesos en paralelo
node tools/render.mjs --html=comp/cover-4x3.html --width=1440 --height=1080 --png=dist/cover-bili.pngGenera portada
python3 tools/bili_kw.py "configurar certificado SSL nginx" "baota https"Investigación de palabras clave B站: top 6 por reproducciones

Dependencias: ffmpeg, Node 18+, Google Chrome local, Python 3 + requests + openai-whisper (modelo small). TTS usa MiMo; la clave se lee de la variable de entorno MIMO_API_KEY o del archivo apuntado por MIMO_ENV_FILE; si ninguna está disponible, se le pide al usuario. Se puede usar otro TTS siempre que genere un WAV por oración.

Áreas propensas a errores

  • Locucionar sin aprobación. Primero envía el texto al usuario; "continuar/empezar/está bien" cuenta como aprobación. Si cambias la redacción por la pronunciación, informa al usuario cada cambio en la entrega.
  • Escribir subtítulos y locución como una sola cosa. Los subtítulos son para que los vea la gente (Nginx, 443, 1.3), la locución es para que la lea el TTS (Engine X, cuatro cuatro tres, uno punto tres). En make_script.py, usa P(subtítulo, pronunciación) para separarlos; la concatenación de las pronunciaciones debe ser igual al texto completo del TTS.
  • Escuchar solo la mezcla completa. El reconocimiento de la mezcla completa identifica mal los términos técnicos; debe hacerse por oración. Para seleccionar tomas, solo mirar la puntuación plain y el resultado --en; el modo prime con sugerencias de términos "corrige" incluso lo mal pronunciado. Las reglas de decisión están en voice.md.
  • Poner segundos fijos en las animaciones. Todas las animaciones después del inicio de la primera oración deben escribirse con T(oración, segmento); después de cambios de velocidad o regrabaciones, los tiempos cambian.
  • Dejar la página vacía al inicio. Si la tarjeta aparece con 2–3 segundos de retraso, la página parece congelada; el contenido debe aparecer en el primer segmento de subtítulo del capítulo.
  • Múltiples animaciones fill: both en el mismo elemento, o IDs duplicados. WAAPI no da error, el elemento puede desaparecer o quedarse en un estado incorrecto; ver composition.md.
  • Abrir la página con file:// para renderizar. Los CSS mask etc. fallan; render.mjs incluye un servidor HTTP local.
  • Portada recortada por la plataforma. B站 recorta una misma imagen a 4:3 y 16:9; TikTok 9:16 se recorta a 3:4; el contenido solo en el área segura.
  • Redirección no permitida. No poner URLs, códigos QR o información de contacto que apunten a sitios reales en imágenes, portada o texto; no escribir "puedes verlo/buscarlo"; los dominios de ejemplo como example.com pueden aparecer en interfaces de demostración y terminales. Los videos publicados en múltiples plataformas no deben usar una plataforma de contenido como ejemplo; los videos promocionales no mencionan precios.
  • Anunciar éxito antes de ver el resultado. Enviar mensajes de progreso solo después de que el comando termine y se haya visto la salida.

Entrega y limpieza

  1. Entrega: video final, portada 4:3 para B站, portada 9:16 para TikTok, dist/copy.txt (título, etiquetas, descripción, marcas de tiempo de capítulos). El video de B站 se publica por defecto también en TikTok y otras plataformas, por lo que se generan tanto la portada vertical como el texto de TikTok; si el usuario especifica una sola plataforma, solo se genera ese conjunto. Listar todos los cambios de redacción por pronunciación, y los puntos de tiempo dudosos para que el usuario los verifique.
  2. Cuando el archivo supere el límite de la herramienta de chat (comúnmente 30MB), primero enviar una vista previa con crf 22 y explicar la ubicación de la versión de alta calidad. Si el envío falla por tiempo de espera y se reenvía, recordar al usuario que puede recibir dos copias.
  3. Después de que el usuario confirme que ha guardado los materiales: archivar los archivos fuente reutilizables (comp/ y los materiales usados, audio/make_script.py, las especificaciones de variantes, script.md, copy.txt, direction.txt, asr-prompt.txt, el script de captura de pantalla, lab/) en la biblioteca de plantillas del usuario (si no hay acuerdo, preguntar al usuario dónde guardarlos, por ejemplo ~/work/<proyecto>/video-template/<número-episodio>/), verificar con diff -r que sean idénticos, y luego eliminar el directorio de trabajo, el perfil temporal del navegador, el contenedor, el servidor de desarrollo (matar por PID, verificar la línea de comandos primero) y las dependencias frontend instaladas solo para las capturas. Conservar la caché del modelo whisper y las imágenes Docker.

Skills relacionados