I am working on a custom animator and i need feedbacks

So heya as said in the title i am working on a custom animator that can use KeyframeSequence instead of animations i think it can be useful for free models because KeyframeSequence do not need to be published it also have functions to modify animations or save them in datastores as a table.

here is the code: (early prototype)

local TweenService = game:GetService('TweenService')
local RunService = game:GetService("RunService")

local AnimationEditor = {}
local Animator = {}

function FindMotorFromName(Character:Model,Name:string):Motor6D
	for i,v in pairs(Character:GetDescendants()) do
		if v:IsA("Motor6D") and v.Part1 and v.Part1.Name == Name then
			return v
		end
	end
end

function GetClosestS(MotorAnimation,Time)
	local Return = MotorAnimation[1]
	local I = -1
	for i,v in pairs(MotorAnimation) do
		if v.Time>Time then
			return Return,I
		else
			Return = v
			I = i
		end
	end
	return Return,I
end

function Animator.CreateAnimation(Character:Model,Animation,Repeat,Speed:number):{Speed:number,Time:number,AdjustSpeed:(speed:number)->(),AdjustTime:(time:number)->(),Play:(FadeTime:number?)->(),Stop:()->(),Remove:()->(),Completed:RBXScriptSignal}
	local Ret = {}
	Speed = Speed or 1
	
	local Time = 0
	
	local Playing = false
	
	local Completed = Instance.new("BindableEvent",script)
	
	local function Play(FadeTime:number)
		if RunService:IsServer() then return end
		if FadeTime>0 then
			local FTime = 0
			local TrF:{CFrame} = {}
			while FTime<FadeTime do
				if Playing == false then return end
				for MotorN,Motor in pairs(Animation) do
					if TrF[MotorN] == nil then
						TrF[MotorN] = FindMotorFromName(Character,MotorN).Transform
					end
					local Last:{Time:number,CFrame:CFrame},LN = GetClosestS(Motor,Time)
					local Next = Motor[LN+1] or Last
					local Per = math.clamp((Time-Last.Time)/(Next.Time-Last.Time),0,1)
					
					local Target = Last.CFrame:Lerp(Next.CFrame,TweenService:GetValue(Per,Enum.EasingStyle[Next.EasingStyle.Name],Enum.EasingDirection[Next.EasingDirection.Name]))
					FindMotorFromName(Character,MotorN).Transform = TrF[MotorN]:Lerp(GetClosestS(Motor,Time).CFrame,FTime/FadeTime)
				end
				local delta = RunService.RenderStepped:Wait()
				FTime+=delta
			end
		end
		
		while Playing do
			
			
			repeat
				if Playing == false then return end
				local delta = RunService.RenderStepped:Wait()
				Time += delta*Speed
				Ret.Time = Time
				
				for MotorN,Motor in pairs(Animation) do
					local Last:{Time:number,CFrame:CFrame},LN = GetClosestS(Motor,Time)
					local Next = Motor[LN+1] or Last
					local Per = math.clamp((Time-Last.Time)/(Next.Time-Last.Time),0,1)

					FindMotorFromName(Character,MotorN).Transform = Last.CFrame:Lerp(Next.CFrame,TweenService:GetValue(Per,Enum.EasingStyle[Next.EasingStyle.Name],Enum.EasingDirection[Next.EasingDirection.Name]))
				end
					
			until Time>AnimationEditor.GetAnimationLenght(Animation) or Time<=0 and Speed<0
			if Speed<0 then
				Time = AnimationEditor.GetAnimationLenght(Animation)
			else
				Time = 0
			end
			if not Repeat then
				Playing = false
			end
		end
		Completed:Fire()
	end
	
	Ret.Time = 0
	Ret.Speed = Speed
	
	
	function Ret.AdjustSpeed(speed:number)
		Speed = speed
		Ret.Speed = speed
	end
	
	function Ret.AdjustTime(Time2:number)
		Time = Time2
	end
	
	function Ret.Play(FadeTime:number?)
		if Playing then return end
		Playing = true
		spawn(function()
			Play(FadeTime or 0)
		end)
	end
	
	function Ret.Stop()
		Playing = false
	end
	
	function Ret.Remove()
		Completed:Destroy()
		Playing = false
	end
	
	Character.Destroying:Connect(Ret.Remove)
	
	Ret.Completed = Completed.Event
	
	
	--local test = Instance.new("Humanoid"):LoadAnimation(Instance.new("Animation"))
	
	
	return Ret
end

function Animator.GetfromKeyframe(Character:Model,Keyframeanimation:KeyframeSequence)
	local Animation = {}
	
	for i,Step in pairs(Keyframeanimation:GetChildren()) do
		for i,Motor:Pose in pairs(Step:GetDescendants()) do
			Animation[Motor.Name] = Animation[Motor.Name] or {}
			Animation[Motor.Name][-1] = {Time=Step.Time,CFrame=Motor.CFrame,EasingStyle=Motor.EasingStyle,EasingDirection=Motor.EasingDirection}
			Animation[Motor.Name] = AnimationEditor.SortSteps(Animation[Motor.Name])
		end
	end

	return AnimationEditor.CreateAnimation(Character,Animation)
end

function StopCharacterAnimations(Character)
	StopAnimations:Fire(Character)
end

function AnimationEditor.CreateAnimation(Character:Model,BaseAnimation)
	BaseAnimation = BaseAnimation or {}
	local Animation = {}
	local Motors = {} for i,v in pairs(Character:GetDescendants())do if v:IsA("Motor6D")then table.insert(Motors,v)end end
	for i,Motor6D:Motor6D in pairs(Motors) do
		Animation[Motor6D.Name] = BaseAnimation[Motor6D.Name] or {}
	end
	return Animation
end

function AnimationEditor.SortSteps(Key:{})
	--sort Key by Time
	local Unsorted = Key
	local Sorted = {}
	repeat
		local Biggest = {Time=math.huge}
		local I = nil
		local Number = 0
		for i,v in pairs(Unsorted) do
			if v.Time<Biggest.Time then
				Biggest = v
				I = i
			end
			Number+=1
		end
		if Number == 0 then return Sorted end
		Unsorted[I or -1] = nil
		table.insert(Sorted,Biggest)
	until Number == 0
	return Sorted
end

function AnimationEditor.FindStep(Key,Time)
	for i,v in pairs(Key) do
		if v.Time==Time then
			return i
		end
	end
	return -1
end

function AnimationEditor.ModifyStep(Animation,Motor,Data)
	Animation[Motor][AnimationEditor.FindStep(Animation[Motor],Data.Time) or -1] = Data
	Animation[Motor] = AnimationEditor.SortSteps(Animation[Motor])
end

function AnimationEditor.RemoveStep(Animation,Motor,Time)
	Animation[Motor][AnimationEditor.FindStep(Animation[Motor],Time)] = nil
end

function AnimationEditor.GetAnimationLenght(Animation:{})
	local Time = 0

	for i,Motor in pairs(Animation) do
		for i,Step:{Time:number} in pairs(Motor) do
			if Step.Time>Time then
				Time = Step.Time
			end
		end
	end

	return Time
end

local Module = {}

Module.AnimationEditor = AnimationEditor
Module.Animator = Animator
return Module

to use this code remove any animator in the character you try to animate

An example of what you can do with it: Table animation - Roblox

Why you should NOT use it:
-not replicated (Transphorm is not possible to modify on the server but im gonna try to fix it later )
-glitch if multiple animations are applied on the same character at the same time but will be fixed
-disable normal animation will be fixed

if you find bugs tell me i would be happy to fix it or if you have suggestions thank for reading hope you enjoy this prototype
Edit: roblox code block made my life hell on this one

2 Likes