local function playKeyframes(rig : Model, keyframes : KeyframeSequence)
local Humanoid = rig:FindFirstChildWhichIsA("Humanoid")
local Animator = Humanoid.Animator
for i, v in Animator:GetPlayingAnimationTracks() do
v:Stop()
end
local offset = {}
local function getMotor6DFromPose(pose : Pose) : Motor6D
for i, v in rig:GetDescendants() do
if v:IsA("Motor6D") and v.Part1.Name == pose.Name and v.Part0.Name == pose.Parent.Name then -- and v.Part0.Name == poseParentName
return v
end
end
end
local children : {Keyframe}? = keyframes:GetKeyframes()
table.sort(children, function(a, b)
return a.Time < b.Time
end)
for nth, keyframe in children do
local time = 0
if children[nth + 1] then
time = children[nth + 1].Time - keyframe.Time
end
for _, pose : Pose? in keyframe:GetDescendants() do
local limb = getMotor6DFromPose(pose)
if limb and pose.CFrame ~= CFrame.new() then
offset[limb] = offset[limb] or limb.C0
local EasingStyle, EasingDirection =
Enum.EasingStyle[pose.EasingStyle.Name],
Enum.EasingDirection[pose.EasingDirection.Name]
pcall(function()
TweenService:Create(limb, TweenInfo.new(time, EasingStyle, EasingDirection), {C0 = offset[limb] * pose.CFrame}):Play()
end)
end
end
wait(time)
end
for i, v in offset do
TweenService:Create(i, TweenInfo.new(0.5), {C0 = v}):Play()
end
end
Unrelated but if you want to get the Animation Rig type of a keyframe sequence just use this function
local function getAnimationRigType(keyframes : KeyframeSequence)
local function rigLimbExists(keyframe, rigType)
local result = Rigs[rigType]:FindFirstChild(keyframe.Name)
return (result and result.Name ~= "HumanoidRootPart")
end
for _, keyframe in keyframes:GetDescendants() do
if rigLimbExists(keyframe, "R6") then
return "R6"
elseif rigLimbExists(keyframe, "R15") then
return "R15"
end
end
end
local function playKeyframes(rig : Model, keyframes : KeyframeSequence)
local offset = {}
local function getMotor6DFromPose(pose : Pose) : Motor6D
for i, v in rig:GetDescendants() do
if v:IsA("Motor6D") and v.Part1.Name == pose.Name and v.Part0.Name == pose.Parent.Name then -- and v.Part0.Name == poseParentName
return v
end
end
end
local children : {Keyframe}? = keyframes:GetKeyframes()
table.sort(children, function(a, b)
return a.Time < b.Time
end)
for nth, keyframe in children do
local time = 0
if children[nth + 1] then
time = children[nth + 1].Time - keyframe.Time
end
for _, pose : Pose? in keyframe:GetDescendants() do
local limb = getMotor6DFromPose(pose)
if limb and pose.CFrame ~= CFrame.new() then
offset[limb] = offset[limb] or limb.C0
local EasingStyle, EasingDirection =
Enum.EasingStyle[pose.EasingStyle.Name],
Enum.EasingDirection[pose.EasingDirection.Name]
local ticked = tick()
spawn(function()
--transform
while tick() - ticked < time do
local cframe = limb.C0
-- n / time
limb.C0 = cframe:Lerp(offset[limb] * pose.CFrame, TweenService:GetValue((tick() - ticked) / time, EasingStyle, EasingDirection))
RunService.PreSimulation:Wait()
end
limb.C0 = offset[limb] * pose.CFrame
end)
end
end
wait(time)
end
end
apologies fro reviving im on my customanimator rampage
one critique is this assumes the animation has keyframes for every joint every keyframe.
Roblox’s account for this if this isn’t the case, it gets the previous joint cf to the next cf checking every keyframe after for it so we can do that sick smooth lerp overtime.