Medios
Fábricas de scene.media: imágenes, SVG, video y Lottie
scene.media carga archivos locales como objetos de la escena: imágenes, SVG, video y animaciones Lottie. Todos son Drawable, así que se colocan, escalan y animan como cualquier forma. Una ruta relativa se resuelve desde la carpeta de recursos de la escena si se fijó con scene.assets.load_project() o scene.assets.assets_dir(...); si no, desde el directorio de trabajo, la carpeta assets/ del script y la carpeta del script, en ese orden (ver Recursos); el audio está en Audio.
from gaanim import Scene
scene = Scene(frame=(16, 9), background="#0f172a")
photo = scene.media.image("assets/cover.png").frame(6, 3.4, fit="cover").move_to(-3.5, 0)
robot = scene.media.svg("assets/robot.svg").scale_to(2).move_to(3.5, 0)
scene.play([photo.animate.fade_in(), robot.animate.write()], duration=1.2)
scene.render()
Imágenes
PNG, JPEG y WebP con marco, recorte y calidad de muestreo. La textura decodificada se comparte entre objetos que usan la misma ruta.
Image que conserva su tipo al encadenar setters. Ajustes, recortes, medidas o calidades inválidos lanzan ValueError.| Nombre | Tipo | Predeterminado | Descripción |
|---|---|---|---|
path | str | obligatorio | Archivo PNG, JPEG o WebP. |
width / height | float | None | None | Tamaño de destino en unidades de escena; sin ellos, la imagen cabe en el área segura. |
fit | str | "contain" | Con width y height, como en Image.frame: contain conserva la imagen entera, cover llena el marco recortando el sobrante por igual a ambos lados y stretch la deforma. |
crop | (x, y, w, h) | None | None | Recorte de la fuente en píxeles, con origen arriba a la izquierda. |
quality | str | "medium" | Muestreo: low (vecino más cercano), medium (bilineal) o high (bicúbico). |
logo = scene.media.image("assets/logo.webp", width=3)
banner = scene.media.image("foto.jpg", width=8, height=2, fit="cover")contain conserva la proporción con bandas transparentes, cover llena el marco recortando el sobrante y stretch deforma. Después de congelarse la declaración, crea un corte reversible en el cursor.foto = scene.media.image("foto.jpg").frame(8, 4.5, fit="cover")normalized=True usa fracciones del tamaño original. obj.animate.crop(...) interpola el recorte para hacer paneos o zoom dentro del marco. Rectángulos fuera de la imagen lanzan ValueError.from gaanim import Scene
scene = Scene(frame=(16, 9), background="#0f172a")
foto = scene.media.image("foto.jpg").frame(8, 4.5, fit="cover")
scene.play([
foto.animate.crop(0.25, 0.25, 0.5, 0.5, normalized=True).duration(1.5)
])
scene.render()
"low", "medium" o "high") en el cursor.foto = scene.media.image("foto.jpg")
aspect = foto.source_width / foto.source_heightSVG
Ilustraciones vectoriales importadas como una jerarquía real de caminos y grupos, con acceso a cada parte por su id.
clipPath y feGaussianBlur como caminos vectoriales normales. El documento se importa a 100 píxeles SVG por unidad lógica, la misma equivalencia que usa el resto del motor (el trazo por defecto de 0.03 equivale a 3 px), con el centro del documento en el origen. scale_to y rotate_to usan como pivote el centro de lo que el SVG dibuja, no el del documento: si el dibujo no está centrado en su lienzo, tras escalarlo el centro del documento ya no queda en el origen; colócalo con move_to, que usa el centro visual, o fija el pivote con with_pivot(0, 0) antes de escalar. Las partes (part(id)) se colocan después de la raíz, así que moverlas no cambia dónde queda el SVG. El tamaño en píxeles es el width/height del documento, o el viewBox si faltan: un SVG de 200 × 200 px mide 2 × 2 unidades en el marco de 16 × 9. Trazos, degradados, clipPath, texto y filtros escalan con la geometría. scale_to(factor) cambia el tamaño de todo el SVG; los anchos de trazo fluidos aplicados a la raíz o a una parte (part(id)), fijos o animados, siguen en unidades lógicas de escena aunque el SVG se escale. Como todo trazo, ninguno sigue una animación de escala posterior. Los detalles de compatibilidad están en Recursos.from gaanim import BLUE, Scene
scene = Scene(frame=(16, 9), background="#f8fafc")
# robot.svg mide 200 px, es decir 2 unidades: scale_to(2.5) lo deja en 5
robot = scene.media.svg("assets/robot.svg").scale_to(2.5).move_to(0, 0)
robot.part("left-arm").fill(BLUE)
scene.play([robot.animate.write().duration(0.8)])
scene.play([robot.part("head").animate.shift_by(0, 0.4).duration(0.6)])
scene.render()
id de un SVG como un Drawable propio. Los nombres distinguen mayúsculas; un nombre desconocido lanza KeyError con la lista de nombres disponibles. El estilo de un grupo llega a todos sus caminos.robot = scene.media.svg("assets/robot.svg").scale_to(2)
head = robot.part("head").fill(GOLD)part.('body', 'elbow', 'forearm', 'head', 'left-arm', 'torso', 'upper-arm')Video
Clips MP4 sincronizados con la línea de tiempo, con su audio. Requieren ffmpeg y ffprobe.
scene.play([clip]) fija su inicio absoluto. Un video finito sin bucle aporta su duración al lote; con bucle no alarga la línea de tiempo. Rangos inválidos lanzan ValueError y los fallos de medios, RuntimeError.| Nombre | Tipo | Predeterminado | Descripción |
|---|---|---|---|
path | str | obligatorio | Archivo MP4 local. |
width / height / fit / crop / quality | — | — | Igual que en image. |
offset | float | 0.0 | Inicio dentro de la fuente, en segundos. |
duration | float | None | None | Duración seleccionada; None llega al final. |
loop | bool | False | Repite el intervalo seleccionado. |
speed | float | 1.0 | Velocidad positiva; conserva el tono del audio. |
audio | bool | True | Reproduce y exporta la primera pista de audio. |
volume | float | 1.0 | Ganancia no negativa. |
from gaanim import Scene
scene = Scene(frame=(16, 9), background="#0f172a")
clip = scene.media.video("clip.mp4", width=9, duration=1.5)
scene.play([clip.animate.fade_in().duration(0.3)])
scene.play([clip])
scene.render()
VideoSegment inerte hasta pasarlo a scene.play o a una composición. Dura (end - start) / speed segundos de escena y no hereda offset, duration ni loop. Antes del primer fragmento se ve el póster; entre fragmentos y después del último se mantiene el último fotograma, sin audio. Cada fragmento se programa una sola vez: para repetirlo crea otro. Los solapamientos sobre el mismo video, estirar composiciones con medios y mezclar fragmentos con scene.play([video]) lanzan ValueError.| Nombre | Tipo | Predeterminado | Descripción |
|---|---|---|---|
start / end | float | obligatorio | Segundos absolutos de la fuente, con 0 <= start < end <= source_duration. |
speed / audio / volume | float | bool | None | None | None hereda el valor del video. |
video = scene.media.video("clip.mp4").frame(8, 4.5)
scene.play([video.segment(start=2, end=5)])
scene.wait(1)
scene.play([video.segment(start=5, end=8, speed=2)])Image; los cambios de fotograma conservan la calidad.10.0 10.0 160 90Lottie y dotLottie
Animaciones vectoriales exportadas desde After Effects, Cavalry u otras herramientas, renderizadas con Velato dentro de la misma escena Vello.
scene.play([clip]) fija el inicio de la reproducción, que sigue el reloj de la escena también al saltar hacia atrás. fade_in, write y create pueden presentar el primer fotograma antes de reproducirlo. Una máquina de estados no alarga la escena: usa scene.wait. Opciones inválidas lanzan ValueError; fallos de archivo, JSON o imágenes, RuntimeError. Los detalles de compatibilidad están en Recursos.| Nombre | Tipo | Predeterminado | Descripción |
|---|---|---|---|
path | str | obligatorio | Lottie JSON o paquete dotLottie v1/v2 local. |
animation_id / theme_id / state_machine_id | str | None | None | Selectores del paquete. Animación y máquina de estados son excluyentes; un JSON no acepta selectores. |
width / height / fit | — | — | Igual que en image. |
offset / duration / loop / speed | — | 0 / hasta el final / False / 1 | Intervalo reproducido, como en video. |
from gaanim import Scene, sequence
scene = Scene(frame=(16, 9), background="#0f172a")
clip = scene.media.lottie("assets/pulse.json", width=3)
scene.play(sequence(clip.animate.fade_in().duration(0.3), clip))
scene.render()
play) y devuelve el clip sin avanzar el tiempo. Entradas desconocidas, tipos incompatibles o números no finitos lanzan ValueError; bool es distinto de los números.clip = scene.media.lottie("assets/button.lottie", state_machine_id="main", width=4)
clip.set_input("active", False)
scene.play([clip])
scene.wait(1)
clip.set_input("active", True)
scene.wait(1)clip.fire_event("reset")
scene.wait(1)None restaura el diseño base. Antes de activar el clip fija el tema inicial.clip.set_theme("gold")
scene.wait(1)['idle', 'active'] ['gold'] ['main']source_width, source_height, frame_rate y source_duration describen la composición original.