Home › Motion
Tween
Flux.tween(target, tweenInfo?) returns a reactive node that animates toward its target over a fixed duration and easing curve, reusing Roblox's TweenInfo without imperative Tween:Play() / Tween:Cancel() boilerplate.
local loadingProgress = Flux.tween(0, TweenInfo.new(1, Enum.EasingStyle.Linear))
local progressBar = Flux.new "Frame" {
BackgroundColor3 = Color3.fromRGB(0, 255, 100),
Size = function()
return UDim2.fromScale(loadingProgress(), 1)
end,
}
-- Smoothly tween toward 1 (100%) over 1 second
loadingProgress(1)Basic Usage
Flux.tween takes two arguments:
target: The value (or reactive source) the tween animates toward.tweenInfo(optional): A RobloxTweenInfocontrolling duration, easing style, direction, repeat count, reverses, and delay. Defaults to0.3seconds withCubicInOuteasing.
The returned node works just like a Signal. Read it with tween(), retarget it with tween(newGoal) or :set(newGoal), and bind it directly to properties.
Reactive Targets
Pass a Signal, Computed, or plain function () -> T as target. Whenever the source updates, the tween smoothly redirects from its current in-flight value toward the new goal:
local isHovering = Flux.signal(false)
local buttonColor = Flux.tween(
function()
return if isHovering() then Color3.fromRGB(80, 80, 80) else Color3.fromRGB(45, 45, 45)
end,
TweenInfo.new(0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
)
local myButton = Flux.new "TextButton" {
Size = UDim2.fromOffset(200, 50),
BackgroundColor3 = buttonColor,
MouseEnter = function() isHovering(true) end,
MouseLeave = function() isHovering(false) end,
}Reactive TweenInfo
tweenInfo can also be a reactive node or function. When it updates, the in-flight animation continues from its current position using the new duration and easing parameters:
local isFastMode = Flux.signal(false)
local targetPosition = Flux.signal(UDim2.fromScale(0, 0))
local slidingPosition = Flux.tween(targetPosition, function()
return if isFastMode()
then TweenInfo.new(0.1, Enum.EasingStyle.Linear)
else TweenInfo.new(0.5, Enum.EasingStyle.Exponential)
end)Lifecycle
When created inside a Scope, a tween's per-frame step registration is cleaned up automatically when the scope is destroyed. To stop and dispose a tween early, call tween:Destroy().
A Bound Tween Is Not Owned by Its Instance
Flux.new and Flux.edit own a getter function bound to a property (Size = function() ... end), but a tween passed straight to a property (Size = Flux.tween(fn)) only gets a binding. Created outside any owner, a tween with a reactive target or tweenInfo keeps its driving Effect subscribed to those sources after the instance is destroyed, and re-runs it whenever they change. Create the tween inside a Scope that is destroyed with the instance, or hand it to the instance's __CLEAN:
local width = Flux.tween(function()
return if isOpen() then UDim2.fromOffset(300, 40) else UDim2.fromOffset(0, 40)
end)
local panel = Flux.new "Frame" {
Size = width,
__CLEAN = { width }, -- destroying `panel` destroys the tween and its Effect
}Supported Data Types
Flux interpolates almost all standard Roblox UI and 3D data types directly, so you never need to split out X, Y, and Z components or calculate alphas manually.
Supported types include:
number& native LuauvectorUDim&UDim2Vector2&Vector3Color3,ColorSequence&ColorSequenceKeypointNumberRange,NumberSequence&NumberSequenceKeypointCFrame&Rect
Passing an unsupported type, such as a boolean, string, or EnumItem, raises an error. The one exception is nil: a motion that starts at nil warns and then follows its target without animating.
Oklab Color Interpolation
When animating a Color3, ColorSequence, or ColorSequenceKeypoint, Flux converts colors into the Oklab perceptual color space instead of interpolating linear RGB, avoiding muddy or grayish midpoints.
The same perceptual space is available as a standalone toolkit (lighten, saturate, blend, and check contrast) on the Color page.