Introduction!
GUIFramework contains of a LocalScript and Module’s to automate the process of animating buttons,
opening & closing frames and highlights unrestricted custom click actions
An important fact is to give user’s with little to none scripting knowledge
the ability to use this framework regarding the major aspects
Everything is picked up by Tags & Attributes within your own GUI elements
Framework’s couple major aspects:
- Hover and click animations
- Sounds whenever interacted with buttons
- Visibility of GUI containers
- Handling of frame opening & closing
- Custom components which execute on button clicks
Difference to other UI frameworks
This framework is purely meant for aspects mentioned above
Any UI element is created by you, and not this framework
Don’t be confused regarding roact or fusion
In this framework we don’t build nor define new UI elements by code
It is no where near to replace/mimic roact nor fusion, those have completely different usage visions
This is mostly an automation framework to handle various tasks
For basic usage;
- Button animations
- Frame opening and closing
- Container visibility
For advanced/custom usage; Yes - You may add script’s
- Toggleable buttons
- Custom components that take action on click
Custom components are optional additions to frame functionality
Custom components are covered in the section: How to use
Who is this meant for? (& benefits)
Developer’s who are looking for a well designed solution which commits to basic but time consuming task(s). Including this to your existing (or new) game is fairly easy as it doesn’t spread around your entire game as much
How the explorer looks after a successful setup
Once properly setup - significant time will be saved while adding new buttons & frames
In addition the framework provides basic & advanced functionality as it allows creating your own components. These components will execute when a button with the same name is pressed.
How to use
Demo Video
Installation & Setup
This how-to-do explains the instructions on a new place
1. Create a new place and ungroup the file to its path
2. Creating a left-sided container (01:13)
As we make the left container, an important thing to note is to add the tag Button
into the ImageButton’s
We do this to tell the framework:
- The button wants to be animated
- The button wants to open/close a frame
3. Creating frames (01:15)
As you can see: the frame’s are opened and closed - We haven’t edited a single script yet
For a frame to be opened by a button, it is important to name your frame and button equally; otherwise they’re not “linked” to each other
Definiton of "Linked"
With the use of CollectionService our framework is able to see every button with our tag Button
Our LocalScript GraphicalUserInterface
then handles the step of trying to open a frame whenever a button is pressed on
Information about close buttons
Both works to close the opened frame:
- Pressing the same ImageButton
- Using the close button
When a new frame is loaded in, and a button named Close
is added, the framework then automatically applies the button animation and listens for a click, to close the opened frame
4. Creating a right-sided container (00:53)
We repeat the process done as in step 2. but this time our container is on the right side
As our buttons match the frame’s name, each button is responsible to open its linked frame
5. Container Visibility (Fullscreen & Non-Fullscreen) (01:04)
How do we make everything else from the screen be gone when a specific frame is shown?
Short
Frame3
[Tags]: Fullscreen
Left
[Tags]: FullHide
[Attributes]: HidePosition UDmi2 {-0.2, 0},{0.5, 0}
Right
[Tags]: Hide
[Attributes]: HidePosition UDmi2 {1.2, 0},{0.5, 0}
-
At first we select
Frame3
from our GUI storage and add the tag Fullscreen to it
This frame basically says “Hey! I want to be in fullscreen!” → See how both containers move out -
Then we add the tag FullHide to our container
Left
The left container only vanishes when an inserted frame with the tag Fullscreen is loaded in -
Container
Right
also needs to be tagged, but this time with Hide as we want our container to disappear when any frame is loaded in -
Lastly, both container’s need an attribute: UDmi2 HidePosition in order to define the container’s move position when being forced to leave the screen
6. Button Interaction Sounds
Provided sounds from creator store can be downloaded here
I do not own these sounds; all credits go to the owner(s)
Sounds.rbxm (2.0 KB)
Make sure to ungroup the model from the .rbxm
file above
With that done, we have just added interaction sound’s to the framework
As of now; the sound name’s need to be as provided otherwise edit of source code is required!
7. Invite Button: Adding a component (PreClone)
We have already created a button named “Invite”, but we didn’t add a frame
as none pre-made frame should be opened, but a specific code run when pressing
that invite button. Our goal is to open the roblox’s invite prompt included in SocialService
Commented snippet of such component
local SocialService = game:GetService("SocialService")
return function(self)
-- check if the player can invites
local success, result = pcall(SocialService.CanSendGameInviteAsync, SocialService, self.player)
if (result) then
-- if a frame is opened; close it
if #self.insertedGui:GetChildren() > 0 then
self:Insert(self.insertedGui:GetChildren()[1].Name)
end
-- prompting roblox's invite frame
SocialService:PromptGameInvite(self.player)
end
-- returning false instead of true
-- to stop further code from running
return false
end
PreClone & PostClone (Custom Components)
What are, when and where do both take part?
Let custom actions happen when a button is clicked - adding new behaviours!
When your button is pressed, the framework looks for a components name which equals to the buttons name; if found → the function returned by the component is called
Two folder’s can be found parented to HandlerGui
; there you’ll have to add your ModuleScripts
More information is given further down this section
Explorer image with both folders
When adding a component to PostClone
folder,
the module will run after the clone of the frame but before parenting it!
Talking about PreClone
When adding a component to PreClone
folder
the module will run before the clone of the frame.
Why’s it useful?
When the component returns false - the code to run the cloning will be canceled meaning it won’t try handling a frame.
An example of usage is covered in [Installation & Setup]
API Documentaton
As previously said, this framework uses module’s
Made with 2 modules, with both serving their own purpose
Covered in this documentation HandlerGUI
, ButtonAnimation
and GraphicalUserInterface
GraphicalUserInterface (LocalScript)
Everything explained in the code - if something is unclear let me know
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local CollectionService = game:GetService("CollectionService")
local player = game:GetService("Players").LocalPlayer
player.PlayerGui:WaitForChild("Modules")
-- requiring both modules
local ButtonAnimation = require(player.PlayerGui.Modules.ButtonAnimation)
local HandlerGUI = require(player.PlayerGui.Modules.HandlerGUI)
local AnimationClassBlacklist = {"ImageLabel"}
function ButtonAdded(button)
-- ButtonAnimation is called to have our button animated
ButtonAnimation(button)
if table.find(AnimationClassBlacklist, button.ClassName) then
return
end
-- calls 'HandlerGUI' with 'button.Name' which is the frame we want to open/close
-- inside the module: a frame's name equal to the button name which is clicked is opened/closed
-- further details in the 'HandlerGUI' documentation: HandlerGUI:Insert(frameName: string, ... : any): ()
button.MouseButton1Up:Connect(function()
HandlerGUI(button.Name)
end)
end
for _, button: ImageButton in next, CollectionService:GetTagged("Button") do
if not button:IsDescendantOf(ReplicatedStorage.GUI) then -- skipping buttons that are inside our GUI storage
-- calls 'ButtonAdded' for every already existing button with tag 'Button'
ButtonAdded(button)
end
end
-- call 'ButtonAdded' whenever a new button with tag 'Button' is added
CollectionService:GetInstanceAddedSignal("Button"):Connect(ButtonAdded)
HandlerGUI (Module)
An example of usage can be found in the provided GraphicalUserInterface
LocalScript
When trying to open a frame from outside the module’s we’ll have to do following:
Module Main
is the worker to handle this when HandlerGUI
Main
is the function that listens for table calls __call = require(script.Main)
Which if no debounce is active, the provided frame is handled
More on the debounce
The time which a debounce is present for, is the time a frame takes to open
Time can be adjusted in the config file defaultSpeed
. It can be acquired within the module as self.defaultSpeed
HandlerGUI functions:
HandlerGUI:Blur(override: boolean?): ()
Function updates the blur state
When override
is given, the blur’s state is forcely set
HandlerGUI:ClearInserted(): ()
Calls :Destroy() on every instance parented to insertedGui
HandlerGUI:CloseButton(frame: GuiObject): ()
Check if a close button inside frame
is given
If found:
- An animation is added (By giving the button a tag Button)
- MouseButton1Up is being connected to close it’s frame when pressed
HandlerGUI:FindInsertedFolder(): (Folder?)
On Module require, this function’s looks for your InsertedGui
Which is in the module itself is referenced to as self.insertedGui
HandlerGUI:Hide(): ()
When called, updates the position of container(s) (Installation & Setup → 5. Container Visibility)
By going through the tags Hide & FullHide
If container’s should move out or in is defined by the amount of children inside self.insertedGui
HandlerGUI:Insert(frameName: string, ... : any): ()
This handles PreClone
& PostClone
; More on that in [How to use] → [PreClone & PostClone (Custom Components)]
If called with frameName
already being inside of self.insertedGui
, it forces the opened to close
If frameName
is not a member of your GUI storage, the function simply returns nil
Happens after PreClone
When the frame is found; it’ll clone and PostClone
runs right after
followed by self:OpenFrame(frame, ...)
& self:CloseButton(frame)
HandlerGUI:OpenFrame(frame: GuiObject, ... : any): ()
Just as the function name says, it opens the frame given
It’s the last function to run when opening a frame
Calling it directly might cause issues; As it force opens the given frame without any checks
Please consider using HandlerGUI:Insert(frameName: string, ... : any): ()
for external usage
HandlerGUI:PlaySound(soundName: string): ()
Looks for a matching sound in SoundService
It clones the sound and applies .PlayOnRemove = true
It’s parented to the workspace and immediately scheduled through Debris
This function is used to play sound’s;
- Button Hover
- Button Click
HandlerGUI:TweenFOV(fieldOfView: number, direction: string?, tweenTime: number?): ()
-
fieldOfView
: CurrentCamera FieldOfView is tweened tofieldOfView
-
direction
: Used for Enum.EasingDirection; If direction is given, parameter will be used for its EasingDirection elseEnum.EasingDirection.Out
is set -
tweenTime
: the time it takes for the fov tween to complete, if not set →self.Config.timeFOV
ButtonAnimation (Module)
Calling ButtonAnimation
In the provided LocalScript GraphicalUserInterface
we see that ButtonAnimation
is also used by directly calling the modules table
→ ButtonAnimation(listen: {Instance}, change: {Instance}?)
What is a worker & when is it created
A new worker is created when calling ButtonAnimation
→ Every worker is unique
It handles the connection part for it’s applied instance(s) of parameter listen
- MouseButton1Down
- MouseButton1Up
- MouseEnter
- MouseLeave
What does ButtonAnimation
return?
It returns function’s, tables, configuration and it’s asigned worker
Most part’s returned can be ignored as it’d be a special usecase
Configuration of a button
What’s more important is being able to change an instances configuration
- Color = Color3
- ScaleFactor = number
-- example of applying an animation to a button
local animation = ButtonAnimation(script.Parent)
Setting a configuration
animation.Config.SetInstanceConfig(button: ImageButton, {Color = Color3, ScaleFactor = number})
This method overwrites the current instance configuration
Updating a configuration
animation.Config.UpdateInstanceConfig(button: ImageButton, {Color = Color3?, ScaleFactor = number?})
- Gets current configuration inside the
config
module -
config
parameter then overwrites the old keys given with the our parameterconfig
- New configuration is returned
Getting a configuration
animation.Config.GetInstanceConfig(button: ImageButton)
Current configuration of button
is returned
An example of changing an instances configuration would
become handy → covered in Installation & Setup
Definition of parameters
listen
- collection of instances which are being connected to
- single instance which is being connected to
A worker is applied to each instance given
More on worker → ButtonAnimation (Module) → Calling ButtonAnimation
If you want multiple buttons to animate whenever any of those are interacted with:
ButtonAnimation({button1, button2, button3})
If you want only a single button to animate:
ButtonAnimation(button)
change
If you want a single button to animate multiple instances simultaneously:
ButtonAnimation(button1, {button2, button3, button4})
If you want a single button to animate another button
ButtonAnimation(button1, button2)
If change is not given, every instance of listen
becomes the change
argument
In the future
- External insertion of PreClone & PostClone
- More config settings
- Source code polishing
and more
Post is soon to be continued with more information covering:
- Toggleable buttons shown in the old post (Updating an instances config - ButtonAnimation)
- PostClone (PreClone is covered)
Old post
Expand
An easy to use framework, aiming to be used by developer’s with and ‘without’ scripting experience!
Accomplished by using Tags & Attributes - suitable for everyone
Handles opening & closing frames with ease!
Click for test place
Features
Button Sounds
Simply create sounds in SoundService set your id and ready!
Note: that those name’s shown need to be matching
Button Container Hiding
Setting Container Tags & Attributes
There’s 2 types of container hiding: fullscreen & non-fullscreen
1. To apply fullscreen:
- Tag your frame with Fullscreen which wants to be in fullscreen!
- Tag your container(s) with FullHide which will only vanish
when a frame with tag Fullscreen is loaded in!
2. To apply non-fullscreen
- Tag your container(s) with Hide to disappear when ANY frame is loaded in
3. Hide Position:
As seen in Images: Explorer & Properties
an attribute is set
- Type: UDmi2
- Attribute name HidePosition
- Defines where container(s) should move when a frame is inserted
Toggleable Buttons
The ButtonAnimation
allows for color switching, but needs some extra code
Code
local player = game:GetService("Players").LocalPlayer
player.PlayerGui:WaitForChild("Modules")
local ButtonAnimation = require(player.PlayerGui.Modules.ButtonAnimation)
local animation = ButtonAnimation(script.Parent)
if player:GetAttribute("Custom1") == nil then
player:SetAttribute("Custom1", false)
end
function Update()
local config = animation.Config.GetInstanceConfig(script.Parent)
config.Color = player:GetAttribute("Custom1")
and Color3.fromRGB(117, 255, 96)
or Color3.fromRGB(255, 69, 72)
animation.Config.SetInstanceConfig(script.Parent, config)
script.Parent.ImageColor3 = animation.Darken(config.Color, 1.25)
end
player:GetAttributeChangedSignal("Custom1"):Connect(Update)
Update()
script.Parent.ImageColor3 = player:GetAttribute("Custom1")
and Color3.fromRGB(81, 255, 69)
or Color3.fromRGB(255, 69, 72)
Reason of implementation:
When a color is switched while hovering, the color would be overwritten with its old color when the hover is ended.
A small example script is provided to prevent this issue from happening
Note: Do not set Button as a tag on the button when using the script, as it would probably cause unknown issues
Automatic GUI Opening
When clicking a button with Button as a tag → clones & opens the frame with an equal name from your GUI folder.
Note: Trying to open an already opened frame will result in an immediate close of it
Automatic Close Button Handling
If you have a close button, name it Close
The framework will handle the MouseClick
Note: Do not set Button as a tag on the close button as its animation will be set automatically!
Programmable Button Actions
PreClone & PostClone
Let actions happen when a button is clicked!
PostClone
When adding a component to PostClone
folder
the module that matches with the button’s name
which as been clicked will run after the clone
of the frame but before parenting it!
Meaning you can change the frame however you want!
Example with attributes
ModuleScript Setup
return function(self, frame, attribute)
frame:SetAttribute("TestAttribute", attribute)
end
LocalScript Setup
LocalScript [Button]:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local player = game:GetService("Players").LocalPlayer
player.PlayerGui:WaitForChild("Modules")
local HandlerGUI = require(player.PlayerGui.Modules.HandlerGUI)
local ButtonAnimation = require(player.PlayerGui.Modules.ButtonAnimation)
ButtonAnimation(script.Parent)
script.Parent.MouseButton1Up:Connect(function()
HandlerGUI(script.Parent.Name, "Hello World")
end)
LocalScript [Frame]:
script.Parent.TextLabel.Text = `"{script.Parent:GetAttribute("TestAttribute")}"`
Result:
Realworld usecase with attributes:
Let’s say your first frame has a grid menu with buttons
6 Buttons - each button has its own unique number (1 to 6)
When clicked - another frame should be opened but with information
about the interaction that happened on the first frame
Now the localscript from above becomes handy
as it passes information to second frame before its parented.
PreClone
When adding a component to PreClone
folder
the module that matches with the button’s name
which as been clicked will run before the clone.
Why’s it useful?
When returning false - the code to run the cloning will be canceled meaning it won’t try opening a frame.
An example with an invite prompt is shown in the video at the top of this post!
Invite Prompt
local SocialService = game:GetService("SocialService")
return function(self)
local success, result = pcall(SocialService.CanSendGameInviteAsync, SocialService, self.player)
if (result) then
if #self.insertedGui:GetChildren() > 0 then
self.Components:Insert(self.insertedGui:GetChildren()[1].Name)
end
SocialService:PromptGameInvite(self.player)
end
return false
end
For purchases: Direct Message or mitex7183
Price at 30K
Made by @mitex7183
END OF OLD POST
Post will most likely be adjusted over the time
Last updated: 2024-06-13T18:08:00Z
For purchases: Direct Message or mitex7183
About feedback and suggestions
For constructive feedback and suggestions write on this post
With a clearer vision of this framework, it is highly appreciated to help improve it along the way
Let me know if any aspects and or features are unclear - I’ll adapt this post
Thanks!
Price at 12.5K
I understand many people in this post are upset/making fun of the high price
However; it is my project and I am the only to decide for what price I want to sell my work for.
Justified or not is each persons opinion
This framework is aimed to be an easy to follow addition to games
Made by @mitex7183
Post will most likely be adjusted over the time
Last updated: 2024-06-15T21:22:00Z