Playing skeletal animations
Bind clips from a .zko to a skeleton with ZActionPlayer, then drive playback from onUpdate.
Skeletal clips ship inside the loaded .zko as zko.actions. Playback is a host-side loop: keep a ZActionPlayer, bind it to a skeleton and a clip, then call update() once per frame.
Pieces
| Piece | Type | Role |
|---|---|---|
| Clip | ZSkeletalAction | Named track data and duration. Does not advance time or write bones. |
| Target | ZSkeleton | Bone hierarchy that receives the pose. Usually model.skeleton. |
| Player | ZActionPlayer | Clock (time, speed, loop, play/pause) and pose commit inside update(). |
setAction takes a skeleton, not a ZModel. update() advances the clock and applies the sampled pose. You do not call sampleAt or write bone matrices yourself.
Play a clip
Keep the player across frames (a field on your activity, view controller, or module). After the scene is built and you have a skinned model:
import zernikalos.action.ZActionPlayer
import zernikalos.search.findFirstModel
val player = ZActionPlayer()
val model = findFirstModel(scene)
val skeleton = model?.skeleton
val action = zko.actions?.firstOrNull()
if (skeleton != null && action != null) {
player.setAction(skeleton, action)
player.play(loop = true)
}In onUpdate:
override fun onUpdate(context: ZContext, done: () -> Unit) {
player.update()
done()
}play(loop = true) repeats when time passes the clip duration. Without looping, playback stops at the end of the clip.
Switching clips
To change action (a UI picker, a state machine, and so on), stop the current clip, bind the new one to the same skeleton, then play again:
player.stop()
player.setAction(skeleton, nextAction)
player.play(loop = true)setAction resets time to zero and applies the pose at the start of the new clip immediately.
Playback controls
| Method | What it does |
|---|---|
play(loop) | Starts (or resumes) playback. loop repeats past duration. |
pause() | Freezes time; the next play continues from currentTime. |
stop() | Pauses, seeks to 0, and reapplies the start pose. |
seek(time) | Jumps to a time in seconds (clamped to the clip) and reapplies the pose. |
setPlaybackSpeed(speed) | Multiplier (1 = normal, 2 = double). |
getProgress() | Normalized progress in [0, 1]. |
resetTimer() | Resets the wall-clock baseline used by parameterless update(), useful after a long pause. |
Readable state: currentTime, isPlaying, duration.
Wall clock vs fixed step
update()— uses elapsed wall time since the last call. This is what most apps call fromonUpdate.update(deltaTimeSeconds)— inject a timestep (fixed-step or your own clock). In JavaScript this overload is exported asupdateWithDelta(dt).
Both advance the clock (when playing) and commit the pose to the bound skeleton.
Related
- Loading a model (.zko) —
zko.actions,findFirstModel, attaching the root - Integrating Zernikalos —
onReady/onUpdatelifecycle ZActionPlayerAPI