Skip to content

Quick start

One point moves across the view, and the same animation is written to three formats.

from kinetickit import Animation, Bounds2D, Point2D, Scene2D, Vec2, ease

dot = Point2D(id="dot", position=Vec2(1, 1), size=8, color="#e4572e")
scene = Scene2D(dot)
scene = scene.bind({scene.camera.ref("view"): Bounds2D(Vec2(0, 0), Vec2(10, 10))})

motion = dot.animate.position.to(Vec2(9, 9), duration=1.5, easing=ease.out_cubic)
animation = Animation(scene, motion)

animation.save("dot.svg", width=400, height=400)  # native animated SVG
animation.save("dot.gif", width=400, height=400, fps=30)  # needs kinetickit[raster]
animation.save("dot.html", width=400, height=440)  # needs kinetickit[interactive]

The point moves from (1, 1) to (9, 9) with cubic ease-out.

The point moves from (1, 1) to (9, 9) with cubic ease-out.

Animation(scene, motion=None, *, registry=..., interactions=None, accessibility=None)
sceneSceneBase

The scene: nodes, overlay and camera. 2D and 3D scenes are both accepted.

motionMotion | NoneDefault: None

The motion tree. None gives a still animation.

interactionsInteractionSpec | NoneDefault: None

Declarative interactions bound to node ids (Typography and accessibility).

accessibilityAccessibilityInfo | NoneDefault: None

Title, descriptions, language and the reduced-motion policy.

The facade that joins an immutable scene to a motion. frames() yields snapshots lazily, sample(t) returns the scene at one time, and save() picks an exporter from the destination suffix.

Animation.save(target, *, renderer=None, **options) → Any
targetstr | PathLike | Destination

A file path, a stream or another destination. The suffix of a path picks the format: .svg, .gif or .html.

rendererstr | NoneDefault: None

Force a renderer: vector, raster or interactive. None follows the format.

Options of the chosen output, such as width, height, fps or title (Output formats).

Writes the animation and returns an ExportManifest. The write is atomic: a failed export leaves no file behind.

Scene2D(*nodes, overlay=(), camera=None)

An immutable collection of 2D nodes plus a camera. bind() returns a new scene with the camera view set instead of changing the original.

Point2D(
    *,
    id,
    opacity=1.0,
    z=0.0,
    visible=True,
    semantics=None,
    position=Vec2(x=0.0, y=0.0),
    size=4.0,
    symbol='circle',
    color=...,
    stroke=None,
    stroke_width=1.0,
)
idstr

The stable id. Motions, interactions and scene transitions find the node by it.

positionVec2Default: Vec2(x=0.0, y=0.0)

Where the point sits, in world coordinates.

sizefloatDefault: 4.0

The marker size in output units.

colorColor | strDefault: ...

Fill colour: a Color or a CSS-style string such as "#e4572e".

opacityfloatDefault: 1.0

From 0 (hidden) to 1 (opaque).

semanticsSemantics | NoneDefault: None

Role, label and reading order for assistive technology.

A circular 2D mark with a stable id, a position, a size, a colour and an opacity. Each of these can be animated through node.animate.

Bounds2D(min, max)
minVec2

The lower-left corner.

maxVec2

The upper-right corner.

An axis-aligned rectangle, used for camera views, clipping, layout and bounds.

Vec2(x, y)
xfloat

Horizontal component.

yfloat

Vertical component.

An immutable two-component vector for positions, directions and sizes.

ease.linear(u)
ease.in_quad(u), ease.out_quad(u), ease.in_out_quad(u)
ease.in_cubic(u), ease.out_cubic(u), ease.in_out_cubic(u)
ease.in_quart(u), ease.in_quint(u), ease.in_sine(u), ease.in_expo(u)
ease.cubic_bezier(x1, y1, x2, y2)

The easing namespace. Time and easing lists every function.

Reading the scene at a time

A scene and a time always give the same state, so you can ask for any moment without playing the animation.

print(animation.duration)  # 1.5
print(animation.sample(0.0).get("dot").position)  # Vec2(x=1.0, y=1.0)
print(animation.sample(0.75).get("dot").position)  # Vec2(x=8.0, y=8.0)
print(animation.sample(1.5).get("dot").position)  # Vec2(x=9.0, y=9.0)

At 0.75 seconds the progress is 0.5, and cubic ease-out gives \(1 - (1 - 0.5)^3 = 0.875\) of the way, so the point is at \(1 + 8 \times 0.875 = 8\).

Composing motions

A motion is a value. Combine motions with then, with_, delay, repeat, yoyo, reverse and trim, and give a moment a name with mark.

from kinetickit import Animation, Bounds2D, Point2D, Scene2D, Vec2

a = Point2D(id="a", position=Vec2(0, 0), size=8)
b = Point2D(id="b", position=Vec2(0, 5), size=8, opacity=0.0)
c = Point2D(id="c", position=Vec2(5, 5), size=4)
scene = Scene2D(a, b, c)
scene = scene.bind({scene.camera.ref("view"): Bounds2D(Vec2(-1, -1), Vec2(11, 11))})

motion = (
    a.animate.position.to(Vec2(5, 5), duration=1.0)
    .then(b.animate.opacity.to(1.0, duration=0.5).with_(c.animate.size.to(9, duration=0.5)))
    .mark("settled")
)
print(Animation(scene, motion).duration)  # 1.5

The GIF and HTML lines need their matching extras. Capability checks run before a destination is opened, so an unsupported combination raises CapabilityError and leaves no partial file (Output formats).

Comments