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

Before:

After:


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)

image

[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
			conn:Disconnect()
		end
		
		-- 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
		end
		
		-- add ThicknessUDim Attribute if it doesn't already have
		if not uiStroke:GetAttribute("ThicknessUDim") then
			uiStroke:SetAttribute("ThicknessUDim",UDim.new(0,uiStroke.Thickness))
		end
		
		
		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
			end
			
			-- Scale of "1" will be 1/10 the average size of the frame
			uiStroke.Thickness = thicknessUDim.Scale * averageSize / 10 + thicknessUDim.Offset
		end
		
		connections["thickness_udim_changed"] = uiStroke:GetAttributeChangedSignal("ThicknessUDim"):Connect(function()
			if not uiStroke:GetAttribute("ThicknessUDim") or typeof(uiStroke:GetAttribute("ThicknessUDim")) ~= "UDim" then
				uiStroke:SetAttribute("ThicknessUDim",UDim.new())
				warn("["..PLUGIN_NAME.."]: don't change 'ThicknessUDim to a non-UDim value while using '"..PLUGIN_NAME.."' plugin")
			end
			updateThickness()
		end)
		
		connections["absolute_size_changed"] = uiStroke.Parent:GetPropertyChangedSignal("AbsoluteSize"):Connect(updateThickness)
		
		if isTextObject then
			connections["text_bounds_changed"] = uiStroke.Parent:GetPropertyChangedSignal("TextBounds"):Connect(function()
				updateThickness()
			end)
		end
		
		updateThickness()
	end
	
	-- reconnect when parent changes
	uiStroke.AncestryChanged:Connect(function()
		connect()
	end)
	
	connect()
end

-- tag all UIStrokes in game
for _,uiStroke in ipairs(game:GetDescendants()) do
	if uiStroke:IsA("UIStroke") then
		onUIStrokeAdded(uiStroke)
	end
end
game.DescendantAdded:Connect(function(uiStroke)
	if uiStroke:IsA("UIStroke") then
		onUIStrokeAdded(uiStroke)
	end
end)

I hope you found this useful!

14 Likes

The plugin can be found here: UIStrokeScale - Roblox

1 Like

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

1 Like

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

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.

1 Like