Skip to content

Home › Utilities

Responsive ​

Flux.Responsive exposes the screen, input device, and player accessibility settings as shared reactive nodes, ready to read or bind directly with zero setup:

luau
Flux.new "ScreenGui" {
    Parent = playerGui,

    Flux.new "Frame" {
        Size = UDim2.fromOffset(800, 600),
        Flux.new "UIScale" { Scale = Flux.Responsive.scale },
    },
}

For safe areas (the Roblox topbar, device notches, and rounded corners), configure Roblox's built-in ScreenGui.ScreenInsets (CoreUISafeInsets or DeviceSafeInsets) and ScreenGui.SafeAreaCompatibility.

Screen & Layout Nodes ​

Viewport ​

Flux.Responsive.viewport (Node<Vector2>) tracks workspace.CurrentCamera.ViewportSize live on the client (and defaults to 1920×1080 off-client):

luau
local isPortrait = Flux.computed(function()
    local vp = Flux.Responsive.viewport()
    return vp.Y > vp.X
end)

Scale ​

Flux.Responsive.scale (Node<number>) computes a UI scale factor from viewport where 1.0 matches config.reference (1920×1080 by default, using "min" fit mode so UI never overflows):

luau
Flux.new "UIScale" { Scale = Flux.Responsive.scale }

Breakpoint ​

Flux.Responsive.breakpoint (Node<"phone" | "tablet" | "desktop">) classifies the viewport width (< 600 phone, < 1024 tablet, ≥ 1024 desktop by default). Pair it with Flux.switch to swap layouts by screen width:

luau
Flux.switch(Flux.Responsive.breakpoint) {
    phone = function() return CompactLayout() end,
    tablet = function() return CompactLayout() end,
    desktop = function() return WideLayout() end,
}

Display Size ​

Flux.Responsive.displaySize (Node<"Small" | "Medium" | "Large">) mirrors GuiService.ViewportDisplaySize, indicating physical screen size ("Small" for phones/handhelds, "Medium" for monitors/laptops, "Large" for TVs/ten-foot interfaces).

Device & Input Nodes ​

Platform ​

Flux.Responsive.platform (Node<"pc" | "mobile" | "console" | "vr">) reflects the active device class on the client, updating live if the player connects a keyboard/mouse or enters VR ("pc" off-client):

luau
Flux.new "TextButton" {
    Size = function()
        return if Flux.Responsive.platform() == "pc"
            then UDim2.fromOffset(160, 36)
            else UDim2.fromOffset(200, 48)
    end,
}

Input ​

Flux.Responsive.input (Node<"keyboard" | "touch" | "gamepad">) tracks UserInputService.PreferredInput live on the client, switching automatically when the player picks up a controller, touches the screen, or reaches for the mouse/keyboard:

luau
local promptText = Flux.computed(function()
    return if Flux.Responsive.input() == "gamepad" then "Press [A]" else "Click to Continue"
end)

Accessibility Nodes ​

Text Size ​

Flux.Responsive.textSize (Node<"Medium" | "Large" | "Larger" | "Largest">) tracks GuiService.PreferredTextSize. Roblox automatically scales text rendering for this setting. Use textSize to give surrounding containers extra breathing room, not to multiply TextSize a second time.

Reduced Motion ​

Flux.Responsive.reducedMotion (Node<boolean>) tracks GuiService.ReducedMotionEnabled. When true, prefer instant state changes or subtle opacity fades over large movement or scale animations.

Preferred Transparency ​

Flux.Responsive.preferredTransparency (Node<number>) tracks GuiService.PreferredTransparency from 0 (fully opaque backgrounds) to 1 (default). Multiply translucent background transparencies by this node to respect the player's contrast preference:

luau
Flux.new "Frame" {
    BackgroundTransparency = function()
        return 0.35 * Flux.Responsive.preferredTransparency()
    end,
}

Configuration ​

Mutate Flux.Responsive.config once at startup before building your UI to customize the default reference resolution, scale mode, clamps, or breakpoint widths:

luau
Flux.Responsive.config.reference = Vector2.new(1280, 720)
Flux.Responsive.config.mode = "height" -- "min" (default) | "width" | "height" | "max"
Flux.Responsive.config.min = 0.5
Flux.Responsive.config.max = 2
Flux.Responsive.config.breakpoints = { phone = 700, tablet = 1100 }

Per-Surface Overrides ​

Use Flux.Responsive.scaleOf(partialConfig?) and Flux.Responsive.breakpointOf(partialConfig?) to create derived nodes with custom thresholds or a custom viewport source (such as a SurfaceGui or Studio DockWidgetPluginGui):

luau
local dockSize = Flux.property(dockWidget, "AbsoluteSize")

local dockScale = Flux.Responsive.scaleOf {
    viewport = dockSize,
    reference = Vector2.new(400, 600),
}

local dockBreakpoint = Flux.Responsive.breakpointOf {
    viewport = dockSize,
    breakpoints = { phone = 320, tablet = 480 },
}