Vídeo explicativo constructivista · Flujo de trabajo
Un único eje temporal, del que derivan las tres ramas posteriores.
① Guión ② TTS como eje ③ Variación BGM ④ Producto final
Texto ──→ Pista de locución (eje temporal) ──→ Música LMMS (niveles) ──→ Imágenes Remotion + Integración de pistas + Portada
│ ▲
└──── Puntos temporales de límite de nivel ────┘
- Fotogramas determinados por la velocidad natural del habla TTS (no al revés, comprimiendo la velocidad)
- Puntos de variación del BGM sincronizados con los puntos de cambio de nivel de la locución
- Producto final alineado con la pista de locución como referencia; el BGM solo actúa como fondo
0. Inicio: leer primero el contrato de rutas (Este paso no se puede saltar)
Este skill no busca herramientas por sí mismo; todas las rutas provienen del contrato escrito por el skill de configuración del entorno:
$VW_CONTRACT (por defecto ~/.config/ideaform/toolchain.json)
CONTRACT="${VW_CONTRACT:-$HOME/.config/ideaform/toolchain.json}"
source "$(dirname "$CONTRACT")/env.sh" # Exporta VW_NODE / VW_VENV / VW_FFMPEG / …
Antes de empezar, verificar tres cosas:
- ¿Existe el archivo de contrato? Si no → pedir al usuario que ejecute primero el skill
ideaform-setup. - ¿
schema_versiones la versión que reconoce este skill? Si no → solicitar volver a ejecutar el skill de configuración del entorno. - ¿
verified_atesnull? Si sí → Advertir al usuario "El entorno no ha pasado la verificación de integridad", reparar antes de continuar. Además,tools.lmms.stkdir_okdebe sertrue; de lo contrario, el BGM se generará en silencio sin errores.
Referencia rápida de campos clave:
| Propósito | Campo del contrato |
|---|---|
| Ejecutar script TTS (edge-tts en el venv) | tools.venv.python |
| Sintetizar audio/video | tools.ffmpeg.path / tools.ffprobe.path |
| Renderizar imágenes | tools.remotion.project / tools.remotion.browser.resolved |
| Renderizar BGM | tools.lmms.apprun |
| Directorio temporal (debe ser un disco grande) | tmpdir |
⚠️
tmpdiren el contrato no es opcional. El/tmplocal solo tiene 10 MB; Remotion empaqueta / pip instala paquetes escribiendo allí →ENOSPC. Cada comando de Remotion debe incluirTMPDIR.
⚠️ Las rutas no se deben resolver (resolver enlaces simbólicos). Las rutas gestionadas por herramientas contienen enlaces simbólicos; resolver el intérprete del venv perderá el contexto del venv, y no se podrán importar los paquetes. Ver raíz del repositorio
docs/03-Contrato-de-rutas.md.
1. Resumen de las cuatro etapas
| Etapa | Qué hace | Entrada | Salida (todo cae en el espacio de trabajo) | Referencia |
|---|---|---|---|---|
| ① Guión | Convertir la entrada del usuario en un guión de locución estructurado por niveles | Entrada del usuario | script.md + texto_locucion.txt (con niveles marcados) | references/stage1-script.md |
| ② TTS como eje | Medir velocidad natural → crear línea de tiempo → generar pista de locución | texto_locucion.txt | plan.json / timeline.ts / voice.wav | references/stage2-tts.md |
| ③ Variación BGM | Límites de nivel → plan de variación → pista LMMS | plan.json + marcas de nivel | bgm-plan.json / bgm.wav | references/stage3-bgm.md |
| ④ Producto final | Remotion organiza imágenes + integra pistas + renderiza + portada | timeline.ts + pistas de audio + bgm-plan.json | final.mp4 + cover.png | references/stage4-render.md · references/cover.md |
La coherencia de estilo se gestiona mediante references/constructivist-style.md,
imágenes y portada comparten la misma paleta de colores / fuentes / rejilla, por lo que son naturalmente consistentes.
2. Etapa uno · Guión (los niveles son un requisito estricto)
El usuario proporciona una entrada (un tema / un material / una idea verbal). El resultado es:
script.md— guión completo, con niveles argumentativos explícitostexto_locucion.txt— una línea por oración para la locución, que consume TTS
Los niveles no son decorativos; son la entrada de la etapa tres. Sin marcas de nivel, la variación del BGM no tiene punto de apoyo.
## Nivel 1 · Introducción
Esta es la primera capa de "El guión como eje temporal".
La pista de locución es el eje temporal de toda la línea de producción.
## Nivel 2 · Desarrollo
Los fotogramas de la imagen están determinados por ella, no al revés.
...
- Una oración = una unidad semántica, no meter dos cosas en una oración (TTS organiza el tiempo por oración; si se mete, alargará la ranura)
- Se recomienda 8–30 caracteres por oración; dividir si es demasiado larga, combinar si es demasiado corta
- Usar punto / signo de interrogación al final para ayudar a TTS a segmentar
Ver detalles en references/stage1-script.md.
3. Etapa dos · TTS como eje (Orden inalterable)
"$VW_VENV/bin/python" skills/ideaform/scripts/make-tts-track.py \
--lines texto_locucion.txt --fps 30 --audio \
--plan-out out/plan.json --ts-out out/timeline.ts
Primero la pista de audio, luego el eje temporal. La línea de tiempo surge de la velocidad real del habla TTS:
① Escribir texto de locución
② make-tts-track.py --lines texto_locucion.txt --fps 30 --audio ← Mide velocidad natural, genera línea de tiempo
③ Usar el TOTAL_FRAMES de salida para escribir la composición de Remotion ← Así se determinan los fotogramas
④ Luego renderizar
Costo del contraejemplo (medido): Si primero se escriben 43 códigos de tiempo fijos según storyboard, el TTS suma 212.90 s de velocidad natural, pero el video solo tiene 174.80 s → obligado a comprimir 1.218x. Esta concesión se habría evitado por completo.
El mismo script también puede hacer lo contrario (cuando ya hay SRT o códigos de tiempo fijos, se usa ajuste de velocidad en dos fases),
pero eso es remedio, no la opción preferida. Ver references/stage2-tts.md.
⚠️ Prohibido pedir al usuario "¿Cuántos minutos tendrá el video final?" La duración = velocidad x cantidad de texto, es salida, no entrada; al comenzar, no se debe preguntar ni dar opciones como "Versión estándar X minutos". Solo informar: "Según este guión, medido: X min Y seg". Si el usuario quiere más/menos → modificar el guión, no el tiempo. (Registrado el 15/10/2026 en el proyecto Guihua, anotación E16)
Salida: plan.json contiene para cada señal start/end/dur/frameStart/frameEnd;
timeline.ts se puede copiar directamente a src/timeline.ts en el proyecto Remotion.
4. Etapa tres · Variación BGM (El alma de este flujo de trabajo)
Punto clave: Cada vez que el discurso entra en un nuevo nivel, la música cambia de forma — pero no cambia de pieza.
# ① Asignar los niveles del guión a números de señal, marcando la función narrativa de cada nivel
"$VW_VENV/bin/python" skills/ideaform/scripts/bgm-plan.py \
--plan out/plan.json \
--layers "1:present,4:develop,6:resolve" \
--key "La menor" --out out/bgm-plan.json
# ② Generar proyecto LMMS según bgm-plan.json y renderizar (usando composer.py de electronic-music-production)
# tools.lmms.apprun del contrato renderiza; bpm y timeline lp1pos deben escribirse según mmp_hints
Seis funciones narrativas (elegir una por nivel):
| Función | Intención | ¿Qué cambia? |
|---|---|---|
present | Presentar·Introducir | Solo mostrar motivo, una sola voz, silencio |
develop | Desarrollar·Profundizar | +bajo +ritmo, secuencia de motivos |
intensify | Enfatizar·Conflicto | Todas las voces, octava arriba, acordes prestados, aumentar dinámica |
contrast | Contrastar·Giro | Cambiar textura sin aumentar volumen: eliminar capas, cambiar timbre, modular |
resolve | Concluir·Regresar | Reducir, volver a la tónica, aumentar el valor del motivo |
sustain | Mantener·Transición | No cambiar (cuando el nivel no cambia, no variar aleatoriamente; diluiría el contraste) |
Reglas estrictas:
- Los elementos de identidad no deben cambiar — célula motívica, centro tonal, tempo base. Si cambian, es cambiar de canción, no variar.
- Cada sección debe cambiar al menos 1 elemento de forma; en
bgm-plan.mdse listarán las "evidencias de variación" para cada sección. Si entre dos secciones adyacentes la evidencia está vacía, significa que falta la marca de nivel. - El punto de variación debe caer en el límite de nivel del discurso (se puede usar
--lead-inpara que la música se adelante ligeramente).
Método completo e implementación en LMMS en references/stage3-bgm.md.
5. Etapa cuatro · Producto final
5.1 Imágenes: Con la pista de locución como eje temporal
cp out/timeline.ts <proyecto_remotion>/src/timeline.ts # Fotogramas/límites de escena se derivan de CUES
cd <proyecto_remotion>
export TMPDIR="$VW_TMPDIR" # ★ Obligatorio
npx remotion studio # Primero mostrar vista previa al usuario
Los límites de escena en el lado de imagen no se escriben con números de fotograma manualmente; se derivan de CUES:
export const SCENES = {
s1: { from: 0, dur: CUES[2].start },
s2: { from: CUES[2].start, dur: CUES[4].start - CUES[2].start },
} as const;
Diagramas estructurales / vías de señal / diagramas de mecanismo → siempre generación determinista, nunca usar IA para generar imágenes.
La IA dibujará estructuras químicas ficticias y no se notará el error — este tipo de material debe ser reproducible y verificable.
Usar scripts/gen-structures.py: SMILES → representación determinista con RDKit
→ componentes Remotion basados en fotogramas.
python3 scripts/gen-structures.py --tsv structures.tsv --out structures
# → svg/*.svg + components/*.tsx (con animación propia) + manifest.json
# → Verificación offline de fórmula molecular (RDKit CalcMolFormula); si no coincide, salida distinta de cero, se puede encadenar con `&&`
- La paleta de colores sigue las opciones oficiales de RDKit (
useBWAtomPalette/singleColourBonds/setSymbolColour), nunca procesar los colores del SVG con expresiones regulares — es reinventar la rueda y se rompe con versiones de RDKit (ver anotación E20). - Los componentes generados usan variables CSS
--mol-dash/--mol-textpara animaciones de línea; el padre debe proporcionarcolor. - Para visualización molecular más amplia (gráficos de rejilla / resaltado de esqueleto / conformación 3D / interacción proteína-ligando), buscar primero skills existentes (ver §7), no forzar dentro de esta línea de producción de video.
5.2 Integración de pistas de audio (dos rutas, por defecto A)
A. Integración en Remotion (recomendada) — usar <Audio> en la composición; el mp4 renderizado incluye las pistas:
<Audio src={staticFile("voice.wav")} />
<Audio src={staticFile("bgm.wav")} volume={0.1694} />
Ese número de volume no se inventa, se calcula a partir del RMS medido:
bash scripts/mix-av.sh --plan-only --voice voice.wav --bgm bgm.wav --drop 9
# RMS de locución = -23.46 dBFS RMS de BGM = -17.04 dBFS
# → BGM necesita -15.42 dB → volume = 0.1694
B. Post-síntesis (video ya renderizado / se quiere regrabar locución):
bash scripts/mix-av.sh --video silent.mp4 --voice voice.wav --bgm bgm.wav --out final.mp4
⚠️ Ruta B debe usar explícitamente
-map 0:v:0 -map 1:a:0. El mp4 de salida de Remotion incluye una pista AAC silenciosa; si no se usa-map, ffmpeg la seleccionará automáticamente → el producto final tiene código de salida 0, duración correcta, se reproduce, pero no hay sonido.mix-av.shya incluye este-map.
5.3 Renderizado y portada
export TMPDIR="$VW_TMPDIR"
npx remotion render <IdComposición> out/video.mp4 --concurrency=3
npx remotion still Cover out/cover.png --props='{...}' # Portada: composición estática, no usar animaciones
- Renderizado por segmentos para videos largos: Un video de 7 minutos renderizado de una sola vez puede agotar la memoria y exceder el tiempo de espera. Usar
--frames=A-Bpor segmentos →concat -c copypara unir sin pérdida. - Portada usar una composición estática con
durationInFrames={1}dentro del componente no usaruseCurrentFrame(en still es siempre 0; el valor inicial de animación haría que los elementos sean invisibles). - Formato de portada en
references/cover.md, normas de estilo enreferences/constructivist-style.md.
6. Entrega sin supervisión visual: Cada etapa debe pasar el validador
El modelo no ve imágenes ni escucha sonido. Por lo tanto, "renderizado exitoso" ≠ "imagen correcta, sonido correcto". Cada paso se mide numéricamente; si no pasa, se rechaza la entrega:
# Autocomprobación de audio (pista TTS, BGM): pico/RMS/recorte/desviación de duración
# Autocomprobación de imagen: color de píxeles / pureza de pasillo / recuento de píxeles de texto
# --layout debe coincidir: cover=formato de portada; scene=escena de video (por defecto).
# La muestra se define según el formato; si se usa incorrectamente, una portada correcta también se considerará fallida (ver 05-Solución de problemas D2).
python3 scripts/verify-video.py cover out/cover.png --layout cover
# Autocomprobación de producto final: fotogramas / duración / tasa de bits de pista (para evitar pista silenciosa)
# Orden de localización de ffprobe: VW_FFPROBE → contrato de ruta toolchain.json → sistema
VW_FFPROBE="$VW_FFPROBE" python3 scripts/verify-video.py video out/final.mp4 --frames 732 --fps 30
El script indica fallo con código de salida distinto de cero, se puede encadenar directamente con &&.
Referencia rápida de criterios comunes:
| Objeto | Criterio | Umbral |
|---|---|---|
| Audio | No silencio | Pico > 1000 y RMS > 100 |
| Audio | Sin recorte | Muestras a escala completa < 0.01% |
| Audio | Alineación de duración | Desviación del plan < 50 ms |
| Portada | Tamaño | 1920×1080 |
| Portada | Renderizado de texto | Píxeles de tinta en área de texto > 300 |
| Portada | Eje sin atravesar texto | Píxeles rojos en área de título < 60 |
| Producto final | Fotogramas | Estrictamente igual al valor planificado |
| Producto final | Pista de audio no silenciosa | Tasa de bits > 64000 bps |
| BGM | Nivel de fondo | 8–12 dB por debajo de la locución |
7. Otras capacidades que se combinan con este skill
| ¿Qué se necesita? | ¿Cuál usar? |
|---|---|
| Detección / instalación / contrato de entorno | ideaform-setup (una sola vez) |
| Skill listo para nuevas herramientas de código abierto (tomar prestado: recolectar de GitHub → verificar seguridad → almacenar) | scripts/harvest-skills.py <nombre_herramienta> de ideaform-setup |
| Gráficos deterministas de estructuras químicas / diagramas de vías | scripts/gen-structures.py de este skill (RDKit → SVG → componentes Remotion) |
| Visualización molecular más amplia (gráficos de rejilla / resaltado de esqueleto / conformación 3D / proteína-ligando) | Skills externos existentes: molecule-visualization de synthetic-sciences/openscience (Apache-2.0), ghutchis/chem-skill (MIT) |
Formato de proyecto LMMS, parámetros de plugins, envolventes eldata | electronic-music-production + su references/05 |
| Composición musical (armonía, motivo, composición sin audio, emergencia) | references/06–10 de electronic-music-production |
| Sintaxis y detalles de renderizado de Remotion | remotion-best-practices |
| Método completo de verificación sin supervisión visual a nivel de píxel | headless-visual-verify |
| Problemas de entorno WSL (/mnt, captura con gh, ruta de audio) | wsl-pitfalls |
8. Lista de entrega
Una vez terminado un video, el espacio de trabajo debe contener:
<espacio_de_trabajo>/
├── script.md Guión con niveles
├── texto_locucion.txt Texto de locución
├── out/
│ ├── plan.json Eje temporal (segundos/fotogramas de cada señal)
│ ├── timeline.ts Línea de tiempo lista para Remotion
│ ├── voice.wav Pista maestra de locución
│ ├── bgm-plan.json Plan de variación + bgm-plan.md (evidencias de variación)
│ ├── bgm.wav Pista BGM
│ ├── video.mp4 Imagen sin sonido (o producto final con pistas integradas)
│ ├── final.mp4 ★ Producto final
│ └── cover.png ★ Portada
└── .tts/ Caché de TTS (conservar; al re-ejecutar solo toma unos segundos)
Antes de entregar, se debe ejecutar todas las verificaciones de la sección 6 e informar honestamente cuáles pasaron y cuáles no se midieron.
9. Auto-evolución: Registrar errores en cuanto se producen
Este flujo de trabajo es un skill compuesto mutable — a medida que se usa, debería adaptarse mejor a tu ritmo de producción:
- Cuando se produce un error y se soluciona → registrarlo en la raíz del repositorio
docs/06-Cuaderno-de-errores.md(formato de seis columnas, numeración consecutiva). ⚠️ No crear otrodocs/enskills/ideaform/— sería un segundo cuaderno y colisionaría con la numeración del original (registrado el 15/10/2026, anotación E19). - Cuando un error se corrige permanentemente con un script/documento (no se evita) → cambiar el estado a
Corregidoe indicar la solución. - Cuando se repite el mismo tipo de error por segunda vez → no registrar una tercera entrada; directamente escribir la defensa en el script (validador / valor por defecto / contrato).
- Al introducir una nueva herramienta de código abierto → primero cosechar y luego actuar:
harvest-skills.py <nombre_herramienta>para buscar skills maduros de la comunidad (con protección de bifurcación, no sobrescribirá tus modificaciones locales); solo si no se encuentra uno adecuado, escribir uno propio. Si el skill cosechado produce errores, también registrarlos. - Antes de finalizar la sesión: ¿hay algo "corregido pero no registrado"?