local function A(A,J)local X={}VisitAllInstances(A,J,function(A,J)for J,o in pairs(J)do local l=o.Keyframes local P=0 for o,l in ipairs(l)do local u=TweenInfo.new(l.Time-P,l.EasingStyle,l.EasingDirection,0,false,0)local y={[J]=l.Value}local k=TweenService:Create(A,u,y)table.insert(X,{Tween=k;DelayTime=P})P=l.Time end end end)return X end local J={}J.__index=J function J.new(X,o)local l={running=false,root=X;tweenTable=o,tweens=A(X,o)}setmetatable(l,J)return l end function J.ResetValues(A)VisitAllInstances(A.root,A.tweenTable,function(A,J)for J,X in pairs(J)do local o=X.InitialValue A[J]=o end end)end function J.PlayTweens(J,A)if J.running then J:PauseTweens()end J.running=true local X={}for A,J in pairs(J.tweens)do local o=J.Tween local l=J.DelayTime if l==0 then o:Play()else table.insert(X,{Tween=o;DelayTime=l,Playing=false})end end local o local l=tick()local P=false o=RunService.Heartbeat:Connect(function()local u=tick()-l if not J.running then J.running=false o:Disconnect()if A then A()end return end if P then local X=true for A,J in pairs(J.tweens)do local o=J.Tween if o.PlaybackState==Enum.PlaybackState.Playing then X=false end end if X then J.running=false o:Disconnect()if A then A()end return end else local A=true for J,X in pairs(X)do if not X.Playing then if u>X.DelayTime then X.Playing=true X.Tween:Play()else A=false end end end P=A end end)end function J.PauseTweens(A)A.running=false for A,J in pairs(A.tweens)do local X=J.Tween X:Cancel()end end return J

local function BuildTweens(root, tweenTable)
	local tweens = {}

	VisitAllInstances(root, tweenTable, function(instance, props)
		for prop, values in pairs(props) do
			local keyframes = values.Keyframes
			local lastTime = 0
			for _, keyframe in ipairs(keyframes) do
				local tweenInfo = TweenInfo.new(keyframe.Time - lastTime,
					keyframe.EasingStyle,keyframe.EasingDirection, 0, false, 0)
				local propTable = {
					[prop] = keyframe.Value
				}
				local tween = TweenService:Create(instance, tweenInfo, propTable)
				table.insert(tweens, {
					Tween = tween,
					DelayTime = lastTime,
				})
				lastTime = keyframe.Time
			end
		end
	end)

	return tweens
end

local TweenUtilities = {}
TweenUtilities.__index = TweenUtilities

function TweenUtilities.new(root, tweenTable)
	local self = {
		running = false,
		root = root,
		tweenTable = tweenTable,
		tweens = BuildTweens(root, tweenTable),
	}
	setmetatable(self, TweenUtilities)
	return self
end

function TweenUtilities:ResetValues()
	VisitAllInstances(self.root, self.tweenTable, function(instance, props)
		for prop, values in pairs(props) do
			local initialValue = values.InitialValue
			instance[prop] = initialValue
		end
	end)
end

function TweenUtilities:PlayTweens(callback)
	if self.running then
		self:PauseTweens()
	end
	self.running = true

	local delayedTweens = {}
	for _, props in pairs(self.tweens) do
		local tween = props.Tween
		local delayTime = props.DelayTime
		if delayTime == 0 then
			tween:Play()
		else
			table.insert(delayedTweens, {
				Tween = tween,
				DelayTime = delayTime,
				Playing = false,
			})
		end
	end

	local heartbeatConnection
	local start = tick()
	local tweensDone = false
	heartbeatConnection = RunService.Heartbeat:Connect(function()
		local now = tick() - start
		if not self.running then
			self.running = false
			heartbeatConnection:Disconnect()
			if callback then
				callback()
			end
			return
		end
		if tweensDone then
			local allDone = true
			for _, props in pairs(self.tweens) do
				local tween = props.Tween
				if tween.PlaybackState == Enum.PlaybackState.Playing then
					allDone = false
				end
			end
			if allDone then
				self.running = false
				heartbeatConnection:Disconnect()
				if callback then
					callback()
				end
				return
			end
		else
			local allPlaying = true
			for _, props in pairs(delayedTweens) do
				if not props.Playing then
					if now > props.DelayTime then
						props.Playing = true
						props.Tween:Play()
					else
						allPlaying = false
					end
				end
			end
			tweensDone = allPlaying
		end
	end)
end

function TweenUtilities:PauseTweens()
	self.running = false
	for _, props in pairs(self.tweens) do
		local tween = props.Tween
		tween:Cancel()
	end
end

return TweenUtilities
