Communitygithub.com

manim-video-explainer

Genera videos explicativos técnicos en 1080p60 con Manim Community, locución neural sincronizada y reproductor HTML5 offline.

¿Qué es manim-video-explainer?

Este skill permite crear videos animados de alta definición (1920x1080 a 60 fps) para explicar arquitecturas de sistemas, procesos paso a paso y conceptos técnicos complejos. Utiliza Manim Community sin dependencia de LaTeX (evitando Tex, MathTex y DecimalNumber) y se apoya en reglas estrictas de conectores ortogonales anclados a puertos para garantizar diagramas de bloques limpios y profesionales. Incluye un sistema opcional de locución neural (TTS) sincronizado con los latidos (beats) de la animación, compatible con Piper offline, cualquier endpoint HTTP compatible con OpenAI /v1/audio/speech, o comandos CLI personalizados; además normaliza el volumen según EBU R128 (-18 LUFS) y genera subtítulos WebVTT. El skill también ofrece un reproductor HTML5 autónomo (sin CDN) con pestañas de capítulos y marcadores de tiempo, ideal para entregar tutoriales narrados, walkthroughs arquitectónicos o presentaciones técnicas sin conexión a internet. Soporta múltiples actos (escenas) para editar sin re-renderizar, verificación de límites de cuadro y colisiones de texto, y concatenación de múltiples actos en un solo video maestro.

Compatible con~Claude Code✓Codex CLI~Cursor
npx skills add https://github.com/iuriimedvedev-dev/manim-video-explainer-skill/tree/HEAD

Preguntar en tu IA favorita

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

Documentación

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ón BeatTimer, 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/speech compatible con OpenAI o un comando TTS personalizado, emite beat_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.264 yuv420p + flujos de audio con ffprobe, 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 con ffmpeg.
  • 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 de Base 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 429 o promoción de quórum de Bloqueo Distribuido y Replicación de Registro de Anticipación).

Mapea cada latido explícitamente antes de codificar:

beat_idvisual_actionmin_visual_seccommentary_script (si se narra)
act1_ingressRenderiza 4 tarjetas de topología Nord + encabezado; anima el paquete de solicitud hacia la Puerta de Enlace3.2Las escrituras entrantes pasan por una puerta de enlace perimetral antes de tocar el almacenamiento con estado.
act1_bucketDecrementa el contador de tokens 100 -> 99; destello de insignia verde ADMITIDO3.8Una verificación atómica de token-bucket absorbe ráfagas de tráfico mientras limita la concurrencia descendente.
act1_rejectActiva animate_blocked_pulse (429 LÍMITE DE TASA SUPERADO) cuando los tokens llegan a 03.5Una 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

  1. Cero Subprocesos TeX: Nunca uses Tex, MathTex, Title o DecimalNumber (que invocan pdflatex/dvisvgm). Usa Text, MarkupText (<b>, <i>, <sub>, <sup>, <span foreground="...">), Code, RoundedRectangle, Arrow, DashedVMobject y MoveAlongPath.
  2. Regla Esquemática de Oro (Cables Ortogonales Anclados a Puertos): NUNCA llames a Arrow(card_a, card_b) directamente sobre dos Mobjects 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 mediante connect_h(card_from, card_to, y=...), connect_v(card_from, card_to, x=...) o connect_elbow(points), anima paquetes con animate_packet_along(self, edge, ...) y valida la geometría del cable con assert_all_orthogonal(connectors, cards).
  3. 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én y < -3.05 vacío siempre que se muestren subtítulos WebVTT.
  4. Importa assets/nord_manim_theme.py: Establece self.camera.background_color = BG_DARK y 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

  1. Escribe narration_manifest.json separando el text limpio de los subtítulos de las anulaciones fonéticas (tts_phonetic_text o phonetic_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."
        }
      ]
    }
  ]
}
  1. 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).

  1. Renderiza el Video Manim 1080p60 Impulsado por tmp/beat_timings.json:
./venv/bin/manim -qh --fps 60 scenes.py Act1RateLimiter
  1. 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:

  1. Copia assets/video_player_template.html a output/index.html.
  2. Personaliza PLAYER_CONFIG (chapters, sources y markers que coincidan con las marcas de tiempo de los latidos de beat_timings.json). Si entregas en un solo idioma, oculta u omite el botón de idioma secundario en #langGroup.
  3. 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.
  4. 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> .vtt correctamente (file:// bloquea las pistas WebVTT a través de CORS, y el http.server básico de Python no maneja rangos parciales). Usa un servidor estático mínimo que admita 206: npx serve output/ o python3 -m http.server --bind 127.0.0.1 8000 (desde el directorio output/).

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 yuv420p y flujo de audio AAC (o están silenciados).
  • Los archivos .vtt tienen 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/

Skills relacionados