What can I do to make my SocialRainbow module code better?

I made this module, and I don’t like that it’s messy

Can you improve this code for me?

--[[
	<SocialRainbow by VSCPlays (originally from @kernelvox (max96git))
	This rainbow module is based on @WinnersTakeAll (RyanLua)'s Shime
	I made this for @kernelvox as @bluebxrrybot and @commitblue said it's not enough for a community resource,
	I want to help @kernelvox succed
	please credit me @VSCPlays for the module and @kernelvox for the idea
	
	The Shime Owner suggested some stuff, so I added some adjustments
]]

--// Services \\--
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

--// Sanity Checks \\--

if not script:IsDescendantOf(ReplicatedStorage) then
	error(`Please put this in {ReplicatedStorage:GetFullName()}, where both the client and the server can access it`)
end

--// Bindables \\--
local event1 = Instance.new("BindableEvent")
local event2 = Instance.new("BindableEvent")
local event3 = Instance.new("BindableEvent")

--// rainbow \\--
local rainbow = {}
rainbow.__index = rainbow

function rainbow.new(item:GuiObject, it:"Border" | "Text" | "Background", cooldown:number?)
	local self = setmetatable({}, rainbow)

	self.itemType = it
	self.item = item
	self.playbackState = Enum.PlaybackState.Completed
	self.cooldown = cooldown or 0
	self.func = function()
		self.playbackState = Enum.PlaybackState.Playing
		local color = Color3.fromHSV((tick() * 4) % 1, 1, 1)
		if self.itemType == "Border" then
			self.item.BorderColor3 = color
		elseif self.itemType == "Text" then
			if self.item.ClassName == "TextBox" or "TextButton" or "TextLabel" then
				self.item.TextColor3 = color
			end
		elseif self.itemType == "Background" then
			self.item.BackgroundColor3 = color
		end
		task.wait(self.cooldown)
	end
	self.Played = event1.Event
	self.Paused = event2.Event
	self.Finished = event3.Event

	return self
end

function rainbow:Play()
	event1:Fire(self.item, self.playbackState)
	self.playbackState = Enum.PlaybackState.Begin
	
	self.func = function()
		self.playbackState = Enum.PlaybackState.Playing
		local color = Color3.fromHSV((tick() * 4) % 1, 1, 1)
		if self.itemType == "Border" then
			self.item.BorderColor3 = color
		elseif self.itemType == "Text" then
			if self.item.ClassName == "TextBox" or "TextButton" or "TextLabel" then
				self.item.TextColor3 = color
			end
		elseif self.itemType == "Background" then
			self.item.BackgroundColor3 = color
		end
		task.wait(self.cooldown)
	end
	
	while true do
		if self.func == nil then
			break
		end
		
		self.func()
	end
end

function rainbow:Pause(seconds:number)
	if self.playbackState ~= Enum.PlaybackState.Playing then
		return
	end

	if seconds == self.cooldown then
		seconds += self.cooldown
	end

	event2:Fire(self.item, self.playbackState, seconds)

	seconds = math.clamp(seconds, 0.1, 10e4)

	self.playbackState = Enum.PlaybackState.Paused
	self.func = nil
	task.wait(seconds)
	self:Play()
end

function rainbow:Stop()
	if self.playbackState ~= Enum.PlaybackState.Playing then
		return
	end

	event3:Fire(self.item, self.playbackState)
	self.playbackState = Enum.PlaybackState.Paused
	self.func = nil
end

return rainbow

Error Handling and Stuffs. (Revised Version Below)

--// Services \\--
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

--// Sanity Checks \\--
assert(script:IsDescendantOf(ReplicatedStorage), "Please put this script in ReplicatedStorage, where both the client and the server can access it.")

--// Bindables \\--
local playedEvent = Instance.new("BindableEvent")
local pausedEvent = Instance.new("BindableEvent")
local finishedEvent = Instance.new("BindableEvent")

--// rainbow \\--
local rainbow = {}
rainbow.__index = rainbow

function rainbow.new(item:GuiObject, category:"Border" | "Text" | "Background", cooldown:number?)
	local self = setmetatable({}, rainbow)

	self.itemCategory = category
	self.item = item
	self.playbackState = Enum.PlaybackState.Completed
	self.cooldown = cooldown or 0
	self.func = nil
	self.playedEvent = playedEvent.Event
	self.pausedEvent = pausedEvent.Event
	self.finishedEvent = finishedEvent.Event

	return self
end

function rainbow:Play()
	playedEvent:Fire(self.item, self.playbackState)
	self.playbackState = Enum.PlaybackState.Begin

	self.func = function()
		self.playbackState = Enum.PlaybackState.Playing
		local color = Color3.fromHSV((tick() * 4) % 1, 1, 1)
		if self.itemCategory == "Border" then
			self.item.BorderColor3 = color
		elseif self.itemCategory == "Text" then
			self.item.TextColor3 = color
		elseif self.itemCategory == "Background" then
			self.item.BackgroundColor3 = color
		end
		task.wait(self.cooldown)
	end

	while self.func do
		self.func()
	end
end

function rainbow:Pause(seconds:number)
	if self.playbackState ~= Enum.PlaybackState.Playing then
		return
	end

	if seconds == self.cooldown then
		seconds = seconds + self.cooldown
	end

	pausedEvent:Fire(self.item, self.playbackState, seconds)

	seconds = math.clamp(seconds, 0.1, 10e4)

	self.playbackState = Enum.PlaybackState.Paused
	self.func = nil
	task.wait(seconds)
	self:Play()
end

function rainbow:Stop()
	if self.playbackState ~= Enum.PlaybackState.Playing then
		return
	end

	finishedEvent:Fire(self.item, self.playbackState)
	self.playbackState = Enum.PlaybackState.Paused
	self.func = nil
end

return rainbow

Cleaned up version
Also stops :Play() from yielding the code and :Pause() without any parameters erroring

Edit: modified last parameter when creating new object to account for adding RunService to make it smoother, instead of cooldown it’s now how long it takes until the rainbow loops (default value is 3)

--[[
	<SocialRainbow by VSCPlays (originally from @kernelvox (max96git))
	This rainbow module is based on @WinnersTakeAll (RyanLua)'s Shime
	I made this for @kernelvox as @bluebxrrybot and @commitblue said it's not enough for a community resource,
	I want to help @kernelvox succed
	please credit me @VSCPlays for the module and @kernelvox for the idea
	
	The Shime Owner suggested some stuff, so I added some adjustments
]]

--// Types \\--
type ItemType = {"Border" | "Text" | "Background"}

--// Services \\--
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

--// Sanity Checks \\--
assert(script:IsDescendantOf(ReplicatedStorage), "Please put this script in ReplicatedStorage, where both the client and the server can access it.")


--// Bindables \\--
local PLAYED_EVENT = Instance.new("BindableEvent")
local PAUSED_EVENT = Instance.new("BindableEvent")
local FINISHED_EVENT = Instance.new("BindableEvent")

--// rainbow \\--
local rainbow = {}
rainbow.__index = rainbow

function rainbow.new(item: GuiObject, itemType: ItemType, rainbowSpeed: number?)
	local self = setmetatable({}, rainbow)

	self.itemType = itemType
	self.item = item
	self.playbackState = Enum.PlaybackState.Completed
	self.rainbowSpeed = rainbowSpeed or 3 --how many seconds until the rainbow loops

	self._connection = nil
	self._currentProgress = 0

	self.Played = PLAYED_EVENT.Event
	self.Paused = PAUSED_EVENT.Event
	self.Finished = FINISHED_EVENT.Event

	return self
end

function rainbow:Play()
	if self._connection then 
		return 
	end

	PLAYED_EVENT:Fire(self.item, self.playbackState)
	self.playbackState = Enum.PlaybackState.Begin

	local function nextFrame(deltaTime: number)
		self.playbackState = Enum.PlaybackState.Playing
		self._currentProgress = (self._currentProgress + (deltaTime / self.rainbowSpeed)) % 1

		local color = Color3.fromHSV(self._currentProgress, 1, 1)

		self.item[self.itemType .. "Color3"] = color
	end

	if RunService:IsServer() then
		self._connection = RunService.Stepped:Connect(nextFrame)
	else
		self._connection = RunService.RenderStepped:Connect(nextFrame)
	end
end

function rainbow:Pause(seconds: number)
	if self.playbackState ~= Enum.PlaybackState.Playing then
		return
	end

	seconds = seconds or 0.1 --default value if no value is provided

	if seconds == self.cooldown then
		seconds += self.cooldown
	end

	seconds = math.clamp(seconds, 0.1, 10e4)

	PAUSED_EVENT:Fire(self.item, self.playbackState, seconds)
	self.playbackState = Enum.PlaybackState.Paused
	
	self._connection:Disconnect()
	self._connection = nil

	task.wait(seconds)
	self:Play()
end

function rainbow:Stop()
	if self.playbackState ~= Enum.PlaybackState.Playing then
		return
	end

	FINISHED_EVENT:Fire(self.item, self.playbackState)
	self.playbackState = Enum.PlaybackState.Paused
	
	self._connection:Disconnect()
	self._connection = nil
end

return rainbow
2 Likes

I put this and made a pull request :wink:

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.