Skip to main content
Version: 0.1.0

Updaters

Updaters are callbacks that run every frame. They let you drive tattva properties with arbitrary logic — useful for reactive layouts, physics-like motion, and procedural animation that doesn't fit the timeline model.

Adding an updater

scene.add_updater(tattva_id, |scene, id, dt| {
// dt = delta time in seconds since last frame
let t = scene.scene_time;
scene.set_position_2d(id, glam::Vec2::new(t.sin() * 3.0, t.cos() * 2.0));
});

The closure receives:

  • scene — mutable reference to the full scene
  • id — the TattvaId this updater is attached to
  • dt — frame delta time in seconds

Circular motion example

let radius = 3.0;
let speed = 1.0; // radians per second

scene.add_updater(particle_id, move |scene, id, _dt| {
let t = scene.scene_time * speed;
scene.set_position_2d(id, glam::Vec2::new(t.cos() * radius, t.sin() * radius));
});

Reactive tattvas

One tattva can read another's state and respond to it. This is how force field visualizations work — each vector arrow reads the particle position and updates its own rotation:

scene.add_updater(vector_id, move |scene, vid, _dt| {
if let Some(source) = scene.get_tattva_any(particle_id) {
let props = murali::frontend::props::DrawableProps::read(source.props());
let particle_pos = props.position;
drop(props);

let delta = vector_pos - particle_pos;
let angle = delta.y.atan2(delta.x);

scene.set_rotation(vid, glam::Quat::from_rotation_z(angle));
}
});

Updaters vs timeline animations

TimelineUpdater
SchedulingTime-based, declarativeRuns every frame
Use caseDefined start/end animationsReactive, physics, procedural
EasingBuilt-inManual
SeekingSupportedNot supported

Use timeline animations for anything with a clear start and end. Use updaters for continuous reactive behavior.