Getting Started
This guide walks you through installing Flux and building your first declarative, reactive UI component in Roblox.
If you haven't read about how Flux works yet, start with the What is Flux? page to see how it differs from traditional Luau UI libraries.
Installation
Flux drops into any Roblox project. Pick whichever method fits your workflow; all three give you the same module.
Wally (Recommended)
Wally is the Luau package manager. Add Flux to the [dependencies] section of your wally.toml, then run wally install:
[dependencies]
Flux = "kohltastrophe/flux@0.1.0"Pinning an exact version keeps builds reproducible; bump it when you want updates. The package lives at wally.run/package/kohltastrophe/flux and installs as a shared dependency, so both the client and the server can require it from your Packages folder.
GitHub Releases (.rbxm)
No toolchain? Download the pre-built Flux.rbxm model instead:
- Navigate to the Flux GitHub Releases page.
- Download the latest
Flux.rbxmfile from the Assets section. - Drag and drop the
.rbxmfile directly into your Roblox Studio viewport. - Place the
Fluxmodule insideReplicatedStorageso both the client and the server can access it.
File Sync
Prefer to vendor the source? Copy the repository's src/ directory into your project (e.g. under your Rojo source tree) and require it from there.
Your First App
Let's build a counter to see Flux in action. We'll create a piece of reactive state, bind it to a TextButton, and mount the result to the local player's screen.
Create a new LocalScript inside StarterPlayerScripts and paste the following code:
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- Require the library
local Flux = require(ReplicatedStorage.Flux)
local new = Flux.new
-- 1. Define your component
local function CounterApp()
-- Create a piece of reactive state (a Signal) initialized to 0
local count = Flux(0)
-- Declaratively build the UI hierarchy
return new "ScreenGui" {
Name = "FluxCounterApp",
ResetOnSpawn = false,
Parent = Players.LocalPlayer:WaitForChild("PlayerGui"),
new "TextButton" {
AnchorPoint = Vector2.new(0.5, 0.5),
Position = UDim2.fromScale(0.5, 0.5),
Size = UDim2.fromOffset(250, 80),
BackgroundColor3 = Color3.fromRGB(30, 30, 35),
TextColor3 = Color3.fromRGB(255, 255, 255),
TextSize = 24,
-- Bind the Text property to an implicit Computed on our reactive state.
-- Interpolating {count} reads its current value automatically.
Text = function()
return `Clicks: {count}`
end,
-- Mutate the state when the button is clicked.
-- count + 1 reads the current value; count(...) sets the result.
Activated = function()
count(count + 1)
end,
},
}
end
-- 2. Call the component function once to generate and mount the instances
CounterApp()Press Play (or F5) and a button appears centered on screen, reading Clicks: 0. Each click bumps the number, and only the button's text re-evaluates, nothing else.
What just happened?
Flux(0)- We created a reactive Signal. This holds our state, initialized to0.function() return ... end- We created an implicit Computed. It runs lazily (only when something needs its result) and only recalculates whencountchanges.Text = function() return ... end- We bound the Computed directly to theTextproperty. Whenevercountupdates, only this label re-evaluates.count(count + 1)-count + 1uses operator overloading to readcount's current value and add1; thencount(...)calls the node to set its new value.Parent = Players.LocalPlayer:WaitForChild("PlayerGui")- SettingParentinside the declarative table mounts the UI as part of construction, keeping everything in one place.
You've installed Flux and built a reactive interface.
Next Steps
- Signals - Learn about the fundamental building block of reactivity.
- Computeds - Discover how to derive and memoize state.
- Effects - Run side effects in response to state changes.
- Scopes - Group nodes, instances, and effects under one lifecycle and tear them all down with a single
:Destroy(). - Creation - Explore the full declarative instance builder.
- Responsive - Scale, breakpoint, and safe-area values for UI that adapts to any screen.
- Layout - Terse helpers for padding, constraints, and layouts.