Hello!
My name is TheVerseer and I made a new module called AutoStroke this module is very useful for UI designers.
The Problem: When making UI using UIStrokes, its hard to make it look good on mobile and other devices, The biggest problem is something roblox could easily fix, for example the UICorner Instance has the ability to use Scale rather than offset, but UIStrokes dont which sucks, for multiple reasons, BillboardGUIs with UIStrokes and ScreenGUIs with uistrokes both suffer for the same reason, on smaller screens those UIStrokes don’t automatically change.
The Solution: My module, known as AutoStroke uses a very simple formula to automatically update the UIStroke on all devices
This doesn’t work cause LocalScripts can’t use require() on external assets. To fix this you can simply grab the module from the creator store and manually put it inside your LocalScript and require it using require(script.MainModule).
Hello, I have remade the module to be more optimized and with clean code (the original module was using getdescendants every heartbeat + setting up a lot of hearbeat connections)
--!strict
--!native
--!optimize 2
local AutoStroke = {}
local RunService = game:GetService("RunService")
local ScreenGuis : {UIStroke} = {}
local BillboardGuis : {
[UIStroke] : {
MaxDistance : number,
GUI : BillboardGui,
}
} = {}
local OriginalThickness : {[UIStroke] : number} = {}
local BaseSize = 1920 + 1080
local Camera = workspace.CurrentCamera
local function GetCharacter(Player : Player) : Model
return Player.Character or Player.CharacterAdded:Wait()
end
local function GetPlayerDistanceFromBillboardGui(Player : Player, GUI : BillboardGui) : number
local Character = GetCharacter(Player)
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart") :: BasePart
local Adornee = GUI.Adornee :: BasePart
return (HumanoidRootPart.Position - Adornee.Position).Magnitude
end
local function GetCameraDistanceFromBillboardGui(GUI : BillboardGui) : number
local Adornee = GUI.Adornee :: BasePart
return (Camera.CFrame.Position - Adornee.Position).Magnitude
end
function AutoStroke:Register(GUI : ScreenGui | BillboardGui, MaxDistance : number)
if GUI:IsA("ScreenGui") then
for _, v in GUI:GetDescendants() do
if not v:IsA("UIStroke") then continue end
OriginalThickness[v] = v.Thickness
table.insert(ScreenGuis, v)
end
elseif GUI:IsA("BillboardGui") then
MaxDistance = MaxDistance or 30
for _, v in GUI:GetDescendants() do
if not v:IsA("UIStroke") then continue end
OriginalThickness[v] = v.Thickness
BillboardGuis[v] = {
GUI = GUI,
MaxDistance = MaxDistance,
}
end
end
end
function AutoStroke:Init()
RunService:BindToRenderStep("AutoStrokeUpdate", Enum.RenderPriority.Camera.Value, function()
local ViewportSize = Camera.ViewportSize
local CurrentSize = ViewportSize.X + ViewportSize.ViewportSize.Y
for _, Stroke in ScreenGuis do
local OriginalSize = OriginalThickness[Stroke]
Stroke.Thickness = math.clamp(OriginalSize / (BaseSize / CurrentSize), 0, OriginalSize)
end
for Stroke, Info in BillboardGuis do
local Distance = GetCameraDistanceFromBillboardGui(Info.GUI)
local Original = OriginalThickness[Stroke]
Stroke.Thickness = math.clamp(Original / (Distance / Info.MaxDistance), 0, Original)
end
end)
end
return AutoStroke