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()
animation preview

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.

FÁBRICAMediaLibrary.imageimage(path: str, *, width: Optional[float] = None, height: Optional[float] = None, fit: str = "contain", crop: Optional[tuple[float, float, float, float]] = None, quality: Literal["low", "medium", "high"] = "medium") -> Image
Crea una Image que conserva su tipo al encadenar setters. Ajustes, recortes, medidas o calidades inválidos lanzan ValueError.
Parámetros
NombreTipoPredeterminadoDescripción
pathstrobligatorioArchivo PNG, JPEG o WebP.
width / heightfloat | NoneNoneTamaño de destino en unidades de escena; sin ellos, la imagen cabe en el área segura.
fitstr"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) | NoneNoneRecorte de la fuente en píxeles, con origen arriba a la izquierda.
qualitystr"medium"Muestreo: low (vecino más cercano), medium (bilineal) o high (bicúbico).
Ejemplo
logo = scene.media.image("assets/logo.webp", width=3)
banner = scene.media.image("foto.jpg", width=8, height=2, fit="cover")
MÉTODOImage.frameframe(width: float, height: float, fit: Literal["contain", "cover", "stretch"] = "contain") -> Self
Fija un marco centrado en unidades de escena. 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.
Ejemplo
foto = scene.media.image("foto.jpg").frame(8, 4.5, fit="cover")
MÉTODOImage.cropcrop(x: float, y: float, width: float, height: float, *, normalized: bool = False) -> Self
Selecciona un rectángulo de la fuente sin mover el marco. El origen es la esquina superior izquierda, con Y hacia abajo; 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.
Ejemplo
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()
animation preview
MÉTODOImage.qualityquality(value: Literal["low", "medium", "high"]) -> Self
Cambia la calidad de muestreo ("low", "medium" o "high") en el cursor.
PROPIEDADImage.source_width / source_heightsource_width: int · source_height: int
Tamaño original en píxeles, independiente del recorte y las transformaciones.
Ejemplo
foto = scene.media.image("foto.jpg")
aspect = foto.source_width / foto.source_height

SVG

Ilustraciones vectoriales importadas como una jerarquía real de caminos y grupos, con acceso a cada parte por su id.

FÁBRICAMediaLibrary.svgsvg(path: str) -> Drawable
Importa geometría, degradados, transformaciones, 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.
Ejemplo
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()
animation preview
MÉTODODrawable.partpart(id: str) -> Drawable
Devuelve la parte con ese 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.
Ejemplo
robot = scene.media.svg("assets/robot.svg").scale_to(2)
head = robot.part("head").fill(GOLD)
MÉTODODrawable.partsparts() -> tuple[str, ...]
Tupla con los nombres que acepta part.
Ejemplo
('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.

FÁBRICAMediaLibrary.videovideo(path: str, *, width: Optional[float] = None, height: Optional[float] = None, fit: Literal["contain", "cover", "stretch"] = "contain", crop: Optional[tuple[float, float, float, float]] = None, quality: Literal["low", "medium", "high"] = "medium", offset: float = 0.0, duration: Optional[float] = None, loop: bool = False, speed: float = 1.0, audio: bool = True, volume: float = 1.0) -> Video
Declarar el video no inicia fotogramas ni audio: 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.
Parámetros
NombreTipoPredeterminadoDescripción
pathstrobligatorioArchivo MP4 local.
width / height / fit / crop / quality——Igual que en image.
offsetfloat0.0Inicio dentro de la fuente, en segundos.
durationfloat | NoneNoneDuración seleccionada; None llega al final.
loopboolFalseRepite el intervalo seleccionado.
speedfloat1.0Velocidad positiva; conserva el tono del audio.
audioboolTrueReproduce y exporta la primera pista de audio.
volumefloat1.0Ganancia no negativa.
Ejemplo
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()
animation preview
MÉTODOVideo.segmentsegment(*, start: float, end: float, speed: Optional[float] = None, audio: Optional[bool] = None, volume: Optional[float] = None) -> VideoSegment
Devuelve un 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.
Parámetros
NombreTipoPredeterminadoDescripción
start / endfloatobligatorioSegundos absolutos de la fuente, con 0 <= start < end <= source_duration.
speed / audio / volumefloat | bool | NoneNoneNone hereda el valor del video.
Ejemplo
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)])
MÉTODOVideo.frame / crop / qualityframe(width, height, fit="contain") · crop(x, y, width, height, *, normalized=False) · quality(value) -> Self
Mismo comportamiento que en Image; los cambios de fotograma conservan la calidad.
PROPIEDADVideo.source_duration / frame_rate / source_width / source_heightsource_duration: float · frame_rate: float · source_width: int · source_height: int
Duración completa de la fuente en segundos (antes de recortes o cambios de velocidad), fotogramas por segundo y tamaño original en píxeles.
Ejemplo
10.0 10.0 160 90

Lottie y dotLottie

Animaciones vectoriales exportadas desde After Effects, Cavalry u otras herramientas, renderizadas con Velato dentro de la misma escena Vello.

FÁBRICAMediaLibrary.lottielottie(path: str, *, animation_id: Optional[str] = None, theme_id: Optional[str] = None, state_machine_id: Optional[str] = None, width: Optional[float] = None, height: Optional[float] = None, fit: Literal["contain", "cover", "stretch"] = "contain", offset: float = 0.0, duration: Optional[float] = None, loop: bool = False, speed: float = 1.0) -> Lottie
Declarar el clip muestra su primer fotograma; 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.
Parámetros
NombreTipoPredeterminadoDescripción
pathstrobligatorioLottie JSON o paquete dotLottie v1/v2 local.
animation_id / theme_id / state_machine_idstr | NoneNoneSelectores 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 / 1Intervalo reproducido, como en video.
Ejemplo
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()
animation preview
MÉTODOLottie.set_inputset_input(name: str, value: float | int | bool | str) -> Lottie
Fija una entrada tipada de la máquina de estados en el cursor (o el estado inicial antes de 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.
Ejemplo
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)
MÉTODOLottie.fire_eventfire_event(name: str) -> Lottie
Dispara un evento declarado en el cursor y devuelve el clip. Requiere que el clip esté activo. Las órdenes simultáneas conservan su orden de declaración y se reproducen igual al buscar y exportar.
Ejemplo
clip.fire_event("reset")
scene.wait(1)
MÉTODOLottie.set_themeset_theme(id: Optional[str] = None) -> Lottie
Aplica un tema estático del paquete en el cursor; None restaura el diseño base. Antes de activar el clip fija el tema inicial.
Ejemplo
clip.set_theme("gold")
scene.wait(1)
PROPIEDADLottie.animation_ids / theme_ids / state_machine_idsanimation_ids: list[str] · theme_ids: list[str] · state_machine_ids: list[str]
Identificadores disponibles en el paquete, en el orden del manifiesto; vacíos para un JSON.
Ejemplo
['idle', 'active'] ['gold'] ['main']
PROPIEDADLottie.warningswarnings: list[str]
Lista de características de la fuente que Velato omite o aproxima. Revísala si el clip no se ve como en la herramienta de origen. source_width, source_height, frame_rate y source_duration describen la composición original.