animation
local animation = require(game.ReplicatedStorage.reel).animationAnimationAsset
Section titled “AnimationAsset”An immutable, packed representation of a KeyframeSequence.
| Field | Meaning |
|---|---|
length |
Last source keyframe time, including marker-only keyframes |
pose_length |
Last keyframe time that contains poses, 0 when the sequence has no poses |
looped |
Source KeyframeSequence.Loop |
priority |
Source priority, with Core remapped to -1 |
channels |
Per-target spans into the packed key arrays |
name_to_channel |
Target name to channel index lookup |
markers |
Dense, time-ordered Marker records from source keyframes |
| packed key arrays | Times, inverse durations, positions, quaternions, and easing functions |
Assets and their internal arrays are frozen after loading. One asset can be shared by every compatible character.
Marker
Section titled “Marker”type Marker = { time: number, name: string, value: string,}Each KeyframeMarker becomes one immutable record in asset.markers.
Markers are separate from pose channels: they never create packed solver keys or an animation binding entry.
A marker-only sequence therefore has an empty channels array and no packed pose data, while its markers and length are still available.
In a mixed sequence, marker-only keyframes likewise do not affect solver keys.
A marker after the final pose extends length, sampling continues to hold the last pose until that time.
The solver does not dispatch marker events or retain playback history.
A player should consume asset.markers as its time position advances, typically using the interval previous_time < marker.time <= current_time.
When looping across the end, query the tail of the clip and then its beginning as two intervals.
This keeps repeated, out-of-order, and parallel solver samples side-effect free.
MarkerAsset
Section titled “MarkerAsset”type MarkerAsset = { length: number, markers: { Marker },}This is the immutable marker-only representation returned by extract_markers().
Its length still uses the last source keyframe, even when that keyframe has no marker.
AnimationBinding
Section titled “AnimationBinding”An immutable mapping between one asset and one rig layout:
| Field | Meaning |
|---|---|
active_count |
Number of matching targets |
active_rig_indices |
Descriptor index for each match |
active_channel_indices |
Asset channel index for the same match |
A binding does not retain an asset or descriptor reference. Always use it with the same asset and compatible descriptor that created it.
Functions
Section titled “Functions”load_keyframe_sequence(sequence)
Section titled “load_keyframe_sequence(sequence)”load_keyframe_sequence(sequence: KeyframeSequence): AnimationAssetReads the pose tree into packed channels.
It traverses children even if a parent pose has zero weight.
A pose with Weight == 0 contributes no key for its own target, any non-zero weight contributes the full pose transform.
If a channel begins after time zero, its first key is duplicated at zero.
Duplicate target names at one timestamp, ambiguous target paths across timestamps, and duplicate or descending channel times are rejected.
A sequence with exactly two source keyframes whose first keyframe is not at time zero is also rejected. Markers and poses both count because this preserves the source shape that avoids the unsupported two-keyframe behavior.
Supported pose easing styles/directions are all the easing styles that roblox natively supports for KeyframeSequences.
extract_markers(sequence)
Section titled “extract_markers(sequence)”extract_markers(sequence: KeyframeSequence): MarkerAssetReads only the sequence length and marker records.
Use it when marker playback metadata is needed without packing pose channels.
It applies the same source-keyframe sorting and unsupported two-keyframe-shape validation as load_keyframe_sequence().
bind_animation(asset, rig_or_desc)
Section titled “bind_animation(asset, rig_or_desc)”bind_animation(asset: AnimationAsset, rig_or_desc: RigState | RigDesc): AnimationBindingBuilds the dense mapping from channels whose names match rig targets.
Passing a RigDesc makes binding sharing explicit, passing a RigState uses its desc.