handanim package

Subpackages

Module contents

class handanim.AnimationEvent(type: AnimationEventType, start_time: float = 0.0, duration: float = 0.0, easing_fun=None, data: dict | None = None)

Bases: object

Represents an animation event occurring on a scene with configurable properties.

Parameters:
  • type (AnimationEventType) – The type of animation to be performed.

  • start_time (float, optional) – The starting time point of the animation in seconds. Defaults to 0.

  • duration (float, optional) – The duration of the animation in seconds. Defaults to 0.

  • easing_fun (callable, optional) – An optional easing function to modify animation progression. Defaults to None.

  • data (dict, optional) – Additional configuration data specific to the animation type. Defaults to an empty dict.

apply(opsset: OpsSet, raw_progress: float) OpsSet

Public entry point called by Scene. Applies easing (if any) then delegates to _apply(). Do not override in subclasses — implement _apply() instead.

subdivide(n_division: int)

Returns subdivision of an event into n_division segments

class handanim.AnimationEventType(value)

Bases: Enum

An enumeration representing different types of animation events.

COMPOSITE = 'composite'
CREATION = 'creation'
DELETION = 'deletion'
MUTATION = 'mutation'
class handanim.Arrow(start_point: tuple[float, float], end_point: tuple[float, float], arrow_head_type: str = '->', arrow_head_size: float = 10.0, arrow_head_angle: float = 45.0, *args, **kwargs)

Bases: Drawable

draw()

Provides the list of operations to be performed to draw this particular drawable object on the canvas

class handanim.CameraAnimation(start_time=0.0, duration=0.0, easing_fun=None, data=None)

Bases: AnimationEvent

Animates the Scene viewport (pan and/or zoom) over time.

Instead of touching any drawable’s OpsSet, this animation changes the world ranges that the Viewport maps to the screen — the “camera” moves, not the content.

Parameters:
  • start_time – When the animation begins (seconds).

  • duration – Length of the animation (seconds).

  • easing_fun – Optional easing function applied to progress.

  • data

    Dict with optional keys: - “from_xrange” (tuple[float, float]): World x range at progress=0.

    Defaults to wherever the camera currently is.

    • ”from_yrange” (tuple[float, float]): World y range at progress=0. Defaults to wherever the camera currently is.

    • ”to_xrange” (tuple[float, float]): World x range at progress=1. Defaults to from_xrange (no movement on x).

    • ”to_yrange” (tuple[float, float]): World y range at progress=1. Defaults to from_yrange (no movement on y).

Usage:

scene.add_camera(CameraAnimation(
    start_time=5, duration=3,
    data={
        "to_xrange": (400, 800),
        "to_yrange": (200, 600),
    }
))
apply_to_viewport(current: Viewport, progress: float) Viewport

Return a new Viewport interpolated toward the target world ranges.

Parameters:
  • current – The viewport state immediately before this event (used as the from_* default when not explicitly specified).

  • progress – Animation progress from 0.0 to 1.0.

Returns:

A new Viewport instance with interpolated world ranges.

class handanim.Circle(center: tuple[float, float], radius: float, *args, **kwargs)

Bases: Ellipse

A specialized Ellipse where the x and y radii are equal, creating a perfect circle.

Parameters:
  • center (tuple[float, float]) – The center coordinates of the circle.

  • radius (float) – The radius of the circle.

class handanim.ColorTransitionAnimation(start_time=0.0, duration=0.0, easing_fun=None, data=None)

Bases: AnimationEvent

Interpolates every SET_PEN color in an OpsSet from start_color to end_color.

At progress=0 all strokes are rendered with start_color; at progress=1 they use end_color. The fill color (if present) is interpolated identically.

Parameters:
  • start_time – When the animation begins (seconds).

  • duration – Length of the animation (seconds).

  • easing_fun – Optional easing function.

  • data – Dict with keys: - “start_color” (tuple[float,float,float]): RGB at progress 0. Required. - “end_color” (tuple[float,float,float]): RGB at progress 1. Required.

class handanim.CompositeAnimationEvent(events: list[AnimationEvent], easing_fun=None, data=None)

Bases: AnimationEvent

Represents a composite animation event that combines multiple animation events.

Parameters:
  • events (List[AnimationEvent]) – A list of animation events to be combined.

  • easing_fun (callable, optional) – An optional easing function to apply to the composite event.

  • data (dict, optional) – Additional configuration data for the composite animation event.

events

The list of animation events in the composite event.

Type:

List[AnimationEvent]

class handanim.Curve(points: list[tuple[float, float]], *args, **kwargs)

Bases: Drawable

A class representing a curve that can be drawn with a sketchy, hand-drawn style.

Allows creating curves with multiple points, supporting various drawing techniques including single line, quadratic, and more complex multi-point curves with randomization to simulate hand-drawn appearance.

points

List of points defining the curve’s shape.

Type:

List[np.ndarray]

draw() OpsSet

Draw the curve

draw_single_curve(opsset: OpsSet, points: list[ndarray] | None = None, close_point: tuple[float, float] | ndarray | None = None) OpsSet

Draws a single human style sketchy curve

draw_single_curve_with_randomization(opsset: OpsSet, points: list[ndarray] | None = None, offset: float = 1.0) OpsSet

Draw a single human style sketchy curve with random derivations

class handanim.CurvedArrow(points: list[tuple[float, float]], arrow_head_type: str = '->', arrow_head_size: float = 10.0, arrow_head_angle: float = 45.0, *args, **kwargs)

Bases: Drawable

draw() OpsSet

Provides the list of operations to be performed to draw this particular drawable object on the canvas

class handanim.Drawable(stroke_style: ~handanim.core.styles.StrokeStyle = <handanim.core.styles.StrokeStyle object>, sketch_style: ~handanim.core.styles.SketchStyle = <handanim.core.styles.SketchStyle object>, fill_style: ~handanim.core.styles.FillStyle | None = None, glow_dot_hint: dict | bool | None = None, id: str | None = None)

Bases: object

A base class representing a drawable object with drawing, transformation, and styling capabilities.

This class provides a standard interface for creating drawable objects that can be drawn on a canvas. Subclasses must implement the draw() method to define specific drawing operations.

id

A unique hexadecimal identifier for the drawable object.

Type:

str

stroke_style

Defines the stroke styling for the drawable.

Type:

StrokeStyle

sketch_style

Defines the sketch styling for the drawable.

Type:

SketchStyle

fill_style

Optional fill style for the drawable.

Type:

Optional[FillStyle]

glow_dot_hint

Optional configuration for glow dot rendering.

Type:

Dict

draw()

Abstract method to generate drawing operations.

translate()

Creates a translated version of the drawable.

scale()

Creates a scaled version of the drawable.

rotate()

Creates a rotated version of the drawable.

anchor(position: str = 'center') tuple[float, float]

Return a named anchor point in world coordinates.

Parameters:

position – One of “center”, “top_left”, “top_right”, “bottom_left”, “bottom_right”, “top”, “bottom”, “left”, “right”.

draw() OpsSet

Provides the list of operations to be performed to draw this particular drawable object on the canvas

get_bbox() BoundingBox
rotate(angle: float)

Rotates the drawable object by the given angle

scale(scale_x: float, scale_y: float)

Scales the drawable object by the given scale factors

translate(offset_x: float, offset_y: float)

Translates the drawable object by the given offset

class handanim.DrawableGroup(elements: Sequence[Drawable], grouping_method='parallel', *args, **kwargs)

Bases: Drawable

A drawable group that manages a collection of drawable elements with specified grouping behavior.

Allows applying transformations or animations to multiple drawable objects either in parallel or series.

Parameters:
  • elements (List[Drawable]) – A list of drawable objects to be grouped.

  • grouping_method (str, optional) – Determines how animations are applied. Can be ‘parallel’ (default) or ‘series’. Defaults to ‘parallel’.

elements

The list of drawable elements in the group.

Type:

List[Drawable]

grouping_method

The method used for applying transformations.

Type:

str

draw() OpsSet

This is useful to apply transformations to the entire group of objects at once

class handanim.Ellipse(center: tuple[float, float], width: float, height: float, *args, **kwargs)

Bases: Drawable

A drawable ellipse primitive with sketchy rendering capabilities.

Supports customizable center, width, height, and sketch-style rendering with optional multi-stroke and roughness effects. Allows for generating ellipses with randomized point generation and stroke variations.

center

The center point of the ellipse

Type:

np.ndarray

width

The width of the ellipse

Type:

float

height

The height of the ellipse

Type:

float

draw() OpsSet

Draw a sketchy version of an ellipse

draw_ellipse_border(opsset: OpsSet) tuple[list, OpsSet]
class handanim.Eraser(objects_to_erase: list[Drawable], drawable_cache: DrawableCache, *args, **kwargs)

Bases: Drawable

A Drawable representing an eraser that can remove specified drawable objects.

objects_to_erase

The list of drawable objects to be erased.

Type:

List[Drawable]

drawable_cache

Cache used for calculating bounding box of objects to erase.

Type:

DrawableCache

The draw method generates a zigzag motion over the bounding box of the objects to be erased, using an expanded pen width to create a pastel blend erasing effect.

draw() OpsSet

Calculates the zigzag motion of the eraser

class handanim.FadeInAnimation(start_time=0.0, duration=0.0, easing_fun=None, data=None)

Bases: AnimationEvent

A class representing a fade-in animation event that gradually increases the opacity of elements.

This animation applies a progressive opacity change from 0 to 1 over a specified duration, creating a smooth fade-in effect for graphical elements.

Parameters:
  • start_time (float, optional) – The time at which the animation begins. Defaults to 0.

  • duration (float, optional) – The total duration of the animation. Defaults to 0.

  • easing_fun (callable, optional) – An optional function to modify the animation’s progress curve. Defaults to None.

  • data (dict, optional) – Additional data associated with the animation. Defaults to None.

class handanim.FadeOutAnimation(start_time=0.0, duration=0.0, easing_fun=None, data=None)

Bases: FadeInAnimation

A class representing a fade-out animation event that gradually decreases the opacity of elements.

This animation applies a progressive opacity change from 1 to 0 over a specified duration, creating a smooth fade-out effect for graphical elements.

Parameters:
  • start_time (float, optional) – The time at which the animation begins. Defaults to 0.

  • duration (float, optional) – The total duration of the animation. Defaults to 0.

  • easing_fun (callable, optional) – An optional function to modify the animation’s progress curve. Defaults to None.

  • data (dict, optional) – Additional data associated with the animation. Defaults to None.

class handanim.FillStyle(**kwargs)

Bases: object

A class that defines the styling configurations for the fills of the primitives.

Allows customization of fill appearance including color, opacity, fill pattern, hachure settings, and fill weight. Defaults to a black fill with full opacity and hachure pattern.

options

Raw keyword arguments passed during initialization

Type:

dict

color

RGB color tuple, defaults to black (0, 0, 0)

Type:

tuple

opacity

Fill opacity from 0-1, defaults to 1

Type:

float

fill_pattern

Pattern for filling, defaults to “hachure”

Type:

str

hachure_angle

Angle of hachure lines in degrees, defaults to 45

Type:

int

hachure_gap

Gap between hachure lines, defaults to 4

Type:

int

hachure_line_width

Width of hachure lines, defaults to 1

Type:

int

zigzag_offset

Offset for zigzag pattern, defaults to -1

Type:

int

fill_weight

Weight/thickness of fill, defaults to 2

Type:

int

class handanim.Flowchart(nodes: list[DrawableGroup], connectors: list[FlowchartConnector], **kwargs)

Bases: DrawableGroup

A complete flowchart assembled from FlowchartNode, FlowchartDiamond, and FlowchartConnector primitives.

Prefer constructing via Flowchart.from_dict(spec) rather than directly.

classmethod from_dict(spec: dict[str, Any], **kwargs) Flowchart

Build a Flowchart from a declarative spec dict.

Expected format:

{
    "nodes": [
        {
            "id": "start",
            "type": "node",        # "node" (default) or "diamond"
            "label": "Start",
            "position": [100, 50],
            "size": [100, 40],     # optional
            "font_size": 12,       # optional
        },
        ...
    ],
    "edges": [
        {
            "from": "start",
            "to": "decision",
            "from_side": "bottom",  # optional, default "bottom"
            "to_side": "top",       # optional, default "top"
            "label": "Yes",         # optional edge label
        },
        ...
    ],
}

Additional keys in each node or edge dict are forwarded as keyword arguments to the underlying primitive (e.g. stroke_style, fill_style).

class handanim.FlowchartConnector(from_node: FlowchartNode | FlowchartDiamond, to_node: FlowchartNode | FlowchartDiamond, from_side: str = 'bottom', to_side: str = 'top', label: str | None = None, label_font_size: int = 10, arrow_head_type: str = '->', arrow_head_size: float = 10.0, arrow_head_angle: float = 45.0, *args, **kwargs)

Bases: Drawable

An auto-routed arrow between two flowchart nodes.

Computes an elbow route from from_node.get_anchor(from_side) to to_node.get_anchor(to_side) at draw time so that moving a node automatically updates the connector without re-construction.

For straight lines (same axis, opposing sides, perfectly aligned), a single Arrow is drawn. Otherwise an L-shaped elbow is used: the connector exits from_node in the from_side direction, turns once at the midpoint, then arrives at to_node from the to_side direction.

draw() OpsSet

Provides the list of operations to be performed to draw this particular drawable object on the canvas

class handanim.FlowchartDiamond(label: str, position: tuple[float, float], size: tuple[float, float] = (100.0, 60.0), font_size: int = 12, stroke_style: ~handanim.core.styles.StrokeStyle = <handanim.core.styles.StrokeStyle object>, sketch_style: ~handanim.core.styles.SketchStyle = <handanim.core.styles.SketchStyle object>, fill_style: ~handanim.core.styles.FillStyle | None = None, **kwargs)

Bases: DrawableGroup

A flowchart decision node: a diamond polygon with a centered Text label.

position is the center. size = (width, height) of the diamond’s bounding box.

get_anchor(side: str = 'center') tuple[float, float]
get_bbox() BoundingBox
class handanim.FlowchartNode(label: str, position: tuple[float, float], size: tuple[float, float] = (100.0, 50.0), font_size: int = 12, stroke_style: ~handanim.core.styles.StrokeStyle = <handanim.core.styles.StrokeStyle object>, sketch_style: ~handanim.core.styles.SketchStyle = <handanim.core.styles.SketchStyle object>, fill_style: ~handanim.core.styles.FillStyle | None = None, **kwargs)

Bases: DrawableGroup

A flowchart process node: a Rectangle with a centered Text label.

position is the center of the node in world coordinates.

get_anchor(side: str = 'center') tuple[float, float]
get_bbox() BoundingBox
class handanim.Line(start: tuple[float, float] | ndarray, end: tuple[float, float] | ndarray, *args, **kwargs)

Bases: Drawable

A drawable line primitive that generates hand-drawn style lines with randomized jitter and bowing effects.

Supports customizable stroke and sketch styles, with options for line curvature, roughness, and multiple line passes to create a hand-drawn appearance. Allows for optional stroke pressure variations and provides methods to draw single or overlapping lines.

start

Starting point coordinates of the line

Type:

np.ndarray

end

Ending point coordinates of the line

Type:

np.ndarray

draw() OpsSet

Draws a hand-drawn-like line with some jitter.

draw_single_line(opsset: OpsSet, move: bool = False, overlay: bool = False) OpsSet
class handanim.LinearPath(points: list[tuple[float, float]], close: bool = False, *args, **kwargs)

Bases: Drawable

A drawable linear path that connects a series of points, with optional closing of the path.

points

A list of (x, y) coordinate points defining the path.

Type:

List[tuple[float, float]]

close

Whether to connect the last point back to the first point. Defaults to False.

Type:

bool, optional

Raises:

ValueError – If fewer than two points are provided.

The path is drawn by creating Line objects between consecutive points, with optional path closure if specified.

draw() OpsSet

Provides the list of operations to be performed to draw this particular drawable object on the canvas

class handanim.Math(tex_expression: str, position: tuple[float, float], font_size: int = 12, font_name: str = 'handanimtype1', *args, **kwargs)

Bases: Drawable

A Drawable class for rendering mathematical expressions using TeX notation.

This class parses a TeX expression and renders individual glyphs using a specified font, supporting custom positioning, scaling, and stroke styling.

tex_expression

The TeX mathematical expression to render

Type:

str

position

The starting position for rendering the expression

Type:

Tuple[float, float]

font_size

The size of the font, defaults to 12

Type:

int, optional

font_name

The name of the font to use for rendering, defaults to “feasibly”

Type:

str

get_glyph_opsset()

Extracts the operations set for a single unicode glyph

draw()

Renders the entire mathematical expression as a set of drawing operations

custom_glyph_opsset(unicode: int, font_size: int) tuple[OpsSet, float, float]
draw() OpsSet

Provides the list of operations to be performed to draw this particular drawable object on the canvas

get_glyph_opsset(unicode: int, font_size: int) tuple[OpsSet, float, float]

Returns the opset for a single glyph of a unicode number

load_font()
standard_glyph_opsset(unicode: int, font_size: int) tuple[OpsSet, float, float]
class handanim.NGon(center: tuple[float, float], radius: float, n: int, *args, **kwargs)

Bases: Polygon

class handanim.Polygon(points: list[tuple[float, float]], *args, **kwargs)

Bases: Drawable

A Polygon class representing a drawable polygon shape.

This class allows creating polygons with a list of points, drawing them with optional stroke and fill styles. It ensures the polygon has at least three points and can render the polygon using a closed linear path with optional filling.

points

A list of (x, y) coordinates defining the polygon vertices.

Type:

List[tuple[float, float]]

Raises:

ValueError – If fewer than three points are provided.

draw() OpsSet

Draw a polygon with the given points

class handanim.Rectangle(top_left: tuple[float, float], width: float, height: float, *args, **kwargs)

Bases: Polygon

A Rectangle class representing a rectangular polygon shape.

This class creates a rectangle by specifying its top-left corner coordinates, width, and height. It inherits from the Polygon class and generates the four vertices of the rectangle automatically.

Parameters:
  • top_left (tuple[float, float]) – Coordinates of the top-left corner of the rectangle.

  • width (float) – Width of the rectangle.

  • height (float) – Height of the rectangle.

get_bbox() BoundingBox
class handanim.RotateAnimation(start_time=0.0, duration=0.0, easing_fun=None, data=None)

Bases: AnimationEvent

Animates a rotation of an OpsSet from 0 to angle degrees over the duration.

The rotation is applied around the center of gravity by default, or around a fixed center point if provided in data.

Parameters:
  • start_time – When the animation begins (seconds).

  • duration – Length of the animation (seconds).

  • easing_fun – Optional easing function.

  • data – Dict with optional keys: - “angle” (float): Total rotation angle in degrees. Default 360. - “center” (tuple[float, float]): Fixed pivot point. Default: center of gravity.

class handanim.RoundedRectangle(top_left: tuple[float, float], width: float, height: float, border_radius: float = 0.1, *args, **kwargs)

Bases: Drawable

draw() OpsSet

Provides the list of operations to be performed to draw this particular drawable object on the canvas

get_bbox() BoundingBox
class handanim.RoundedSquare(top_left: tuple[float, float], side_length: float, border_radius: float = 0.1, *args, **kwargs)

Bases: RoundedRectangle

class handanim.Scene(width: int = 1280, height: int = 720, fps: int = 24, background_color: tuple[float, float, float] = (1, 1, 1), viewport: Viewport | None = None)

Bases: object

A Scene represents an animation composition where drawables and events are managed.

Handles the creation, timeline, and rendering of animated graphics with configurable viewport, background, and frame settings. Supports creating snapshots and full video renders of animated sequences.

width

Width of the rendering surface in pixels.

Type:

int

height

Height of the rendering surface in pixels.

Type:

int

fps

Frames per second for video rendering.

Type:

int

background_color

RGB color for scene background.

Type:

tuple

viewport

Defines coordinate mapping between world and screen space.

Type:

Viewport

add(event: AnimationEvent, drawable: Drawable)

Adds an animation event to a drawable primitive in the scene.

Handles different scenarios including: - Composite animation events (recursively adding sub-events) - Drawable groups with parallel or sequential event distribution - Single event and drawable cases

Manages event tracking, drawable caching, and object timelines.

Parameters:
  • event (AnimationEvent) – The animation event to be added.

  • drawable (Drawable) – The drawable primitive to apply the event to.

add_camera(event) None

Register a CameraAnimation that controls the viewport over time.

Camera events are kept separate from drawable events and are applied per-frame in the render loop without touching any drawable’s OpsSet.

Parameters:

event – A CameraAnimation instance (or any object with an apply_to_viewport(viewport, progress) method).

create_event_timeline(max_length: float | None = None)

Creates a timeline of animation events and calculates the OpsSet for each frame.

This method processes all drawable events, determines active objects at each frame, and generates a list of OpsSet operations representing the animation progression.

Parameters:
  • fps (int, optional) – Frames per second for the animation. Defaults to 30.

  • max_length (Optional[float], optional) – Maximum duration of the animation. Defaults to None.

  • verbose (bool, optional) – If True, provides detailed logging during animation calculation. Defaults to False.

Returns:

A list of OpsSet operations for each frame in the animation.

Return type:

List[OpsSet]

export_beamer(output_dir: str, n_frames: int = 6, times: list[float] | None = None, title: str = 'Handanim Slides', max_length: float | None = None) str

Export animation keyframes as a compilable Beamer/LaTeX slide deck.

Each keyframe becomes one overlay on a single frame, so the slides animate forward when presented. Produces PDF images + a .tex file.

Parameters:
  • output_dir – Directory to write PDFs and the .tex file.

  • n_frames – Number of evenly-spaced keyframes (ignored if times given).

  • times – Explicit list of timestamps to render.

  • title – Title shown on the Beamer title page.

  • max_length – Total animation duration override.

Returns:

Path to the generated .tex file.

export_storyboard(n_frames: int, output_dir: str, format: str = 'svg', max_length: float | None = None) list[str]

Export evenly-spaced keyframes as a storyboard.

Parameters:
  • n_frames – Number of frames to export.

  • output_dir – Directory to write output files.

  • format – “svg” or “pdf”.

  • max_length – Total animation duration override.

Returns:

List of output file paths.

find_key_frames()

Find the key frames that we need to calculate for the animation Key frames are the frames where an object is created or deleted

get_active_objects(t: float)

Determines the list of object IDs that are active at a specific time point.

Calculates object visibility by toggling their active status based on their timeline. An object becomes active when its timeline reaches a time point, and its status alternates with each subsequent time point.

Parameters:

t (float) – The time point (in seconds) to check object activity.

Returns:

A list of object IDs that are active at the given time point.

Return type:

List[str]

get_animated_opsset_at_time(drawable_id: str, t: int, event_and_progress: list[tuple[AnimationEvent, float]], drawable_events_mapping: dict[str, list[AnimationEvent]]) OpsSet
get_current_time() float

Returns the end time of the latest event in the scene, or 0.0 if empty.

get_object_event_and_progress(object_id: str, t: int, drawable_events_mapping: dict[str, list[AnimationEvent]]) list[tuple[AnimationEvent, float]]
get_viewport_bounds() tuple[float, float, float, float]

Retrieves the viewport’s boundaries in world coordinates.

Returns:

A tuple containing (x_min, x_max, y_min, y_max) representing the viewport’s world coordinate boundaries.

Return type:

Tuple[float, float, float, float]

static place_relative(target: Drawable, reference: Drawable, target_anchor: str = 'center', reference_anchor: str = 'center', offset: tuple[float, float] = (0.0, 0.0)) Drawable

Position target so that its anchor aligns with a reference drawable’s anchor.

Returns the translated target — does not mutate the original (consistent with the immutability invariant).

Parameters:
  • target – The drawable to reposition.

  • reference – The drawable to align against.

  • target_anchor – Anchor name on the target (e.g. “top_left”, “center”).

  • reference_anchor – Anchor name on the reference.

  • offset – Additional (dx, dy) offset after alignment.

Usage:

label = Text("hello", position=(0, 0))
label = Scene.place_relative(label, rect, "top", "bottom", offset=(0, -20))
render(output_path: str, max_length: float | None = None)

Render the animation as a video file.

This method generates a video by creating a timeline of animation events and rendering each frame using Cairo graphics. The video is saved to the specified output path with the configured frame rate.

Parameters:
  • output_path (str) – Path to save the output video file.

  • max_length (Optional[float], optional) – Maximum duration of the animation. Defaults to None.

render_handout(output_path: str, n_frames: int = 6, times: list[float] | None = None, max_length: float | None = None) str

Render a single multi-page PDF with one animation frame per page.

Either provide explicit times or let n_frames evenly-spaced keyframes be chosen automatically.

Parameters:
  • output_path – Path to the output PDF file.

  • n_frames – Number of evenly-spaced frames (ignored if times is given).

  • times – Explicit list of timestamps (in seconds) to render.

  • max_length – Total animation duration override.

Returns:

The output file path.

render_keyframes(times: list[float], output_dir: str, format: str = 'svg', prefix: str = 'frame', max_length: float | None = None) list[str]

Batch export snapshots at multiple timestamps.

Computes the event timeline once, then renders each requested frame.

Parameters:
  • times – List of timestamps (in seconds) to export.

  • output_dir – Directory to write output files.

  • format – “svg” or “pdf”.

  • prefix – Filename prefix; files are named {prefix}_{i:03d}_{time:.2f}.{format}.

  • max_length – Total animation duration override.

Returns:

List of output file paths.

render_snapshot(output_path: str, frame_in_seconds: float, max_length: float | None = None)

Render a snapshot of the animation at a specific time point as an SVG or PDF file.

Parameters:
  • output_path (str) – Path to the output file (.svg or .pdf).

  • frame_in_seconds (float) – The exact time point (in seconds) to render.

  • max_length (Optional[float], optional) – Total duration of the animation. Defaults to None.

set_viewport_to_identity()

Resets the viewport to an identity transformation, mapping world coordinates directly to screen coordinates.

wait(duration: float) float

Insert a pause of duration seconds after the current last event.

Returns the time at which the next event should start.

Usage:

scene.add(SketchAnimation(start_time=0, duration=2), rect)
t = scene.wait(1.0)  # t = 3.0
scene.add(SketchAnimation(start_time=t, duration=2), circle)
class handanim.SketchAnimation(start_time=0.0, duration=0.0, easing_fun=None, data=None)

Bases: AnimationEvent

A class representing a sketch animation event that progressively renders drawing operations.

This animation supports partial rendering of drawing and fill operations with configurable timing and optional glowing dot effects. It allows for smooth, incremental visualization of drawing sequences.

wait_before_fill

Delay in seconds before starting fill animation, capped at half the total duration.

Type:

float

get_partial_sketch()

Calculates a partial OpsSet representing the current sketching progress.

apply()

Applies the sketch animation to a given OpsSet at a specific progress point.

get_partial_sketch(opsset: OpsSet, progress: float) OpsSet

Calculate a partial OpsSet representing the sketching progress of an operation set.

Parameters:
  • OpsSet – The full drawn opsset on which to apply partial sketching

  • progress (float) – The progress of sketching, ranging from 0.0 to 1.0.

Returns:

A new OpsSet containing the operations up to the specified progress point,

with the last operation potentially being partially completed.

Return type:

OpsSet

class handanim.SketchStyle(**kwargs)

Bases: object

A class that defines the styling configurations for sketchy, hand-drawn style renderings.

bowing

Amount of bowing/waviness in lines, defaults to 1

Type:

int

max_random_offset

Maximum random offset for sketch lines, defaults to 2

Type:

int

roughness

Roughness of sketch lines, defaults to 1

Type:

int

curve_tightness

Tightness of curves, defaults to 0

Type:

int

curve_fitting

Curve fitting parameter, defaults to 0.95

Type:

float

curve_step_count

Number of steps for curve rendering, defaults to 9

Type:

int

disable_multi_stroke

Flag to disable multi-stroke rendering, defaults to False

Type:

bool

disable_font_mixture

Flag to disable font mixture, defaults to True

Type:

bool

class handanim.Square(top_left: tuple[float, float], side_length: float, *args, **kwargs)

Bases: Rectangle

class handanim.StrokeStyle(**kwargs)

Bases: object

A class that defines the styling configurations for the strokes of the boundaries of the primitives.

Allows customization of stroke appearance including color, width, opacity, and pressure characteristics. Defaults to a black, 1-pixel wide constant pressure stroke with full opacity.

options

Raw keyword arguments passed during initialization

Type:

dict

color

RGB color tuple, defaults to black (0, 0, 0)

Type:

tuple

width

Stroke width in pixels, defaults to 1

Type:

int/float

opacity

Stroke opacity from 0-1, defaults to 1

Type:

float

stroke_pressure

Pressure mode for stroke rendering, defaults to StrokePressure.CONSTANT

Type:

StrokePressure

class handanim.Table(top_left: tuple[float, float], n_rows: int, n_cols: int, cell_width: float, cell_height: float, data: list[list[str]] | None = None, headers: list[str] | None = None, cell_font_size: int = 12, header_font_size: int = 14, stroke_style: ~handanim.core.styles.StrokeStyle = <handanim.core.styles.StrokeStyle object>, sketch_style: ~handanim.core.styles.SketchStyle = <handanim.core.styles.SketchStyle object>, fill_style: ~handanim.core.styles.FillStyle | None = None, header_fill_style: ~handanim.core.styles.FillStyle | None = None, header_stroke_style: ~handanim.core.styles.StrokeStyle | None = None, **kwargs)

Bases: DrawableGroup

A grid of Rectangle + Text cells with optional header-row styling.

Each cell is a DrawableGroup([rect, text]) stored in self.cells[row][col]. Row groups (self.row_groups[r]) contain the leaf rect/text drawables for all cells in that row — they are kept flat (no nested DrawableGroups) so that group-level scene animations apply correctly.

The Table itself is a flat parallel DrawableGroup of all leaf drawables, so scene.add(event, table) animates every cell simultaneously.

Parameters:
  • top_left – (x, y) world coordinates of the table’s top-left corner.

  • n_rows – Total rows, including the header row if headers is provided.

  • n_cols – Number of columns.

  • cell_width – Width of each cell in world units.

  • cell_height – Height of each cell in world units.

  • data – 2-D list of cell strings, indexed [row][col]. Rows with a header start at data[0] = row 1 of the grid. Missing entries default to “”.

  • headers – Column header strings for row 0. If provided, row 0 uses header_stroke_style / header_fill_style instead of the defaults.

  • cell_font_size – Font size for data cells.

  • header_font_size – Font size for header cells.

  • stroke_style – Stroke style for data cells.

  • sketch_style – Sketch style shared by all cells.

  • fill_style – Fill style for data cells (None = no fill).

  • header_stroke_style – Override stroke style for header cells.

  • header_fill_style – Override fill style for header cells.

animate_by_cell(anim_class: type, start_time: float = 0.0, total_duration: float = 1.0, **anim_kwargs) TableRevealEvent

Build a staggered cell-reveal animation in row-major order.

Each cell gets an equal slice of total_duration. Both the rect and the text inside a cell animate together (the cell’s DrawableGroup is the target).

Parameters:
  • anim_class – Any AnimationEvent subclass (e.g. SketchAnimation).

  • start_time – When the first cell’s animation begins, in seconds.

  • total_duration – Total wall-clock span covering all cells.

  • **anim_kwargs – Forwarded to each anim_class constructor.

Returns:

TableRevealEvent whose .add_to_scene(scene) registers all pairs.

animate_by_row(anim_class: type, start_time: float = 0.0, total_duration: float = 1.0, **anim_kwargs) TableRevealEvent

Build a staggered row-reveal animation.

Each row gets an equal slice of total_duration, starting after the previous row’s slice begins. All cells in a row animate in parallel.

Parameters:
  • anim_class – Any AnimationEvent subclass (e.g. SketchAnimation).

  • start_time – When the first row’s animation begins, in seconds.

  • total_duration – Total wall-clock span covering all rows.

  • **anim_kwargs – Forwarded to each anim_class constructor.

Returns:

TableRevealEvent whose .add_to_scene(scene) registers all pairs.

get_bbox() BoundingBox
class handanim.TableRevealEvent(pairs: list[tuple[Any, DrawableGroup]])

Bases: CompositeAnimationEvent

A CompositeAnimationEvent that pairs each sub-event with its target drawable.

Returned by Table.animate_by_row() and Table.animate_by_cell(). Because Scene.add() always requires an explicit drawable, callers must unpack these pairs themselves — use add_to_scene() as a one-liner convenience.

pairs

List of (AnimationEvent, DrawableGroup) in reveal order.

Usage:

reveal = table.animate_by_row(SketchAnimation, start_time=0, total_duration=3)
reveal.add_to_scene(scene)

# or inspect and filter manually:
for event, drawable in reveal.pairs:
    scene.add(event, drawable)
add_to_scene(scene: Any) None
class handanim.Text(text: str, position: tuple[float, float], font_size: int = 12, *args, **kwargs)

Bases: Drawable

A Drawable text primitive that renders text using font glyphs with customizable styling.

Supports rendering text with random font selection, scaling, and sketch-style variations. Converts text characters into drawing operations (OpsSet) that can be rendered.

text

The text to be rendered

Type:

str

position

Starting position for text rendering

Type:

Tuple[float, float]

font_size

Size of the rendered text. Defaults to 12.

Type:

int, optional

scale_factor

Additional scaling factor. Defaults to 1.0.

Type:

float, optional

get_random_font_choice()

Selects a font for text rendering

get_glyph_strokes(char)

Converts a character into drawing operations

get_glyph_space()

Calculates character and space widths

draw()

Generates the complete set of drawing operations for the text

autofit(bbox: BoundingBox)
draw() OpsSet

Provides the list of operations to be performed to draw this particular drawable object on the canvas

get_glyph_space() tuple[float, float]

Gives the width of the space, or an average width

get_glyph_strokes(char) tuple[OpsSet, float]

Gives the glyph operations as well the width of the char for offsetting purpose

get_random_font_choice() tuple[str, str]

Chooses a random font from the available fonts

wrap(bbox: BoundingBox, line_height_factor: float = 1.5)

Pre-compute line breaks so that no line of text exceeds bbox.width.

Splits self.text on spaces and greedily accumulates words onto the current line until adding the next word would exceed bbox.width, then starts a new line. The text block is anchored at bbox.top_left.

Parameters:
  • bbox – The bounding box to wrap text within.

  • line_height_factor – Multiplier on font_size for the vertical gap between lines. 1.5 gives comfortable spacing; 1.2 is tighter.

class handanim.TranslateFromAnimation(start_time=0, duration=0, easing_fun=None, data=None)

Bases: TranslateToAnimation

A class representing a translate from a point animation event.

This animation translates an OpsSet from a specified point to its current center of gravity over the course of the animation’s duration, using an optional easing function.

Inherits from TranslateToAnimation and reverses the progress to achieve the “from” translation effect.

Parameters:
  • start_time (float, optional) – The start time of the animation. Defaults to 0.

  • duration (float, optional) – The duration of the animation. Defaults to 0.

  • easing_fun (callable, optional) – An optional easing function to modify animation progress. Defaults to None.

  • data (dict, optional) – A dictionary containing animation data, including the starting ‘point’. Defaults to None.

apply()

Applies the translation from the specified point to the OpsSet’s center of gravity.

class handanim.TranslateToAnimation(start_time=0.0, duration=0.0, easing_fun=None, data=None)

Bases: AnimationEvent

A class representing a translate to a point animation event.

This animation translates an OpsSet from its current center of gravity to a specified point over the course of the animation’s duration, using an optional easing function.

Parameters:
  • start_time (float, optional) – The start time of the animation. Defaults to 0.

  • duration (float, optional) – The duration of the animation. Defaults to 0.

  • easing_fun (callable, optional) – An optional easing function to modify animation progress. Defaults to None.

  • data (dict, optional) – A dictionary containing animation data, including the target ‘point’. Defaults to None.

_opsset_apply()

Calculates and applies the translation of the OpsSet.

apply()

Applies the translation to the given OpsSet at the specified progress.

class handanim.VectorSVG(svg_doc, position: tuple[float, float] = (0, 0), *args, **kwargs)

Bases: Drawable

A drawable class that accepts an SVG document and renders it as a Drawable as close to the original SVG as possible.

Note

This feature was contributed by Hamd Waseem (https://github.com/hamdivazim).

svg_doc

The parsed SVG document object from svgelements.

position

The base (x, y) offset for the SVG.

Type:

tuple[float, float]

draw() OpsSet

Parse SVG elements and convert them into a set of drawing operations

classmethod from_svg_file(svg_file_path: str, *args, **kwargs) VectorSVG

Create a VectorSVG instance from a file path

classmethod from_svg_string(svg_string: str, *args, **kwargs) VectorSVG

Create a VectorSVG instance from an SVG string

class handanim.ZoomInAnimation(start_time=0.0, duration=0.0, easing_fun=None, data=None)

Bases: AnimationEvent

A class representing a zoom-in animation event that scales an OpsSet progressively.

This animation scales the operations set from its original size to a larger size based on the provided progress value. It is typically used for creating or expanding visual elements.

Parameters:
  • start_time (int, optional) – The start time of the animation. Defaults to 0.

  • duration (int, optional) – The duration of the animation. Defaults to 0.

  • easing_fun (callable, optional) – An optional easing function to modify the animation progress. Defaults to None.

  • data (Any, optional) – Additional data associated with the animation. Defaults to None.

class handanim.ZoomOutAnimation(start_time=0.0, duration=0.0, easing_fun=None, data=None)

Bases: ZoomInAnimation

A class representing a zoom-out animation event that scales an OpsSet progressively.

This animation scales the operations set from its current size to a smaller size based on the provided progress value. It is typically used for shrinking or removing visual elements.

Parameters:
  • start_time (int, optional) – The start time of the animation. Defaults to 0.

  • duration (int, optional) – The duration of the animation. Defaults to 0.

  • easing_fun (callable, optional) – An optional easing function to modify the animation progress. Defaults to None.

  • data (Any, optional) – Additional data associated with the animation. Defaults to None.