Stateful systems
Conditions, integration and simulations resolved before rendering.
Contents:
k.when: Edge-triggered effect: whencondgoes from false to true, it fires an animation or emits an event.k.integrate: Integral of an expression with respect to the change ind=(defaultk.time), starting at the cursor, withinitial=andclamp=(lo, hi).k.simulate: Fixed-step simulation:step(state, dt) -> state, run in Python during resolve.k.State: Base of simulation states: plain fields (floats, bools, pairs) plusk.Events. class Ball(k.State): y: float = 4.0 v: float = 0.0 bounce: k.Event[Impact]k.trace: Trail: the lastlengthseconds of the path of a moving point (usuallyobj.world.position), drawn as a stroke.k.Trail: Trail: the lastlengthseconds of the path of a moving point (usuallyobj.world.position), drawn as a stroke.
Back to the reference index.
k.when (function)#
k.when(
cond: BoolVal,
action: Animation | EventSource[P],
*,
once: bool = False,
rearm: BoolVal | None = None,
) -> Effect
Edge-triggered effect: when cond goes from false to true, it fires an animation or emits an event. It does not move the cursor. Without rearm=, the condition must become false again before it fires again; once=True fires only the first time.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
cond |
BoolVal |
required | Edge-triggered effect: when cond goes from false to true, it fires an animation or emits an event. |
action |
Animation | EventSource[P] |
required | Edge-triggered effect: on false → true, start action (an animation) or fire it (an event). |
once |
bool |
False |
Without rearm=, the condition must become false again before it fires again; once=True fires only the first time. |
rearm |
BoolVal | None |
None |
Without rearm=, the condition must become false again before it fires again; once=True fires only the first time. |
Example:
@k.scene
def trigger(s: k.Scene):
x = k.signal(-4.0)
dot = k.Dot(r=0.25, x=x)
s.add(dot)
k.when(x >= 2, k.flash(dot, color=k.YELLOW))
s.play(x.to(4), duration=3, ease=k.ease.linear)
See also: event.on, s.wait_for, k.integrate.
k.integrate (function)#
k.integrate(
expr: FloatVal,
d: FloatVal | None = None,
*,
initial: float = 0.0,
clamp: tuple[float, float] | None = None,
) -> Expr[float]
Integral of an expression with respect to the change in d= (default k.time), starting at the cursor, with initial= and clamp=(lo, hi). It is precomputed during resolve; the result is a read-only signal. A clock used as d= must advance linearly.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
expr |
FloatVal |
required | |
d |
FloatVal | None |
None |
Integral of an expression with respect to the change in d= (default k.time), starting at the cursor, with initial= and clamp=(lo, hi). |
initial |
float |
0.0 |
Integral of an expression with respect to the change in d= (default k.time), starting at the cursor, with initial= and clamp=(lo, hi). |
clamp |
tuple[float, float] | None |
None |
Integral of an expression with respect to the change in d= (default k.time), starting at the cursor, with initial= and clamp=(lo, hi). |
Example:
@k.scene
def tank(s: k.Scene):
flow = k.signal(0.5)
level = k.integrate(flow, initial=0.0, clamp=(0, 3))
water = k.Rect(w=2, h=level + 0.01, fill=k.BLUE, fill_opacity=0.8).place(at="center")
s.add(water)
s.wait(2)
s.play(flow.to(-1), duration=1)
s.wait(2)
See also: k.when, k.time, k.Component.
k.simulate (function)#
k.simulate(
step: Callable[[StateT, float], StateT],
state: StateT,
dt: float = 0.00416667,
until: float | None = None,
) -> Simulation[StateT]
Fixed-step simulation: step(state, dt) -> state, run in Python during resolve. The state is a subclass of k.State (float, bool or pair fields with defaults, plus k.Event[P] events); states are values, so the step returns st.replace(field=...) and emits events with st.event.emit(payload) — an immediate effect at the simulated instant, not part of the returned value (event without payload: bounce: k.Event, st.bounce.emit()). The step is plain Python (if, min, math all work). Each field becomes a signal (sim.y) and each event a source (sim.bounce). Start it with s.start(sim); sim.done fires at the end (until=).
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
step |
Callable[[StateT, float], StateT] |
required | |
state |
StateT |
required | |
dt |
float |
0.00416667 |
|
until |
float | None |
None |
Start it with s.start(sim); sim.done fires at the end (until=). |
Example:
class Fall(k.State):
y: float = 3.0
v: float = 0.0
def step(st: Fall, dt: float) -> Fall:
return st.replace(y=st.y + st.v * dt, v=st.v - 9.8 * dt)
@k.scene
def fall(s: k.Scene):
sim = k.simulate(step, Fall(), dt=1 / 240, until=1)
s.add(k.Circle(r=0.3, y=sim.y))
s.start(sim)
s.wait_for(sim.done)
See also: event.on, s.wait_for, k.Event.
k.State (class)#
k.State(**values: object)
Base of simulation states: plain fields (floats, bools, pairs) plus k.Events.
class Ball(k.State): y: float = 4.0 v: float = 0.0 bounce: k.Event[Impact]
Documented together with k.simulate.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
**values |
object |
variadic |
Members:
replace: A copy with some fields changed (states are values).
k.State.replace (method)
state.replace(**changes: object) -> State
A copy with some fields changed (states are values).
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
**changes |
object |
variadic |
k.trace (function)#
k.trace(point: VecVal, length: float = 2.0, **style: Unpack[StyleKeywords]) -> Trail
Trail: the last length seconds of the path of a moving point (usually obj.world.position), drawn as a stroke. It is sampled from the timeline, so rendering stays pure.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
point |
VecVal |
required | |
length |
float |
2.0 |
Trail: the last length seconds of the path of a moving point (usually obj.world.position), drawn as a stroke. |
**style |
Unpack[StyleKeywords] |
variadic | Keyword arguments (StyleKeywords): name: str | None, key: str | None, x: FloatVal, y: FloatVal, position: VecVal, rotate: FloatVal, anchor: VecVal, z: FloatVal, scale: FloatVal, scale_x: FloatVal, scale_y: FloatVal, opacity: FloatVal, visible: BoolVal, fill: ColorVal, fill_opacity: FloatVal, stroke: ColorVal, stroke_width: FloatVal, dash: FloatsVal, color: ColorVal. |
Example:
@k.scene
def trail(s: k.Scene):
dot = k.Dot(r=0.15, x=k.cos(k.time * 2) * 3, y=k.sin(k.time * 3) * 2)
trail = k.trace(dot.world.position, length=1.5, stroke=k.TEAL)
s.add(trail, dot)
s.wait(4)
k.Trail (class)#
k.Trail(point: VecVal, length: float = 2.0, **props: Unpack[StyleKeywords])
Documented together with k.trace. Trail: the last length seconds of the path of a moving point (usually obj.world.position), drawn as a stroke. It is sampled from the timeline, so rendering stays pure.
Parameters:
| Name | Type | Default | Description |
|---|---|---|---|
point |
VecVal |
required | |
length |
float |
2.0 |
|
**props |
Unpack[StyleKeywords] |
variadic | Keyword arguments (StyleKeywords): name: str | None, key: str | None, x: FloatVal, y: FloatVal, position: VecVal, rotate: FloatVal, anchor: VecVal, z: FloatVal, scale: FloatVal, scale_x: FloatVal, scale_y: FloatVal, opacity: FloatVal, visible: BoolVal, fill: ColorVal, fill_opacity: FloatVal, stroke: ColorVal, stroke_width: FloatVal, dash: FloatsVal, color: ColorVal. |
Props (animatable with .to(), settable with .set() or in the constructor):
| Prop | Kind | Default | Interpolation |
|---|---|---|---|
fill |
color | theme.fg |
linear |
fill_opacity |
float | 0.0 |
linear |
stroke |
color | theme.fg |
linear |
stroke_width |
float | theme.stroke_width |
linear |
dash |
floats | () |
step_end |
point |
vec2 | (0.0, 0.0) |
linear |
length |
float | 2.0 |
linear |
Props inherited from k.Node: x, y, rotate, scale, scale_x, scale_y, anchor, opacity, z, visible.
Inherited from k.Node: set, to, unbind, edge, age, entered, exited, copy, place, to_place, unpin.