Manim 1080p60 Sistema de Video Explicativo Técnico y Locución Sincronizada
Resumen y Recursos Incluidos
Crea videos explicativos técnicos nítidos y deterministas en 1920x1080 @ 60fps y walkthroughs de arquitectura en Python puro usando Manim Community sin necesidad de pdflatex o MacTeX.
Opcionalmente, empareja las animaciones con locución neural de precisión de muestra (Piper ONNX offline, cualquier endpoint HTTP /v1/audio/speech compatible con OpenAI, o TTS CLI personalizado), normalización de sonoridad EBU R128, subtítulos WebVTT .vtt sincronizados y un reproductor HTML5 offline sin CDN.
assets/nord_manim_theme.py: Tokens de paleta de colores Nord Polar/Frost/Aurora, constantes de diseño de marco seguro, ayuda de sincronizaciónBeatTimer, primitivas libres de LaTeX (make_header_banner,make_node_card,make_badge,animate_blocked_pulse,safe_fit_text) y conectores esquemáticos ortogonales estrictos anclados a puertos (connect_h,connect_v,connect_elbow,animate_packet_along,assert_all_orthogonal).assets/video_player_template.html: Reproductor de cine HTML5 Nord oscuro/claro autónomo y sin CDN con pestañas de capítulos, marcadores de tiempo cliqueables, velocidad de reproducción (0.75x..2.0x) y cambio opcional de audio/subtítulos bilingües.check_scene_bounds.py: Verificador de diseño previo al renderizado que comprueba las escenas de Manim o puntos de control JSON para detectar desbordamiento del marco[-6.8, 6.8] x [-3.75, 3.75]y colisiones de etiquetas de texto hermanas.mux_narration.py: CLI de Python de la biblioteca estándar que sintetiza WAV por latido mediante Piper, un endpoint HTTP/v1/audio/speechcompatible con OpenAI o un comando TTS personalizado, emitebeat_timings.json, ensambla una pista WAV maestra de precisión de muestra, rellena clones de fotogramas de video finales (tpad=stop_mode=clone) para que el habla nunca se recorte, opcionalmente normaliza la sonoridad (--loudnorm-lufs -18.0), multiplexa H.264 + AAC (+faststart) y escribe subtítulos.vtt.lint.py: Verificador del paquete de salida que comprueba H.264yuv420p+ flujos de audio conffprobe, monotonicidad de encabezados/pistas WebVTT y las invariantes CSP/sin CDN/sin emoji del reproductor HTML5 offline.references/manim-layout-and-choreography.md: Léelo al diseñar topologías de múltiples nodos, enrutamiento ortogonal de bus/codo, contadores dinámicos, flechas bidireccionales o concatenación de múltiples escenas conffmpeg.references/voiceover-and-commentary.md: Léelo al redactar manifiestos de narración, instrucciones de prosodia del narrador natural, glosarios de pronunciación fonética, normalización EBU R128 o pistas de locución bilingües.
1. Storyboard y Diseño Narrativo Multi-Acto
Antes de escribir código Manim, estructura la explicación en actos discretos y una tabla de storyboard latido por latido.
Mantén una clase Scene por Acto para que las ediciones en el Acto 2 nunca requieran re-renderizar el Acto 1 o el Acto 3:
- Acto 1 — Configuración y Admisión de Solicitudes: Introduce la topología, los invariantes y la guardia de entrada (ej.,
Cliente -> API Gateway -> Limitador de Tasa Token-Bucket). - Acto 2 — Ejecución en Estado Estacionario: Traza la ruta de datos principal y las transiciones de estado (ej., búsqueda de un solo vuelo en
Caché de Lectura-> hidratación deBase de Datos Primaria-> reescritura TTL). - Acto 3 — Modos de Fallo y Recuperación: Demuestra lo que sucede cuando se superan los límites o fallan los nodos (ej., rechazo por ráfaga
HTTP 429o promoción de quórum deBloqueo Distribuido y Replicación de Registro de Anticipación).
Mapea cada latido explícitamente antes de codificar:
beat_id | visual_action | min_visual_sec | commentary_script (si se narra) |
|---|---|---|---|
act1_ingress | Renderiza 4 tarjetas de topología Nord + encabezado; anima el paquete de solicitud hacia la Puerta de Enlace | 3.2 | Las escrituras entrantes pasan por una puerta de enlace perimetral antes de tocar el almacenamiento con estado. |
act1_bucket | Decrementa el contador de tokens 100 -> 99; destello de insignia verde ADMITIDO | 3.8 | Una verificación atómica de token-bucket absorbe ráfagas de tráfico mientras limita la concurrencia descendente. |
act1_reject | Activa animate_blocked_pulse (429 LÍMITE DE TASA SUPERADO) cuando los tokens llegan a 0 | 3.5 | Una vez que se agota la capacidad de ráfaga, los llamadores en exceso fallan rápidamente con HTTP 429 en lugar de poner en cola infinitamente. |
2. Creación Libre de LaTeX con Manim Community
Configuración de Entorno Aislado
Provisa Manim (y piper-tts opcional) dentro de un entorno virtual aislado; verifica que ffmpeg y ffprobe estén en PATH:
uv venv venv
uv pip install --python venv/bin/python manim piper-tts
Reglas Estrictas de Esquemática Libre de LaTeX y Ortogonal
- Cero Subprocesos TeX: Nunca uses
Tex,MathTex,TitleoDecimalNumber(que invocanpdflatex/dvisvgm). UsaText,MarkupText(<b>,<i>,<sub>,<sup>,<span foreground="...">),Code,RoundedRectangle,Arrow,DashedVMobjectyMoveAlongPath. - Regla Esquemática de Oro (Cables Ortogonales Anclados a Puertos): NUNCA llames a
Arrow(card_a, card_b)directamente sobre dosMobjects al construir diagramas de bloques de arquitectura: Manim apunta rayos entre los centros del cuadro delimitador y produce flechas diagonales torcidas cada vez que los anchos de las tarjetas o las posiciones Y difieren. Enruta cada borde medianteconnect_h(card_from, card_to, y=...),connect_v(card_from, card_to, x=...)oconnect_elbow(points), anima paquetes conanimate_packet_along(self, edge, ...)y valida la geometría del cable conassert_all_orthogonal(connectors, cards). - Cuadrícula de Coordenadas de Marco Seguro: El lienzo 16:9 de Manim abarca
[-7.11, 7.11] x [-4.0, 4.0]. Mantén todo el contenido creado dentro de[-6.6, 6.6] x [-3.5, 3.5]y mantény < -3.05vacío siempre que se muestren subtítulos WebVTT. - Importa
assets/nord_manim_theme.py: Estableceself.camera.background_color = BG_DARKy construye tarjetas, conectores ortogonales, animaciones de paquetes y retenciones de latidos de manera consistente:
from pathlib import Path
import sys
SKILL_DIR = Path(__file__).resolve().parent
sys.path.insert(0, str(SKILL_DIR))
sys.path.insert(0, str(SKILL_DIR / "assets"))
from manim import Create, FadeIn, Scene, VGroup
from check_scene_bounds import dump_checkpoints
from nord_manim_theme import (
ACCENT_BLUE, ACCENT_CYAN, BG_DARK, STATUS_ERR, STATUS_OK,
BeatTimer, animate_blocked_pulse, animate_packet_along,
assert_all_orthogonal, connect_h, make_header_banner, make_node_card,
)
class Act1RateLimiter(Scene):
def construct(self) -> None:
self.camera.background_color = BG_DARK
timer = BeatTimer("tmp/beat_timings.json")
checkpoints: list[dict] = []
header = make_header_banner(
"Acto 1 / Admisión de Solicitudes",
"Puerta de Enlace API y Limitador de Tasa Token-Bucket",
)
gw = make_node_card("API Gateway", "TLS + Coincidencia de Ruta", width=2.5, accent=ACCENT_CYAN).move_to([-4.5, 0.2, 0])
limiter = make_node_card("Limitador de Tasa", "Bucket: 100 tok", width=2.5, accent=ACCENT_BLUE).move_to([-1.5, 0.2, 0])
cache = make_node_card("Caché de Lectura", "TTL de Vuelo Único", width=2.5, accent=ACCENT_CYAN).move_to([1.5, 0.2, 0])
db = make_node_card("Base de Datos Primaria", "Quórum WAL", width=2.5, accent=STATUS_OK).move_to([4.5, 0.2, 0])
e_gw_lim = connect_h(gw, limiter)
e_lim_cache = connect_h(limiter, cache)
e_cache_db = connect_h(cache, db, dashed=True)
assert_all_orthogonal([e_gw_lim, e_lim_cache, e_cache_db], [gw, limiter, cache, db])
edges = VGroup(e_gw_lim, e_lim_cache, e_cache_db)
self.play(FadeIn(header), FadeIn(gw), FadeIn(limiter), FadeIn(cache), FadeIn(db), Create(edges), run_time=1.1)
spent = animate_packet_along(self, e_gw_lim, label="POST /pedidos", run_time=0.7)
timer.hold(self, "act1_ingress", consumed_anim_s=1.1 + spent, fallback_s=3.2, checkpoints=checkpoints)
spent = animate_packet_along(self, e_lim_cache, label="token=99", color=STATUS_OK, run_time=0.7)
timer.hold(self, "act1_bucket", consumed_anim_s=spent, fallback_s=3.8, checkpoints=checkpoints)
spent = animate_blocked_pulse(self, limiter, reason_label="429 LÍMITE DE TASA SUPERADO", color=STATUS_ERR, run_time=0.95)
timer.hold(self, "act1_reject", consumed_anim_s=spent, fallback_s=3.5, checkpoints=checkpoints)
dump_checkpoints(checkpoints, "tmp/act1_bounds.json")
Verifica Límites y Cero Colisiones Antes del Renderizado 1080p60
Verifica siempre la geometría del diseño en segundos antes de lanzar un renderizado completo 1080p60:
# Opción A: Gancho de prueba en vivo sobre cada llamada Scene.wait() (< 3s, codificación MP4 cero)
./venv/bin/python .agents/skills/manim-video-explainer/check_scene_bounds.py \
--module scenes.py --scene Act1RateLimiter
# Opción B: Inspecciona el JSON de puntos de control emitido después de un renderizado -ql rápido
python3 .agents/skills/manim-video-explainer/check_scene_bounds.py \
--json tmp/act1_bounds.json
Lee references/manim-layout-and-choreography.md para plantillas de coordenadas de varios niveles, contadores dinámicos ValueTracker y reglas de limpieza anticolisión.
3. Locución Opcional Sincronizada con Latidos (mux_narration.py)
La Regla de Oro de la Narración
NUNCA leas los títulos de las tarjetas en pantalla, las flechas o las cadenas de insignias textualmente.
Los espectadores ya ven "API Gateway -> Limitador de Tasa" inmediatamente. Escribe comentarios de proceso explicativos que indiquen por qué ocurre cada transición, qué invariante protege el sistema y qué causa el rechazo o la recuperación.
Flujo de Trabajo de Dos Pasos Primero el Latido
- Escribe
narration_manifest.jsonseparando eltextlimpio de los subtítulos de las anulaciones fonéticas (tts_phonetic_textophonetic_glossary) para que los acrónimos técnicos (WAL,gRPC,TTL,p99,HTTP 429) se pronuncien de forma natural sin contaminar los subtítulos.vtt:
{
"lead_in_s": 0.20,
"inter_beat_gap_s": 0.25,
"phonetic_glossary": {
"WAL": "write-ahead log",
"TTL": "T T L",
"HTTP 429": "H T T P cuatro veintinueve"
},
"scenes": [
{
"id": "act1",
"beats": [
{
"id": "act1_ingress",
"min_visual_s": 3.2,
"text": "Las escrituras entrantes terminan en la puerta de enlace antes de tocar el almacenamiento con estado."
},
{
"id": "act1_bucket",
"min_visual_s": 3.8,
"text": "Una verificación atómica de token-bucket absorbe el tráfico de ráfagas mientras limita la concurrencia de la base de datos."
},
{
"id": "act1_reject",
"min_visual_s": 3.5,
"text": "Cuando los tokens de ráfaga se agotan a cero, los llamadores en exceso fallan rápidamente con HTTP 429."
}
]
}
]
}
- Paso 1 — Sintetiza WAV por Latido y Emite Tiempos Exactos:
# Opción A: TTS neuronal Piper ONNX offline (cero llamadas de red)
python3 .agents/skills/manim-video-explainer/mux_narration.py \
--manifest tmp/narration_manifest.json \
--scene-id act1 \
--wav-dir cache/beats_en \
--piper-bin ./venv/bin/piper \
--model ~/.cache/piper-voices/en_US-lessac-medium.onnx \
--emit-timings tmp/beat_timings.json
# Opción B: TTS neuronal HTTP compatible con OpenAI (/v1/audio/speech, urllib de la biblioteca estándar)
python3 .agents/skills/manim-video-explainer/mux_narration.py \
--manifest tmp/narration_manifest.json \
--scene-id act1 \
--wav-dir cache/beats_en \
--http-tts-url https://api.openai.com/v1/audio/speech \
--http-tts-key-env OPENAI_API_KEY \
--http-tts-model gpt-4o-mini-tts \
--http-tts-voice cedar \
--http-tts-instructions "Narrador técnico documental tranquilo y claro; pausas breves en las cláusulas." \
--emit-timings tmp/beat_timings.json
(Cualquier sintetizador CLI personalizado también se puede usar mediante --tts-cmd "my-tts --out {wav} --text {text}", o los archivos .wav pre-renderizados se pueden colocar directamente en --wav-dir).
- Renderiza el Video Manim 1080p60 Impulsado por
tmp/beat_timings.json:
./venv/bin/manim -qh --fps 60 scenes.py Act1RateLimiter
- Paso 2 — Ensamblaje de Pista Maestra de Precisión de Muestra, Normalización de Sonoridad, Guardia de Cola y Multiplexación AAC:
python3 .agents/skills/manim-video-explainer/mux_narration.py \
--manifest tmp/narration_manifest.json \
--scene-id act1 \
--wav-dir cache/beats_en \
--video media/videos/scenes/1080p60/Act1RateLimiter.mp4 \
--loudnorm-lufs -18.0 \
--output output/act1_en.mp4 \
--vtt output/act1_en.vtt
mux_narration.py coloca cada WAV de latido en round(start_s * sample_rate) en una pista maestra PCM de 16 bits, extiende el fotograma de video final mediante tpad=stop_mode=clone siempre que el habla final supere la duración del video (cero palabras recortadas), opcionalmente aplica la normalización de sonoridad EBU R128 (--loudnorm-lufs -18.0) para que el volumen se mantenga constante en todos los capítulos, codifica -c:a aac -b:a 160k -movflags +faststart y escribe output/act1_en.vtt.
Lee references/voiceover-and-commentary.md para transformaciones de comentarios Malos vs. Buenos, anulaciones fonéticas en idiomas distintos del inglés y flujos de trabajo de audio bilingües.
4. Codificación Web, Concatenación de Múltiples Escenas y Reproductor HTML5 Offline
Codificación Compatible con Web y Concatenación de Carrete Maestro
Para walkthroughs silenciosos (sin mux_narration.py), asegura la compatibilidad universal con navegadores/QuickTime (yuv420p + átomo moov movido):
ffmpeg -y -i media/videos/scenes/1080p60/Act1RateLimiter.mp4 \
-c:v libx264 -pix_fmt yuv420p -crf 23 -movflags +faststart \
output/act1_silent.mp4
Para ensamblar múltiples MP4 de actos narrados en un carrete maestro continuo:
printf "file 'act1_en.mp4'\nfile 'act2_en.mp4'\nfile 'act3_en.mp4'\n" > output/concat.txt
ffmpeg -y -f concat -safe 0 -i output/concat.txt \
-c:v libx264 -pix_fmt yuv420p -crf 21 -c:a aac -b:a 160k -movflags +faststart \
output/master_en.mp4
Reproductor de Cine HTML5 Autónomo Opcional
Al entregar un walkthrough de múltiples capítulos o un paquete explicativo bilingüe:
- Copia
assets/video_player_template.htmlaoutput/index.html. - Personaliza
PLAYER_CONFIG(chapters,sourcesymarkersque coincidan con las marcas de tiempo de los latidos debeat_timings.json). Si entregas en un solo idioma, oculta u omite el botón de idioma secundario en#langGroup. - Mantén todos los estilos, iconos SVG monocromáticos y scripts 100% en línea para que el paquete funcione sin conexión sin CDN externos.
- Nota de Servicio HTTP
206 Partial Content: Los navegadores requieren respuestas HTTP Byte-Range (206) para desplazarse por las líneas de tiempo de<video>y cargar los archivos<track>.vttcorrectamente (file://bloquea las pistas WebVTT a través de CORS, y elhttp.serverbásico de Python no maneja rangos parciales). Usa un servidor estático mínimo que admita206:npx serve output/opython3 -m http.server --bind 127.0.0.1 8000(desde el directoriooutput/).
5. Verificación de Integridad de Entrega
Ejecuta lint.py en el directorio output/ para confirmar la corrección técnica antes de la entrega al usuario:
python3 .agents/skills/manim-video-explainer/lint.py --dir output/
El verificador confirma:
- Los archivos MP4 contienen flujo de video H.264 en
yuv420py flujo de audio AAC (o están silenciados). - Los archivos
.vtttienen encabezado WebVTT válido, marcas de tiempo monotónicas y tiempos de cola cero. index.html(si está presente) contiene estilos/scripts en línea, cero solicitudes a CDN y cero emojis que puedan romperse con fuentes SVG.
Si falla alguna verificación, lint.py imprime un mensaje de error detallado y sale con código de salida distinto de cero.
Referencias Adicionales
references/manim-layout-and-choreography.md: Diseño de escenas con múltiples nodos, contadores dinámicos, flechas curvas/bidireccionales y concatenación de actos.references/voiceover-and-commentary.md: Redacción de manifiestos de narración, control de pronunciación y guiones bilingües.
Resumen de Comandos (Secuencia de Construcción Típica)
# 1. Verificar límites de escena y geometría (render de prueba rápido)
python3 .agents/skills/manim-video-explainer/check_scene_bounds.py \
--module scenes.py --scene Act1RateLimiter
# 2. Opcional: Sintetizar locución y emitir tiempos
python3 .agents/skills/manim-video-explainer/mux_narration.py \
--manifest tmp/narration_manifest.json \
--scene-id act1 \
--wav-dir cache/beats_en \
--http-tts-url https://api.openai.com/v1/audio/speech \
--http-tts-key-env OPENAI_API_KEY \
--http-tts-model gpt-4o-mini-tts \
--http-tts-voice cedar \
--emit-timings tmp/beat_timings.json
# 3. Renderizar video 1080p60
./venv/bin/manim -qh --fps 60 scenes.py Act1RateLimiter
# 4. Opcional: Multiplexar audio, normalizar sonoridad y escribir subtítulos
python3 .agents/skills/manim-video-explainer/mux_narration.py \
--manifest tmp/narration_manifest.json \
--scene-id act1 \
--wav-dir cache/beats_en \
--video media/videos/scenes/1080p60/Act1RateLimiter.mp4 \
--loudnorm-lufs -18.0 \
--output output/act1_en.mp4 \
--vtt output/act1_en.vtt
# 5. Verificar integridad de la salida
python3 .agents/skills/manim-video-explainer/lint.py --dir output/