UIStrokeScale - Easily scale UIStrokes

TL:DR: The plugin adds a UDim attribute to UIStrokes which can be used in place of the Thickness property, allowing you to use scale in addition to offset.

UIStroke Scale Plugin:

Plugin Demo



How it works

The plugin adds a simple UDim Attribute to every UIStroke in the game, and automatically sets the Thickness property accordingly.

How to use:

  1. Download and install the plugin.
  2. Set the ThicknessUDim attribute in the properties window or in a script like you would any UDim value.

Scale: The Scale part of the UDim scales with the size of the frame (a Scale value of 1 will equal 1/10th of the average frame size)

Offset: The Offset part of the UDim determines the offset in pixels irrespective of screen size. It functions identically to the default Thickness property.

You can use both Scale and Offset values at the same time.

UIStroke Scale LocalScript:

The plugin can only scale UIStrokes while in Studio. In order to scale during a live game, the plugin will attempt to inject a LocalScript into ReplicatedFirst. This requires enabling Script Injection permission. Alternatively the code below can be copied into a LocalScript and parented to ReplicatedFirst. (the second method won’t allow for automatic updates should there be any)


[Note]: If the 'UIStrokeScale script is removed, scaling will occur only in Studio and cause unintended results in a live game

Other notes:

  • Avoid setting the Thickness property of UIStrokes as they will be completely overwritten by ThicknessUDim. To achieve the same behavior as Thickness, simply set the Offset part of the UDim and leave the Scale set to 0.

  • While in team create with multiple people who have the plugin enabled, UIStrokes on BillboardGuis will appear to glitch out. Unfortunately this is unavoidable due to the nature of BillboardGui’s changing their AbsoluteSize relative to the Camera. Multiple people in a session means multiple cameras changing the same value. This is only an oddity in Studio and will not affect live games.

  • The UIStrokeScale LocalScript can be used without the plugin. Certain features will not work like automatically creating ThicknessUDim Attributes and scaling UIStrokes while in edit mode. The latter makes it difficult to adjust UI elements, for this reason it is not recommended to use the LocalScript standalone.

UIStrokeScale LocalScript code
-- [UIStrokeScaled]
-- written by batteryday

-- LocalScript/game.ReplicatedFirst

local PLUGIN_NAME = script.Name

-- UiStroke --
local function onUIStrokeAdded(uiStroke)
	local connections = {}

	local function connect()
		-- disconnect previous connection
		for _,conn in pairs(connections) do
		-- uiStroke must have a parent that is a GuiBase2d
		if not uiStroke.Parent or not uiStroke.Parent:IsA("GuiBase2d") then return end
		-- text objects
		local isTextObject = false
		if uiStroke.Parent:IsA("TextLabel") or uiStroke.Parent:IsA("TextButton") or uiStroke.Parent:IsA("TextBox") then
			isTextObject = true
		-- add ThicknessUDim Attribute if it doesn't already have
		if not uiStroke:GetAttribute("ThicknessUDim") then
		local function updateThickness()
			local thicknessUDim = uiStroke:GetAttribute("ThicknessUDim")
			local averageSize = (uiStroke.Parent.AbsoluteSize.X + uiStroke.Parent.AbsoluteSize.Y) / 2
			-- use TextBounds for TextObjects
			if isTextObject and uiStroke.ApplyStrokeMode == Enum.ApplyStrokeMode.Contextual then
				averageSize = (uiStroke.Parent.TextBounds.X + uiStroke.Parent.TextBounds.Y) / 2
			-- Scale of "1" will be 1/10 the average size of the frame
			uiStroke.Thickness = thicknessUDim.Scale * averageSize / 10 + thicknessUDim.Offset
		connections["thickness_udim_changed"] = uiStroke:GetAttributeChangedSignal("ThicknessUDim"):Connect(function()
			if not uiStroke:GetAttribute("ThicknessUDim") or typeof(uiStroke:GetAttribute("ThicknessUDim")) ~= "UDim" then
				warn("["..PLUGIN_NAME.."]: don't change 'ThicknessUDim to a non-UDim value while using '"..PLUGIN_NAME.."' plugin")
		connections["absolute_size_changed"] = uiStroke.Parent:GetPropertyChangedSignal("AbsoluteSize"):Connect(updateThickness)
		if isTextObject then
			connections["text_bounds_changed"] = uiStroke.Parent:GetPropertyChangedSignal("TextBounds"):Connect(function()
	-- reconnect when parent changes

-- tag all UIStrokes in game
for _,uiStroke in ipairs(game:GetDescendants()) do
	if uiStroke:IsA("UIStroke") then
	if uiStroke:IsA("UIStroke") then

I hope you found this useful!


The plugin can be found here: UIStrokeScale - Roblox


Awesome plugin! Would love to also see something similar for UI. (For example when using UIStroke)


This topic was made a few months ago but I recommend changing the attribute to Scale, not ThicknessUDim.

You want a scale for UIStroke? You’ve come to the right place.

Am I misunderstanding something? That’s what he is showing.


I wasn’t completely sure if it works with UI. I thought it only worked with surfaceguis

Edit: now that i think about it im pretty sure that it works with ui too lol

1 Like

I was going to do that at first, but using Thickness to determine offset and to scale the UIStroke would have been overly complicated and more prone to bugs, especially with regards to BillboardGui. Adding a UDim was the simplest way and is consistent with the rest of the UI elements that have UDim.

UIStrokeScale applies to UIStrokes and works with ScreenGUI's, SufaceGUI's, and BillboardGUI's.

1 Like

I hope roblox officially turns thickness into a UDim property, because i saw this concern with UIStrokes just not scaling with scale of things. This can be very useful if you have to rely on that property.


Very useful plugin, I loved it! However theres a small Issue i’ve found while using this and I wanted to ask if you know what I could do to possibly fix it:

The Scaling from UIStroke set to Contextual on a TextLabel is based off of the Text’s size, which leads to the scaling being altered depending on how many characters the text itself has.
This leads to having a completely volatile Stroke size, as stuff like counters, currency indicators, and any sort of text from a textlabel that needs to be constantly changed to have an inconsistent stroke size.

Is there any way to resolve this currently?

1 Like

Wait does this mean, If someone has a different screen resolution, while this plugin is active it will scale the UI stroke?

if so, oh my goodness I’ve been looking for something like this because when people use smaller screens my strokes make my GUI’s look horrendous, and when they use a screen that is very big it just ends up looking super thin too.

Also using other methods that scale like the default frame borders don’t work for me because if you make the frame transparent, they also go transparent unlike strokes.

You can just delete the check for textobjects in the updateThickness function of the localscript. Then it works ingame.

1 Like