UI made with Fusion (the better roact /wink/)

I was for a long time trying to understand how to use Roact. Couldn’t.
There’s not enough data out there that is targeted to people that don’t understand how building UI is with code. Roact’s documentation for instance for me feels like it ignores anyone who doesn’t understand those concepts.

So, I gave up, was like “Who cares? I’m going to continue just doing what I always did.”
On that same day (today/yesterday) Fusion was released.

I was like “OMG COOL”, and that’s fine, I was yeah I’m not gonna use it.
Then I tried it out… I could not stop. Playing with Roact was unfun, confusing, made me anxious.
Not the case with Fusion.

Using Fusion was fun, simple, fast, didn’t make me mad, and most importantly it was straight-forward.

Fusion is way more targeted torwards simpler use, and that’s really cool, because it allows you to do things way more easily, without as much code or memory being used.

For instance, Fusion doesn’t have trees / mounting. It just returns you the instance you created. Making tweening way easier and for my use cases, convenient.
Fusion does have a tweening part dedicated to it, I have not used it, I only used pure TweenService at this time, and even then it was still extremely straight forward to do it.

While the code I set up everything with is not the best most perfect code, it works, just fine, runs, just fine, and it’s mostly pretty scalable, not hard to add new menus and buttons to it.

It is extremely simple right now, but the important thing is that I was able to do it. Something I never could with Roact because of it’s complexity.

If you wanna learn how to use Roact, don’t. I highly recommend that you check out Fusion instead as your first library to use, I can guarantee you won’t regret it.

With all that said,
Here’s what I’ve got so far.

You can also test it out yourself in here.


Right now, it’s just a simple button that tweens an menu, but for me, it was something I could’ve not done before, and that’s an achieving for me.

Also, yes I will be adding more into this, expanding this UI project to use all features I can test.
Any updates will be posted here.

If you wanna check out Fusion (please do), check it out here:

Go on releases, get the .rbxm file and import it to your game.

22 Likes

Nice job, the UI looks modern and nice and the UI animation is smooth.

1 Like

Fusion looks very interesting and I’ve been following it since its “Components” days. Will definitely be giving it a try at some point, and seeing how it compares with Roact.

2 Likes

This seems like a pretty good module and Yes I am going to use parentheses,
It took me a decade amount time to understand the module, and I have to say it pretty good, but there were some problems that confused me a bit,

Problems I had

First let say I wanted to play a sound, by pressing a button, but I couldn’t really find a way for me to use Play(), I thought the state might work but I realize there was no way to called Play() from the text button table. Also is OnEvent an RBXScriptSignal, I’m been trying to figure out a way to disconnected it

Overall

this is a pretty good module, it is easier than roact, I did manage to create a simple toggle on which was pretty fire.

source code
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local LocalPlayer = game:GetService("Players").LocalPlayer
local Fusion = require(ReplicatedStorage.Fusion)

FrameVisible = Fusion.State(false)

local ScreenGui = Fusion.New("ScreenGui") {
	Enabled = true,
	IgnoreGuiInset = true,
	
	ResetOnSpawn = true,
	Parent = LocalPlayer.PlayerGui,
	[Fusion.Children] = {
		Fusion.New("ImageLabel") {
			Size = UDim2.new(0, 474 , 0, 352),
			Position = UDim2.new(0.32, 0, 0.261, 0),
			Image = "http://www.roblox.com/asset/?id=3617100",
			
			Name = "hey",
			Visible = Fusion.Computed(function()
				return FrameVisible:get()
			end),
		},
		
		
		Fusion.New("TextButton") {
			Size = UDim2.new(0, 200, 0, 50),
			Position = UDim2.new(0, 0, 0.918, 0),
			BorderColor3 = Color3.fromRGB(46, 46, 46),
			BorderMode = Enum.BorderMode.Outline,
			BorderSizePixel = 4,
			
			Text = "Open Frame Hint(it rick rolled)",
			[Fusion.OnEvent "Activated"] = function()
				FrameVisible:set(not FrameVisible:get())
			end,
		}
	}
}
2 Likes

Update

Added a lot of cool stuff today!

Now, I’m using BadgeService3, there’s some cool new badges you can try out using, there will be more in the future!

Now there’s a “Seconds Played” value, this just keeps track of how long you’re in game, it saves, etc.

Now I’m using BS3 for awards you can get by staying in-game. There’s for 1 minute, 5 minutes, and 10 minutes. I’m probably gonna add more and more new things in-game, my next plan is to add a music player, people can request music, choose to listen to it, etc.

Because I’m using badges, now the Badge menu actually has badges on it!

You can check it out by joining the game. Also, here’s a video as example of what I talked about above.

1 Like

I agree with you! Feels much more understandable and pretty hype to use it! (Currently waiting for Roblox-TS version) .

3 Likes

Hey OP, thanks for the feedback on Fusion, it’s really great to see someone who shares the same opinion on Fusion, even though it is still in preview and highly experimental in usability.

I always wanted to code UI by describing the look of the UI, instead of writing constructor instructions for every object inside the UI itself, which is really tiring to write and look at, but unable to because of Roact.

I am “somewhat experienced” with Roact, I have used it a lot, but I know that not everyone prefers the syntax used in Roact, nor the lifecycles for all instances created inside Roact (mount, reconcile, etc). This results in difficulty to use Roact in a team project where majority is not experienced with neither Roact or React, and may not prefer Roact at the end. Disallowing me to create UI declaratively.

Now, with Fusion, I am bold enough to create UI fully with Fusion, without being concerned. Without the complicated ideology on UI lifecycles and reconciling, majority of coders in Roblox can easily create maintainable user interface components in 100% code, even if they do not have any experience in web development or any sort.

As a result, not only the development team I work with can easily read the code and alter it, but also the upper heads, who may not be really experienced in coding, can still read the code and imagine how the component/screen look like! Killing two birds with one stone it is.


Though, there’s something I am not so satisfied with, it’s the documentation.

I get that Fusion is still preview and is not optimal for large-scale projects yet, but it does not really make sense to leave API references for some libraries to be empty, kinda expect at least a list of all public methods/members of that library without any description or code examples. Whatever.

Critical libraries like Tween/Spring/Instance etc, is really lackluster and simply not enough to at least learn the basics of the Fusion library.

So, at the moment, to actually learn how Fusion works, you have to both read the documentation, and dig into the source code. Which isn’t ideal. Though, don’t let this push you away from using Fusion, Fusion is a nice library and you should consider switching for your future developers and your colleagues.


7 Likes

I completely agree with what you said.

I agree, I haven’t even checked the sources for Tween as of the moment because you can just use TweenService so easily because of the nature of how it works, that it’s almost not an worry for me.
(To be honest idek still what would be difference with using the tween library inside it as of the moment because of how it works)

2 Likes

Cool UI system!
As everyone has been saying Fusion is very easy and intuitive to work with, and I’ve been having a lots of fun with it even though some documentations are lacking.

For other people who may be wondering how Springs can be used, its pretty simple. (Haven’t figured out how to use Tween yet, it always snaps to the state’s value for some reason :frowning:

--Fusion Test
--Yuuwa0519
--August 28th, 2021

--Services
local Players: Players = game:GetService("Players")

--Modules
local Fusion: {[string]: any} = require(script.Fusion)

local New: any = Fusion.New
local Children: any = Fusion.Children
local OnEvent: any = Fusion.OnEvent
local OnChange: any = Fusion.OnChange
local State: any = Fusion.State
local Computed: any = Fusion.Computed
local ComputedPairs: any = Fusion.ComputedPairs
local Compat: any = Fusion.Compat
local Tween: any = Fusion.Tween
local Spring: any = Fusion.Spring

--Objs
local me: Player = Players.LocalPlayer
local PlayerGui: PlayerGui = me:WaitForChild("PlayerGui")

--Functions
local function Switch(props: {[string]: any}): any
	local on: boolean = false
	
	local switchPos: any = State(0)
	local switchSpring: any = Spring(switchPos)
	
	local switchColor: any = State(Color3.fromRGB(255, 0, 4))
	
	return New "Frame" {
		Size = UDim2.fromScale(1, 0.05),
		
		BackgroundTransparency = 1,
		
		[Children] = {
			New "TextLabel" {
				Size = UDim2.fromScale(0.6, 1),
				
				BackgroundTransparency = 1,
				TextColor3 = Color3.fromRGB(255, 255, 255),
				Text = props.Property
			},
			
			New "Frame" {
				Position = UDim2.fromScale(0.6, 0),
				Size = UDim2.fromScale(0.4, 1),
				
				BackgroundTransparency = 1,
				
				[Children] = {
					New "Frame" {
						AnchorPoint = Vector2.new(0, 0.5),
						Position = UDim2.fromScale(0, 0.5),
						Size = UDim2.fromScale(0.9, 0.3),
						
						BorderSizePixel = 0,
						BackgroundColor3 = Color3.fromRGB(168, 168, 168)
					},
					New "Frame" {
						AnchorPoint = Vector2.new(0, 0.5),
						Position = Computed(function()
							return UDim2.fromScale(switchSpring:get(), 0.5)
						end),
						Size = UDim2.fromScale(0.1, 1),
						
						BorderSizePixel = 0,
						BackgroundColor3 = switchColor
					},
					
					New "TextButton" {
						Size = UDim2.fromScale(1, 1),

						BackgroundTransparency = 1,
						Text = "",
						
						[OnEvent "Activated"] = function()
							if on then
								switchPos:set(0)
								switchColor:set(Color3.fromRGB(255, 0, 4))
							else
								switchPos:set(0.9)
								switchColor:set(Color3.fromRGB(0, 34, 255))
							end
							
							on = not on
						end,
					},
				}
			}
		}
	}
end

local function Menu(props: {[string]: any}): any
	local open: boolean = false
	local menuPosX: any = State(1.15)
	local xSpring: any = Spring(menuPosX)
	
	return {
		Activator = New "TextButton" {
			AnchorPoint = Vector2.new(1, 0.5),
			Position = UDim2.fromScale(1, 0.5),
			Size = UDim2.fromScale(0.05, 0.05),
			
			BackgroundColor3 = Color3.fromRGB(0, 255, 21),
			Text = "",
			
			[Children] = {
				New "UIAspectRatioConstraint" {
					DominantAxis = Enum.DominantAxis.Height,
					AspectRatio = 1
				},
				New "UICorner" {
					CornerRadius = UDim.new(0, 5)
				}
			},
			
			[OnEvent "Activated"] = function()
				if open then
					menuPosX:set(1.15)
				else
					menuPosX:set(0.5)
				end
				
				open = not open
			end,
		},
		
		Menu = New "Frame" {	
			AnchorPoint = Vector2.new(0.5, 0.5),
			Position = Computed(function()
				return UDim2.fromScale(xSpring:get(), 0.5)
			end),
			Size = UDim2.fromScale(0.3, 0.5),
			
			BorderColor3 = Color3.fromRGB(255, 255, 255),
			BackgroundColor3 = Color3.fromRGB(83, 83, 83),
			
			[Children] = {
				New "UICorner" {
					CornerRadius = UDim.new(0, 5)
				},
				New "UIListLayout" {
					Padding = UDim.new(0, 10)
				},
				
				ComputedPairs(props.Properties, function(index: number, property: string)
					return Switch {
						Property = property
					}
				end)
			}
		}
	}
end


--Main
local newUI: any = New "ScreenGui" {
	Parent = PlayerGui,
	ResetOnSpawn = false,
	IgnoreGuiInset = true,
	ZIndexBehavior = Enum.ZIndexBehavior.Sibling,

	[Children] = {
		Menu {
			Properties = {
				"Switch A",
				"Switch B",
				"Feed Snack"
			}
		}
	}
}

3 Likes

I’ve been looking at fusion for a few days and I can’t figure out how to use the built-in tween scheduler.

I have a frame that loads in and does its own thing. After 3 seconds I want to change the frame’s position. Anyone have a clue on how to achieve this?

local Tween_Info = TweenInfo.new(10, Enum.EasingStyle.Bounce, Enum.EasingDirection.In)
local Shadow_Position = Blend.State(UDim2.fromScale(0.5, 0.5))

local Frame = Blend.New "Frame" {
	Name = "Loading_Frame";
	Parent = _G.UI_Screen;
	Position = UDim2.fromScale(0.5, 0.5);
	AnchorPoint = Vector2.new(0.5, 0.5);
	Size = UDim2.fromScale(1, 1);
	BackgroundColor3 = Color3.fromRGB(0, 0, 0);
	BorderColor3 = Color3.fromRGB(27, 42, 53);
	ZIndex = 10;
	[Blend.Children] = {
		Blend.New "Frame" {
			Name = "Bar";
			Position = UDim2.fromScale(0.5, 0.5);
			AnchorPoint = Vector2.new(0.5, 0.5);
			Size = UDim2.fromScale(0.5, 0.006);
			BorderColor3 = Color3.fromRGB(27, 42, 53);
			SizeConstraint = Enum.SizeConstraint.RelativeXX;
			ZIndex = 10;
			[Blend.Children] = {
				Blend.New "Frame" {
					Name = "Inside";
					Position = UDim2.fromScale(0, 0.500001);
					AnchorPoint = Vector2.new(0.5, 0.5);
					Size = UDim2.fromScale(0, 1);
					BackgroundColor3 = Color3.fromRGB(125, 255, 136);
					BorderColor3 = Color3.fromRGB(27, 42, 53);
					ZIndex = 10;
				};
			};
		};
		Blend.New "TextLabel" {
			Position = UDim2.fromScale(0.5, 0.45);
			AnchorPoint = Vector2.new(0.5, 0.5);
			Size = UDim2.fromScale(0.15, 0.025);
			BackgroundTransparency = 1;
			BorderColor3 = Color3.fromRGB(27, 42, 53);
			Font = Enum.Font.SourceSansLight;
			SizeConstraint = Enum.SizeConstraint.RelativeXX;
			Text = "0/820";
			TextColor3 = Color3.fromRGB(255, 255, 255);
			TextScaled = true;
			TextWrapped = true;
		};
		Blend.New "Frame" {
			Name = "Shadow";
			Position = Shadow_Position
			AnchorPoint = Vector2.new(0.5, 0.5);
			Size = UDim2.fromScale(1, 1);
			BackgroundColor3 = Color3.fromRGB(0, 0, 0);
			BorderColor3 = Color3.fromRGB(27, 42, 53);
			ZIndex = 15;
			[Blend.Children] = {
				Blend.New "UIGradient" {
					Transparency = NumberSequence.new({
						NumberSequenceKeypoint.new(0, 1),
						NumberSequenceKeypoint.new(0.03, 0.3),
						NumberSequenceKeypoint.new(0.1, 0),
						NumberSequenceKeypoint.new(1, 0)
					});
				};
			};
		};
	};
}

delay(3, function()
--	Shadow_Position:set(UDim2.fromScale(2, 0.5))
--	Shadow_Position:set(Blend.Tween(Shadow_Position, Tween_Info))
--  I want to tween (Shadow_Position) to UDim2.fromScale(2, 0.5)
end)

@elttob Also any news on these tabs being added to the github documentation page?

Animation
  Tweens
  Springs
  Project 3: Switches
1 Like

The documentation is being reworked for v0.2 and these pages will be included as part of that overhaul.

Great to hear that!
Any estimated date though?

I do not provide date estimates for any of my projects - development time is always uncertain and changes continuously based on circumstances.

You can view boards to see how much of v0.2 has been completed here: Fusion v0.2 (github.com)

Documentation writing is done separately - there’s no public project board for this at the moment.

1 Like

Do you know how to make state now? because the latest fusion doesn’t have state.

From looking at the sources, Value seems to replace State. If your scripts are long and already depend on an earlier version, using local State = Fusion.Value to replace local State = Fusion.State should fix any issues.

I’m curious on the main pros and cons you have with Roact and Fusion, mind sharing? (preferably in a bulleted list)