Introduce my UI Module

Hello my fellows : P
I’m here to introduce the module which might help you in GUI field, especially tween one

Why should I use this module?

  • In case you want to make an animation for a Frame or Textbutton, you have to use TweenService and add a bunch of things, but with this module, it will make your code much more clear.

Suppose, I want to make hover animation for all buttons, if I don’t use UI Module it will takes a lot of time to make the animation

overview:


all buttons Size have set to Scale

without module:

local TS = game:GetService("TweenService")
local duration = 0.1
local scale = 1.05
local tweenInfoHover = TweenInfo.new(duration, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
local tweenInfoUnhover = TweenInfo.new(duration, Enum.EasingStyle.Quad, Enum.EasingDirection.In)

local ScreenGui = script.Parent

for _, button in ScreenGui:GetChildren() do
	if button.ClassName ~= 'TextButton' then continue end
	
	local originalSize = button.Size
	
	local Hover = TS:Create(button,tweenInfoHover,{Size = UDim2.fromScale(originalSize.X.Scale * scale, originalSize.Y.Scale * scale)})
	local Unhover = TS:Create(button,tweenInfoUnhover,{Size = originalSize})
	
	button.MouseEnter:Connect(function()
		Hover:Play()
	end)
	
	button.MouseLeave:Connect(function()
		Unhover:Play()
	end)
end

with module:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UI = require(ReplicatedStorage:WaitForChild("UI"))
local ScreenGui = script.Parent
local duration = 0.1
local style = 'Quad'

for _, button in ScreenGui:GetChildren() do
	if button.ClassName ~= "TextButton" then continue end
	local newUI = UI.new(button)
	
	newUI
		:Hover(function()
			newUI:Rescale(1.05,duration,style)
		end)
		:UnHover(function()
			newUI:Rescale(1,duration,style,'In')
		end)
end

both of them work at the same thing. But according to the code I send above, the one with module is way less code than the first one.

Plus, when using hover event from the UI Module, it supports sound effect, all you gotta do is change the other audio from Sound Folder

Here’s the file:
UI.rbxm (11.7 KB)

Everything has explained in HowtoUse Folder to use the module

Here’s what I want to achieve in this post:

  1. make the module itself run faster (optimization)
  2. add more functions (ideas)
  3. get feedback from you (yes you)

DISCLAIMER:
all functions that using TweenService cannot stop tween while playing
the UI Module is still in early development (there might be some bugs)

Thank you!

That’s pretty bad because
TweenService is already super abstracted, and your module makes it much worse as well as makes it somehow even less optimized. I was expecting you to simply make a function to act as a macro, but you went the OOP-slop path, sadly.
Also does not have strict mode, which makes it pretty hard to read.


More: rather than using strict types to lint issues without loss of performance, you… LITERALLY bloat and destroy all of performance with A LOT of dynamic checks.


All remaining “typecheck” hints make absolutely no sense:
image
image
image
Luau is not JavaScript. Luau is meant to be used for sandboxed modding (like Roblox) and to run on any hardware (must be pretty optimized), but you attempt to enforce non-compatible, bad-performance-wise paradigms from Python and JS.

The whole module is just filled with bad decisions. I’m sorry, but it is, in fact, the truth.


TL;DR:
Overall, the design choices here harm performance and readability. If you want this to shine, I’d recommend rethinking the OOP-heavy approach and focusing on lightweight utility functions with strict mode.

3 Likes

I think you should learn how UI frameworks are typically set up, because they solve this problem the best. Some UI frameworks you can try include Seam (my own), Fusion, Vide, or React.

Here is a Tween example with Seam:

local Button = script.Parent -- Is an image button
local State = Value("Idle")

New(Button, {
	Size = Tween(Computed(function(Use) -- Tween size based on state
		if Use(State) == "Idle" then
			return UDim2.fromScale(0.3, 0.05)
		elseif Use(State) == "Hover" then
			return UDim2.fromScale(0.325, 0.05)
		end
	end), TweenInfo.new(0.3)),
	
	[OnEvent "MouseEnter"] = function()
		State.Value = "Hover"
	end,
	
	[OnEvent "MouseLeave"] = function()
		State.Value = "Idle"
	end,
})

Which looks like this:

RobloxStudioBeta_6Gy7EtbUPi


As for what you have, here are my complaints:

  • You should not have sound instances inside your module, it’s bad practice
  • Your events and effects are extremely specific to certain niche cases, and not broad enough to be flexible to what people might actually need
  • Documentation is not readable, you should really document things outside of your code
  • You can’t cancel animations
  • You should input properties as dictionaries when there are as many as there are
  • Effect and event method names are not that great
  • The syntax is overall not that readable
3 Likes

Thank you for your thought!
Perhaps, I have to get some practical experience

Here’s what I don’t understand

This is my first time hearing OOP and macro.

Can you give me any source for these stuffs?
That would be extremely helpful.

1 Like

Macro usually refers to automatization of repeatable pattern.
In a way function could be a “macro” if compiler desides to inline it.

You’re right, I’ll note that :memo:

My English is pretty bad, so there are some points that I can’t get it.

Here’s what I understand so far:

  • You should not have sound instances inside your module, it’s bad practice
    → That’s mean adding sound is unnecessary (user can use their custom sound folder instead). The main thing about module is just UI, so I get to focus on this major problem rather than putting something else.

  • Your events and effects are extremely specific to certain niche cases, and not broad enough to be flexible to what people might actually need
    → hmm :thinking: maybe add more functions?

  • Documentation is not readable, you should really document things outside of your code
    → Okay, I have to learn how to make documentation in specific way but readable, and put it outside the module as well.

  • You can’t cancel animations
    → You’re right, that’s one of the biggest cons from the UI Module. What do you think if I should restart to create this module from the 0?

  • You should input properties as dictionaries when there are as many as there are
    → I don’t understand this one

  • Effect and event method names are not that great
    → I don’t know how to make a name that goes straight to the point :sob: ; can you give me some practice to naming a function? Or maybe I should find it by myself :slight_smile:

  • The syntax is overall not that readable
    → That’s true. Would it be okay, if you can give me some source to make a good syntax structure?

I mean, yes, sound is not needed, but I meant putting the actual instances in your module is bad practice.

No, you need to rethink how your UI module works. Like I said, look at how UI frameworks do it – they are state-based and reactive, and that means you can have one state that you can reuse anywhere and everywhere. Animations in those frameworks are more fleshed-out states that can react to other states, and etc.

Here is my example I gave earlier, but rearranged and with more comments to help you break it down:

local State = Value("Idle") -- The most basic type of state

local TweenTarget = Computed(function(Use) -- Tween size based on state
	if Use(State) == "Idle" then -- Is the state "Idle"?
		-- If so, use the normal size
		return UDim2.fromScale(0.3, 0.05)
	elseif Use(State) == "Hover" then -- Is the state "Hover"?
		-- If so, make the size bugger
		return UDim2.fromScale(0.325, 0.05)
	end
end)

New(Button, {
	-- Basically, instead of just snapping to two sizes (via computed),
	-- we can input the computed state into a tween state and thus make
	-- it animate.
	
	Size = Tween(TweenTarget, TweenInfo.new(0.3)),

	[OnEvent "MouseEnter"] = function() -- Same as Button.MouseEnter:Connect(function)
		State.Value = "Hover"
	end,

	[OnEvent "MouseLeave"] = function() -- Same as Button.MouseLeave:Connect(function)
		State.Value = "Idle"
	end,
})

I seriously recommend you read the docs and TRY one of these UI frameworks to see how they work. And hey, who knows, maybe you find that they solve the problems you had and thus you don’t need to make a UI module.

So instead of something like this:

local function TestFunction(Foo : number, Bar : string)
	print(Foo, Bar)
end

You do something like this:

local function TestFunction(Options : {Foo : number, Bar : string})
	print(Options.Foo, Options.Bar)
end

Try researching naming conventions for code.

Again, UI frameworks solve this problem.

1 Like

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