Scene
Scenes, the timeline cursor and the blocks that shape time (s.play, s.start, s.during).
Contents:
k.scene: Turns a functiondef name(s: k.Scene)into a scene.k.SceneDef: A scene function plus its configuration.k.Scene: Timeline of one scene.k.TimeSpan: Where aplay/startlanded.k.time: Global scene time in seconds, as a read-only signal.
Methods in this area:
s.play: Schedules animations at the cursor and advances the cursor to their end.s.start: Schedules animations at the cursor without moving it: this is how to run something in the background (clocks, simulations, continuous motion) while the script continues.s.wait: Advances the cursor bydseconds (default 1).s.wait_for: Moves the main cursor to the time of an event (thecount-th firing after the cursor) and returns theEventInfo.s.add: Puts objects in the scene instantly, at the cursor.s.remove: Takes objects out of the scene instantly, at the cursor.s.mark: Creates a time anchor at the cursor without moving it and returns the time.s.during:withblock that applies state changes on entry and reverts them, animated, on exit.s.tempo:withblock that multiplies the speed of everything inside:s.tempo(4)divides durations and waits by 4.s.voice: Narratedwithblock: takes text (TTS from the provider inkinemo.toml) or an audio file, and lasts at least as long as the audio.
Back to the reference index.
k.scene (function)#
k.scene(fn: SceneFn) -> SceneDef
k.scene(
*,
size: str | tuple[int, int] = "1080p",
fps: float = 60,
background: ColorLike | None = None,
seed: int = 0,
tail: float = 0.5,
theme: Theme | str | None = None,
camera: str = "2d",
params: dict[str, Param] | None = None,
name: str | None = None,
) -> Callable[[SceneFn], SceneDef]
Written as: @k.scene(size="1080p", fps=60, background=None, seed=0, tail=0.5, theme=None, camera="2d", params=None, name=None)
Turns a function def name(s: k.Scene) into a scene. The body runs exactly once, in the build phase, and produces a timeline; the frame at time t is a pure function of t. The decorator arguments (size, fps, background, seed, tail, theme, parameters) take precedence over kinemo.toml.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
size |
str | tuple[int, int] |
"1080p" |
Output size: a preset name ("1080p", "4k", "vertical", ...) or (width, height) in pixels. |
fps |
float |
60 |
Frames per second of the final render. |
background |
ColorLike | None |
None |
Background color; None uses the theme's bg. |
seed |
int |
0 |
Seed for random and numpy.random during the build, so scenes are reproducible. |
tail |
float |
0.5 |
Seconds added after the last animation ends. |
theme |
Theme | str | None |
None |
A k.Theme or the name of one in k.themes ("dark", "light", "blueprint"). |
camera |
str |
"2d" |
"2d" or "3d". |
params |
dict[str, Param] | None |
None |
Scene parameters (k.Int, k.Float, k.Bool, k.Choice, k.Str), passed to the function by name. |
name |
str | None |
None |
Scene name used by --scene; defaults to the function name. |
Example:
@k.scene(size="1080p", fps=60, tail=0.5)
def hello(s: k.Scene):
title = k.Text("Hello, kinemo").place(at="center")
s.play(k.write(title))
s.play(title.to(color=k.BLUE, scale=1.5))
s.wait(1)
See also: s.play, k.Text, k.Int.
k.SceneDef (class)#
k.SceneDef(fn: SceneFn, config: SceneConfig)
A scene function plus its configuration. Building runs the function exactly once.
Documented together with k.scene.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
fn |
SceneFn |
required | |
config |
SceneConfig |
required |
Attributes:
| Attribute | Type | Description |
|---|---|---|
scenedef.config |
||
scenedef.fn |
||
scenedef.name |
Members:
build: Run the build phase and return the scene with its finished timeline.
k.SceneDef.build (method)
scenedef.build(params: dict[str, object] | None = None, **overrides: object) -> Scene
Run the build phase and return the scene with its finished timeline.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
params |
dict[str, object] | None |
None |
|
**overrides |
object |
variadic |
k.Scene (class)#
k.Scene(config: SceneConfig)
Timeline of one scene. Code runs once; every call records something at the cursor.
Documented together with s.play.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
config |
SceneConfig |
required |
Attributes:
| Attribute | Type | Description |
|---|---|---|
s.config |
||
s.cursor |
Build cursor in seconds. | |
s.frame |
Frame | |
s.lints |
||
s.theme |
Theme |
Members:
builder: The native IR builder of this scene (outputs: frames, video, inspect).duration: Total length in seconds (known after the build).play: Schedules animations at the cursor and advances the cursor to their end.start: Schedules animations at the cursor without moving it: this is how to run something in the background (clocks, simulations, continuous motion) while the script continues.wait: Advances the cursor bydseconds (default 1).mark: Creates a time anchor at the cursor without moving it and returns the time.marks: Named marks: name → time in seconds.during:withblock that applies state changes on entry and reverts them, animated, on exit.tempo:withblock that multiplies the speed of everything inside:s.tempo(4)divides durations and waits by 4.add: Puts objects in the scene instantly, at the cursor.remove: Takes objects out of the scene instantly, at the cursor.wait_for: Moves the main cursor to the time of an event (thecount-th firing after the cursor) and returns theEventInfo.voice: Narratedwithblock: takes text (TTS from the provider inkinemo.toml) or an audio file, and lasts at least as long as the audio.
k.Scene.builder (property)
s.builder: Builder # read-only
The native IR builder of this scene (outputs: frames, video, inspect).
k.Scene.duration (property)
s.duration: float # read-only
Total length in seconds (known after the build).
k.Scene.play (method)
s.play(
*anims: Animation,
duration: float | None = None,
ease: EaseLike | None = None,
at: float | None = None,
) -> TimeSpan
Schedules animations at the cursor and advances the cursor to their end. Multiple arguments run in parallel (s.play(a, b) is by definition s.play(k.par(a, b))). duration= sets the total duration of the group, rescaling its contents.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
*anims |
Animation |
variadic | |
duration |
float | None |
None |
duration= sets the total duration of the group, rescaling its contents. |
ease |
EaseLike | None |
None |
|
at |
float | None |
None |
Example:
@k.scene
def steps(s: k.Scene):
a = k.Circle(r=0.8).place(at="center")
b = k.Square(1.4).place(right_of=a, gap=0.6)
s.play(k.draw(a), k.draw(b), duration=2)
s.play(a.to(color=k.RED))
See also: s.start, k.par, s.wait.
k.Scene.start (method)
s.start(
*anims: Animation,
duration: float | None = None,
ease: EaseLike | None = None,
at: float | None = None,
) -> TimeSpan
Schedules animations at the cursor without moving it: this is how to run something in the background (clocks, simulations, continuous motion) while the script continues. Returns a TimeSpan; h.done is an event at the end of the animation.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
*anims |
Animation |
variadic | |
duration |
float | None |
None |
|
ease |
EaseLike | None |
None |
|
at |
float | None |
None |
Example:
@k.scene
def background(s: k.Scene):
dot = k.Dot(r=0.2, x=-4)
title = k.Text("In parallel").place(at="top", margin=0.8)
s.add(dot)
s.start(dot.to(x=4), duration=3)
s.play(k.write(title))
s.wait(2)
See also: s.play, s.wait_for, k.simulate.
k.Scene.wait (method)
s.wait(d: float = 1.0) -> TimeSpan
Advances the cursor by d seconds (default 1). It is the script's pause: nothing is scheduled, but whatever was started with s.start keeps running.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
d |
float |
1.0 |
Advances the cursor by d seconds (default 1). |
Example:
@k.scene
def pause(s: k.Scene):
title = k.Text("Think for a moment").place(at="center")
s.play(k.write(title))
s.wait(1.5)
s.play(k.fade_out(title))
k.Scene.mark (method)
s.mark(name: str | None = None, slide: bool = False) -> float
Creates a time anchor at the cursor without moving it and returns the time. Named marks are stored in s.marks[name] (useful with at=); slide=True defines a slide break for kinemo render --format slides.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
name |
str | None |
None |
|
slide |
bool |
False |
Named marks are stored in s.marks[name] (useful with at=); slide=True defines a slide break for kinemo render --format slides. |
Example:
@k.scene
def presentation(s: k.Scene):
title = k.Text("Part 1").place(at="center")
s.play(k.write(title))
s.mark("part2", slide=True)
s.play(title.to(text="Part 2"))
s.wait(1)
k.Scene.marks (property)
s.marks: dict[str, float] # read-only
Named marks: name → time in seconds.
k.Scene.during (method)
s.during(
*anims: Animation,
duration: float | None = None,
ease: EaseLike | None = None,
revert: Literal['instant'] | float | Ease | None = None,
) -> Iterator[None]
with block that applies state changes on entry and reverts them, animated, on exit. The revert uses the same duration and easing; revert="instant", revert=0.3 or revert=k.ease.out change that. Only accepts reversible animations (.to, k.indicate).
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
*anims |
Animation |
variadic | |
duration |
float | None |
None |
|
ease |
EaseLike | None |
None |
|
revert |
Literal['instant'] | float | Ease | None |
None |
The revert uses the same duration and easing; revert="instant", revert=0.3 or revert=k.ease.out change that. |
Example:
@k.scene
def highlight(s: k.Scene):
a = k.Circle(r=0.6)
b = k.Circle(r=0.6)
row = k.Row(a, b, gap=1).place(at="center")
s.play(k.draw(row))
with s.during(a.to(color=k.YELLOW), b.to(color=k.YELLOW), duration=0.3):
s.play(row.swap(0, 1))
s.wait(0.5)
See also: obj.to, k.indicate, group.swap.
k.Scene.tempo (method)
s.tempo(factor: float, to: float | None = None) -> Iterator[None]
with block that multiplies the speed of everything inside: s.tempo(4) divides durations and waits by 4. s.tempo(1, to=8) speeds up progressively over the block. Nested tempos multiply; k.time is not affected.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
factor |
float |
required | |
to |
float | None |
None |
s.tempo(1, to=8) speeds up progressively over the block. |
Example:
@k.scene
def speed_up(s: k.Scene):
dots = [k.Dot(r=0.2) for _ in range(6)]
row = k.Row(*dots, gap=0.6).place(at="center")
s.add(row)
with s.tempo(1, to=4):
for d in dots:
s.play(k.indicate(d), duration=0.5)
See also: s.during, k.stagger.
k.Scene.add (method)
s.add(*objs: Node)
Puts objects in the scene instantly, at the cursor. Creating an object does not put it in the scene: it enters with s.add or with an entrance verb (k.draw, k.write, k.fade_in, k.grow).
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
*objs |
Node |
variadic |
Example:
@k.scene
def instant(s: k.Scene):
box = k.Rect(w=3, h=1.5).place(at="center")
label = k.Text("Ready").place(inside=box)
s.add(box, label)
s.wait(1)
s.play(box.to(color=k.GREEN))
See also: s.remove, k.draw, k.fade_in.
k.Scene.remove (method)
s.remove(*objs: Node)
Takes objects out of the scene instantly, at the cursor. After that the object does not accept .to() (error K0102) until it enters again with an entrance verb.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
*objs |
Node |
variadic |
Example:
@k.scene
def cut(s: k.Scene):
a = k.Text("Before").place(at="center")
b = k.Text("After").place(at="center")
s.add(a)
s.wait(1)
s.remove(a)
s.add(b)
s.wait(1)
See also: s.add, k.fade_out, k.shrink.
k.Scene.wait_for (method)
s.wait_for(
event: EventSource[P],
count: int = 1,
timeout: float | None = None,
) -> EventInfo[P]
Moves the main cursor to the time of an event (the count-th firing after the cursor) and returns the EventInfo. It only sees what has already been scheduled, so the usual pattern is s.start(...) followed by s.wait_for(...). timeout= is required when the source has no guaranteed end.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
event |
EventSource[P] |
required | Move the cursor to the count-th firing of event after it (what is scheduled so far). |
count |
int |
1 |
Moves the main cursor to the time of an event (the count-th firing after the cursor) and returns the EventInfo. |
timeout |
float | None |
None |
timeout= is required when the source has no guaranteed end. |
Example:
@k.scene
def wait_for_it(s: k.Scene):
dot = k.Dot(r=0.2, x=-5)
title = k.Text("Moving...").place(at="top", margin=0.8)
s.add(dot)
h = s.start(dot.to(x=5), duration=3)
s.play(k.write(title))
s.wait_for(h.done)
s.play(k.fade_out(dot, title))
See also: k.when, event.on, s.start.
k.Scene.voice (method)
s.voice(
narration: str,
*,
voice: str | None = None,
gain: float = 1.0,
) -> Iterator[None]
Narrated with block: takes text (TTS from the provider in kinemo.toml) or an audio file, and lasts at least as long as the audio. Words marked [word]{name} become s.marks[name] at the moment they are spoken. Without a TTS provider, the voice becomes silence with an estimated duration and lint W1401 warns.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
narration |
str |
required | |
voice |
str | None |
None |
|
gain |
float |
1.0 |
Example:
@k.scene
def narrated(s: k.Scene):
tri = k.Triangle.right(3, 4, scale=0.6).place(at="center")
with s.voice("Every right [triangle]{tri} hides a relation."): # kinemo: allow W1401
s.play(k.draw(tri))
s.start(k.indicate(tri), at=s.marks["tri"])
k.TimeSpan (class)#
k.TimeSpan(start: float, end: float)
Where a play/start landed. h.done is an event at its end.
Documented together with s.start.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
start |
float |
required | Where a play/start landed. |
end |
float |
required |
Members:
duration: Length of the span in seconds.done: Event fired at the end of the span (s.wait_for(h.done)).
k.TimeSpan.duration (property)
timespan.duration: float # read-only
Length of the span in seconds.
k.TimeSpan.done (property)
timespan.done: EventSource[None] # read-only
Event fired at the end of the span (s.wait_for(h.done)).
k.time (constant)#
k.time: Expr[float] # read-only signal
Global scene time in seconds, as a read-only signal. It is the right way to express clocks and continuous motion, because it advances linearly and is never eased. Works at module level, in contexts and in components.
Example:
@k.scene
def clock(s: k.Scene):
hand = k.Line(start=(0, 0), end=(0, 2), rotate=-k.time * 90)
label = k.Text(lambda: f"{k.time():.1f} s").place(at="top", margin=0.8)
s.add(hand, label)
s.wait(4)
See also: k.signal, x.map, k.integrate.