scene.slides reúne componentes editoriales listos para presentaciones y videos explicativos: insignias, tarjetas, rótulos, listas, tablas y la identidad visual de cada segmento. Cada componente se mide a partir de su texto y devuelve un grupo Drawable que se coloca y anima como cualquier objeto.

from gaanim import Scene

scene = Scene(frame=(16, 9), theme="presentation")
heading = scene.slides.section_header("Resultados", kicker="03").move_to(0, 2.6)
metric = scene.slides.stat_card("98%", "Precisión", delta="+4.2%", variant="success").move_to(-2.2, -0.4)
note = scene.slides.card("Conclusión", "El solver converge en 12 ms.", variant="accent").move_to(2.4, -0.4)
scene.play([heading.animate.fade_in(), metric.animate.grow_from_center(), note.animate.fade_in()], duration=1.0)
scene.render()
animation preview

Los componentes comparten opciones de estilo:

  • variant: tono semántico del tema ("neutral", "accent", "success", "warning" o "danger").
  • appearance: "soft" (fondo suave), "solid" (fondo lleno) u "outline" (solo borde).
  • color, background y border: colores explícitos que sustituyen los del tema.
  • Las medidas (width, padding, gap, radius…) están en unidades de escena.

Texto vacío, variantes desconocidas o medidas inválidas lanzan ValueError.

Insignias y chips

Etiquetas cortas de estado, categoría o metadatos que se ajustan a su texto.

FÁBRICASlideKit.badgebadge(text: str, *, variant: Literal["neutral", "accent", "success", "warning", "danger"] = "neutral", appearance: Literal["soft", "solid", "outline"] = "soft", padding: tuple[float, float] = (0.18, 0.10), radius: Optional[float] = None, font_size: Optional[float] = None, min_width: Optional[float] = None, color: Optional[ColorLike] = None, background: Optional[ColorLike] = None, border: Optional[ColorLike] = None, font: Optional[str] = None, weight: Optional[int] = None, style: Optional[TextStyle] = None, markup: Optional[bool] = None) -> Drawable
Insignia en el origen cuyo panel se mide con el mismo texto que se dibuja. Colócala con .move_to(...).
Parámetros
NombreTipoPredeterminadoDescripción
textstrobligatorioEtiqueta no vacía.
radiusfloat | NoneNoneNone da forma de píldora a partir de la altura medida.
min_widthfloat | NoneNoneAncho mínimo del panel.
font / weightstr | None / int | NoneNoneFamilia y peso de la etiqueta; sustituyen a style.
styleTextStyle | NoneNoneTipografía sobre el rol label del tema; su color, si lo tiene, sustituye el de la variante.
markupbool | NoneNoneFalse deja * y _ literales, como en scene.text; None sigue text_markup del tema.
Ejemplo
tag = scene.slides.badge("LISTO", variant="success", appearance="solid").move_to(-2.4, 1.2)
code = scene.slides.badge("_vel_max", font="DejaVu Sans Mono", weight=600, markup=False)
scene.play([tag.animate.grow_from_center()])
FÁBRICASlideKit.chipchip(text: str, *, dot: bool = True, variant: Literal["neutral", "accent", "success", "warning", "danger"] = "neutral", appearance: Literal["soft", "solid", "outline"] = "soft", padding: tuple[float, float] = (0.14, 0.08), radius: Optional[float] = None, font_size: Optional[float] = None, color: Optional[ColorLike] = None, background: Optional[ColorLike] = None, border: Optional[ColorLike] = None, font: Optional[str] = None, weight: Optional[int] = None, style: Optional[TextStyle] = None, markup: Optional[bool] = None) -> Drawable
Insignia compacta con un punto opcional del color de la variante (dot=True), para filtros, estados y metadatos. Acepta las mismas opciones tipográficas que badge.
Ejemplo
live = scene.slides.chip("En vivo", variant="danger", appearance="outline")

Tarjetas

Paneles de altura automática para contenido, métricas y citas.

FÁBRICASlideKit.cardcard(title: str, body: Optional[str] = None, footer: Optional[str] = None, *, width: float = 4.2, min_height: float = 1.8, padding: tuple[float, float] = (0.28, 0.24), gap: float = 0.14, radius: float = 0.18, variant: Literal["neutral", "accent", "success", "warning", "danger"] = "neutral", appearance: Literal["soft", "solid", "outline"] = "soft", color: Optional[ColorLike] = None, background: Optional[ColorLike] = None, border: Optional[ColorLike] = None) -> Drawable
Tarjeta con título, cuerpo y pie. Cada hueco usa un rol de texto del tema y se mide al construirla.
Parámetros
NombreTipoPredeterminadoDescripción
titlestrobligatorioEncabezado.
body / footerstr | NoneNoneCuerpo con ajuste de línea y pie opcional.
width / min_heightfloat4.2 / 1.8Ancho fijo y altura mínima.
Ejemplo
result = scene.slides.card("Resultado", "El solver converge.", "12 ms", variant="accent")
FÁBRICASlideKit.stat_cardstat_card(value: str, label: str, *, delta: Optional[str] = None, width: float = 2.8, min_height: float = 1.7, padding: tuple[float, float] = (0.24, 0.20), gap: float = 0.08, radius: float = 0.18, variant: Literal["neutral", "accent", "success", "warning", "danger"] = "neutral", appearance: Literal["soft", "solid", "outline"] = "soft", color: Optional[ColorLike] = None, background: Optional[ColorLike] = None, border: Optional[ColorLike] = None) -> Drawable
Tarjeta de métrica con valor, etiqueta y variación opcional (delta). El valor y la variación usan el tono de la variante; no se infiere signo ni formato numérico.
Ejemplo
metric = scene.slides.stat_card("98%", "Precisión", delta="+4.2%", variant="success")
FÁBRICASlideKit.quote_cardquote_card(quote: str, attribution: Optional[str] = None, *, width: float = 6.2, padding: tuple[float, float] = (0.32, 0.28), gap: float = 0.16, radius: float = 0.18, variant: Literal["neutral", "accent", "success", "warning", "danger"] = "neutral", appearance: Literal["soft", "solid", "outline"] = "soft", color: Optional[ColorLike] = None, background: Optional[ColorLike] = None, border: Optional[ColorLike] = None) -> Drawable
Cita con comillas tipográficas y atribución opcional alineada a la derecha.
Ejemplo
quote = scene.slides.quote_card("La claridad importa.", "Gaanim", appearance="outline")

Rótulos y encabezados

Portadas, cabeceras de sección y rótulos anclados a los bordes seguros.

FÁBRICASlideKit.title_cardtitle_card(title: str, subtitle: Optional[str] = None, *, width: float = 7.6, height: float = 3.2, panel: bool = False, background: Optional[ColorLike] = None, color: Optional[ColorLike] = None, accent: Optional[ColorLike] = None) -> Drawable
Portada centrada con título, regla y subtítulo opcional, animable como un solo grupo. panel=True la enmarca; accent colorea la regla.
Ejemplo
from gaanim import Scene
scene = Scene(frame=(16, 9), background="#0f172a")
opening = scene.slides.title_card("Movimiento vectorial", "Una explicación técnica", panel=True)
scene.play([opening.animate.fade_in().duration(0.7)])
scene.render()
animation preview
FÁBRICASlideKit.section_headersection_header(title: str, *, kicker: Optional[str] = None, subtitle: Optional[str] = None, width: float = 7.2, align: Literal["left", "center", "right"] = "left", rule: bool = False, padding: tuple[float, float] = (0.24, 0.18), gap: float = 0.10, radius: float = 0.12, variant: Literal["neutral", "accent", "success", "warning", "danger"] = "neutral", appearance: Literal["soft", "solid", "outline"] = "soft", color: Optional[ColorLike] = None, background: Optional[ColorLike] = None, border: Optional[ColorLike] = None) -> Drawable
Encabezado de sección con antetítulo (kicker) y subtítulo opcionales. align (left, center o right) alinea todos los huecos; rule=True añade una regla de acento horizontal.
Ejemplo
heading = scene.slides.section_header("Método", kicker="02", align="center")
FÁBRICASlideKit.bannerbanner(title: str, subtitle: Optional[str] = None, *, position: Literal["top", "bottom"] = "top", width: Optional[float] = None, margin: float = 0.32, padding: tuple[float, float] = (0.28, 0.18), gap: float = 0.08, radius: float = 0.14, variant: Literal["neutral", "accent", "success", "warning", "danger"] = "neutral", appearance: Literal["soft", "solid", "outline"] = "soft", color: Optional[ColorLike] = None, background: Optional[ColorLike] = None, border: Optional[ColorLike] = None) -> Drawable
Franja anclada al borde seguro superior o inferior (position). Con width=None ocupa el ancho seguro menos margin; su altura sigue al título y al subtítulo.
Ejemplo
notice = scene.slides.banner("Simulación completa", position="bottom", variant="success")
FÁBRICASlideKit.lower_thirdlower_third(title: str, subtitle: Optional[str] = None, *, kicker: Optional[str] = None, side: Literal["left", "right"] = "left", width: float = 5.2, margin: float = 0.32, padding: tuple[float, float] = (0.28, 0.20), gap: float = 0.08, radius: float = 0.16, variant: Literal["neutral", "accent", "success", "warning", "danger"] = "neutral", appearance: Literal["soft", "solid", "outline"] = "soft", color: Optional[ColorLike] = None, background: Optional[ColorLike] = None, border: Optional[ColorLike] = None) -> Drawable
Rótulo inferior anclado a una esquina segura (side="left" o "right"), con antetítulo, título y subtítulo que usan los roles del tema y se ajustan al ancho.
Ejemplo
speaker = scene.slides.lower_third("Ada Lovelace", "Matemática", kicker="PONENTE")
FÁBRICASlideKit.calloutcallout(text: str, target: Drawable, *, offset: tuple[float, float] = (1.6, 0.96), width: float = 2.4, height: float = 0.72, background: Optional[ColorLike] = None, color: Optional[ColorLike] = None) -> Drawable
Llamada con tarjeta, texto y conector que apunta a target desde offset y lo sigue de forma nativa, sin callbacks de Python por fotograma.
Ejemplo
from gaanim import GOLD, Scene
scene = Scene(frame=(16, 9), background="#0f172a")
mass = scene.geometry.dot(0.15).fill(GOLD).move_to(-0.5, 0)
note = scene.slides.callout("Masa en movimiento", mass, offset=(1.625, 0.875))
scene.play([mass.animate.shift_by(1, 0).duration(1.0), note.animate.fade_in().duration(0.4)])
scene.render()
animation preview

Listas y tablas

Agendas con viñetas y tablas técnicas compactas.

FÁBRICASlideKit.bulletsbullets(items: Sequence[str], *, width: float = 7.2, gap: float = 0.68, bullet_radius: float = 0.08, bullet_color: Optional[ColorLike] = None, color: Optional[ColorLike] = None) -> Drawable
Lista con viñetas como un solo objeto. Cada punto se alinea a la izquierda, justo después de su viñeta, y se ajusta al resto de width. Ajusta width, gap, bullet_radius y bullet_color.
Ejemplo
from gaanim import GOLD, Scene
scene = Scene(frame=(16, 9), background="#0f172a")
agenda = scene.slides.bullets(["Preparar", "Animar", "Exportar"], gap=0.6, bullet_color=GOLD).move_to(0, 0.5)
scene.play([agenda.animate.fade_in().duration(0.6)])
scene.render()
animation preview
FÁBRICASlideKit.tabletable(headers: Sequence[str], rows: Sequence[Sequence[str]], *, width: float = 7.6, row_height: float = 0.58, header_background: Optional[ColorLike] = None, rule_color: Optional[ColorLike] = None, color: Optional[ColorLike] = None) -> Drawable
Tabla con cabecera y reglas. Cada fila debe tener tantas celdas como cabeceras. Para tablas con celdas combinadas usa scene.text.typst(...) (ver Texto).
Ejemplo
from gaanim import Scene
scene = Scene(frame=(16, 9), background="#0f172a")
tbl = scene.slides.table(["Método", "Error", "Tiempo"], [["Base", "0.18", "48 ms"], ["GPU", "0.04", "15 ms"]]).move_to(0, 0)
scene.play([tbl.animate.fade_in().duration(0.6)])
scene.render()
animation preview

Identidad de la presentación

Logo, pie, regla y número de diapositiva comunes a todos los segmentos.

MÉTODOSlideKit.brandbrand(*, logo: Optional[str] = None, footer: Optional[str] = None, slide_numbers: bool = True, number_anchor: Optional[AnchorName | Anchor] = None, rule: bool = True, show_on_cover: bool = False, logo_scale: float = 1.0) -> None
Configura la identidad que se dibuja en cada segmento, por encima del contenido. Llámalo una vez, al principio. Consulta Presentaciones.
Parámetros
NombreTipoPredeterminadoDescripción
logostr | NoneNoneSVG o imagen; se ajusta a 0.6 unidades de alto en la esquina segura superior derecha.
footerstr | NoneNoneTexto del pie. Empieza en el borde izquierdo del área segura y, si es muy largo, se reduce para caber.
slide_numbers / ruleboolTrue / TrueNúmero de diapositiva y regla del pie; la regla ocupa el ancho del área segura.
number_anchorAnchor | NoneNoneSin él, el número sigue al pie, abajo a la izquierda. Con un Anchor, va solo en ese punto del área segura: Anchor.BOTTOM_RIGHT lo deja libre de una barra de progreso a lo largo del borde inferior.
show_on_coverboolFalseMuestra la identidad también en la portada: el primer segmento y los que usan una plantilla de portada.
logo_scalefloat1.0Multiplica el tamaño del logo.
Ejemplo
scene.slides.brand(logo="assets/logo.svg", footer="LAB · 2026")
scene.segment("Portada")
scene.wait(0.5)
scene.segment("Contenido")
scene.wait(0.5)
MÉTODOSlideKit.targettarget(seconds: Optional[float]) -> None
Fija cuánto debe durar la presentación. Presenter View la cuenta hacia atrás en LEFT; la que fijes en la propia vista o con gaanim --present --duration la sustituye. scene.segment(..., target=) fija la de cada diapositiva. Un valor que no sea un número positivo lanza ValueError. Consulta El tiempo de la charla.
Parámetros
NombreTipoPredeterminadoDescripción
secondsfloat | NoneobligatorioDuración prevista de la charla entera; None la quita.
Devuelve: None — No añade nada a la escena.
Ejemplo
scene.slides.target(20 * 60)
scene.segment("Portada", target=60)
scene.wait(0.5)