UIStroke Render Artifact

I wrote a simple script in order to resize UIStrokes. Here it is:

--!strict
local PlayerGUI = game.Players.LocalPlayer.PlayerGui :: typeof(game.StarterGui)
local ReplicatedStorage = game:GetService("ReplicatedStorage")


local FRAME_SIZE_ATTRIBUTE = "DefaultAbsoluteSizeX"
local STROKE_THICKNESS_ATTRIBUTE = "DefaultThickness"


local containers = {PlayerGUI, ReplicatedStorage.Blaster}
local camera = workspace.CurrentCamera


local StrokeHandler = {}


function StrokeHandler.update(self: StrokeHandler)
	for _, container in containers do
		for _, child in container:GetDescendants() do
			if not child:IsA("UIStroke") then continue end
			local defaultThickness = child:GetAttribute(STROKE_THICKNESS_ATTRIBUTE)
			local parent = child.Parent
			local defaultSize = parent:GetAttribute(FRAME_SIZE_ATTRIBUTE)
			child.Thickness = parent.AbsoluteSize.X * defaultThickness / defaultSize
		end
	end
end


function StrokeHandler.Init(self: StrokeHandler)
	self:update()
	camera:GetPropertyChangedSignal("ViewportSize"):Connect(function()
		print("Updating!")
		self:update()
	end)
end


type StrokeHandler = typeof(StrokeHandler)


return StrokeHandler

So basically i just have attributes on each UIStroke and each TextLabel, Frame with sizes on my phone and using this data I simply resize it for any other device.

But I got this strange artifact:

If I remove call of self:update(), there is no glitch. Also, if we change this line:

child.Thickness = parent.AbsoluteSize.X * defaultThickness / defaultSize

to this:

child.Thickness = 2

We also don’t have a glitch. It’s really strange. I don’t manipulate any positions of UI or something like that. Glitch also disappears after ScreenGUI with UI was displayed on the screen once. On every other new appearing there will not be this glitch. I got this glitch currently on all UI with tweens. I will appreciate any help

1 Like

it might be a floating point related thing

but how? i manipulate stroke thickness, it’s not related to position at all. as you can see in the video, frame appears on the final point of a tween for a one frame

a huge floating point might be causing some issues like 0.0763… or something

excuse me? can you explain a little bit more, i don’t get your point

While I can’t comment for sure on what is causing this issue, it might be many things contributing to it. These could be: when you run update, what math you use, or UIStroke just not liking the numbers you give it (as Ryan mentioned, floating point numbers, numbers with very precise decimals which can cause imperfections).

Thankfully, there is an easy way out of this mess. There’s a beta feature for UIStroke which released recently which lets you auto-scale strokes on all devices. Someone wonderful made a post on how to convert your strokes to the new system. I presume their math might be worth comparing with your code for a possible fix, assuming the issue is math related. You could also try out the beta feature and migrate your strokes to auto-scale using the same code. This should have no issues.

2 Likes

big numbers == pc harder time to render
roblox engine old == worse rendering

and floating point numbers are pretty “big” for computers.
So maybe try making a number go from 0.0763927843902 to 0.076

Unfortunately I started to do all of that because of the fact that I am experiencing really strange behaviour using stroke update.

I did really easy math right from this topic and it doesn’t work for some of strokes (for me it was TextLabel stroke, you can see my comment being the last in this topic)

can you show us the number which is being set as the thickness?

I tried to replace it with this:

math.round(parent.AbsoluteSize.X * defaultThickness / defaultSize, 3)

And it also didn’t help, unfortunately.

This is the kind of numbers I tried to set:

holy it’s def floating point issue

but how it is a floating point issue even with a round? i tried even with 1

Assuming “broken” means the script is not properly converting for auto-scale, we know text rendering is always different than frame rendering. Text size calculation is not straightforward, as it varies between fonts and sizes. So the script I mentioned may not do that.

I ran the script and some of my TextLabels did have wonky scale. In this case, you may just have to manually fix this on a case-by-case basis.

If you prefer not to use the script converting to auto-scale, you can try what Ryan mentioned which is to clamp decimal precision to two points in your code. So a number like 2.12 instead of 2.1254332453.

oh sorry I didn’t see it mb

what the hell is this statement LOL

best explanation ever :smiling_face_with_sunglasses:

Roblox UI uses floating-point scaling, but when rendering, pixel rounding can cause ± 1 px jitter. Forcing the final pixel size to an even integer prevents subpixel alignment issues and texture tearing, especially with borders, outlines, or stroked UI elements

Useless to fix, so just leave it like that, or just write a custom roundNumber function

1 Like

But how it’s related to text size calculation? I thought that what new UI Stroke updates does is simply takes AbsoluteSize of TextLabel and uses the formula to get size of stroke. It’s the same process as with frames.

I have tried even doing this:

child.Thickness = math.round(parent.AbsoluteSize.X * defaultThickness / defaultSize)

i simply take integer part of a number

and i am still having the glitch

That’s because your text is animated, meaning it has to tween from 2 to 4, forcing it to reach into uneven integers like 3.