introduction
Reel is a custom animation solver that aims to have 1:1 roblox animation solver behavior. It also implements additive and subtractive animation blending.
Installation
Section titled “Installation”Either grab the .rbxm from the latest release
or get it through wally:
reel = "unityjaeger/reel@0.2.0"Use Cases
Section titled “Use Cases”- no instances needed, enabling things like ping compensation for hit detection
- additive and subtractive animation blending
- full control, if you want specific behavior then you can implement that into a custom player
Usage Example
Section titled “Usage Example”Minimal playback example.
local reel = require(game.ReplicatedStorage.reel)
local animation = reel.animationlocal rig_api = reel.riglocal solver = reel.solver
local RunService = game:GetService("RunService")
local sequence = game.ServerStorage.Walklocal character = workspace.Character
local asset = animation.load_keyframe_sequence(sequence)local rig = rig_api.load_rig(character)local binding = animation.bind_animation(asset, rig.desc)
local state = { binding = binding, time_position = 0, weight = 1, priority = nil, -- use asset.priority}
local prepared = solver.prepare_tracks({ { asset = asset, state = state },})
local started_at = os.clock()
RunService.PreAnimation:Connect(function() local elapsed = os.clock() - started_at if asset.looped and asset.length > 0 then state.time_position = elapsed % asset.length else state.time_position = math.min(elapsed, asset.length) end
solver.solve_prepared(rig, prepared)
for index, motor in rig.motors do motor.Transform = rig.transforms[index] end
for index, bone in rig.bones do bone.Transform = rig.transforms[index] endend)The one-track path does not need blend scratch.
solve_prepared() writes only to rig.transforms; committing Motor6D.Transform, AnimationConstraint.Transform, and Bone.Transform remains the caller’s responsibility.
Frame responsibilities
Section titled “Frame responsibilities”Before solving, update each active track’s time_position and weight.
Reel does not manage speed, loops, fades, stopping, events, or replication.
Prepare the dense track list when its membership or priority structure changes:
prepared = solver.prepare_tracks(current_tracks, prepared)You may update time_position and weight without preparing again.
Re-prepare when a track is added, removed, replaced, or receives a different priority.