Builtin Library
README.md
Clip
Single animation clip wrapper (Node subclass). Wraps one Channel per
animation channel in the asset, plus a pose buffer and a playhead.
evaluate() samples every channel at the current time into the buffer.
The pose buffer is initialised to rest pose
(translation = 0, rotation = identity quat, scale = 1) at
construction. Each evaluate() overwrites only the slots authored by
channels; unauthored slots stay at rest pose. This means a Mixer
slerping two clips that don't author rotations produces identity, not
(0,0,0,0).
Exports
Clip.new(animAsset: AnimAsset, layout: Layout, looping: boolean, speed: number?) -> Clip— construct a Clip from an animation asset.Clip:update(dt: number)— advance the playhead. Wraps whenlooping, clamps + finishes otherwise.Clip:evaluate() -> TypedBuffer— sample every channel into the pose buffer and return it. Caller must NOT destroy.Clip:setPlaying(p: boolean)— pause/resume the playhead.Clip:rewind()— rewind to t=0, clearfinished, resume.Clip:destroy()— free every Channel handle and the pose buffer.
Types:
Layout = { boneOrder: { string }, stride: number? }AnimChannel = { target_bone: string, path: string, times: { number }, values: { number }, interp: string? }AnimAsset = { duration: number?, channels: { AnimChannel }? }
Usage
local Clip = require("@builtin::systems.anim.AnimGraph.Node.Clip")
local clip = Clip.new(asset, layout, true, 1.0)
clip:update(dt)
local pose = clip:evaluate()
Notes
- The Clip owns its pose buffer and all
Channelhandles.destroy()is required to release them — Lua's GC does not free engine resources. - Only channels with a known
path(translation/rotation/scale) and atarget_bonepresent inlayout.boneOrderare wired up; others are silently dropped. - Looping uses modulo wrap. Non-looping clips clamp to
durationand setfinished = true,playing = false.