En esta guía aprenderás a comprobar que un cambio en el código no alteró lo que se ve. gaanim --diff captura fotogramas exactos de una escena, los compara con una versión que ya aprobaste y genera un informe HTML para revisar las diferencias en el navegador.

Dónde se guardan las capturas

Cada escena tiene su propia carpeta dentro del proyecto:

tests/visual/<nombre-de-la-escena>/
  baseline/  # capturas aprobadas y manifest.json: guárdalas en git
  current/   # captura de la versión actual: local
  report/    # informe HTML y JSON y mapas de calor: local

Por ejemplo, escenas/intro.py usa automáticamente tests/visual/escenas/intro/. No hace falta escribir las rutas de baseline, current ni report.

Flujo normal

  1. Elige los instantes que quieres capturar. El script llama a scene.snapshots(...) cuando existe la variable de entorno GAANIM_SNAPSHOTS; gaanim --diff la define y ejecuta la captura sin abrir ventana:

    import os
    if os.environ.get("GAANIM_SNAPSHOTS"):
        scene.snapshots(os.environ["GAANIM_SNAPSHOTS"], [0.0, 0.5, 1.0])
  2. Cuando la escena se vea como quieres, apruébala. --bless guarda la captura como versión aprobada (baseline/):

    gaanim --diff --example escenas/intro.py --bless
  3. Después de cada cambio, captura otra vez y compara con la versión aprobada. El comando imprime la ruta de report/index.html; ábrela en el navegador:

    gaanim --diff --example escenas/intro.py

--bless sobrescribe la versión aprobada: úsalo solo cuando hayas revisado y aceptado el cambio visual.

Si prefieres capturar las pausas del script, scene.stops devuelve cada scene.stop() con su instante y scene.cursor da el instante actual de la escena:

if os.environ.get("GAANIM_SNAPSHOTS"):
    scene.snapshots(os.environ["GAANIM_SNAPSHOTS"], [stop.time for stop in scene.stops])

Capturar cada pausa de una presentación

Para revisar una presentación, --capture-stops captura el fotograma que se ve en cada scene.stop() sin tocar el script: no hace falta llamar a scene.snapshots ni leer GAANIM_SNAPSHOTS. El script solo debe terminar con scene.render().

gaanim --diff --example mi-charla --capture-stops --capture-only
gaanim --diff --example mi-charla --capture-stops --stops 12,30 --capture-only
  • Cada pausa se captura en su instante exacto: las animaciones anteriores ya terminaron, y una pausa al final de un segmento conserva ese segmento en pantalla.
  • Los archivos se llaman stop_0001.png, stop_0002.png… según la numeración global de las pausas (desde 1), así que la versión aprobada y la actual se emparejan por pausa aunque cambien los tiempos.
  • --stops acepta números y rangos (12,30, 3-7) de esa misma numeración.
  • --sections resultados,cierre y --from resultados capturan solo las pausas de esos segmentos, claves de Section o nombres de SectionStep (ver Presentaciones); se combinan con --stops y conservan la numeración global.
  • Además de manifest.json, escribe stops.json con el número, el instante, el segmento, el nombre de la pausa y el archivo de cada captura.
  • Funciona con --bless y --capture-only, pero no con --no-capture.
  • Solo compara si la versión aprobada tiene su propio stops.json. Si no hay versión aprobada, o se hizo con scene.snapshots, captura, avisa de que no hay nada que comparar y termina con éxito. --bless con --capture-stops reemplaza el manifest.json aprobado: no lo uses sobre una versión de scene.snapshots que quieras conservar.

Paquetes de reproducción

Un paquete .gaanim (ver Compartir sin Python) también se compara, sin Python: --example con un paquete captura siempre sus pausas, así que no hace falta --capture-stops, y admite --stops, --sections y --from.

gaanim --diff --example mi-charla.gaanim --bless
gaanim --diff --example mi-charla.gaanim

Las capturas de un paquete son idénticas a las de --capture-stops sobre el script que lo grabó, así que puedes comparar la versión aprobada de uno con la actual del otro usando --baseline y --current, por ejemplo para comprobar que un paquete compartido muestra lo mismo que el proyecto.

Automatizar y tolerar diferencias

gaanim --diff --example escenas/intro.py --pixel-threshold 4 --max-changed-ratio 0.0001
  • --no-capture compara los PNG que ya están en current/.
  • --capture-only escribe current/ (o la carpeta de --current <DIR>) y termina sin comparar ni modificar la versión aprobada.
  • --capture-stops y --stops <LISTA> capturan cada scene.stop() en lugar de usar scene.snapshots (ver arriba).
  • --tests-root <DIR> cambia la carpeta raíz, que por defecto es tests/visual.
  • --pixel-threshold y --max-changed-ratio fijan cuánto puede cambiar cada píxel y qué proporción de píxeles puede cambiar sin que cuente como diferencia.

Para comparar dos carpetas cualesquiera, indica las rutas a mano con --baseline, --current y --output:

gaanim --diff --baseline capturas/antes --current capturas/despues --output capturas/informe

Leer el resultado

El informe JSON incluye, para cada captura, el instante, el porcentaje de píxeles modificados, el error medio, la diferencia máxima y el rectángulo que contiene el cambio. El comando termina con código 0 si no hay diferencias, 1 si las hay y 2 ante errores, así que sirve tal cual en integración continua.

report/index.html funciona sin conexión y muestra lo mismo que el JSON:

  • La lista lateral filtra por fallos, cambiados o ausentes y busca por nombre.
  • Siete modos de comparación: diff, versión aprobada, actual, lado a lado, cortina, superposición con opacidad y parpadeo. Las teclas 1 a 7 los alternan.
  • Un recuadro marca el área cambiada; B lo oculta.
  • ←/→ recorren las capturas, F ajusta a la ventana, 0 muestra el tamaño real y +/− (o Ctrl + rueda) cambian el zoom. ? lista todos los atajos.
  • La dirección de la página incluye la captura y el modo, para compartir un enlace a un fotograma concreto.