anyx

Build vector animations from programmatic descriptions

View project on GitHub

Welcome to “anyx” documentation

anyx (pronounced as “anix”) is a python library designed for easily producing high-quality (vector) graphics animations with ease. Although anyx is built with no assumption about its downstream area of application, it is mostly targeted towards scientific community for creating beautiful scientific/technical illustrations. anyx is created as a programmatic alternative to heavyweight and (sometimes) proprietary graphical software. Unlike low-level libraries like pygame, anyx allows users to simply write a description of a target scene and compile it down to the required modality (Video, Animated GIFs etc). The development of anyx is motivated largely by a similar project called manim.

Design of the library

anyx is designed to have a reasonably small sized “core” and a large “library” on top of it. The “core” of anyx contains its lowest level APIs, which is fairly minimal. It also contains the implementations of its conceptual primitives namely GraphicsObject, Kernel and Scene. Technically, the core is sufficient to write any animation you’ll ever need, but requires a lot of effort. The “library”, built entirely on top of the “core”, is there to make our lives easier by providing a collection of useful definitions that are otherwise tedious to write. Finally, as a future target, we aim to keep the APIs as consistent as possible over versions.

Anatomy of an anyx program

Before we move on to describe the core conceptual components, let’s look at a simplistic example:

import anyx
from anyx.library import glib
from anyx.library.utils import Point

with anyx.VideoRecorder('output.mp4', resolution=(512, 512), fps=60) as recorder:

    class my_scene(anyx.Scene):
        ring = glib.Circle(center=(50., 50.), thickness=3.0, radius=20., stroke_color='red')
        
        @anyx.kernel(duration=1.0)
        def move(obj, _, t) -> ring:
            obj.center = Point(50,50) * (1. - t) + Point(200,200) * t
            obj.radius = 30. * t

    recorder << my_scene
  1. Firstly, we need an anyx.VideoRecorder instance which is solely responsible for actually producing the video stream from a given description of a scene. The video file is written only when a scene (my_scene class) is streamed into the recorder with recorder << my_scene statement.

  2. A scene is described in a class inherited from anyx.Scene. It contains the objects present in the scene along with their behaviours during animation.

  3. The only object in the above program is a Circle instance called ring. An object has lots of attributes (like center, thickness, radius) which together define the state of an object (i.e. how it is rendered).

  4. An object alone cannot define a dynamic scene - a behaviour must be associated with it. Technically, anyx terms it an “Animation Kernel”. A kernel is a function that “defines how the state of an object changes over time”. A kernel can be defined by decorating a native python function with @anyx.kernel(..) having a signature def name_of_kernel(obj, _, t): ... where obj is the attached object and t is the “lifetime” parameter (runs from 0 -> 1 during animation).