Skip to content

Animation

Animations are typically loaded from 3D files (glTF, FBX) and control node transforms, morph targets, or skeletal poses over time.

local anims = scene:get_animations() -- array of all animations
local anim = scene:get_animation("Walk") -- by name, nil if not found
PropertyTypeAccessDefaultDescription
namestringr/oAnimation clip name
durationnumberr/oLength in seconds
speednumberr/w1.0Playback speed multiplier
loopboolr/wfalseLoop when reaching the end
timenumberr/wCurrent playhead in seconds
playingboolr/oWhether currently playing
anim:play() -- start from current time
anim:pause() -- freeze at current time
anim:stop() -- stop and reset to time 0
anim:seek(1.5) -- jump to 1.5 seconds
-- Play at half speed, looped
anim.speed = 0.5
anim.loop = true
anim:play()

Register callbacks at specific times or on completion:

-- Fire at a specific time
anim:on_time(2.0, function()
print("2 seconds into the animation!")
end)
-- Fire when the animation finishes
anim:on_complete(function()
print("animation done")
end)

Control blend shape weights on mesh nodes. Morph targets are defined on meshes and controlled per-node:

local face = scene:find_node("Face")
-- Set individual weights (0.0 – 1.0)
face:set_morph_weight("smile", 0.8)
face:set_morph_weight("blink_L", 1.0)
-- Query
local w = face:get_morph_weight("smile") -- 0.8
local all = face:get_morph_weights() -- { smile=0.8, blink_L=1.0 }
local names = face:get_morph_target_names() -- { "smile", "blink_L", ... }

Sync an animation to the DAW timeline so it follows the playhead automatically:

local anim = scene:get_animation("Performance")
anim:sync_to_timeline(0) -- 0 = offset in seconds (start of timeline)
anim:unsync() -- return to manual control

When synced, the animation’s time tracks pl.timeline.position minus the offset. Play/pause follows the transport.

local timeline = pl.timeline
timeline.position -- number, current playhead in seconds (r/o)
timeline.playing -- bool (r/o)
timeline.bpm -- number (r/o)
timeline.beat -- number, current beat (r/o)
-- React to transport events
timeline:on_play(function() ... end)
timeline:on_pause(function() ... end)
timeline:on_seek(function(time) ... end)

Trigger animations from MIDI events:

pl.midi:on_note(1, function(note, velocity)
local anim = scene:get_animation("Hit")
anim:seek(0)
anim:play()
end)
pl.midi:on_cc(1, 40, function(value)
-- Use CC to control morph weight
local face = scene:find_node("Face")
face:set_morph_weight("smile", value / 127)
end)
local walk = scene:get_animation("Walk")
local wave = scene:get_animation("Wave")
walk.loop = true
walk:play()
-- After 5 seconds, blend to wave
walk:on_time(5.0, function()
walk:stop()
wave:play()
end)
wave:on_complete(function()
walk:play() -- back to walking
end)