[Release]: Fade ScreenGui Module

Hello! :wave:

I’ve created a very useful ModuleScript that will greatly improve your :sparkles: quality of life :sparkles: (it’s free too!)

Short Summary

This ModuleScript can fade in and out ScreenGui’s by calling its “toggleWindow”-function.

The ScreenGui(s) can be referenced in the ModuleScript and that’s all the setup you need!!

View The ModuleScript In Action (+Tutorial)

Get The ScriptModule For Free

Roblox Model Link

Code

Here’s The Code Of The ScriptModule:

-- Place this ModuleScript preferably in your StarterGui. It should be placed somewhere where the client can reach it from a LocalScript.

-- Services & References
----------------------------------------------------------------------------------------------------
local TweenService = game:GetService('TweenService')
local windowInstances = {}
local initialValue = {}
----------------------------------------------------------------------------------------------------

-- Variables you can change
----------------------------------------------------------------------------------------------------
local fadeTime = .1 -- seconds
local tweenInfoFast = TweenInfo.new(fadeTime, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut)

-- These are the property-values you want to keep/save when fading in the ScreenGui
------------------------------------------------------------------------------------
local instanceValuesToKeep = {
	['Frame'] = { 'BackgroundTransparency' },
	['TextLabel'] = { 'TextTransparency' },
	['ImageLabel'] = { 'BackgroundTransparency', 'ImageTransparency' },
	['TextButton'] = { 'BackgroundTransparency', 'TextTransparency' },
	['ImageButton'] = { 'BackgroundTransparency', 'ImageTransparency' },
	['ViewportFrame'] = { 'BackgroundTransparency', 'ImageTransparency' },
	['ScrollingFrame'] = { 'ScrollBarImageTransparency' },
}
------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------

-- Functions
----------------------------------------------------------------------------------------------------
function fadeIn(tweensForFadeIn: { Tween }, window: ScreenGui)
	window.Enabled = true
	for _, tween in ipairs(tweensForFadeIn) do
		tween:Play()
	end
end

function fadeOut(tweensForFadeOut: { Tween }, window: ScreenGui)
	for _, tween in ipairs(tweensForFadeOut) do
		tween:Play()
	end
	wait(fadeTime)
	window.Enabled = false
end

function toggleWindow(window: ScreenGui)
	if windowInstances[window] then
		local tweensForFadeIn = {}
		local tweensForFadeOut = {}

		for j, element in pairs(windowInstances[window]['elements']) do
			local fadeIns = {}
			local fadeOuts = {}

			-- Here I have added a "special" condition. If an element has the name "Window", it will fade in to 0.2 Transparency and also move 20 pixels up/down accordingly.
			-- You can add more of these by creating else if's under it.
			-- The reason I added this condition was so that the window would add or subtract 20 pixels to its original position. Now it is compatible with e.g. dragging it around.
			----------------------------------------------------------------------------------------------------
			if element.Name == 'Window' then
				fadeIns = { BackgroundTransparency = .2, Position = element.Position - UDim2.new(0, 0, 0, 20) }
				fadeOuts = { BackgroundTransparency = 1, Position = element.Position + UDim2.new(0, 0, 0, 20) }
				------------------------------------------------------------------------------------------------

			else if initialValue[element] then
					fadeIns = initialValue[element]
					for s, propert in pairs(fadeIns) do
						fadeOuts[s] = 1
					end
				end
			end

			if fadeIns ~= {} then
				table.insert(tweensForFadeIn, TweenService:Create(element, tweenInfoFast, fadeIns))
				table.insert(tweensForFadeOut, TweenService:Create(element, tweenInfoFast, fadeOuts))
			else
				print('NO INITIAL VALUES FOUND!!! Something has gone terribly wrong with the element:',element)
			end
		end
		if window.Enabled then
			_G.lockMouse = true
			fadeOut(tweensForFadeOut, window)
		else
			_G.lockMouse = false
			fadeIn(tweensForFadeIn, window)
		end
	else
		print("Instance has not been referenced yet!")
		addFromScreenGui(window)
		toggleWindow(window)
	end
end

function hideWindow(window: ScreenGui)
	if window.Enabled then
		toggleWindow(window)
	end
end

function showWindow(window: ScreenGui)
	if not window.Enabled then
		toggleWindow(window)
	end
end

function saveInitial(elements: { Instance })
	local elementsToKeep = {}
	for i, element in pairs(elements) do
		-- Check if classname is referenced in instanceValuesToKeep array
		local valuestoKeep = instanceValuesToKeep[element.ClassName]

		-- Check if instance name is referenced in instanceValuesToKeep array
		if valuestoKeep == nil then
			valuestoKeep = instanceValuesToKeep[element.Name]
		end

		-- If classname or name was found;
		if valuestoKeep then
			for j, property in pairs(valuestoKeep) do
				if initialValue[element] == nil then
					initialValue[element] = {}
				end
				-- Set value if property doesnt exist
				if initialValue[element][property] == nil then
					initialValue[element][property] = element[property]
				end
			end

			table.insert(elementsToKeep, element)
		else
			--print('No data-properties set for: ',element.ClassName)
		end
	end
	return elementsToKeep
end

function saveInstances(screenGui: ScreenGui, keep: { Instance })
	if keep then
		if windowInstances[screenGui] == nil then
			windowInstances[screenGui] = {
				['elements'] = {}
			}
		end

		local existing = windowInstances[screenGui]['elements']
		local tab = {}

		if existing ~= {} then
			for i, a in ipairs(existing) do
				table.insert(tab, a)
			end
		end

		-- Check if instance is already saved
		for j, b in ipairs(keep) do
			if not table.find(existing, b) then
				table.insert(tab, b)
			end
		end

		windowInstances[screenGui]['elements'] = tab
	end
end

function addFromScreenGui(screenGui: ScreenGui)
	local allChildren = screenGui:GetDescendants()
	local keep = saveInitial(allChildren)
	saveInstances(screenGui, keep)
end
----------------------------------------------------------------------------------------------------

-- Add your ScreenGui's here or require() the moduleScript and call moduleVarName.addFromScreenGui()
----------------------------------------------------------------------------------------------------
addFromScreenGui(game.Players.LocalPlayer.PlayerGui:WaitForChild('Equipment'))
addFromScreenGui(game.Players.LocalPlayer.PlayerGui:WaitForChild('Inventory'))
addFromScreenGui(game.Players.LocalPlayer.PlayerGui:WaitForChild('Loot'))
addFromScreenGui(game.Players.LocalPlayer.PlayerGui:WaitForChild('ItemWheel'))
addFromScreenGui(game.Players.LocalPlayer.PlayerGui:WaitForChild('SettingsMenu'))
----------------------------------------------------------------------------------------------------

return {
	toggleWindow = toggleWindow,
	addFromScreenGui = addFromScreenGui,
	showWindow = showWindow,
	hideWindow = hideWindow,
}

Text Tutorial

  1. Insert the ModuleScript somewhere where the client can require() the ModuleScript (preferably StarterGui-folder).

  2. Edit the ModuleScript and change the fadeTime to your desired time in seconds. This controls how fast the ScreenGui will fade (it affects all ScreenGui’s referenced):

local fadeTime = .1 -- seconds
  1. Scroll to the bottom and edit/replace the example-references with your own desired ScreenGui(s):
addFromScreenGui(game.Players.LocalPlayer.PlayerGui:WaitForChild('ScreenGuiName'))
  1. You’re all set! Now you can add a reference to the toggleWindow() function and call it from your LocalScript:

Here’s an example of what your LocalScript could look like

This LocalScript should be placed as a direct child of the ScreenGui you wish to fade:

-- Window Toggle Module Starts Here
--------------------------------------------------------------
local windowToggle = require(game.Players.LocalPlayer.PlayerGui:WaitForChild('Modules'):WaitForChild('FadeScreenGuiModule'))
--------------------------------------------------------------

-- Functions
--------------------------------------------------------------
function toggleInventory()
	windowToggle.toggleWindow(script.Parent)
end
--------------------------------------------------------------

-- Complete button
--------------------------------------------------------------
script.Parent.Window.Complete.Activated:Connect(toggleInventory)
--------------------------------------------------------------

Aditional Features

Add During Runtime

If you want to add your ScreenGui during runtime, you can do so by Requiring the ScriptModel in a LocalScript and by calling the addFromScreenGui() function, with your new ScreenGui as its parameter.

Here’s an example:
local MyNewScreenGui = script.Parent

local windowToggle = require(game.Players.LocalPlayer.PlayerGui:WaitForChild('Modules'):WaitForChild('FadeScreenGuiModule'))

windowToggle.addFromScreenGui(MyNewScreenGui)

ScreenGui Hierarchy

Below is an example of how the hierarchy of your ScreenGui could look like.
The ScriptModule does not care about how things are setup, it will only fade Transparency values (unless the name of the Instance is called “Window” exactly)

Prevent elements inside scripts to update

The Script Module does not contain an exclusion-mode, considering it does not crawl through the elements children. I use the :GetDescendants function, which doesn’t allow much room for customization.

Therefore, if you wish to exclude any elements, such as elements inside of LocalScripts or elements that are used as templates; I suggest placing them inside the ReplicatedFirst folder, and reference them from there. This will leave them unchanged by the Script Module.

Specifically Show or Hide ScreenGuis

You can show a ScreenGui by using the showWindow() function. To hide a ScreenGui, use hideWindow()
The example below will show a screengui when Q is held down and hide it once Q is released.

Here’s an example:
local windowToggle = require(game.ReplicatedFirst:WaitForChild('Modules'):WaitForChild('FadeScreenGuiModule'))
local UserInputService = game:GetService("UserInputService")

-- Input
--------------------------------------------------------------
UserInputService.InputBegan:Connect(function(input)
	if input == Enum.KeyCode.Q then
		windowToggle.showWindow(script.Parent)
	end
end)

UserInputService.InputEnded:Connect(function(input)
	if input == Enum.KeyCode.Q then
		windowToggle.hideWindow(script.Parent)
	end
end)
--------------------------------------------------------------

In-Depth Tutorial

As per requested by a commentor, I’ve created a short in-depth video-tutorial from start to finish on how to use this ModuleScript.

Check it out here:

Future Changes

Add support for more InstanceTypes

As of right now, I have only included support for a handful of InstanceTypes. These are the most common ones I’ve used, however the ModuleScript can have its usability improved if more InstanceTypes were to be added.

Below is an example of the InstanceTypes currently supported. You can expand this list and specify which Properties of each InstanceType you wish to “Save” when fading in values.

local instanceValuesToKeep = {
	['Frame'] = { 'BackgroundTransparency' },
	['TextLabel'] = { 'TextTransparency' },
	['ImageLabel'] = { 'BackgroundTransparency', 'ImageTransparency' },
	['TextButton'] = { 'BackgroundTransparency', 'TextTransparency' },
	['ImageButton'] = { 'BackgroundTransparency', 'ImageTransparency' },
	['ViewportFrame'] = { 'BackgroundTransparency', 'ImageTransparency' },
	['ScrollingFrame'] = { 'ScrollBarImageTransparency' },
}

Better Documentation

This post could be improved(?) and more comments could be added to the ModuleScript, explaining its core functionality better.

Add More Examples

More Example-scripts should be added to improve readability and intuity.

Feedback Is Always Appreciated!

If you have any feedback, it is greatly appreciated! I wish to improve this script, therefore any feedback (both positive and negative) is welcome :smiling_face_with_three_hearts:

24 Likes

This is a well-designed resource that would probably be very popular. Good job!

The only question I have is: Why create the module if the CanvasGroup object is being released by Roblox? I believe both do the same thing in general.

3 Likes

Hey, Dan :grinning:
Thank you!

To be honest, I am not 100% up to speed with Roblox’ future changes and didn’t know about this :sweat_smile: I also wanted to create something modular and reusable, where I’d have more control over my ScreenGui(s).

The goal was to collect all functions into a singular point that could be referenced from multiple entries.

I’ve read up on the CanvasGroup now and I can tell it is almost exactly the same as my ModularScript :joy: However I beleive, and hope, that this ModularScript could come in handy for someone needing help with their functions or methods.

I am very confident that the up-and-coming CanvasGroup will be an awesome asset to have nonetheless.
Thanks for telling me about the CanvasGroup! :grin:

Recent Updates:

  • Added a nil-check to see if an instance already is referenced (prevent duplicates)

  • Added a nil-check to see if an initial-value has already been defined (in order to prevent overwriting values if you plan on updating the referenced instances)

  • Added ImageLabel to the list of supported ui-elements

  • Added a failsafe for when the ScreenGui has not been referenced and is called to fade. It is no longer necessary to reference the ScreenGuis at the bottom of the ModuleScript, however it is strongly recommended to reference them, to prevent bugs

  • Added functions to Show or Hide screenguis: showWindow() and hideWindow()

  • Added more script-examples to documentation

1 Like

i found a glitch if you added a object during the tween the object will. be glitched

1 Like

Hey, paulocezarnbr!

Are you able to give me some more info regarding this?

Correct me if I am wrong:

  • When you execute the .toggleWindow(ScreenGui)-function, while the Tween is playing, add a UI-Element that has not been referenced yet, does that produce the “glitch” you are referring to?
1 Like

yes i have a inventory system that add new elements every time.

1 Like

I think what could solve your issue is to call addFromScreenGui() before calling toggleWindow().

Like this:

local MyScreenGui = script.Parent

local windowToggle = require(game.Players.LocalPlayer.PlayerGui:WaitForChild('Modules'):WaitForChild('FadeScreenGuiModule'))

function toggleInventory()
	windowToggle.addFromScreenGui(MyScreenGui) -- Add new elements to reference
	windowToggle.toggleWindow(MyScreenGui) -- Toggle window
end

-- Now call toggleInventory() whenever you need to toggle your inventory.

Make sure the items added to your inventory are visible before calling addFromScreenGui().

Let me know if this works! :+1:
Else I will create a fallback for when descendants are not already referenced :slight_smile: