Responsive Roblox UI: Scaling, Constraints, and Safe Areas
Responsive Roblox UI: Scaling, Constraints, and Safe Areas

Roblox provides several complementary tools for building interfaces that adapt to different content and displays: UDim2 scale and offset values, AnchorPoint, automatic sizing, size constraints, safe-area insets, and Studio's Device Emulator.

Combine Scale and Offset

A UDim2 has Scale and Offset components for both axes. Scale is relative to the corresponding dimension of the container, while Offset contributes a pixel value.

Code: Select all

-- 40% of the parent width and 25% of its height
panel.Size = UDim2.fromScale(0.4, 0.25)

-- A 24-pixel displacement on both axes
panel.Position = UDim2.fromOffset(24, 24)

-- Full parent width minus 32 pixels; fixed height of 64 pixels
panel.Size = UDim2.new(1, -32, 0, 64)
Combining the two components lets a dimension remain relative to its container while including a fixed pixel adjustment.

Set AnchorPoint deliberately

AnchorPoint defines the point within a GUI object from which its position and size are applied. Each component ranges from 0 to 1; the default value of (0, 0) places the anchor at the object's top-left corner.

To center an object around the center of its container:

Code: Select all

panel.AnchorPoint = Vector2.new(0.5, 0.5)
panel.Position = UDim2.fromScale(0.5, 0.5)
If Position is centered but AnchorPoint remains (0, 0), the object's top-left corner is placed at the container's center.

Use AutomaticSize for variable content

AutomaticSize resizes a GuiObject to fit its descendants. It can operate along the X axis, Y axis, or both axes. Roblox identifies localized text and user-entered text as use cases for automatic sizing.

A card can use a defined width and an automatically calculated height:

Code: Select all

local card = script.Parent.HUDRoot
card.Size = UDim2.new(0.28, 0, 0, 0)
card.AutomaticSize = Enum.AutomaticSize.Y

local list = card.StatusList
list.Size = UDim2.new(1, 0, 0, 0)
list.AutomaticSize = Enum.AutomaticSize.Y
For a ScrollingFrame, use AutomaticCanvasSize to resize its canvas. That property changes CanvasSize, whereas AutomaticSize changes an object's base Size.

Apply size constraints

UISizeConstraint

UISizeConstraint sets minimum and maximum pixel dimensions for a GuiObject:

Code: Select all

local constraint = Instance.new("UISizeConstraint")
constraint.MinSize = Vector2.new(220, 0)
constraint.MaxSize = Vector2.new(420, 1000)
constraint.Parent = panel
When a layout such as UIListLayout and a UISizeConstraint both control an object, the constraint overrides the layout's sizing.

UIAspectRatioConstraint

UIAspectRatioConstraint enforces a width-to-height ratio. An AspectRatio of 1 maintains a 1:1 ratio:

Code: Select all

local ratio = Instance.new("UIAspectRatioConstraint")
ratio.AspectRatio = 1
ratio.Parent = icon
This constraint also overrides layout-controlled sizing when both affect the same object.

UITextSizeConstraint

UITextSizeConstraint sets minimum and maximum font sizes for a text-bearing GuiObject. When TextScaled is enabled, the scaled text respects those limits:

Code: Select all

label.TextScaled = true

local textConstraint = Instance.new("UITextSizeConstraint")
textConstraint.MinTextSize = 12
textConstraint.MaxTextSize = 24
textConstraint.Parent = label
Roblox advises against setting MinTextSize below 9, because smaller text can be difficult for many viewers to read.

Respect safe areas

ScreenGui.ScreenInsets controls the safe-area insets for the contents of a ScreenGui. Its default value, CoreUISafeInsets, keeps descendant GUI objects inside the core UI safe area and clear of top-bar buttons and screen cutouts. Roblox recommends this setting when a ScreenGui contains interactive elements.

Code: Select all

local screenGui = script.Parent :: ScreenGui
screenGui.ScreenInsets = Enum.ScreenInsets.CoreUISafeInsets
Example HUD setup

The following example combines safe insets, relative width, automatic height, fixed padding, and minimum and maximum dimensions. Its numerical values are illustrative project settings.

Code: Select all

--!strict

local screenGui = script.Parent :: ScreenGui
local root = screenGui:WaitForChild("HUDRoot") :: Frame
local list = root:WaitForChild("StatusList") :: Frame

screenGui.ScreenInsets = Enum.ScreenInsets.CoreUISafeInsets

root.AnchorPoint = Vector2.new(0, 0)
root.Position = UDim2.fromOffset(16, 16)
root.Size = UDim2.new(0.28, 0, 0, 0)
root.AutomaticSize = Enum.AutomaticSize.Y

local rootConstraint = root:FindFirstChildOfClass("UISizeConstraint")
if not rootConstraint then
    rootConstraint = Instance.new("UISizeConstraint")
    rootConstraint.Parent = root
end
rootConstraint.MinSize = Vector2.new(220, 0)
rootConstraint.MaxSize = Vector2.new(420, 1000)

local padding = root:FindFirstChildOfClass("UIPadding")
if not padding then
    padding = Instance.new("UIPadding")
    padding.Parent = root
end
padding.PaddingTop = UDim.new(0, 10)
padding.PaddingBottom = UDim.new(0, 10)
padding.PaddingLeft = UDim.new(0, 12)
padding.PaddingRight = UDim.new(0, 12)

list.Size = UDim2.new(1, 0, 0, 0)
list.AutomaticSize = Enum.AutomaticSize.Y

local layout = list:FindFirstChildOfClass("UIListLayout")
if not layout then
    layout = Instance.new("UIListLayout")
    layout.Parent = list
end
layout.FillDirection = Enum.FillDirection.Vertical
layout.SortOrder = Enum.SortOrder.LayoutOrder
layout.Padding = UDim.new(0, 8)
Test with the Device Emulator

Roblox Studio's Device Emulator is available from the Test menu. It can show how on-screen UI appears at different resolutions and aspect ratios. Emulation mode also supports view-size adjustments and switching between portrait and landscape orientations.

Selecting a mobile device automatically enables touch simulation during playtesting. The emulator supports simulated single-touch and two-touch gestures.

Editorial reference: TOG-EDITORIAL-90