I Need Critiques on this Custom Credits System

Hello, as the title suggests, I need some people to critique my code so I can change anything that may be an issue or give tips on making systems like this in the feature. I am trying to make this an Open Source asset.

This is made with OOP and has other modules to change the themes, add people, etc easily. This is the first time I have made one of these.

if possible, please provide suggestions, criticism, etc. Thanks for reading :wink:

FILE: Credits.rbxm (16.6 KB)

CODE:
Main Local Script:

local plr = game:GetService("Players").LocalPlayer
local PlayerGui = plr:WaitForChild("PlayerGui")

local CreditSG = PlayerGui:WaitForChild("Credits")

local MainModule = require(script:WaitForChild("UserInterface"))
local ThemeModule = require(script:WaitForChild("Themes"))

repeat
	task.wait()
until game:IsLoaded()

local LeadDeveloper = {
	
	[1] = {
		
		["UserId"] = ;
		
		["Info"] = {
			
			"Lead Programmer";
			"Lead Map Designer";
			
		}
		
	}
	
}

local CoOwner = {

	[1] = {

		["UserId"] = ;

		["Info"] = {

			"Idea-Maker";
			"Planner";

		};

	};
	
	[2] = {

		["UserId"] = ;

		["Info"] = {

			"Also Planner";

		};
		
	};
	
}

local Modeler = {

	[1] = {

		["UserId"] = ;

		["Info"] = {

			"Modeler";

		}

	}

}

local Lead = MainModule.newHeader("LEAD DEVELOPERS", Color3.fromRGB(200, 17, 1), 1, LeadDeveloper) -- First arg is a new list name, 2nd arg is the color of the List Name, Third is the Priority (if you put 1, it will be the top of the list), and last argument is a table full of info.
local CoOwners = MainModule.newHeader("Co-Owners", Color3.fromRGB(39, 181, 138), 2, CoOwner)
local Modelers = MainModule.newHeader("Modelers", Color3.fromRGB(186, 12, 169), 3, Modeler)

Lead:create(CreditSG:WaitForChild("Frame"):WaitForChild("CreditScroll"))
CoOwners:create(CreditSG:WaitForChild("Frame"):WaitForChild("CreditScroll"))
Modelers:create(CreditSG:WaitForChild("Frame"):WaitForChild("CreditScroll"))

task.delay(1, function()
	ThemeModule.ChangeThemes(CreditSG, "Dark")
end)

MainModule:

local PLAYERS = game:GetService("Players")

local Alphabet = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}

local module = {}
module.__index = module

local Cache = script:WaitForChild("Cache")

function module.newHeader(HeaderName: string, HeaderColor: Color3, Priority: number, UserIds: array)--HeaderName = AreaName; Priority = Closest to the top of the list: 1 = top
	local self = {}
	self.Header = HeaderName
	self.HeaderColor = HeaderColor
	self.Priority = Priority
	self.Users = UserIds
	
	return setmetatable(self, module)
end

function module:create(parent)
	for i, v in pairs(self.Users) do
		print(i, v)
		local List = Cache:WaitForChild("List"):Clone()

		local Text = List:WaitForChild("A")
		Text.Text = self.Header
		Text.TextColor3 = self.HeaderColor

		local UserFrame = List:WaitForChild("User")
		local UserNameText = UserFrame:WaitForChild("Username")
		local UserProfileImage = UserFrame:WaitForChild("ImageLabel")
		local UserSkills = UserFrame:WaitForChild("Skills")
		
		UserSkills.TextColor3 = self.HeaderColor
		UserSkills.Text = table.concat(v["Info"], ", ")
		
		UserNameText.Text = PLAYERS:GetNameFromUserIdAsync(v["UserId"])
		UserProfileImage.Image = PLAYERS:GetUserThumbnailAsync(v["UserId"], Enum.ThumbnailType.HeadShot, Enum.ThumbnailSize.Size150x150)
		
		if #self.Users > 1 then
			UserFrame:WaitForChild("UISizeConstraint").MaxSize = Vector2.new(300, 65)
			UserFrame:WaitForChild("UISizeConstraint").MinSize = Vector2.new(300, 50)
			
		elseif #self.Users <= 1 then
			UserFrame:WaitForChild("UISizeConstraint").MaxSize = Vector2.new(250, 85)
			UserFrame:WaitForChild("UISizeConstraint").MinSize = Vector2.new(250, 50)
		end
		
		if i > 1 then
			UserFrame.Parent = parent:FindFirstChild(Alphabet[self.Priority])
			
			List:Destroy() --Can prevent a memory leak I think
		elseif i <= 1 then
			List.Name = Alphabet[self.Priority]
			List.Parent = parent
		end
	end
end

return module

Themes Module:

local Themes = {
	
	["Dark"] = {
		
		["Main"] = Color3.fromRGB(50,50,50); --Titles/Layers/etc
		["Second"] = Color3.fromRGB(35,35,35); --background
		["Text"] = Color3.fromRGB(255,255,255);
		["UiStroke"] = Color3.fromRGB(255,255,255);
		
		["Font"] = Enum.Font.SourceSansBold;
		
	};
	
	["Light"] = {
		
		["Main"] = Color3.fromRGB(255, 255, 255);
		["Second"] = Color3.fromRGB(190, 190, 190);
		["Text"] = Color3.fromRGB(0, 0, 0);
		["UiStroke"] = Color3.fromRGB(0, 0, 0);
		
		["Font"] = Enum.Font.SourceSansBold;
		
	};
	
	["Lunar"] = {
		
		["Main"] = Color3.fromRGB(31, 13, 88); 
		["Second"] = Color3.fromRGB(23, 18, 53);
		["Text"] = Color3.fromRGB(255, 255, 255);
		["UiStroke"] = Color3.fromRGB(136, 0, 255);
		
		["Font"] = Enum.Font.SourceSansBold;
		
	};
	
}

local module = {}

function GetThemeFromString(Name: string)
	if typeof(Name) == "string" then
		for k, v in pairs(Themes) do
			if Name:match(k) then
				print(v)
				return v
			end
		end
	end
end

function module.ChangeThemes(UI: ScreenGui, theme: string)
	local selectedTheme = GetThemeFromString(theme)
	
	for i, v in pairs(UI:GetDescendants()) do
		if v:IsA("Frame") or v:IsA("ScrollingFrame") then
			if v:GetAttribute("FrameType") then
				print(v)
				v.BackgroundColor3 = selectedTheme[v:GetAttribute("FrameType")]
			end
			
		elseif v:IsA("TextLabel") or v:IsA("TextButton") then
			v.Font = selectedTheme["Font"]
			if v.Name ~= "Skills" and v.Name ~= "A" then
				v.TextColor3 = selectedTheme["Text"]
			end
			
		elseif v:IsA("UIStroke") then
			v.Color = selectedTheme["UiStroke"]
		end
	end
end

return module