video-flow: flujo de trabajo para videos explicativos renderizados con código
En una frase: primero piensa en "qué enseñar", luego convierte eso en una línea de tiempo computable y, finalmente, haz que el navegador dibuje cada fotograma. Resultado final =
render(t)de Canvas/HTML + capturas de pantalla con headless Chrome + FFmpeg + TTS/música/subtítulos opcionales.
Este Skill divide un "video" en 8 fases comprobables. Cada fase tiene un producto entregable y puntos de verificación; si algún paso no es apto, no se debe pasar al siguiente.
0. Cuándo usar / No usar
Usar:
- Convertir un PDF, PPT, DOCX, artículo, página web, video o un tema en un video explicativo de 1 a 5 minutos.
- Necesitar un video con "texto claro, datos precisos, posibilidad de modificar un fotograma y reproducible" (ventaja estructural del renderizado con código frente a los modelos generativos).
- Requerir múltiples versiones (vertical, cuadrado, panorámico) o versiones en varios idiomas.
- Necesitar narración, subtítulos y música, y desear que todo el proceso sea repetible.
No usar:
- Si se necesita un video con actores reales/escenas realistas -> usar modelos generativos de video o grabación real; este Skill solo maneja "la capa de código".
- Si solo se trata de editar material existente -> usar herramientas de edición o un Agent.
- Si solo se desea generar un MP4 sin definir el storyboard ni el guion -> el resultado parecerá una plantilla; se recomienda completar los pasos 1 y 2 primero.
1. Reglas estrictas (si se viola alguna, rehacer)
- La imagen es una función pura del tiempo: la página debe exponer
window.render(t); dadot, la imagen es única.- Prohibido:
Date.now(), aleatoriedad sin semilla, estado impulsado porrequestAnimationFrame,transition/animationde CSS, caché entre fotogramas. - Las animaciones acumulativas (partículas, agua) deben simularse con un paso fijo desde 0 hasta
t, o mediante una fórmula analítica.
- Prohibido:
- La línea de tiempo es la única fuente de verdad: el storyboard, la narración, la música, los efectos de sonido y los subtítulos se derivan del mismo
timeline.json. - Primero el storyboard, luego el código: sin
storyboard.mdyscript.json, no se escribe código de escena. - No inventar hechos: los números, años, nombres de personas y fórmulas deben provenir del material original; si hay incertidumbre, marcarlo con
[pendiente de verificar]y listarlo por separado en la entrega. - Sin marca de agua ni logotipo por defecto: a menos que el usuario proporcione un logotipo o nombre de marca; por defecto, el pie de página solo muestra información del curso/tema.
- Una sola codificación: el audio se mezcla y ecualiza en la fase WAV, y solo se codifica una vez a AAC; evitar recodificaciones.
- Pasar el QA antes de la entrega: verificar fotogramas perdidos, fotogramas negros, sonoridad, duración, subtítulos y sincronización audio-video; ver paso 8.
2. Entrada y productos
Entrada (cualquiera, se pueden combinar)
| Tipo | Procesamiento |
|---|---|
scripts/ingest.py extrae texto; si es escaneo o tiene caracteres extraños, rasterizar automáticamente a PNG y "mostrar la página" al modelo | |
| PPTX | Extraer título, cuerpo y notas de cada diapositiva; opcionalmente exportar diapositivas clave como imágenes |
| DOCX / Markdown / TXT | Extraer directamente a source/source.md |
| URL de página web | Extraer el cuerpo del texto; conservar el enlace de origen |
| Video | Metadatos con ffprobe + captura de fotogramas en puntos específicos; si no hay ASR, que el humano complemente el contenido |
| Tema libre | Una frase o esquema del usuario; primero pedir al usuario que confirme "los hechos que deben aparecer" |
Estructura del proyecto
<project>/
project.json # Metadatos: título/audiencia/objetivo/formato/estilo/voz/música/marca
source/ # Material fuente (source.md, pages/*.png, meta.json)
storyboard.md # Tabla de storyboard: qué se dice en cada escena, imagen, duración, narración, puntos clave
script.json # Legible por máquina: scenes[] (type/guion/visual/vo/duración)
build/ # index.html + lib.js + theme.js + scenes.js + timeline.js
audio/ # vo/*.wav, bgm, mix.wav
frames/ # JPEG por fotograma
out/ # final.mp4 / final.srt / poster.png
qa/ # report.md + hojas de contacto + fotogramas extraídos
Usar scripts/init_project.py para generar la estructura de una vez.
3. Flujo de trabajo (8 pasos)
Paso 0: Verificar el entorno
python scripts/check_env.py
Requisitos: Python 3.10+, FFmpeg/ffprobe, un navegador con motor Chromium, numpy/scipy.
Recomendado: edge-tts (voz neuronal en línea), pypdf, python-pptx, python-docx, Pillow.
Instalar lo que falte según las indicaciones; si no se puede instalar, degradar (sin narración / voz del sistema / audio escrito a mano).
Paso 1: Leer el material fuente y extraer la "estructura pedagógica"
Responder primero 5 preguntas (escribirlas en brief de project.json):
- ¿Quién es la audiencia? ¿Qué saben ya?
- Después de verlo, deberían poder decir/hacer qué? (1–3 objetivos verificables)
- ¿Cuál es el punto más fácil de malinterpretar/difícil?
- ¿Qué hechos/fórmulas/datos deben aparecer? ¿Cuáles son las fuentes?
- ¿Duración y formato? ¿Plataforma (aula/móvil/redes sociales)?
No seguir el orden de las páginas del original. Reorganizar usando una de las 4 estructuras de references/storytelling.md:
- Cadena causal (recomendada para ciencias/ingeniería);
- Problema → solución → verificación;
- Error → corrección → transferencia;
- Línea de tiempo/proceso.
Paso 2: Elegir estilo y formato
Según references/styles.md, elegir 1 estilo (silicon / paper / blueprint / neon / swiss) y según references/formats.md elegir formato.
Reglas:
- Contenido "chips/ingeniería/datos" → silicon / blueprint;
- "Humanidades/biología/historia" → paper;
- "Lanzamiento/marketing/joven" → neon / swiss;
- Una pantalla, un tema; en vertical, reorganizar la disposición, no recortar horizontal a vertical.
Paso 3: Escribir storyboard y guion
Generar storyboard.md (para humanos) y script.json (para máquinas). Cada escena debe incluir:
type(title/concept/process/compare/formula/bars/quote/recap/custom)kicker(subtítulo),headline(conclusión en una frase),points(≤3 puntos)vo(narración, 1–2 frases; si no hay voz en off, dejar vacío)visual(datos concretos de gráficos/tablas/flujos/fórmulas)duration(puede estar vacío; se determinará automáticamente por la duración de la narración)
5 reglas estrictas para escribir el guion:
- El texto en pantalla ≠ guion de narración: en pantalla solo palabras clave/conclusiones; la narración explica.
- Máximo 1 conclusión + 3 puntos de apoyo por pantalla; título ≤ 18 caracteres, línea de texto ≤ 22 caracteres.
- Cada 2–4 segundos debe haber un cambio (elemento, escena, énfasis), pero sin explosiones de partículas.
- Primero escribir una "lista prohibida": fondo degradado + letras grandes centradas, todas las elementos fundidos, texto pequeño llenando la pantalla, destellos sin sentido.
- Marcar las frases con hechos con su fuente; si hay incertidumbre, añadir
[pendiente de verificar].
Paso 4: Generar narración y línea de tiempo
# Opcional: si no hay locución, saltar y asignar duration explícita a cada escena
python scripts/tts.py --project . --voice zh-CN-XiaoxiaoNeural --rate +3%
python scripts/timeline.py --project .
tts.pygeneraaudio/vo/<id>.wav(48 kHz), aplica EQ/compresión ligera; soporta--from-dirpara usar grabaciones humanas.timeline.pygenerabuild/timeline.jsytimeline.jsonusando la duración real de la narración:scene.duration = head + voDuration + tail, para escenas sin narración usardurationexplícita.- A partir de aquí, solo modificar
script.jsony volver a ejecutar estos dos pasos, no editar el timeline manualmente.
Paso 5: Construir la página e implementar las escenas
Usar la plantilla:
python scripts/init_project.py --dir my-video --title "..." --format 16:9 --style silicon
# Editar build/content generado por timeline.py; las escenas genéricas ya están implementadas, solo ajustar script.json
- Las escenas genéricas (8 tipos) están en
build/scenes.js, leenCONTENTpara renderizar; suficientes para la mayoría de videos explicativos. - Para gráficos especializados (chips, circuitos, anatomía, mapas, moléculas), escribir
build/custom.js:Enwindow.CUSTOM['s3'] = function(u, D, sc, ctx){ /* usar helpers de lib.js para dibujar */ };script.json, asignartype: "custom"a esa escena. - Trabajar una escena a la vez: primero renderizar 3 fotogramas estáticos (
scripts/render.py --still 1.2,2.4,3.6), verificar desbordamiento de texto, superposiciones, tamaño del objeto principal, luego continuar.
Paso 6: Renderizar
python scripts/render.py --project . --fps 30
# Renderizar solo un segmento: --start 8 --duration 4
# Reutilizar Chrome existente: --cdp http://127.0.0.1:9333
# Dejar que el script inicie Chrome: --launch-chrome
Salida: frames/f00000.jpg...; soporta reanudación (los fotogramas existentes de más de 2KB se saltan).
Chrome sin cabeza y sandbox: si el entorno prohíbe IPC/tuberías de Chrome, ejecutar en un entorno permitido, o usar
--cdppara conectarse a un Chrome ya iniciado.
Paso 7: Música, efectos de sonido, mezcla y subtítulos
python scripts/audio.py --project . # Sintetizar BGM + colocar narración + duck + master
python scripts/srt.py --project . # Generar out/final.srt
- Sin narración:
audio.py --no-bgmo solo usar música proporcionada por el usuario. - Música del usuario: colocarla en
audio/music.*,audio.pyhará loop/corte y duck automáticamente. - Sonoridad objetivo por defecto: −14.2 LUFS, pico real ≤ −1.5 dBFS; el audio se codifica una sola vez.
Paso 8: Codificación + QA + Entrega
python scripts/encode.py --project . # frames+mix+srt → out/final.mp4
python scripts/qa.py --project . # qa/report.md + collage de fotogramas
El QA debe pasar todo (ver references/qa.md):
- Duración/formato/fotogramas por segundo/pista de audio/pista de subtítulos correctos;
- Sin fotogramas negros de ≥0.25 s; sin espacios en blanco, sin texto superpuesto, sin desbordamiento;
- Sonoridad dentro de ±1 LU del objetivo, pico real ≤ −1.5 dBFS;
- El primer fotograma no es negro; la última escena tiene cierre;
- Lista de hechos coherente con el material fuente;
[pendiente de verificar]listado por separado.
Entrega: out/final.mp4, out/final.srt, poster.png, storyboard.md, script.json, qa/report.md, tiempo de renderizado y deficiencias conocidas.
4. Tipos de escenas genéricas (plantilla ya implementada)
| type | Uso | Campos clave |
|---|---|---|
title | Apertura/capítulo | title/subtitle/kicker |
concept | Un concepto + 3 puntos clave | headline/points/visual |
process | Proceso/pasos (3–5) | steps[] |
compare | Comparación de dos partes | left/right |
formula | Fórmula + explicación | formula/notes[] |
bars | Comparación de datos | items[{label,value}] |
quote | Cita/conclusión | quote/author |
recap | Mapa de resumen | nodes[]/takeaway |
custom | Gráfico especializado | Escribir custom.js propio |
Para añadir un nuevo tipo: agregar window.SCENES_IMPL['type'] en scenes.js y documentar el contrato de datos en references/pipeline.md.
5. Formatos y área segura
| Formato | Tamaño | Área segura | Tamaño de título | Tamaño de texto |
|---|---|---|---|---|
| 16:9 | 1920×1080 | 96 izq/der / 64 sup/inf | 72–120 | 28–40 |
| 9:16 | 1080×1920 | 64 izq/der / 160 sup/inf | 64–96 | 32–44 |
| 1:1 | 1080×1080 | 72 en todos los lados | 56–88 | 28–40 |
| 4:5 | 1080×1350 | 80 en todos los lados | 60–92 | 30–42 |
En vertical, reorganizar: título arriba, gráfico en medio, conclusión abajo; no comprimir horizontalmente. La plantilla usa layout() para cambiar según el formato; consultar references/formats.md.
6. Fallos comunes → Soluciones
| Síntoma | Causa raíz | Solución |
|---|---|---|
| Pantalla negra/blanca | Error JS, render no definido, tamaño de canvas 0 | render.py --still, ver consola; asignar ancho/alto explícito al canvas |
| Fuente incorrecta/primer fotograma con fuente de respaldo | Fuente no cargada | Esperar document.fonts.ready antes de poner READY=true; para CJK usar cadena de respaldo del sistema |
Mismo t produce dos imágenes diferentes / parpadeo en paralelo | Uso de rAF/timer/random/estado entre fotogramas | Convertir a función pura; hash(seed); resorte cerrado |
| Texto superpuesto/desbordado | No se verificaron fotogramas estáticos por escena | 3 fotogramas estáticos por escena + extraer fotogramas a 360px de ancho en vertical |
| Desincronización audio-video | Audio comienza en 0 vs video comienza en otro punto; TTS frase por frase | Misma línea de tiempo; TTS completo; -ss antes de -i |
| Sonoridad fluctuante | Múltiples loudnorm/codificaciones | Ganancia estática solo en fase WAV; una codificación AAC |
| Renderizado demasiado lento | 4K/subfotogramas/pincel/WebGL | Primero probar a 960×540; subfotogramas solo para movimientos rápidos; workers en paralelo |
| Chrome no arranca | sandbox limita IPC/tuberías | Ejecutar en entorno permitido, o --cdp conectar a Chrome ya iniciado |
7. Puntos de extensión
- Nuevo estilo: copiar
templates/styles/*.json, modificar paleta/fuentes/tipo de fondo; añadir una fila enstyles.md. - Nueva escena: registrar en
build/scenes.js; o escribir gráfico especializado enbuild/custom.js. - Locución humana: colocar grabaciones como
<scene-id>.wavenaudio/vo_human/, usartts.py --from-dirsolo para remuestreo/tratamiento ligero. - Multilingüe: un
script.<lang>.json+ voz TTS correspondiente; la línea de tiempo puede reutilizar las mismas imágenes (tener en cuenta diferencias de longitud de texto). - Múltiples formatos: mismo
script.jsoncon diferentesproject.formatpara reiniciar/renderizar; el diseño se adapta conlayout(). - Marca:
project.json.brandproporciona texto de logotipo/color/pie de página; desactivado por defecto.
8. Documentos de referencia
references/pipeline.md: línea de tecnología completa, contrato derender(t), renderizado CDP, parámetros FFmpeg, modelo de datos de línea de tiempo.references/inputs.md: extracción de PDF/PPT/DOCX/URL/video y OCR de respaldo.references/storytelling.md: 4 estructuras pedagógicas, tabla de ritmo, reglas de guion.references/styles.md: paletas/fuentes/animaciones/temas aplicables de los 5 estilos.references/formats.md: formatos, área segura, reglas de reorganización vertical.references/audio.md: opciones TTS, grabación humana, síntesis de música, ducking, sonoridad, codificación única.references/qa.md: lista de verificación de aceptación y comandos automáticos.