Zernikalos
Quick Start

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

PieceTypeRole
ClipZSkeletalActionNamed track data and duration. Does not advance time or write bones.
TargetZSkeletonBone hierarchy that receives the pose. Usually model.skeleton.
PlayerZActionPlayerClock (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

MethodWhat 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 from onUpdate.
  • update(deltaTimeSeconds) — inject a timestep (fixed-step or your own clock). In JavaScript this overload is exported as updateWithDelta(dt).

Both advance the clock (when playing) and commit the pose to the bound skeleton.

On this page