跳转至

快速开始

一个点在视野中移动,同一段动画写成三种格式。

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)  # 原生动态 SVG
animation.save("dot.gif", width=400, height=400, fps=30)  # 需要 kinetickit[raster]
animation.save("dot.html", width=400, height=440)  # 需要 kinetickit[interactive]

点用三次 ease-out 从 (1, 1) 移到 (9, 9)。

点用三次 ease-out 从 (1, 1) 移到 (9, 9)。

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

场景:节点、叠层与相机。2D 与 3D 场景都可以。

motionMotion | None默认值: None

动作树。None 表示静止的动画。

interactionsInteractionSpec | None默认值: None

绑定到节点编号的声明式交互(参见文本与无障碍)。

accessibilityAccessibilityInfo | None默认值: None

标题、说明文本、语言与减少动态的处理方式。

把不可变场景与动作接在一起的门面。frames() 会逐张产生快照,sample(t) 返回某个时间点的场景,save() 依目的档的扩展名选择导出器。

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

文件路径、串流或其他输出目标。路径的扩展名决定格式:.svg、.gif 或 .html。

rendererstr | None默认值: None

指定绘图端:vector、raster 或 interactive。None 则依格式决定。

所选输出的选项,例如 width、height、fps 或 title(参见输出格式)。

写出动画并返回 ExportManifest。写档是原子操作:导出失败时不会留下半个文件。

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

由 2D 节点与一个相机组成的不可变集合。bind() 会返回设好相机视野的新场景,不会修改原来的场景。

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

稳定的编号。动作、交互与场景转场都靠它找到节点。

positionVec2默认值: Vec2(x=0.0, y=0.0)

点的位置,使用世界坐标。

sizefloat默认值: 4.0

标记大小,单位同输出。

colorColor | str默认值: ...

填色:Color,或像 "#e4572e" 这样的字符串。

opacityfloat默认值: 1.0

从 0(隐藏)到 1(不透明)。

semanticsSemantics | None默认值: None

给辅助科技使用的角色、标签与阅读顺序。

一个圆形的 2D 标记,有稳定编号、位置、大小、颜色与透明度。这些属性都能通过 node.animate 制作动画。

Bounds2D(min, max)
minVec2

左下角。

maxVec2

右上角。

与坐标轴平行的矩形,用于相机视野、裁切、版面与范围。

Vec2(x, y)
xfloat

水平分量。

yfloat

垂直分量。

不可变的二维矢量,用来表示位置、方向与大小。

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)

缓动函数的命名空间。时间与缓动列出所有函数。

读出某个时间的场景

场景加上时间,一定得到相同的状态,所以不必播放动画,就能问任何一个时刻的样子。

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)

0.75 秒时进度是 0.5,三次 ease-out 走完 \(1 - (1 - 0.5)^3 = 0.875\),所以点在 \(1 + 8 \times 0.875 = 8\)。

组合动作

动作是一个值。用 then、with_、delay、repeat、yoyo、reverse 与 trim 把动作组合起来,并用 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

GIF 与 HTML 那两行需要对应的额外安装项。能力检查会在打开目的档之前运行,所以不支持的组合会抛出 CapabilityError,而且不会留下半个文件(参见输出格式)。

评论