Tutorial
Make sure to follow the installation guide and have Fuel in ReplicatedStorage.Packages before following the tutorial.
Simple "Hello World!" UI
Let's create a simple UI that displays the text "Hello World".
Create a LocalScript
in StarterPlayer.StarterPlayerScripts
.
We'll start by importing Fuel into our script and getting a reference to PlayerGui
.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local Fuel = require(ReplicatedStorage.Packages.Fuel)
local PlayerGui = Players.LocalPlayer.PlayerGui
We can now create an "element" that represents how we want our UI to look.
local app = Fuel.Rbx.RootInstance({ instance = PlayerGui }, {
Fuel.Rbx.ScreenGui({}, {
Fuel.Rbx.TextLabel({ text = "Hello World!", size = UDim2.fromScale(1, 1), opacity = 0 })
})
})
Then we need to have Fuel create this tree of elements by "applying" it to a new "handle".
Fuel.Core.handle().apply({ app })
Finished code:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local Fuel = require(ReplicatedStorage.Packages.Fuel)
local PlayerGui = Players.LocalPlayer.PlayerGui
local app = Fuel.Rbx.RootInstance({ instance = PlayerGui }, {
Fuel.Rbx.ScreenGui({}, {
Fuel.Rbx.TextLabel({ text = "Hello World!", size = UDim2.fromScale(1, 1), opacity = 0 })
})
})
Fuel.Core.handle().apply({ app })
Let's create a counter!
This next example will showcase a UI that updates over time. Let's import Fuel, and create a new handle.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local Fuel = require(ReplicatedStorage.Packages.Fuel)
local PlayerGui = Players.LocalPlayer.PlayerGui
local handle = Fuel.Core.handle()
Now, we can use a loop to create an element and apply it to our handle every second.
local count = 0
while true do
local text = if count == 1
then "It's been "..count.." second"
else "It's been "..count.." seconds"
local app = Fuel.Rbx.RootInstance({ instance = PlayerGui }, {
Fuel.Rbx.ScreenGui({}, {
Fuel.Rbx.TextLabel({
text = text,
size = UDim2.fromScale(1, 1),
opacity = 0
})
})
})
handle.apply({ app })
count += 1
task.wait(1)
end
Improving the counter via functional components.
We can improve the counter in the previous example by making it a component. Making it into a component will allow us to reuse it across our UI.
Let's start by just importing Fuel:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Fuel = require(ReplicatedStorage.Packages.Fuel)
Now, let's create a functional component for a single element.
local Counter = Fuel.Core.statefulElement(function(hooks, props: {
-- Define the properties our component can take
size: UDim2,
position: Fuel.Align,
anchorPoint: Fuel.Align,
})
local count, setCount = hooks.useState(0)
local text = if count == 1
then "It's been "..count.." second"
else "It's been "..count.." seconds"
-- The effect will run whenever count changes, and increment the count
-- a second later, creating an infinite loop.
hooks.useEffect(function()
local thread = task.delay(1, setCount, function(count)
return count + 1
end)
-- Cleanup method will run when the component is going to be unmounted
return function()
task.cancel(thread)
end
end, { count })
-- In the current version of Fuel, context is not propagated to elements
-- created by a component, so we must make the component consume the parent
-- context and pass it explicitly. This should change in future versions!
local parent = hooks.useContext(Fuel.Rbx.parentContext)
return Fuel.Rbx.RootInstance({ instance = parent }, {
Fuel.Rbx.TextLabel({
text = text,
size = props.size,
position = props.position,
anchorPoint = props.anchorPoint,
opacity = 0
})
})
end)
Now that we've created a Counter
component, we can use it across our code like so:
local app = Fuel.Rbx.RootInstance({ instance = PlayerGui }, {
Fuel.Rbx.ScreenGui({}, {
Counter({
size = UDim2.fromScale(1, 0.5),
position = "Top",
anchorPoint = "Top",
}),
})
})
local handle = Fuel.Core.handle()
handle.apply({ app })
-- After 5 seconds, create a new counter:
local app = Fuel.Rbx.RootInstance({ instance = PlayerGui }, {
Fuel.Rbx.ScreenGui({}, {
Counter({
size = UDim2.fromScale(1, 0.5),
position = "Top",
anchorPoint = "Top",
}),
Counter({
size = UDim2.fromScale(1, 0.5),
position = "Bottom",
anchorPoint = "Bottom",
}),
})
})
handle.apply({ app })
In this example, the second counter will have it's own distinct count 5 seconds behind.