VectorMathAnim

The canvas is the top-level object that manages all visual objects, camera controls, frame generation, and export. Every VectorMation script creates exactly one VectorMathAnim instance.


Constructor

class VectorMathAnim(save_dir, width=1920, height=1080, scale=1, verbose=False)

Create a new canvas with a given save directory and viewport size.

Parameters:
  • save_dir (str) – Directory where SVG frames are saved. Created automatically if it does not exist.

  • width (int) – ViewBox width in pixels (default 1920).

  • height (int) – ViewBox height in pixels (default 1080).

  • scale (int) – Pixel scale factor applied to the output <svg> element. 1 gives native resolution; 2 doubles it.

  • verbose (bool) – When True, enable DEBUG-level logging.

The canvas creates a default viewBox of 0 0 width height and maintains an internal clock (canvas.time) used by generate_frame_svg() when no explicit time is given.

duration: float

Read-only property. Returns the total animation duration in seconds, auto-detected from the latest animation end time across all registered objects and camera keyframes.

viewbox: tuple

The current (x, y, width, height) viewBox. Readable and writable. Writing sets all four viewBox attributes from the current canvas time onward.

from vectormation.objects import *

canvas = VectorMathAnim(save_dir='svgs/my_animation', verbose=True)

Example: Basic scene

"""Basic canvas scene with shapes."""
from vectormation.objects import *

v = VectorMathAnim()
v.set_background(fill='#1a1a2e')

c = Circle(r=100, cx=600, cy=540, fill='#58C4DD', fill_opacity=0.8)
r = Rectangle(200, 140, x=1220, y=470, fill='#E74C3C', fill_opacity=0.8)
t = Text('Hello!', x=960, y=300, font_size=60, fill='#fff',
         stroke_width=0, text_anchor='middle')

v.add(c, r, t)

v.show(end=0)

Scene Setup

VectorMathAnim.set_background(creation=0, z=-1, grid=False, grid_spacing=60, grid_color='#333', **styling)

Add a full-canvas background rectangle. Optional grid lines can be overlaid for alignment or debugging.

Parameters:
  • creation (float) – Time at which the background appears.

  • z (int) – Z-order (default -1, behind everything).

  • grid (bool) – Draw grid lines over the background.

  • grid_spacing (float) – Distance (pixels) between grid lines.

  • grid_color (str) – Grid line colour.

  • styling – Any additional SVG styling (fill, fill_opacity, etc.). When no fill is given the Styling defaults apply.

Returns:

self (for chaining).

Calling set_background again replaces the previous background.

canvas.set_background(fill='#1a1a2e')
canvas.set_background(fill='#0d1b2a', grid=True, grid_spacing=135)

Adding and Removing Objects

VectorMathAnim.add_objects(*args)

Register one or more objects for rendering. Objects are drawn each frame sorted by z-order.

Parameters:

args – VObject or VCollection instances.

Returns:

self (for chaining).

add is an alias for add_objects.

circle = Circle(r=80, fill='#58C4DD')
label  = Text(text='Hello', x=960, y=540)
canvas.add_objects(circle, label)
# or equivalently:
canvas.add(circle, label)
VectorMathAnim.remove(*args)

Remove objects from the canvas so they are no longer rendered.

Parameters:

args – Objects previously added via add_objects().

Returns:

self (for chaining).

VectorMathAnim.clear()

Remove all objects from the canvas except the background and defs. Useful for multi-scene scripts that rebuild the scene between segments.

Returns:

self (for chaining).

VectorMathAnim.add_def(def_obj)

Register a gradient, clip path, or filter for the <defs> block. The object must have an id attribute and a to_svg_def(time) method.

Aliases: add_gradient, add_clip_path.

Returns:

self (for chaining).

VectorMathAnim.add_section(time)

Add a section break at the given time. Sections allow pausing playback in the browser viewer (press N to jump to the next section). They are also used by export_sections().

Parameters:

time (float) – Section boundary time in seconds.

Returns:

self (for chaining).


Frame Generation

VectorMathAnim.generate_frame_svg(time=None)

Return the complete SVG string for a single frame at the given time.

Parameters:

time (float) – Timestamp to render. Defaults to canvas.time.

Returns:

SVG string (including XML declaration and <svg> wrapper).

Return type:

str

This is the core rendering method. It:

  1. Evaluates the animated viewBox at time.

  2. Emits any <defs> (gradients, clip paths).

  3. Collects all objects whose show attribute is True at time.

  4. Sorts them by z-order.

  5. Runs updaters on each object.

  6. Calls to_svg(time) on each object and concatenates the result.

  7. Rounds floating-point numbers for compact output.

VectorMathAnim.write_frame(time=None, filename=None)

Write an SVG frame to disk.

Parameters:
  • time (float) – Timestamp (defaults to canvas.time).

  • filename (str) – Output path. Defaults to <save_dir>/gen.svg.


Camera Controls

All camera methods animate the SVG viewBox, which effectively pans and zooms the visible region. They return self for chaining.

VectorMathAnim.camera_shift(dx, dy, start, end, easing=smooth)

Pan the camera by (dx, dy) pixels over [start, end].

Parameters:
  • dx (float) – Horizontal shift in pixels.

  • dy (float) – Vertical shift in pixels.

  • start (float) – Animation start time.

  • end (float) – Animation end time.

  • easing – Easing function (default smooth).

# Slowly pan 400px to the right over 2 seconds
canvas.camera_shift(400, 0, start=1, end=3)
VectorMathAnim.camera_zoom(factor, start, end, cx=None, cy=None, easing=smooth)

Example: camera_zoom

"""Camera zoom example."""
from vectormation.objects import *

v = VectorMathAnim()
v.set_background(fill='#1a1a2e')

c1 = Circle(r=60, cx=500, cy=400, fill='#58C4DD', fill_opacity=0.8)
c2 = Circle(r=60, cx=1420, cy=640, fill='#E74C3C', fill_opacity=0.8)
c1.fadein(start=0, end=0.5)
c2.fadein(start=0, end=0.5)

v.camera_zoom(2.5, start=1, end=2.5, cx=500, cy=400)
v.camera_reset(3.5, 5)

v.add(c1, c2)

v.show(end=6)

Zoom the camera by factor around the point (cx, cy) over [start, end]. factor > 1 zooms in; factor < 1 zooms out.

Parameters:
  • factor (float) – Zoom factor.

  • start (float) – Animation start time.

  • end (float) – Animation end time.

  • cx (float) – Zoom centre x (default: canvas centre).

  • cy (float) – Zoom centre y (default: canvas centre).

  • easing – Easing function (default smooth).

# Zoom 2x into the upper-left quadrant
canvas.camera_zoom(2, start=0, end=2, cx=480, cy=270)
VectorMathAnim.camera_follow(obj, start, end=None)

Make the camera continuously track an object, keeping it centred in the viewport. If end is given, the camera freezes at its position at that time.

Parameters:
  • obj (VObject) – Object to follow.

  • start (float) – When tracking begins.

  • end (float) – When tracking ends (None = track indefinitely).

Example: camera_follow

"""Camera follow example."""
from vectormation.objects import *

v = VectorMathAnim()
v.set_background(fill='#1a1a2e')

dot = Dot(cx=200, cy=540, r=14, fill='#58C4DD')
dot.fadein(start=0, end=0.3)
dot.shift(dx=1600, start=0.5, end=4.5)

line = Line(200, 540, 200, 540, stroke='#58C4DD', stroke_width=3)
line.p2.set_onward(0, dot.c.at_time)
v.camera_zoom(3, start=0, end=0.5)
v.camera_follow(dot, start=0.5, end=4.5)

v.add(line, dot)

v.show(end=5)
VectorMathAnim.camera_reset(start, end, easing=smooth)

Reset the camera to the default full-canvas viewBox (0 0 width height) over [start, end].

Parameters:
  • start (float) – Animation start time.

  • end (float) – Animation end time.

  • easing – Easing function (default smooth).

VectorMathAnim.focus_on(*objects, start, end, padding=100, easing=smooth)

Pan and zoom the camera to tightly frame the given objects (with padding), maintaining the canvas aspect ratio.

Parameters:
  • objects – One or more VObject/VCollection instances to frame.

  • start (float) – Animation start time.

  • end (float) – Animation end time.

  • padding (float) – Extra padding (pixels) around the bounding box.

  • easing – Easing function (default smooth).

canvas.focus_on(circle, label, start=1, end=2, padding=80)
# ... inspect detail ...
canvas.camera_reset(3, 4)

Display

VectorMathAnim.browser_display(start=0, end=None, fps=60, port=8765, hot_reload=False)

Open a browser-based viewer with real-time playback over WebSocket. The viewer supports zoom (scroll wheel), playback speed control, keyboard shortcuts, and a timeline scrubber.

Parameters:
  • start (float) – Playback start time. Negative values are relative to the end (e.g. -3 starts 3 seconds before the end).

  • end (float) – Playback end time. None auto-detects from the last animation. 0 displays a single static frame at start (no animation).

  • fps (int) – Frames per second.

  • port (int) – WebSocket server port.

  • hot_reload (bool) – When True, watches the calling script for file changes and automatically re-runs it, allowing a live development workflow.

Keyboard shortcuts in the browser viewer:

Key

Action

Space / P

Pause / resume playback

R

Restart from the beginning

, / .

Step backward / forward one frame

Left / Right

Previous / next section

- / + / Up / Down

Slower / faster (0.25x increments)

09

Jump to 0%–90%

Home / End

Jump to start / end

F

Reset zoom to fit

S / Shift+S

Save SVG / PNG

C

Copy SVG to clipboard

L

Toggle loop

B

Cycle background

G

Toggle grid overlay

I

Inspect mode

M

Measure tool

N

Toggle snap

D

Debug panel

?

Help overlay

Q

Quit the server

Single-picture mode:

Pass end=0 to display a static frame without animation. This is useful for debugging layouts.

# Static preview at t=0
canvas.browser_display(start=0, end=0)

Export

VectorMathAnim.export_png(time=0, filename='frame.png', scale=None)

Export a single frame as a PNG image.

Parameters:
  • time (float) – Timestamp to render.

  • filename (str) – Output file path.

  • scale (int) – Pixel scale factor. None uses the canvas scale.

Requires cairosvg (pip install cairosvg).

VectorMathAnim.export_video(filename='animation.mp4', start=0, end=None, fps=60, scale=None)

Export the animation as an MP4 video.

Parameters:
  • filename (str) – Output file path.

  • start (float) – Start time.

  • end (float) – End time (None = auto-detect).

  • fps (int) – Frames per second.

  • scale (int) – Pixel scale factor (1 = 1920x1080, 2 = 3840x2160).

Requires cairosvg and ffmpeg.

canvas.export_video('output.mp4', fps=30, end=10)
VectorMathAnim.export_gif(filename='animation.gif', start=0, end=None, fps=30, scale=None, loop=0)

Export the animation as an animated GIF.

Parameters:
  • filename (str) – Output file path.

  • start (float) – Start time.

  • end (float) – End time (None = auto-detect).

  • fps (int) – Frames per second.

  • scale (int) – Pixel scale factor.

  • loop (int) – Number of loops (0 = infinite).

Requires cairosvg and Pillow.

VectorMathAnim.export_sections(prefix='section')

Export each section boundary as a standalone SVG file. Files are written to the canvas save directory as <prefix>_000.svg, <prefix>_001.svg, etc.

Parameters:

prefix (str) – Filename prefix.


Inspection

VectorMathAnim.get_all_objects()

Return a list of all registered objects (excluding the background).

Return type:

list[VObject]

VectorMathAnim.find_by_type(cls)

Return all objects matching a given class (including subclasses).

Parameters:

cls (type) – The class to filter by (e.g. Circle, Text).

Return type:

list[VObject]

VectorMathAnim.find(predicate)

Return all objects where predicate(obj) returns True.

Parameters:

predicate (callable) – Filter function.

Return type:

list[VObject]

VectorMathAnim.get_object_count(time=None)

Return the number of visible objects at the given time (excludes the background).

Parameters:

time (float) – Timestamp (default 0).

Return type:

int

VectorMathAnim.list_objects_by_type(time=None)

Return a dict mapping class names to lists of visible objects of that type at the given time.

Parameters:

time (float) – Timestamp (default 0).

Return type:

dict[str, list[VObject]]

VectorMathAnim.get_visible_objects_info(time=None)

Return a list of dicts with 'class' and 'id' keys for each visible object at the given time.

Parameters:

time (float) – Timestamp (defaults to canvas time).

Return type:

list[dict]

VectorMathAnim.get_snap_points(time=None)

Extract snappable points (vertices, endpoints, centres) from all visible objects at the given time. Used internally by the browser viewer’s snap-to-grid feature.

Parameters:

time (float) – Timestamp (defaults to canvas time).

Return type:

list[tuple]


CLI Utility

parse_args()

Parse common command-line arguments for VectorMation scripts. Returns an argparse.Namespace with the following fields:

Flag

Type

Default

Description

-v / --verbose

bool

False

Enable verbose (debug) logging

--port

int

8765

Browser viewer WebSocket port

--fps

int

60

Frames per second

-o / --output

str

None

Output file path (e.g. out.mp4, frame.png)

-d / --duration

float

None

Animation duration override (seconds)

--start

float

None

Playback start time

--end

float

None

Playback end time

--hot-reload

bool

False

Re-run script on file change in browser viewer

from vectormation.objects import *

args = parse_args()
canvas = VectorMathAnim(save_dir='svgs/demo', verbose=args.verbose)

From the command line:

python my_script.py -v --fps 30 --hot-reload
python my_script.py -o animation.mp4

Workflow Examples

Basic setup

A minimal script that creates a canvas, adds an object with an animation, and opens the browser viewer.

from vectormation.objects import *

args = parse_args()
canvas = VectorMathAnim(save_dir='svgs/basic', verbose=args.verbose)
canvas.set_background(fill='#1a1a2e')

circle = Circle(r=100, fill='#58C4DD', fill_opacity=0.8)
circle.fadein(0, 1)
circle.shift(dx=400, start=1, end=3)

canvas.add(circle)

canvas.browser_display(fps=args.fps, port=args.port, hot_reload=args.hot_reload)

Camera animation

Combine camera methods to guide the viewer’s attention through a scene.

from vectormation.objects import *

args = parse_args()
canvas = VectorMathAnim(save_dir='svgs/camera', verbose=args.verbose)
canvas.set_background()

c1 = Circle(r=50, cx=300, cy=300, fill='#58C4DD')
c2 = Circle(r=50, cx=1600, cy=700, fill='#83C167')
c1.fadein(0, 0.5)
c2.fadein(0, 0.5)

# Focus on the first circle
canvas.focus_on(c1, start=1, end=2, padding=80)

# Reset to full view
canvas.camera_reset(3, 4)

# Zoom into the second circle
canvas.camera_zoom(3, start=5, end=6, cx=1600, cy=700)

# Reset again
canvas.camera_reset(7, 8)

canvas.add(c1, c2)
canvas.browser_display(fps=args.fps, port=args.port)

Browser preview with hot reload

Hot reload watches the script file for changes and re-runs it automatically, enabling a rapid edit-save-preview loop.

from vectormation.objects import *

args = parse_args()
canvas = VectorMathAnim(save_dir='svgs/dev', verbose=args.verbose)
canvas.set_background(fill='#0d1b2a')

t = Text(text='Edit me!', x=960, y=540, font_size=72,
         fill='#fff', stroke_width=0, text_anchor='middle')
t.write(0, 1)

canvas.add(t)
canvas.browser_display(fps=args.fps, port=args.port, hot_reload=True)

Run with:

python my_script.py --hot-reload

Export video

Use export_video for MP4 output or export_gif for animated GIFs. Use export_video for headless render pipelines.

from vectormation.objects import *

args = parse_args()
canvas = VectorMathAnim(save_dir='svgs/export', verbose=args.verbose)
canvas.set_background(fill='#1a1a2e')

rect = Rectangle(200, 200, fill='#E76F51')
rect.fadein(0, 1)
rect.rotate_by(1, 4, degrees=360)

canvas.add(rect)

# Export a video
canvas.export_video('spinning_rect.mp4', fps=30, end=5)

# Export a single PNG frame
canvas.export_png(time=2.5, filename='frame_at_2.5s.png')

# Export an animated GIF
canvas.export_gif('spinning_rect.gif', fps=15, end=5)

Sections for structured playback

Sections create pause points in the browser viewer, useful for presentation-style animations.

from vectormation.objects import *

args = parse_args()
canvas = VectorMathAnim(save_dir='svgs/sections', verbose=args.verbose)
canvas.set_background()

title = Text(text='Part 1', x=960, y=540, font_size=72,
             fill='#fff', stroke_width=0, text_anchor='middle')
title.write(0, 1)
canvas.add_section(2)  # pause here

subtitle = Text(text='Part 2', x=960, y=640, font_size=48,
                fill='#aaa', stroke_width=0, text_anchor='middle')
subtitle.write(2, 3)
canvas.add_section(4)  # pause here again

canvas.add(title, subtitle)
canvas.browser_display(fps=args.fps, port=args.port)

Tips and Best Practices

One canvas per script. Each script should create a single VectorMathAnim instance. The canvas manages a global save directory used by TeX caching and frame output.

Use parse_args() for flexibility. Using args.output to conditionally call export_video makes your script usable both interactively and in CI pipelines.

Add objects before displaying. All objects must be registered with add_objects (or add) before calling browser_display or export_video. Objects added after display starts will not appear.

Auto-detected end time. When end=None, the canvas scans every registered object’s last_change attribute plus its own camera keyframes to determine the animation duration. This means objects created but not added to the canvas do not contribute to the end time.

Z-ordering. Objects are drawn sorted by their z attribute. Lower values render first (behind); higher values render on top. The background defaults to z=-1. Use obj.to_front() or obj.to_back() for quick adjustments, or obj.set_z(value) for precise control.

Static previews. Use browser_display(end=0) to display a single frame at start without animation. This is handy for checking layouts and positioning before adding animations.

Camera methods chain. All camera methods return self, so you can chain them:

(canvas
    .camera_zoom(2, start=0, end=1)
    .camera_shift(200, 0, start=1, end=2)
    .camera_reset(3, 4))

Scale for high-DPI export. Pass scale=2 to the constructor or to export_video / export_png to render at 2x resolution (3840x2160 for the default 1920x1080 canvas).

Hot reload workflow. Run your script with --hot-reload, keep the browser tab open, and edit your script in a separate editor. On each file save the animation restarts with your changes.