I’ve always felt like it was impossible to find a guide on how to create Roblox guis which scale for all devices. I often heard things like Scale, Offset, and Aspect Ratio Constraints being discussed around this topic, but could never figure out how to correctly use them.
I recently discovered a method for scaling guis, which is extremely easy to use. It’s composed of a single pre-written script and it requires us to insert a UI Scale instance into our guis. There are a few more things to consider, but I guarantee this is extremely easy.
Scaling Script
This script modifies the UI Scale instance we include in our guis to resize it on different devices. We’ll talk more specifically about how the script works further in the Creating the UI Scale section.
- Create a Local Script inside of the StarterPlayer/StarterPlayerScripts
- Paste the following code inside of the script:
local collection_service = game:GetService("CollectionService")
local GUI_service = game:GetService("GuiService")
local workspace_service = game:GetService("Workspace")
local scale_component_to_base_resolution: {[UIScale]: Vector2} = {}
-- Required property `AbsoluteContentSize` is not in `UILayout` superclass.
type scrolling_frame_layout_component = UIGridStyleLayout | UIListLayout
local layout_component_to_rescaling_connection: {[scrolling_frame_layout_component]: RBXScriptConnection?} = {}
local camera = workspace_service:FindFirstChild("Camera")
local actual_viewport_size: Vector2? = nil
local has_initialized = false
local function rescale(scale_component: UIScale, base_resolution: Vector2)
assert(actual_viewport_size ~= nil)
scale_component.Scale = 1 / math.max(base_resolution.X / actual_viewport_size.X, base_resolution.Y / actual_viewport_size.Y)
end
local function rescale_all()
local top_inset, bottom_inset = GUI_service:GetGuiInset()
actual_viewport_size = camera.ViewportSize - top_inset - bottom_inset
for scale_component, base_resolution in scale_component_to_base_resolution do
rescale(scale_component, base_resolution)
end
end
local function register_scale(component: UIScale)
local base_resolution = component:GetAttribute("base_resolution")
assert(typeof(base_resolution) == "Vector2")
scale_component_to_base_resolution[component] = base_resolution
end
local function register_scrolling_frame_layout_component(layout_component: scrolling_frame_layout_component)
local scale_component_referral = layout_component:FindFirstChild("scale_component_referral")
assert(scale_component_referral:IsA("ObjectValue"))
assert(scale_component_referral.Value ~= nil)
assert(scale_component_referral.Value:IsA("UIScale"))
local scale_component: UIScale = scale_component_referral.Value
local scrolling_frame = layout_component.Parent
assert(scrolling_frame ~= nil)
assert(scrolling_frame:IsA("ScrollingFrame"))
-- https://devforum.roblox.com/t/automaticcanvassize-working-with-uilistlayout-and-uiscale-causes-wrong-automatic-size/1334861.
layout_component_to_rescaling_connection[layout_component] = layout_component:GetPropertyChangedSignal(
"AbsoluteContentSize"
):Connect(function()
scrolling_frame.CanvasSize = UDim2.fromOffset(
layout_component.AbsoluteContentSize.X / scale_component.Scale,
layout_component.AbsoluteContentSize.Y / scale_component.Scale
)
end)
scrolling_frame.CanvasSize = UDim2.fromOffset(
layout_component.AbsoluteContentSize.X / scale_component.Scale,
layout_component.AbsoluteContentSize.Y / scale_component.Scale
)
print('set')
end
local function initialize()
assert(has_initialized == false)
has_initialized = true
collection_service:GetInstanceAddedSignal("scale_component"):Connect(function(object: Instance)
assert(object:IsA("UIScale"))
register_scale(object)
rescale(object, scale_component_to_base_resolution[object])
end)
collection_service:GetInstanceRemovedSignal("scale_component"):Connect(function(object: Instance)
assert(object:IsA("UIScale"))
scale_component_to_base_resolution[object] = nil
end)
for _, object in collection_service:GetTagged("scale_component") do
assert(object:IsA("UIScale"))
register_scale(object)
end
collection_service:GetInstanceAddedSignal("scrolling_frame_layout_component"):Connect(function(object: Instance)
assert(object:IsA("UIGridStyleLayout") or object:IsA("UIListLayout"))
register_scrolling_frame_layout_component(object)
end)
for _, object in collection_service:GetTagged("scrolling_frame_layout_component") do
assert(object:IsA("UIGridStyleLayout") or object:IsA("UIListLayout"))
register_scrolling_frame_layout_component(object)
end
collection_service:GetInstanceRemovedSignal("scrolling_frame_layout_component"):Connect(function(object: Instance)
assert(object:IsA("UIGridStyleLayout") or object:IsA("UIListLayout"))
local rescaling_connection = layout_component_to_rescaling_connection[object]
assert(rescaling_connection ~= nil)
rescaling_connection:Disconnect()
layout_component_to_rescaling_connection[object] = nil
end)
camera:GetPropertyChangedSignal("ViewportSize"):Connect(rescale_all)
rescale_all()
end
initialize()
Changing Screen Size
Roblox gives us an easy way to visualize what our GUI looks like on different screen sizes and devices. We want to use this tool to create all of our guis at the same screen size.
- Click the
TEST
tab between theAVATAR
&VIEW
tab at the top of Studio - Click the
Device
button in theEmulation
pane - Set the device to
HD 1080 1920 x 1080
or your preferred device - Set the mode to
Fit to Window
to enlarge the display
Creating the Gui
Creating the Container Frame
Let’s create the main frame which will contain all of the other components of our gui.
There are two important things we should keep in mind when creating this frame:
- The size of this container element should be set using Offset.
- The position should be set using Scale, but you can also use Offset with Scale as well.
This only applies to the container element, which holds all of the other GUI components. You can use any combination of scale and offset for both the position and size of elements stored inside the container element.
Using Scale & Offset for Positioning
Scale can be used for the position if we want to anchor the frame from an edge or the center of the screen.
The following is an example of how you could create a currency display GUI by using both offset and scale.
- Center the Frame vertically by setting the scaled Y of its Anchor Point & Position to
0.5
- Give it some space from touching the left side of the screen by setting its offset X of the Position to
5
- Turn the frame into a rectangle by setting its Size to
0, 85, 0, 30
Here we use offset for the X of the Position, to move the frame slightly away from touching the edge of the screen.

Using Scale for Positioning
We’ll now convert that currency label to look like the settings frame we’re going for.
- Let’s center the frame by setting its Anchor Point & scaled Position to 0.5 on both the X & Y axis. (The offset of both axes should be
0
) - Let’s enlarge the frame by setting its size to
0, 500, 0, 550
Here we use only scale to center the frame.

Creating the Inner Elements
When it comes to the inner elements we’re able to use any combination of scale and offset for the position and size. Let’s create a basic title for a Settings gui.
I’m only going to include property changes that are relevant to the lesson.
- Create a Text Label within the Frame
- Set the Size in offset to
300
for the X and50
for the Y- Or you could set the Size in scale to
0.6
for the X &0.091
for the Y
- Or you could set the Size in scale to
- Center it horizontally by setting the Anchor Point & Position’s X scale to
0.5
- Or you could use Offset for the X Position by setting it to
250
- Or you could use Offset for the X Position by setting it to
- Move it slightly down from the top by setting the Y offset of the Position to
5
- Or you could use Scale for the Y Position by setting it to
0.009
- Or you could use Scale for the Y Position by setting it to
Sizing the Text
Today is the day you stop using the Text Scaled property when working with Text instances! Rather than using Text Scaled, we will modify the Text Size property to resize our Text.
- Increase the Text Size to
62

Creating the Exit Text Button using Offset
We’ll create two exit buttons to display how we can use scale or offset for sizing the inner elements.
- Create a Text Button
- Set the Size in offset to
135
for the X and25
for the Y - Center it horizontally by setting the Anchor Point & Position’s X scale to
0.5
- Move it slightly down from the top by setting its Position’s Y offset to 10
- Increase the text size by setting its Text Size property to 24

Creating the Exit Text Button using Scale
- Duplicate the previous Text Button we created
- Set the Size in scale to
0.091
for the X and0.08
for the Y - Move it slightly below the previous Text Button by setting its Position’s Y offset to 30

Creating the UI Scale
Since we have finished creating the Gui, we need to do one final step to automatically scale the Gui with different device sizes.
- Create a UI Scale inside of the Screen Gui
- Add a Collection Service tag to it called
scale_component
- Add a Vector 2 attribute to it called
base_resolution
with the value of1920, 1080
which is the resolution we created the GUI at
The script we created earlier uses the Collection Service to find UI Scale objects with the scale_component
tag. It uses the value of base_resolution
as well to scale the GUI.

Testing
Let’s see what this GUI will look like on a smaller device.
- Set the device to
iPhone 4S 480 x 320
or your preferred device
Begin testing the game and you should instantly see the GUI scaled correctly to the smaller device.

Sources
- Open-Source Roblox Game can be downloaded to see examples of scaled guis using this method.
- Discord thread inside the Roblox OSS Community: This is where I originally found this method. I’d highly encourage you to read more in there!
- Dev Forum thread with another script solution and explanation.
- Github gist of the original script.