Scene, el lienzo lógico, la línea de tiempo, los segmentos, la cámara y la salida
Scene es el punto de entrada de toda animación: crea los objetos, programa la línea de tiempo, organiza los segmentos y entrega el resultado al ejecutable de Gaanim. Cada script crea una escena, la llena y termina con scene.render().
from gaanim import BLUE, Scene
scene =Scene(frame=(16, 9), background="#0f172a")
dot = scene.geometry.circle(0.6).fill(BLUE)
scene.play([dot.animate.create().duration(0.8)])
scene.wait(0.5)
scene.render()
Esta página documenta la escena, su lienzo (scene.canvas), su cámara (scene.camera) y las secciones. Los métodos comunes de los objetos están en Drawable, las animaciones en Animaciones y los temas en Temas y colores. Para ejecutar, validar y exportar un script, consulta la línea de comandos.
Los píxeles de salida no se eligen aquí sino al previsualizar o exportar, así que la composición es la misma a cualquier resolución. Un marco no finito o no positivo, WGSL inválido o un tema desconocido lanzan ValueError; un theme de otro tipo lanza TypeError. La antigua forma Scene(width, height) en píxeles ya no se acepta.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
frame
tuple[float, float]
(16.0, 9.0)
Ancho y alto del marco lógico, centrado en el origen. Toda la geometría, los márgenes, los tamaños de texto y los trazos usan esta unidad.
background
BackgroundLike | None
None
Color, Brush o Background. Tiene prioridad sobre el fondo del tema.
margin
float | None
None
Margen uniforme en unidades lógicas; reduce el área segura.
theme
ThemeName | Theme | None
"technical"
Nombre o alias de un tema incluido, o un Theme. None crea la escena sin tema.
post
PostProcess | None
None
Postprocesado WGSL aplicado a todos los segmentos que no lo sustituyan.
Devuelve: Scene — Una escena vacía, lista para crear objetos.
Ejemplo
from gaanim import Scene
scene =Scene(frame=(16, 9), background="#0f172a", margin=0.5, theme="presentation")
print(scene.canvas.frame_width, scene.canvas.safe_width) # 16.0 15.0
16.0 15.0
Sin theme, la escena usa el tema technical: fondo gris casi negro (#121212), texto y ejes claros y formas rellenas con el color de acento. Un background explícito gana al fondo del tema, y los colores de cada objeto ganan a los del tema. theme=None deja un lienzo sin tema: fondo blanco (si no pasas background) y objetos sin estilo también blancos, así que tendrás que darles color. Consulta Canvas.set_theme.
Capacidades
Las fábricas viven en handles que pertenecen a la escena. Un objeto de una escena no puede usarse en otra: pasarlo lanza ValueError.
Agenda y barra de progreso de secciones. Ver Secciones.
scene.assets
Carpeta de recursos, precarga y recarga. Ver Recursos.
shape = scene.geometry.circle(1)
title = scene.text("Resultado", role="title")
page = scene.layout.column([title, shape])
value = scene.viz.parameter(0.0)
PROPIEDADScene.canvascanvas: Canvas
Marco, área segura, márgenes, fondo, tema, fuentes y postprocesado. Los miembros de marco y área segura están abajo; los de estilo, en Temas y colores.
Las narraciones (Scene.voiceover, Scene.narration_script y Scene.live_take) están en Audio.
Marco lógico y área segura
El marco es el rectángulo que se ve, en unidades lógicas y centrado en el origen: con el predeterminado de 16 × 9, x va de -8 a 8 e y de -4.5 a 4.5. El área segura es el marco menos los márgenes; la usan el layout (within="safe") y las colocaciones en bordes y esquinas.
PROPIEDADCanvas.frame_widthframe_width: float
Devuelve: float — Ancho del marco lógico; 16.0 en una escena predeterminada.
PROPIEDADCanvas.frame_heightframe_height: float
Devuelve: float — Alto del marco lógico; 9.0 en una escena predeterminada.
PROPIEDADCanvas.aspect_ratioaspect_ratio: float
Devuelve: float — Ancho dividido entre alto del marco.
PROPIEDADCanvas.safe_widthsafe_width: float
Devuelve: float — Ancho del marco menos los márgenes izquierdo y derecho.
PROPIEDADCanvas.safe_heightsafe_height: float
Devuelve: float — Alto del marco menos los márgenes superior e inferior.
"widescreen" da un marco 16 × 9 con área segura 15 × 8, "vertical" un marco 9 × 16 con área segura 8 × 13.5 y "square" un marco 10 × 10 con área segura 9 × 9.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
name
"widescreen" | "vertical" | "square"
obligatorio
Composición estándar.
Devuelve: None — Reemplaza el marco lógico y el área segura.
Cada llamada a play o wait avanza el cursor de autoría. Las animaciones de una misma lista empiezan juntas; llamadas sucesivas van una detrás de otra. scene.launch(...) (o play(..., advance=False)) empieza en el cursor sin moverlo, para una animación larga que sigue mientras programas lo demás.
Programa el bloque de forma atómica: un Anim ya usado, de otra escena, repetido o que escribe un canal ocupado en el mismo tramo lanza ValueError sin aplicar ningún cambio. duration y easing son valores por defecto; los que fija cada Anim o cada grupo tienen prioridad.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
items
Playable | Sequence[Playable]
obligatorio
Un Anim, audio, vídeo, Lottie o Composition, o una lista que se reproduce en paralelo.
duration
float | None
None
Duración para las animaciones que no fijan la suya.
easing
Easing | None
None
Easing para las animaciones que no fijan el suyo.
advance
bool
True
Con False el cursor no se mueve: el bloque empieza y sigue sonando bajo lo que programes después. Es lo mismo que scene.launch.
Devuelve: None — Avanza el cursor hasta el final del bloque, salvo con advance=False.
Ejemplo
from gaanim import BLUE, GOLD, Easing, Scene
scene =Scene(frame=(16, 9), theme="technical")
circle = scene.geometry.circle(0.8).fill(BLUE).move_to(-1.6, 0)
rect = scene.geometry.rect(1.8, 1.0).fill(GOLD).move_to(1.6, 0)
scene.play([circle.animate.create(), rect.animate.grow_from_center()], duration=0.8)
scene.play(circle.animate.shift_by(1.2, 0), easing=Easing.SNAPPY)
scene.render()
Empieza el bloque en el cursor y deja el cursor donde estaba: lo que programes después (esperas, otros play, cortes, segmentos) ocurre mientras el bloque sigue. Sirve para un giro que dura varios cortes o una música de fondo. Animar el mismo canal del mismo objeto antes de que termine lanza ValueError. El vídeo acaba en el cursor, así que lo que siga corriendo ahí se corta; gaanim check lo avisa. Los objetos de un segmento salen de pantalla al terminar este, salvo que scene.persist los mantenga.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
items
Playable | Sequence[Playable]
obligatorio
Lo mismo que acepta play.
duration / easing
float | Easing | None
None
Valores por defecto, como en play.
Devuelve: None — No mueve el cursor.
Ejemplo
import math
rueda = scene.geometry.regular_polygon(6, 1.5).fill("#38bdf8")
puntos = [scene.geometry.dot(0.2).move_to(x, -3) for x in (-4, -2, 0, 2, 4)]
scene.launch(rueda.animate.rotate_by(math.tau).duration(5.0))
for punto in puntos:
scene.play(punto.animate.fade_in().duration(1.0))
Rejilla de tempo para cortar a tiempo con la música: scene.beats(n) convierte pulsos en segundos y scene.wait_until(beat=n) o scene.wait_until(bar=n) llevan el cursor a un pulso o al inicio de un compás. Si el cursor ya pasó ese pulso, wait_until lanza ValueError y dice cuánto se alargó el plano anterior, en vez de desfasarse en silencio. La barra de reproducción del editor dibuja una línea en cada compás. Valores no válidos lanzan ValueError.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
bpm
float
obligatorio
Pulsos por minuto; positivo.
offset
float
0.0
Segundo de la línea de tiempo donde cae el pulso 0, el primer tiempo de la música.
Desvanece a la vez, con easing suave, todos los objetos del segmento activo. Es la forma rápida de cerrar una escena.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
seconds
float
obligatorio
Duración del fundido.
Devuelve: None — Avanza el cursor seconds.
Ejemplo
from gaanim import Scene
scene =Scene(frame=(16, 9), theme="technical")
title = scene.text("Fin", role="title")
scene.play(title.animate.write())
scene.fade_out_all(0.6)
scene.render()
PROPIEDADScene.cursorcursor: float
Cuenta a través de todos los segmentos y es de solo lectura.
Devuelve: float — Posición del cursor de autoría, en segundos absolutos de la línea de tiempo.
Da nombre al instante actual de la línea de tiempo global. Es solo un metadato: no pausa la reproducción. El editor lo dibuja como una banderita violeta sobre la barra de tiempo (al pasar el cursor muestra el nombre y un clic salta a él), y gaanim export --from / --to lo aceptan en lugar de segundos. Un nombre vacío, repetido o que se lee como número lanza ValueError. Para instantes dentro de una Composition, usa label.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
name
str
obligatorio
Nombre único del instante; se recortan los espacios.
Devuelve: None — No añade duración ni mueve el cursor.
gaanim export escena.py --output climax.mp4 --from climax --to fin
PROPIEDADScene.markersmarkers: list[SceneMarker]
Cada SceneMarker tiene name, time (segundos absolutos) y segment (el segmento activo al crearlo).
Devuelve: list[SceneMarker] — Los marcadores creados hasta ahora, en orden temporal.
Ejemplo
scene.wait(1.5)
scene.marker("climax")
print([(m.name, m.time) for m in scene.markers]) # [('climax', 1.5)]
[('climax', 1.5)]
Segmentos
Un segmento es la unidad estructural de la escena: agrupa objetos, define la transición de entrada, las notas para Presenter View, la plantilla y un fondo propio. Los límites entre segmentos son continuos; stop() marca dónde la reproducción interactiva espera al presentador.
Crea el segmento y lo activa. La primera llamada sustituye al segmento implícito inicial, que aún no tiene contenido. Un nombre vacío o repetido, una transición en el primer segmento, un target que no sea un número positivo de segundos o un guion ilegible lanzan ValueError; un post de otro tipo lanza TypeError.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
name
str
obligatorio
Nombre no vacío, único en la escena sin distinguir mayúsculas.
transition
Transition | None
None
Transición de entrada desde el segmento anterior. Ver Transiciones.
notes
str | None
None
Notas del orador que muestra Presenter View; una línea [stop] marca dónde avanzas. La sección ## nombre del guion, si existe, las sustituye (ver El guion de la charla).
template
Callable[..., Layout] | None
None
Plantilla de Python que se rellena después con Segment.bind.
background
BackgroundLike | None
None
Fondo solo mientras el segmento está activo; None usa el de la escena.
post
PostProcess | False | None
None
Postprocesado del segmento: otro PostProcess, False para ninguno o None para heredar scene.canvas.post.
target
float | None
None
Segundos que prevés dedicarle al presentar. Presenter View compara con él el tiempo que pasas en la diapositiva (ver El tiempo de la charla). La de la charla entera se fija con scene.slides.target.
Devuelve: Segment — Handle que aceptan link y bind.
Rellena la plantilla del segmento. Un hueco obligatorio que falta o uno que no existe lanzan TypeError; un segmento sin plantilla lanza ValueError. Las plantillas incluidas (title_slide, lecture, comparison…) se importan desde gaanim.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
slots
**Any
{}
Un argumento con nombre por hueco de la plantilla.
Devuelve: Layout — El layout raíz del segmento.
Ejemplo
results = scene.segment("Resultados", template=comparison, notes="Compara los dos modelos.")
results.bind(title=scene.text("Resultados", role="title"), left=baseline, right=proposed)
scene.stop("comparación")
Desenfoque de movimiento de este segmento en las exportaciones y las capturas, en lugar del de la escena. Los segmentos sin uno propio usan el de la escena, así que cada segmento puede comparar un ángulo de obturador o una phase. Un cuadro justo en un corte pertenece al segmento que entra. Un valor fuera de rango lanza ValueError.
MÉTODOScene.linklink(from_: Segment, to: Segment, transition: Transition) -> None
Declara la transición entre dos segmentos ya creados. Hace falta para Transition.morph, cuyos pares incluyen objetos del segmento de destino. Un segmento de otra escena, o un to que no va después de from_, lanzan un error.
Pausa la reproducción interactiva cuando el cursor llega a este instante. En el límite de un segmento, el segmento saliente sigue visible hasta que se avanza, así que no hace falta un wait() final. Si la diapositiva todavía está entrando con su transición, la pausa espera a que termine y avanza el cursor hasta ahí, para que la presentación nunca descanse en una diapositiva a medio entrar. La exportación, las capturas y los seeks ignoran las pausas. Después de un live_take() grabado, la pausa espera tanto como la pausa real del orador (ver Audio). Con loop, la animación se coloca justo después de la pausa y, en lugar de congelar la imagen, se repite mientras el orador habla: el siguiente paso sale del bucle y sigue desde su final, y retroceder lo salta. Al exportar se reproduce una vez. Para que la repetición no salte, haz que el bucle termine como empieza. Un nombre vacío, una segunda pausa en el mismo instante del segmento o un bucle sin duración lanzan ValueError.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
name
str | None
None
Etiqueta de la pausa en Presenter View.
loop
Anim | list | None
None
Animación ambiental, con la misma forma que scene.play, que se repite mientras la presentación descansa en la pausa.
until
Condition | None
None
Condición del público con la que la pausa avanza sola al presentar. Ver Avanzar por sí sola.
Devuelve: None — Sin loop, no añade duración ni cambia la imagen, salvo lo que falte de la transición de entrada; con loop, avanza además el cursor lo que dura el bucle.
Ejemplo
scene.play([result.animate.write().duration(0.6)])
scene.stop("resultado")
scene.wait(0.5)
# Las flechas siguen moviéndose mientras se explica la pausa.
scene.stop("dos-placas", loop=sequence(
arrow.animate.shift_by(0.5, 0).duration(0.75),
arrow.animate.shift_by(-0.5, 0).duration(0.75),
))
Describe el público inventado que juega la escena fuera de una presentación en vivo. En la previsualización, la exportación y las capturas sus jugadores entran a la sala, responden cada encuesta y cuestionario, el reloj baja y la clasificación suma sus puntos; las zonas vivas también lo usan. Las respuestas de una pregunta llegan entre que se abre y la pausa donde la presentación las esperaría. Los mismos argumentos dan siempre el mismo ensayo. Sin llamarlo ensayan 12 jugadores. Sin jugadores o con más de 200, un apodo vacío o repetido, skill o speed fuera de 0–1 o un arrive negativo lanzan ValueError. Ver Ensayo.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
players
int | Sequence[str]
12
Cuántos jugadores (Ana, Beto, Caro…) o sus apodos, en orden de llegada; de 1 a 200.
seed
int
0
Elige otro grupo: otros tiempos, respuestas y personajes.
arrive
float | None
None
Segundos en que entran todos; por defecto, entre scene.audience() y la primera pausa de la sala.
skill
float | Sequence[float]
0.6
Qué parte de las preguntas aciertan en promedio, de 0 a 1; con equipos, puede ser un valor por equipo.
speed
float
0.5
Qué tan pronto responden, de 0 (al final) a 1 (al instante).
Pide a cada jugador un dato más al unirse, como su código de alumno o su nombre completo, para que el profesor sepa quién es quién. El dato nunca llega a la pantalla: solo aparece en los resultados que guarda la presentación y en gaanim relay results. Quien ya se había unido sigue jugando y lo da la próxima vez que se una. Un texto vacío o de más de 40 caracteres, o un segundo ask distinto en la misma escena, lanzan ValueError. Ver Guardar los resultados.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
ask
str
obligatorio
Lo que el teléfono pide además del apodo, como "Código de alumno"; de 1 a 40 caracteres.
required
bool
True
Si nadie puede unirse sin responderlo.
Devuelve: None —
Ejemplo
scene.roster("Código de alumno")
audience = scene.audience()
Hace que el juego se juegue por equipos. Los puntos de cada jugador suman para su equipo. Teams da names, colors, score(i), players(i) y average(i) (Parameter), leader() (el índice del equipo que va ganando) y bar(i, ...). En las zonas vivas cada jugador sabe p.team, p.team_index, p.team_count, p.team_score y p.team_rank. El ensayo reparte a sus jugadores igual. Menos de 2 o más de 6 equipos, un nombre vacío, largo o repetido, colores que no sean un #rrggbb por equipo, u otros equipos distintos en la misma escena lanzan ValueError. Ver Equipos.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
names
Sequence[str]
obligatorio
Los equipos, de 2 a 6, con nombres de hasta 20 caracteres.
choose
bool
False
Si el teléfono pregunta a qué equipo unirse; si no, el relay pone a cada jugador en el que tiene menos.
colors
Sequence[str] | None
None
Un #rrggbb por equipo, como lo muestran los teléfonos; por defecto rosa, azul, naranja, verde, violeta y turquesa.
Devuelve: Teams — Los datos de los equipos; no dibuja nada.
Ejemplo
teams = scene.teams(["Rojo", "Azul"])
for team, x in [(0, -4), (1, 4)]:
scene.viz.readout(teams.score(team), format=".0f").move_to(x, 0)
Abre una encuesta en el cursor. Recibe votos mientras una presentación está entre este punto y poll.close(), o el final del segmento. La escena decide cómo mostrarla con los datos de Poll: qr(tamaño) y bar(respuesta, ...) devuelven drawables; votes(i), share(i) y total() devuelven Parameter que siguen los votos en vivo; code y url son el código de la sesión y la dirección de votación. Al presentar un paquete .gaanim solo las barras siguen los votos en vivo; lo que pase por un computed muestra lo que se grabó. Fuera de una presentación vota el ensayo (scene.rehearsal). Ver Encuestas a la audiencia. Una pregunta o respuesta vacía, una respuesta repetida, menos de 2 o más de 6 respuestas, o pesos de rehearse que no sean uno por respuesta, negativos o todos cero lanzan ValueError.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
question
str
obligatorio
Pregunta que responde la audiencia.
options
Sequence[str]
obligatorio
Entre 2 y 6 respuestas distintas.
multiple
bool
False
Deja elegir varias respuestas; total() y share(i) cuentan a los teléfonos que respondieron.
image
str | PathLike | None
None
Una imagen, relativa al script, que los teléfonos muestran sobre la pregunta.
rehearse
Sequence[float] | None
None
Un peso por respuesta para el voto del ensayo ([1, 3] hace la segunda tres veces más popular); sin él vota al azar.
Devuelve: Poll — Los datos de la encuesta; no dibuja nada.
Abre un cuestionario al estilo Kahoot: una encuesta con respuesta correcta. Los teléfonos se unen al juego con un apodo, responden una sola vez antes de que se acabe el tiempo y una respuesta correcta gana points × (1 − tiempo / time / 2). quiz.reveal() marca dónde la presentación revela la respuesta en los teléfonos, quiz.remaining() es la cuenta atrás en segundos y scene.leaderboard da la clasificación. Una parte de rehearse fuera de 0–1 lanza ValueError. Ver Modo competencia.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
question
str
obligatorio
Pregunta del juego.
options
Sequence[str]
obligatorio
Entre 2 y 6 respuestas distintas.
correct
int | Sequence[int]
obligatorio
Índice de la respuesta correcta (0 para la primera), o una lista para selección múltiple: acierta quien marca todas y ninguna otra.
time
int
20
Segundos para responder, de 5 a 300, medidos por el reloj del relay.
points
int
1000
Puntos máximos de una respuesta correcta, de 100 a 10000.
image
str | PathLike | None
None
Una imagen que los teléfonos muestran sobre la pregunta.
rehearse
float | Sequence[float] | None
None
La parte del ensayo que acierta, de 0 a 1 (0.3 para una pregunta difícil), o un peso por respuesta; sin él responden según su skill.
Devuelve: Poll — Los datos del cuestionario, como scene.poll.
La clasificación del juego: los jugadores de los cuestionarios de la escena, de mejor a peor. Cada método recibe un puesto (0 para el primero): name(i, size=, weight=, font=, align=) devuelve el apodo como texto en vivo, points(i) y players() devuelven Parameter y bar(i, ...) una barra relativa al primero. Con ellos diseñas una lista, un podio o lo que quieras. Todo sigue a los resultados en vivo también al presentar un .gaanim, que guarda los glifos de los apodos; fuera de una presentación ordena a los jugadores del ensayo por los puntos de sus respuestas.
Devuelve: Leaderboard — Los datos de la clasificación; no dibuja nada.
Abre una zona viva en el cursor, hasta zone.close() o el final del segmento: al presentar, cada jugador llega como su personaje y el comportamiento lo coloca en cada cuadro; fuera de una presentación juega el ensayo. El comportamiento y la actualización se compilan, así que un .gaanim los ejecuta sin Python. Algo que el compilador no admite lanza gaanim.live.BehaviorError señalando la línea; unos límites vacíos, un tamaño no positivo, una expresión desconocida, state sin update (o al revés) o más de 8 números lanzan ValueError. Ver Zonas vivas.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
audience
Audience
obligatorio
El público de scene.audience().
behavior
Callable[[Player], Pose]
obligatorio
Una función de Python que recibe al jugador p y devuelve pose(x, y, ...); se compila al llamar.
bounds
tuple[float, float, float, float]
(-8, -4.5, 8, 4.5)
(x0, y0, x1, y1): los personajes se recortan a esta caja.
size
float
1.2
Alto de un personaje a escala 1.
squash
float
0.04
Cuánto se estira en la dirección en que se mueve, por unidad de velocidad (hasta max_stretch, 1,4).
lean
float
0.05
Cuánto se inclina al moverse de lado (hasta max_lean, 0,35 radianes).
follow
float
1.0
Cuánto se balancean orejas, sombreros y brotes detrás del movimiento.
look
float
0.4
Cuánto miran los ojos hacia donde va.
names
bool
False
Dibuja el apodo bajo los pies (name_size, name_color, name_gap, name_weight).
state
Mapping[str, float] | None
None
Números que la zona guarda por jugador (hasta 8) y dónde empieza cada uno.
update
Callable[[Player], State] | None
None
Calcula cada STEP (1/60 s) los siguientes números de state y devuelve state(...).
Devuelve: LiveZone — La zona; close() la cierra en el cursor.
Ejemplo
from gaanim.live import pose
audience = scene.audience()
defen_fila(p):
returnpose(-6+ p.index *1.2, -3, express="happy")
zone = scene.live_zone(audience, en_fila, names=True)
Un personaje como los que crea el público en su teléfono, y que se mueve igual que allí. character.express("happy") hace una expresión desde el cursor; con loop=True la repite hasta la siguiente, y express() vuelve a su cara. Expresiones: happy, sad, hurt, winner y surprised. Como todo depende del tiempo de la línea de tiempo, saltar y exportar dan el mismo resultado.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
avatar
Sequence[int] | None
None
Las partes: cuerpo, color, ojos, boca y extra. Sin ellas se deducen de name.
name
str
""
El apodo, que también marca el ritmo con que parpadea.
size
float
2.0
Alto en unidades, con sombreros y orejas.
Devuelve: Character — Un dibujable que respira, parpadea y hace expresiones.
El público del juego: los jugadores en el orden en que entraron, cada uno en un puesto (0 para el primero). name(i, size=, weight=, font=, align=) devuelve el apodo como texto en vivo; count(), joined(i) (1 si el puesto está ocupado, 0 si no) y age(i) (segundos desde que entró, hasta 60) devuelven Parameter; qr(size), url y code sirven para invitar. Con ellos diseñas una sala de espera, una arena o lo que quieras. Una escena que lo usa pide el apodo en cuanto el teléfono abre la página. Fuera de una presentación entran los jugadores del ensayo, uno tras otro. Ver Sala de espera.
Devuelve: Audience — Los datos del público; no dibuja nada.
Cada SceneStop tiene name (o None), time en segundos absolutos y segment. Léela al final del script, antes de render(), para pedir una captura por pausa; gaanim --diff --capture-stops hace lo mismo sin cambiar el script.
Devuelve: list[SceneStop] — Las pausas creadas hasta ahora, en orden temporal.
Ejemplo
if snapshots := os.environ.get("GAANIM_SNAPSHOTS"):
scene.snapshots(snapshots, [stop.time for stop in scene.stops])
Al empezar un segmento, los objetos de los anteriores dejan de verse. Estos tres métodos cambian a qué segmento pertenece un objeto, en el cursor actual y sin alterar su estado visual. Un objeto de otra escena lanza ValueError.
Adopta objetos en el segmento activo. Un objeto visible en el segmento anterior queda quieto durante la transición automática y luego pasa a ser contenido del segmento activo. Llamarlo después de play() o wait() actúa en ese instante.
Nombra las capas de dibujo de la escena. Todo objeto de una capa (Drawable.z_layer) se dibuja encima de todos los de las capas de detrás, sea cual sea su z_index, que solo ordena dentro de cada capa. Sirve para que lo que va encima (ventanas, lupas, etiquetas, un cursor) no dependa de un z_index mayor que cualquiera del resto del diagrama. Una escena nombra sus capas una vez; repetir las mismas no hace nada. Sin nombres, con un nombre vacío o repetido, con un default que no está entre ellos o con capas distintas a las ya nombradas lanza ValueError.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
names
str
obligatorio
Nombres de las capas, de atrás hacia adelante.
default
str | None
None
Capa de los objetos sin z_layer; sin él, la primera.
Mantiene objetos visibles y animables en los segmentos siguientes, desde el cursor actual. Las transiciones automáticas (cross_fade, slide…) no los afectan. Con el mismo z_index, un objeto persistente se dibuja encima del contenido de los segmentos, durante las transiciones y fuera de ellas; con un z_index menor queda debajo (una rejilla persistente con z_index(-1)), salvo en una transición por shader, que lo compone encima de la mezcla. Un objeto invisible sigue invisible hasta que una animación de entrada cambia su opacidad. Un objeto que no estaba en pantalla antes del segmento actual y se persiste al empezarlo entra con ese segmento: su transición de entrada lo revela como al resto del segmento, y pasa a ser global cuando termina. Para dejarlo fuera de esa transición, créalo y persístelo antes de scene.segment(...).
Termina la persistencia y devuelve los objetos al segmento activo. Al inicio de un segmento, el objeto queda quieto durante la transición de entrada y después pasa a ser local. Nunca oculta ni elimina el objeto: la siguiente transición lo trata como contenido saliente normal.
La identidad de una presentación (logo, pie, número de diapositiva) se configura una vez con scene.slides.brand(...); consulta Presentaciones.
Secciones
Section agrupa pasos de contenido que se construyen con funciones de Python. Cada paso abre su propio segmento; la función recibe la escena y crea contenido y pausas sin volver a llamar a segment. Estas clases se importan desde gaanim.
Una clave, un título o una lista de pasos vacíos lanzan ValueError; un paso de otro tipo, TypeError. section.build(scene, *, on_enter=None) abre cada segmento, llama a on_enter(scene, progress) y ejecuta la función del paso; devuelve los Segment en orden y no inserta pausas. Reutiliza la misma instancia para repetir la sección: el progreso vuelve a empezar y los nombres de segmento incluyen clave, visita, número y nombre del paso. Las excepciones se propagan sin deshacer lo ya creado.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
key
str
obligatorio
Identidad estable de la sección; única entre las secciones de una escena.
steps
Sequence[SectionStep]
obligatorio
Pasos en orden; se copian al crear la sección.
title
str | None
None
Nombre que muestran la agenda y la barra de progreso; sin él se usa key.
Devuelve: Section — Tiene key, title y steps.
Ejemplo
from gaanim import Scene, Section, SectionStep
scene =Scene(frame=(16, 9), theme="technical")
defcontexto(scene):
title = scene.text("Contexto", size=0.5)
scene.play(title.animate.write())
scene.stop()
defpropuesta(scene):
title = scene.text("Propuesta", size=0.5)
scene.play(title.animate.write())
scene.stop()
section =Section("introduccion", [
SectionStep(name="Contexto", build=contexto, notes="Presenta el problema."),
SectionStep(name="Propuesta", build=propuesta),
])
defal_entrar(scene, progress):
print(progress.key, progress.index, progress.total, progress.fraction)
segments = section.build(scene, on_enter=al_entrar)
scene.render()
key y step identifican la sección y el paso; index (desde 1) y total cuentan los pasos; visit (desde 1) cuenta las repeticiones de la sección; segment es el Segment recién abierto, útil para bind. fraction vale index / total. Las pausas dentro de un paso no avanzan el progreso.
Devuelve: SectionProgress — Contexto que recibe on_enter.
PROPIEDADScene.sectionssections: SceneSections
Construyen las dos piezas de navegación de una charla sobre una base neutra de colores del tema. Cada parte es un drawable normal que puedes reestilizar, animar u ocultar. Las secciones pueden ser instancias de Section, claves o pares (clave, título).
Devuelve: SceneSections — Fábricas agenda(...) y progress_rail(...).
Agenda.scene.sections.agenda(sections, current=None, *, direction="column", pitch=0.5, styles=None, item=None, marker=None, marker_gap=0.3) devuelve un Agenda. Cada entrada está en uno de tres estados, done, current o upcoming, y se coloca por su punto izquierdo-central a pitch unidades de la anterior, en columna o en fila. Cada entrada guarda un drawable por estado y solo muestra el suyo, así que un estado puede cambiar peso, color o contenido: focus hace un fundido cruzado entre ellos. Por defecto done usa foreground, current usa accent con peso 700 y upcoming usa muted; styles={"current": TextStyle(...)} sustituye cualquiera de ellos e item=lambda scene, entry, state: ... sustituye el texto por cualquier drawable. marker=lambda scene: ... añade un indicador a marker_gap de la entrada actual que se desliza con focus. Para anotar esas funciones, NavigationEntry y NavigationState se importan desde gaanim.
agenda.item(key) es el grupo de una entrada, agenda.items("done") las entradas en un estado y agenda.variant(key, "current") el drawable de ese estado.
agenda.focus(key) y agenda.advance(steps) cambian el estado de inmediato; agenda.animate.focus(key) y agenda.animate.advance() devuelven composiciones para scene.play, con easing= opcional. Los destinos aceptan una clave, un índice desde 0, un Section o un SectionProgress.
Barra de progreso.scene.sections.progress_rail(sections=None, *, length=12.0, thickness=0.08, orientation="horizontal", segmented=False, ...) devuelve un ProgressRail. Una barra continua es una sola pista con una marca en cada límite de sección; segmented=True da a cada sección su propia pista, separadas por gap. rail.animate.to(progress) llena las secciones anteriores a un SectionProgress y su parte de pasos; un número en [0, 1] fija la fracción de toda la barra. rail.animate.enter(section) marca una sección como actual sin llenar nada, como en una diapositiva divisoria. captions=True nombra cada sección sobre su tramo y la colorea por estado. Las partes son track, fills, marks, captions y label, y los argumentos track=, mark= y caption= sustituyen sus formas. Las barras se llenan de izquierda a derecha, o hacia arriba con orientation="vertical".
Salida
MÉTODOScene.renderrender() -> None
Llámalo una vez, al final del script. Qué se hace con la escena (previsualizarla, validarla, exportarla o capturarla) lo decide el comando que ejecuta el script. Fuera de la aplicación de Gaanim, por ejemplo con python main.py, lanza RuntimeError.
Devuelve: None — Entrega la línea de tiempo al ejecutable de Gaanim.
Ejemplo
from gaanim import Scene
scene =Scene(frame=(16, 9))
scene.wait(0.5)
scene.render()
MÉTODOScene.snapshotssnapshots(directory: str, times: Sequence[float]) -> int
Pide al ejecutable que capture seeks exactos para la comparación visual. Sin gaanim --diff, o con otra ruta, lanza RuntimeError. Consulta Capturas y comparación visual.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
directory
str
obligatorio
La ruta que gaanim --diff pasa en GAANIM_SNAPSHOTS.
times
Sequence[float]
obligatorio
Instantes absolutos que se capturan.
Devuelve: int — Número de fotogramas capturados.
Ejemplo
import os
if snapshots := os.environ.get("GAANIM_SNAPSHOTS"):
scene.snapshots(snapshots, [0.0, 1.0])
Elige el fotograma que un archivo .gaanim guarda como portada, la imagen que el explorador de archivos muestra tras gaanim register, y la imagen del proyecto en el Inicio. Sin llamarlo, la portada es el fotograma de la primera pausa o, sin pausas, el del primer segmento que más muestra. Un time negativo o no finito lanza ValueError. Consulta Compartir sin Python.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
time
float | None
None
Instante de la línea de tiempo, en segundos; None toma el cursor.
Devuelve: None — Solo marca el instante.
Ejemplo
titulo = scene.text("Resultados").scale_by(2)
scene.play(titulo.animate.write())
scene.thumbnail()
Variación reproducible
MÉTODOScene.randomrandom(seed: int = 0) -> Random
La misma semilla da los mismos valores en cualquier plataforma, así que la escena sale igual en la previsualización y en la exportación.
Ruido simplex fractal con semilla, evaluado de forma nativa en cada fotograma sin llamar a Python; la reproducción, los seeks y la exportación coinciden. Valores inválidos lanzan ValueError.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
frequency
float
1.0
Rapidez con que cambia el valor.
amplitude
float
1.0
El valor queda en [-amplitude, amplitude] alrededor de center.
octaves
int
1
Capas de detalle fino, de 1 a 8.
seed
int
0
Semilla del ruido.
center
float
0.0
Valor central.
Devuelve: Computed — Un escalar reactivo que depende del tiempo de la línea de tiempo.
scene.camera controla qué parte del mundo se ve. Sus métodos directos aplican un corte en el cursor, sin avanzar el tiempo, y devuelven la cámara para encadenar. Los mismos métodos bajo scene.camera.animate devuelven un Anim que se programa con scene.play junto a cualquier otra animación y admite .duration(), .delay() y .easing().
from gaanim import BLUE, GOLD, Scene
scene =Scene(frame=(16, 9), background="#0f172a")
circle = scene.geometry.circle(0.8).fill(BLUE).move_to(-4, 1)
square = scene.geometry.square(1.2).fill(GOLD).move_to(4, -1)
scene.play([scene.camera.animate.frame_to(circle, margin=0.6).duration(0.8)])
scene.play([scene.camera.animate.frame_to(square, margin=0.6).duration(0.8)])
scene.play([scene.camera.animate.reset().duration(0.6)])
scene.render()
Los destinos de posición (pan_to, follow, look_at, bind_*) aceptan un Drawable, un AnchorPoint, un PointRef o una tupla 2D o 3D. El zoom y la rotación aceptan también Parameter, Variable y Computed. Las APIs de cámara rechazan valores no finitos, zooms, campos de visión y planos de recorte inválidos, poses de look_at degeneradas e influencias fuera de [0, 1] con ValueError, sin recortar valores en silencio.
No tiene duración. Registra la pose escrita en el script antes de los bindings, los efectos temporales, el shake y la vista de inspección del editor, así que restaurarla da el mismo resultado al previsualizar, buscar y exportar.
Devuelve: CameraState — La pose que la cámara tiene en el cursor.
MÉTODOCamera.savesave(name: str) -> CameraState
Captura la pose actual y la guarda con un nombre para restore.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
name
str
obligatorio
Nombre no vacío; reemplaza una pose guardada con el mismo nombre.
Devuelve: CameraState — La pose capturada.
MÉTODOCamera.toto(state: CameraState) -> Camera
Salta a la pose en el cursor. Una pose de otra escena lanza ValueError.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
state
CameraState
obligatorio
Pose de esta escena.
Devuelve: Camera — La misma cámara.
MÉTODOCamera.restorerestore(name: str) -> Camera
Salta a una pose guardada. Un nombre desconocido lanza ValueError.
Cada método devuelve un Anim nuevo; construirlo no cambia nada hasta pasarlo a scene.play. Un movimiento dura un segundo salvo que .duration() fije otra; la duration de scene.play sustituye ese valor por defecto, como en las demás animaciones. shake (medio segundo la sacudida senoidal) y whip_pan (0,4 s) tienen sus propios valores por defecto, que scene.play también sustituye; una sacudida con trauma dura hasta apagarse.
Devuelve: CameraAnimation — El vocabulario animado de la cámara.
Entre una pose ortográfica y una en perspectiva, el movimiento va en perspectiva desde o hacia la vista equivalente a la ortográfica, y solo es ortográfico en su extremo ortográfico: el contenido 3D queda siempre delante del ojo. Una pose de otra escena lanza ValueError.
Con "exponential" el zoom sigue z0 * (z1 / z0) ** p, donde p es el progreso con easing: el área visible cambia en la misma proporción en cada fotograma y un zoom de 8× se lee a velocidad constante. "linear" usa z0 + (z1 - z0) * p. Un zoom constante no positivo o una interpolación desconocida lanzan ValueError.
Sigue a los objetos si se mueven durante el movimiento, y al terminar la cámara conserva el último encuadre.
interpolation
"exponential" | "linear"
"exponential"
Con "exponential" el zoom es exponencial y el desplazamiento acompaña al cambio de ancho visible, así que la vista escala alrededor de un punto fijo y el contenido viaja en línea recta. "linear" interpola posición y zoom por separado.
Devuelve: Anim — Seguimiento durante la duración del Anim. Al terminar, la cámara se queda en la pose que alcanzó, calculada con la posición del objetivo al final del play, y el siguiente movimiento parte de ahí.
Sigue el modelo de trauma: el desplazamiento es proporcional a trauma ** 2, así que un golpe leve apenas se nota y uno fuerte sacude mucho. Traslación y giro salen de ruido coherente con semilla. Dura trauma / decay segundos (un segundo con decay=0); un .duration() más corto también vuelve suavemente al reposo, y el easing no cambia el decaimiento. Se suma después de follow, encuadre y bindings, y es función pura del tiempo. Pasar solo amplitude (sin trauma, decay, rotation ni seed) mantiene la sacudida sinusoidal anterior: amplitude es el pico, frequency cuenta oscilaciones por clip (8 por defecto) y dura 0.5 s. Valores negativos o trauma mayor que 1 lanzan ValueError.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
amplitude
float | None
0.4
Desplazamiento máximo en unidades de escena con trauma 1.
frequency
float | None
12
Frecuencia del ruido en Hz.
trauma
float | None
0.8
Intensidad inicial, en [0, 1].
decay
float | None
1.5
Trauma que se pierde por segundo.
rotation
float | None
0.02
Giro máximo en radianes con trauma 1.
seed
int | None
0
Semilla del ruido.
Devuelve: Anim — Sacudida que termina en reposo.
Ejemplo
scene.play([scene.camera.animate.shake(trauma=0.8, decay=1.5, frequency=12, rotation=0.02, seed=0)])
scene.play([scene.camera.animate.shake(trauma=0.4, seed=3)]) # un golpe más leve
Lee la trayectoria en coordenadas de escena cuando se reproduce la animación, como Anim.move_along. El giro de orient se calcula en cada fotograma, así que nunca salta. Easing predeterminado: suave. Una ruta de otra escena, start o end fuera de [0, 1] o iguales, o un rotate_offset no finito lanzan ValueError.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
route
Drawable
obligatorio
Drawable cuya trayectoria recorre la cámara.
orient
bool
False
Gira la vista para que el sentido de avance apunte a la derecha de la pantalla.
rotate_offset
float
0.0
Giro extra en radianes; -math.pi / 2 apunta el avance hacia arriba.
start / end
float
0.0 / 1.0
Tramo recorrido, como fracciones de longitud de arco; start > end lo recorre al revés.
Paneo rápido de 0.4 s salvo .duration, con easing exponencial de entrada y salida: casi todo el recorrido ocurre en un instante a mitad de camino. Con blur, los fotogramas exportados y los snapshots del barrido reciben un desenfoque de movimiento de 360° y 24 subfotogramas aunque la escena no tenga uno propio; la vista previa sigue nítida, como con canvas.motion_blur.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
to / y
Endpoint | float
obligatorio
Destino, como en pan_to.
blur
bool
True
Desenfoque de movimiento en los fotogramas del barrido.
Devuelve: Anim — Paso animado a la proyección ortográfica. Desde una cámara en perspectiva, el ojo se aleja por su eje de visión mientras el campo de visión se cierra: el objetivo sigue centrado, la profundidad se aplana y la proyección pasa a ortográfica al terminar, con la misma pose. Desde una cámara ortográfica, anima el zoom.
Devuelve: Anim — Vuelta animada a la pose y proyección predeterminadas. Desde una cámara en perspectiva, el movimiento sigue en perspectiva hacia la vista equivalente a la 2D y pasa a ortográfica al terminar.
Una capa de parallax agrupa drawables que están más lejos o más cerca de la cámara que el plano de la escena. Con la cámara ortográfica, sus miembros se desplazan 1 / depth del paneo de cámara: el fondo lejano se mueve despacio y el primer plano pasa rápido, sin 3D real. No confundir con Scene.z_layers (orden de dibujo con nombre), Drawable.view_layer (filtro de vistas de cámara) ni con .layer(nombre) de gráficos y ejes (una parte del objeto).
La capa ve una cámara centrada en posición / depth y con zoom zoom ** (1 / depth); la rotación afecta a todas por igual. depth=1 se comporta como el resto de la escena, depth=3 se mueve a un tercio de la velocidad de la cámara, depth=0.6 pasa más rápido y math.inf no se desplaza ni hace zoom, como Drawable.hud salvo por la rotación. Sacudida, seguimiento y bindings también mueven las capas; un miembro convertido en HUD con Drawable.hud sigue fijo en pantalla. Las capas lejanas se dibujan detrás de las cercanas: su z_index por defecto es round(-100 * ln(depth)), limitado a ±900, y cada miembro suma el suyo. Con cámara en perspectiva las capas no se mueven, porque la profundidad real ya produce parallax. Una profundidad no positiva lanza ValueError.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
depth
float
obligatorio
Distancia a la cámara en unidades de la distancia del plano de la escena; positiva, math.inf permitido.
Devuelve: ParallaxLayer — Capa vacía; es un Drawable cuyos miembros se añaden con add.
Ejemplo
import math
from gaanim import*
scene =Scene(frame=(16, 9), background="#1d2b53")
sky = scene.layer(depth=math.inf).add(scene.geometry.circle(0.9).fill(GOLD).move_to(4.5, 2.6))
far = scene.layer(depth=3.0)
for i inrange(6):
far.add(scene.geometry.polygon([(-2.4, 0), (0, 2.6), (2.4, 0)]).fill("#3b4a7a").move_to(-8+ i *4.2, -1.4))
for i inrange(8):
scene.geometry.rect(0.5, 1.2).fill("#8a5a3b").move_to(-6+ i *3, -2.0)
near = scene.layer(depth=0.6)
for i inrange(5):
near.add(scene.geometry.circle(0.9).fill("#1f4d33").move_to(-7+ i *5, -3.3))
scene.play([scene.camera.animate.pan_to(6, 0).duration(3)])
scene.render()
Mueve los drawables a la capa conservando su posición actual; añadirlo a otra capa lo mueve allí. Mover, desvanecer o animar la capa actúa sobre todos sus miembros. Un drawable de otra escena, la propia capa u otra capa lanzan ValueError.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
drawable
Drawable
obligatorio
Primer drawable que entra en la capa.
*others
Drawable
obligatorio
Más drawables.
Devuelve: Self — La misma capa, para encadenar.
Ejemplo
far = scene.layer(depth=3.0)
far.add(scene.geometry.circle(1.0).move_to(4, 2), scene.geometry.square(1.0).move_to(-4, 2))
print(far.depth) # 3.0
3.0
Profundidad de campo
Las capas de parallax pueden desenfocarse según su distancia al foco, como con una lente real: cada capa se desenfoca aperture * |1 - focus / depth| unidades de escena, como máximo max_blur. Las capas a la profundidad focus quedan nítidas y el desenfoque crece al alejarse de ella hacia delante o hacia atrás; una capa en math.inf se desenfoca aperture. Los drawables fuera de capas, y los HUD dentro de ellas, nunca se desenfocan. Cada capa se desenfoca como una sola imagen, con un efecto de shader en su raíz que reemplaza cualquier shader_effect puesto en la propia capa; una capa desenfocada se dibuja fuera de pantalla y cuesta más.
Fija la profundidad de campo en el cursor. Los valores omitidos se conservan; al principio el foco es 1, la apertura 0 (sin desenfoque) y max_blur 0.5. Un foco no finito o no positivo, o una aperture o max_blur negativos o no finitos lanzan ValueError.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
focus
float | None
None
Profundidad nítida, finita y positiva; 1 es el plano de la escena.
aperture
float | None
None
Escala del desenfoque, en unidades de escena; 0 lo apaga.
max_blur
float | None
None
Desenfoque máximo, en unidades de escena.
Devuelve: Camera — La cámara.
Ejemplo
import math
from gaanim import*
scene =Scene(frame=(16, 9), background="#1d2b53")
far = scene.layer(depth=3.0)
for i inrange(5):
far.add(scene.geometry.polygon([(-2.4, 0), (0, 2.6), (2.4, 0)]).fill("#3b4a7a").move_to(-8+ i *4.2, -1.2))
for i inrange(6):
scene.geometry.rect(0.5, 1.2).fill("#8a5a3b").move_to(-6.5+ i *2.6, -2.0)
near = scene.layer(depth=0.5)
for i inrange(4):
near.add(scene.geometry.circle(0.9).fill("#1f4d33").move_to(-6+ i *4.4, -3.4))
scene.camera.depth_of_field(focus=1.0, aperture=0.12)
scene.wait(0.5)
scene.play([scene.camera.animate.focus_to(3.0).duration(1.5)])
scene.render()
MÉTODOCameraAnimation.depth_of_field / focus_to
depth_of_field anima los mismos valores que Camera.depth_of_field; focus_to(focus) es el cambio de foco (rack focus). El foco se mueve en profundidad inversa, así que pasa de forma pareja por capas cercanas y lejanas; la apertura y max_blur cambian linealmente. Easing predeterminado: suave.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
focus
float
obligatorio
Nueva profundidad nítida.
Devuelve: Anim — Cambio animado de la profundidad de campo.
Un binding es una restricción de cámara que no se dibuja: desde que se crea (salvo con enabled=False) escribe los canales que declara en cada fotograma, también a través de segmentos. influence es un escalar en [0, 1] que mezcla el binding con la pose anterior, y los bindings posteriores se componen sobre los anteriores. follow y el encuadre dinámico actúan después, y el shake se suma al final.
Necesita center, zoom o rotation, y selecciona la proyección ortográfica.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
center
Endpoint | None
None
Punto que sigue el centro de la vista.
zoom
ScalarSource | None
None
Zoom reactivo.
rotation
ScalarSource | None
None
Giro reactivo en radianes.
influence
ScalarSource | None
None
Peso en [0, 1]; sin él, 1.
enabled
bool
True
Activo desde el cursor actual.
Devuelve: CameraConstraint — El binding, con enable() y disable().
Ejemplo
import math
theta = scene.viz.parameter(0.0)
focus = scene.geometry.point_ref(
computed(lambda t: t *2.25, inputs=[theta]),
computed(lambda t: math.sin(t *2), inputs=[theta]),
)
rig = scene.camera.bind_2d(center=focus, zoom=computed(lambda t: 1+ t *0.3, inputs=[theta]))
scene.play([theta.animate.set(1.0).duration(2.0)])
rig.disable()
MÉTODOCameraConstraint.enableenable() -> None
Devuelve: None — Activa el binding en el cursor actual.
MÉTODOCameraConstraint.disabledisable() -> None
Los cambios quedan registrados en la línea de tiempo: un seek anterior vuelve a verlo activo.
Devuelve: None — Desactiva el binding en el cursor actual.
Vistas de cámara
Una vista de cámara muestra dentro de una figura lo que ve una segunda cámara. Drawable.camera_view (en Drawable) convierte cualquier figura cerrada en pantalla; scene.camera.inset monta de una vez la pantalla, el marco y los conectores. Ambos devuelven un CameraView.
Muestra un detalle ampliado en una pantalla aparte. El marco sigue el zoom, así que siempre recuadra lo que la pantalla muestra en reposo. Lanza ValueError con un zoom o tamaño no positivo, un shape o at desconocido, o un target reactivo sin follow.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
target
Endpoint
obligatorio
Qué ampliar: un punto, un objeto o un punto de anclaje. Con follow=True, cualquier extremo reactivo.
zoom
float | Parameter
2.0
Aumento de la pantalla en reposo.
at
Anchor | tuple[float, float]
Anchor.TOP_RIGHT
Esquina o borde del fotograma donde va la pantalla (Anchor.CENTER la centra), o punto donde se centra.
size
float | tuple[float, float] | None
None
Ancho de la pantalla, o diámetro si es un círculo; por defecto, el 30 % del ancho de la escena (20 % para un círculo). size=(ancho, alto) fija ambos lados de un rectángulo.
aspect
float | None
None
Proporción ancho / alto de un rectángulo y su marco; por defecto, la del fotograma. Úsala para encuadrar entero un panel alto o una barra de herramientas. Un círculo no admite aspect.
shape
str
"rounded"
"rect", "rounded" o "circle".
follow
bool
False
El marco sigue a target mientras se mueve.
connectors
bool
True
Dos líneas que unen las esquinas enfrentadas del marco y la pantalla.
color
Color | None
None
Trazo de la pantalla, el marco y los conectores; por defecto, el acento del tema.
fixed
bool
False
Fija la pantalla a la imagen como un HUD, para que no se mueva con scene.camera.
background / exclude / layers
obligatorio
Como en Drawable.camera_view. Los conectores nunca aparecen en la vista.
Devuelve: CameraView — La vista, con sus connectors.
Ejemplo
from gaanim import Anchor, CYAN, GOLD, Scene
scene =Scene(frame=(16, 9), background="#0f172a")
for i inrange(24):
scene.geometry.dot(0.05).fill(CYAN if i %2else GOLD).move_to(-6+0.25* i, -1+0.15* (i %5))
view = scene.camera.inset((-4, -0.7), zoom=4, at=Anchor.TOP_RIGHT)
scene.play([view.animate.pop_out().duration(0.8)])
scene.play([view.animate.pan_to(-1.5, -0.7).duration(1.2), view.animate.zoom_to(8).duration(1.2)])
scene.render()
PROPIEDADCameraView.screenscreen: Drawable
Devuelve: Drawable — La figura que muestra la vista.
PROPIEDADCameraView.frameframe: Drawable
Devuelve: Drawable — El objeto que hace de cámara; se anima como cualquier otro.
Una vista creada con un número devuelve un Computed; con un Parameter o Computed, lo devuelve tal cual. Si el tamaño del marco fija el zoom, lanza ValueError.
Devuelve: Parameter | Computed — El zoom como valor reactivo, para lecturas y vínculos.
Fija el zoom en el cursor actual. Si el tamaño del marco fija el zoom, escala el marco para alcanzarlo, medido con su fit sobre ambos tamaños en ese punto. Un zoom no positivo, o una vista que sigue un Computed, lanza ValueError.
El zoom propio de la vista cambia a velocidad percibida constante; un Parameter se anima de forma lineal y una vista con zoom de marco escala el marco.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
zoom
float
obligatorio
Aumento final.
Devuelve: Anim — La animación.
MÉTODOCameraViewAnimation.pan_to / rotate_to
Versiones animadas de CameraView.pan_to y CameraView.rotate_to.
La pantalla sale de la región que ve su cámara y crece hasta su sitio. Encogida sobre esa región muestra la escena a tamaño real, así que la vista brota de la escena sin saltos. Si es la primera animación de la pantalla, hace de entrada: hasta que empieza, la pantalla (y en un inset, el marco y los conectores) está oculta. Tras pop_in, la devuelve a donde estaba y los vuelve a mostrar.
Devuelve: Anim — La animación.
MÉTODOCameraViewAnimation.pop_inpop_in() -> Anim
Encoge la pantalla de vuelta a la región que ve su cámara y, al llegar, la oculta junto con el marco y los conectores de un inset, así que una capa de vista deja de verse sobre la escena. Es la salida simétrica de pop_out; el siguiente pop_out los vuelve a mostrar. En una vista de camera_view, el marco es tuyo y conserva su visibilidad.
Devuelve: Anim — La animación.
Cámara 3D
La cámara 3D usa coordenadas de mundo (x, y, z) y ángulos en radianes. Las primitivas 3D están en Geometría. Para una introducción, consulta la guía Cámara y 3D.
Coloca la cámara en eye mirando a target. Los extremos se resuelven después del layout reactivo; eye y target deben ser distintos y up no puede ser nulo ni paralelo a la dirección de la mirada.
La cámara avanza o retrocede por su línea de visión hasta factor veces su distancia al objetivo de look_at mientras el campo de visión cambia para que el plano del objetivo conserve su tamaño en pantalla: el fondo se estira (factor mayor que 1) o se precipita. La distancia cambia exponencialmente. Solo el contenido 3D lo muestra, porque la capa 2D no se mueve con una cámara en perspectiva. Sin perspective o con la cámara sobre su objetivo avisa y no hace nada. Un factor no finito o no positivo lanza ValueError.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
factor
float
obligatorio
Multiplicador positivo de la distancia al objetivo.
El editor tiene una cámara de inspección separada de scene.camera, que nunca cambia las capturas, Presenter View ni la exportación. Empieza desactivada; cada vez que se activa con I (o con el botón Interactive de la barra de overlays, O) parte de una copia de la cámara de la escena en ese instante.
Num0: alterna entre Free 3D y Camera View (la cámara de la escena).
En 3D, arrastrar con el botón derecho: orbitar; con el central o Mayús + izquierdo: desplazar. En 2D, arrastrar con cualquier botón desplaza la vista y la escena sigue al cursor; un clic sin arrastrar selecciona el objeto.
Rueda: hacia arriba acerca y hacia abajo aleja. En 2D acerca hacia el punto bajo el cursor, que se queda quieto.
W, A, S, D: desplazan la cámara. Las flechas siguen navegando entre paradas y escenas.
Mientras la inspección está activa, un clic en la vista previa no avanza a la siguiente parada; Enter y las flechas sí. Arrastrar o usar la rueda sobre los paneles del editor no mueve la cámara.
F: encuadra la selección, o toda la escena si no hay nada seleccionado.
R: restablece y encuadra; I: activa o desactiva la inspección.
El marco de salida visible conserva el marco lógico y su proporción, y la selección con el ratón se limita a ese marco. Mientras la escena tiene contenido 3D, la barra de tiempo desactiva el ajuste magnético.
Overlays del editor
O muestra una barra con guías que se dibujan solo en el editor, nunca en las capturas ni en la exportación. O o Esc la ocultan.
Bounds (B): el marco de salida y su tamaño en unidades lógicas.
Coordinates (C): los ejes con sus marcas y el punto bajo el cursor en unidades de la escena. Mantén Mayús para ajustarlo a la grilla y pulsa Ctrl+C (Cmd+C en macOS) para copiarlo como tupla, lista para pegar en move_to((x, y)). La etiqueta se oculta sobre los paneles del editor.
Grid (G): líneas cada 1, 2 o 5 unidades (o sus potencias de diez), según el zoom. Durante la inspección cubren toda la vista, no solo el marco. En 3D es una grilla sobre el plano XZ alrededor del punto que mira la cámara, con el eje X en rojo y el Z en azul.
Guides (M): márgenes seguros de acción (90 %) y de títulos (80 %), y los tercios del marco.
Layout (K): inspecciona las cajas como las herramientas de desarrollo de un navegador. Cada caja lleva un contorno discontinuo y las zonas del segmento actual un contorno turquesa con su nombre. Al pasar el cursor por una caja se colorean su padding (verde), las celdas de sus hijos (azul), sus márgenes (naranja) y los gaps entre ellos (morado), con una etiqueta de su tipo, tamaño, padding y gap en px de diseño. Sigue la caja en cada momento de la línea de tiempo, también mientras se reorganiza.
El objeto seleccionado se enmarca con su centro y su tamaño en unidades, y el Inspector muestra sus propiedades (ver más abajo).
Con la inspección activa, la barra muestra el zoom de la vista (o Free 3D) en azul cuando ya no coincide con la cámara de la escena, y un botón para restablecerla (R). El botón de captura guarda el fotograma actual como PNG, sin overlays (Ctrl+Mayús+S). El icono de teclado lista todos los atajos.
El editor recuerda qué overlays dejaste activados entre sesiones; el modo en sí siempre empieza oculto.
Inspector, consola y animaciones
Con los overlays visibles, un clic en la vista previa selecciona un objeto y el Inspector (botón de la barra) muestra:
su tipo con el vocabulario del script (circle, rounded_rect, text…) y el nombre que le diste con named;
la línea del script que lo creó, con Open para ir a ella en tu editor de código y Copy para llevarte archivo:línea. Si lo creó una función tuya, debajo aparecen las líneas que la llamaron (called from main.py · line 11), cada una también se abre con un clic;
su posición, rotación (en radianes, como rotate_to, y en grados), escala, tamaño y centro en unidades de la escena; su relleno y su trazo con el color en hexadecimal, y su opacidad;
su z_index, su capa, su profundidad de parallax o si es HUD, si es visible, el texto que dibuja y cuántos hijos tiene.
Sin nada seleccionado, el inspector muestra la cámara de la escena: su posición, rotación, zoom (o campo de visión, recorte y objetivo en perspectiva), el encuadre y, si está activa, la profundidad de campo. Los valores son los del instante de la línea de tiempo, así que cambian al reproducir o recorrer la escena. Un clic sobre una letra selecciona el texto entero y, a igual z_index, gana la caja más pequeña bajo el cursor: la etiqueta sobre su tarjeta, el miembro dentro de su grupo. Inside … sube al grupo que lo contiene. Las líneas siguen siendo correctas tras cada recarga, aunque la recarga reutilice segmentos ya compilados.
La Console (J, o el botón de la barra) reúne lo que antes solo llegaba a la terminal: los avisos de Gaanim y de Python (warnings.warn), lo que escribe print, los errores del script con su traceback y las líneas de estado de cada recarga. Cada mensaje ocupa una fila y enlaza con la línea del script que lo produjo; un clic en la fila muestra debajo el mensaje completo y, si lo tiene, su traceback. Filtra por errores, avisos y mensajes, busca por texto o archivo, copia lo listado como en la terminal y limpia la lista. Por defecto muestra solo la última ejecución del script; History conserva las anteriores. Mientras está oculta, una insignia arriba a la izquierda cuenta los errores y avisos de la última ejecución y la abre con un clic.
Animations (T, o el botón de la barra) abre sobre la barra de reproducción una línea de tiempo de la escena: una fila por objeto animado, más la de la cámara, y un bloque por cada play que lo anima, coloreado por tipo (movimiento, transformación, aparición, estilo, trazo o cámara). Las animaciones de las letras de un texto aparecen en la fila del texto. Muestra el segmento bajo el cabezal; Whole scene muestra toda la escena, y la búsqueda filtra por objeto o por animación. Un clic o un arrastre en la regla mueve el cabezal. Un clic en un bloque pausa, lleva el cabezal a su inicio y selecciona el objeto para verlo en el inspector; un doble clic abre la línea del play. Al pasar el cursor, el bloque muestra su duración, su curva, la línea del play y las líneas desde las que se llamó. Un clic en el nombre de la fila selecciona el objeto y un doble clic abre la línea que lo creó. Mientras está oculto, el panel no cuesta nada por fotograma.
El inspector aparece arriba a la derecha y el panel de animaciones sobre la barra de reproducción. Arrastra cualquiera de los dos por su cabecera (la fila con los puntos) para llevarlo a otro sitio de la ventana; se queda ahí al cambiar de selección y nunca sale de la pantalla. Un doble clic en la cabecera lo devuelve a su sitio. Mientras el panel de animaciones está en su sitio, la consola se coloca encima de él.
Open usa el comando de GAANIM_EDITOR (por ejemplo code --goto {file}:{line}); sin ella, el primero que encuentre en el PATH entre VS Code (code), Cursor, VSCodium, Zed y Sublime Text, y si no hay ninguno abre el archivo con la aplicación predeterminada, que no salta a la línea. El panel de error del script también ofrece Open in the editor.
Recorte y máscaras
Cualquier objeto vectorial puede recortar a otro con una máscara viva que se recalcula en cada fotograma: consulta Drawable.clip y Drawable.no_clip.