Overview
Flux is a reactive UI library for Luau. State updates batch once per frame, and only the Instance properties that actually change get touched.
local count = Flux.signal(0)
local stats = Flux.store({ kills = 0, deaths = 0 })
local function CounterButton()
return Flux.new "TextButton" {
Size = UDim2.fromOffset(200, 50),
BackgroundColor3 = Color3.fromRGB(0, 120, 255),
Text = function()
return `Clicks: {count()} | K/D: {stats.kills}/{stats.deaths}`
end,
Activated = function()
count(count() + 1)
stats.kills += 1
end,
}
endCore Principles
1. Lazy & Frame-Batched
Dormant computations sleep with zero subscriptions until something observes them. When bound to the UI or an Effect, updates batch once per frame (RunService.PreRender on the client, Heartbeat on the server) and run in dependency order before effects fire. If a computed value produces the same result, downstream bindings don't wake up.
2. Direct Property Updates
Flux doesn't build or diff a virtual DOM tree. State changes flow straight to the property bindings that read them. When a player's health changes, only the health bar's Size updates.
3. Run-Once Components
Components in Flux are plain Luau functions that run once to create Instances and attach reactive bindings. After mounting, the component function never runs again. Only the individual property bindings re-run when their dependencies change.
4. Strictly Typed UI
Flux.new and Flux.edit build and wire up Roblox instances in one table with --!strict autocomplete for properties, events, and children. Reactive nodes also overload __call and standard operators (count + 1, `Clicks: {count}`), so expressions stay short.
Batteries Included
- Reactive State: Track values with
Flux.signal,Flux.computed,Flux.effect, and nestedFlux.storeproxies. - Networked State: Replicate server-authoritative and per-player signals to clients with
Flux.Sync. - Declarative Instances: Build trees with
Flux.newor wire up existing templates withFlux.edit. - Scoped Cleanup: Wrap a tree in
Flux.scopeto tear down all of its instances and reactions with a single:Destroy()call. - Control Flow & Lists: Render conditional branches with
Flux.showandFlux.switch, or map dynamic lists withFlux.forValue. - Built-in Motion: Animate any state with physics springs, tweens, or perceptual color blending.
- UI Utilities: Read screen breakpoints, track pointer and gamepad interactions, and drop in terse layout constraints.
- Async & Testing: Run cancellable
Flux.asynctasks, catch failures withFlux.safe, and step a virtualFlux.Clockin tests.
See Getting Started to install Flux and build your first component.