Skip to content

Motion ​

Animation: spring and tween return nodes that animate toward a reactive target, stepped once per frame.

luau
local width = Flux.spring(function() return if open() then 300 else 0 end)

Types ​

Spring type ​

luau
type Spring<T> = Graph.Node<T> & {
	-- Adds `delta` to the spring's current velocity without changing its target.
	impulse: (self: any, delta: T) -> (),
	-- Replaces the spring's velocity outright without changing its target.
	setVelocity: (self: any, velocity: T) -> (),
	-- Sets the spring's current animated value immediately without altering its target or velocity.
	setCurrent: (self: any, value: T) -> (),
	-- Jumps both the target and current value to `value` and zeroes the velocity.
	snap: (self: any, value: T) -> (),
}

Functions ​

step ​

luau
Motion.step(dt: number?)

Advances every active spring and tween by the same dt seconds, or by the time since the last step. Wired automatically to RunService.PreRender on a client and RunService.Heartbeat on a server, so you call it yourself only to step motion in tests: Flux.Motion.step(1 / 60).

Open Documentation

spring ​

luau
Motion.spring<A>(target: A, frequency: Reactive<number>?, damping: Reactive<number>?, initialVelocity: any?): Spring<Unwrap<A>>

Creates a node that springs toward target, animating any supported value type (numbers, Vector2, UDim2, Color3, …). When target is reactive, the spring retargets on every change, carrying its momentum through. frequency sets oscillations per second (default 1, where higher values snap faster) and damping sets the damping ratio (1 is critically damped with no overshoot, <1 springs past and settles, >1 is sluggish; default 1); both may be reactive. initialVelocity sets the starting velocity in the target's type (read once; omit to start at rest). Read the returned node anywhere to subscribe to the live animated value.

luau
local size = Flux.spring(function() return if open() then 300 else 0 end, 4)

Open Documentation

tween ​

luau
Motion.tween<A>(target: A, tweenInfo: Reactive<TweenInfo>?): Graph.Node<Unwrap<A>>

Creates a node that animates toward target over a fixed duration described by a TweenInfo (easing style, direction, time, repeats). When target or the TweenInfo is reactive, the tween restarts toward the new goal from its current value, without the DelayTime (a retarget never waits). Read the returned node to subscribe to the live animated value. Prefer a Flux.spring for momentum-driven, interruptible motion.

Open Documentation

Oklab ​

fromLinear ​

luau
Motion.Color.Oklab.fromLinear(color: Color3): Vector3

Converts a Color3 in linear sRGB space to a Vector3 in Oklab space

toLinear ​

luau
Motion.Color.Oklab.toLinear(color: Vector3, clamped: boolean?): Color3

Converts a Vector3 in Oklab space to a Color3 in linear sRGB space.

fromRGB ​

luau
Motion.Color.Oklab.fromRGB(rgb: Color3): Vector3

Converts a Color3 in sRGB space to a Vector3 in Oklab space

toRGB ​

luau
Motion.Color.Oklab.toRGB(lab: Vector3, clamped: boolean?): Color3

Converts a Vector3 in Oklab space to a Color3 in sRGB space

lighten ​

luau
Motion.Color.Oklab.lighten(lab: Vector3, amount: number): Vector3

Raises Oklab lightness by amount; a negative amount darkens

saturate ​

luau
Motion.Color.Oklab.saturate(lab: Vector3, amount: number): Vector3

Raises chroma by amount, preserving hue and lightness; a negative amount desaturates

rotateHue ​

luau
Motion.Color.Oklab.rotateHue(lab: Vector3, degrees: number): Vector3

Rotates hue by degrees, preserving chroma and lightness.

grayscale ​

luau
Motion.Color.Oklab.grayscale(lab: Vector3): Vector3

Removes all chroma, preserving Oklab lightness.

mix ​

luau
Motion.Color.Oklab.mix(lab1: Vector3, lab2: Vector3, alpha: number): Vector3

Returns an Oklab Vector3 linearly interpolated between lab1 and lab2 by the given alpha. Equivalent to lab1:Lerp(lab2, alpha).

sRGB ​

fromLinear ​

luau
Motion.Color.sRGB.fromLinear(color: Color3): Color3

Converts linear sRGB space to sRGB space

toLinear ​

luau
Motion.Color.sRGB.toLinear(color: Color3): Color3

Converts sRGB space to linear sRGB space

Color ​

lighten ​

luau
Motion.Color.lighten(c: Color3, amount: number): Color3

Raises the perceptual lightness of a Color3 by amount, working in Oklab so the shift looks uniform across hues. A negative amount darkens.

Open Documentation

saturate ​

luau
Motion.Color.saturate(c: Color3, amount: number): Color3

Raises the chroma of a Color3 by amount (making it more vivid) while preserving its perceptual hue and lightness in Oklab. Achromatic colors have no hue to grow along and pass through unchanged. A negative amount desaturates (washes it out), stopping at gray.

Open Documentation

rotateHue ​

luau
Motion.Color.rotateHue(c: Color3, degrees: number): Color3

Rotates the hue of a Color3 by degrees around the Oklab color wheel, preserving chroma and lightness. degrees is in degrees (not turns); 360 is a full revolution and negative values rotate the other way.

Open Documentation

grayscale ​

luau
Motion.Color.grayscale(c: Color3): Color3

Strips all chroma from a Color3, returning the neutral gray of the same perceptual lightness in Oklab. A truer gray than averaging RGB channels.

Open Documentation

mix ​

luau
Motion.Color.mix(a: Color3, b: Color3, t: number): Color3

Perceptually blends two Color3s in Oklab, where t is the fraction from a (0) to b (1). Mixing through Oklab avoids the muddy midpoints of a raw RGB lerp. t is unclamped: values outside [0, 1] extrapolate, matching how Flux.spring and Flux.tween animate color.

Open Documentation

luminance ​

luau
Motion.Color.luminance(c: Color3): number

The WCAG relative luminance of a Color3, from 0 (black) to 1 (white). This is the perceived brightness used to compute Color.contrast, weighting green most and blue least.

Open Documentation

contrast ​

luau
Motion.Color.contrast(a: Color3, b: Color3): number

The WCAG contrast ratio between two Color3s, from 1 (identical) to 21 (black on white). The result is order-independent. WCAG asks for at least 4.5 for body text and 3 for large text.

Open Documentation

readable ​

luau
Motion.Color.readable(bg: Color3, dark: Color3?, light: Color3?): Color3

Picks whichever foreground Color3 reads more legibly on bg: the one with the higher WCAG contrast ratio. dark and light default to black and white; pass your own brand tints to keep on-brand text readable over any background.

Open Documentation

Spring ​

Constructors: Motion.spring · Motion.tween

set ​

luau
Spring:set<T>(value: T)

Retargets the animation: the motion now eases toward value from wherever it currently is, preserving momentum. Equivalent to calling the motion node directly, motion(value). A node passed as the goal is read once; to follow a reactive goal continuously, pass it as the constructor's target.

Open Documentation

impulse ​

luau
Spring:impulse<T>(delta: T)

Adds delta to the spring's current velocity to nudge it without changing the goal, such as on a drag release or flick. Spring only; calling it on a Flux.tween warns and is ignored.

Open Documentation

setVelocity ​

luau
Spring:setVelocity<T>(velocity: T)

Overwrites the spring's velocity outright, replacing any existing momentum without changing the goal. Use impulse to add to the current velocity instead. Spring only; calling it on a Flux.tween warns and is ignored.

Open Documentation

setCurrent ​

luau
Spring:setCurrent<T>(value: T)

Sets the spring's current animated value immediately without altering the current target or velocity, waking it if it was sleeping.

snap ​

luau
Spring:snap<T>(value: T)

Jumps the spring to value at rest: the goal and the animated value both become value and the velocity drops to zero, so nothing animates until the next retarget. Use it to place a spring without a transition, e.g. on first show or when a drag hands back to the spring. A node passed as value is read once. Spring only; calling it on a Flux.tween warns and is ignored.

Open Documentation