Ui within studio does not behave the same as it does within a live game

Swapping images within game does not behave the same way from live game to studio

Studio:

Ingame:

Preload asyn is used for both!

all this is, is a while true loop changing the image quickly

Expected behavior

I would assume that the replication SHOULD behave similarly enough but it appears that the behaviors are drastically different

Additionally I get using rectsize and rect offset fixes this while yes I could do this the issue remains that the resolution lost due to the spritesheet is still major and noticeable especially with the frame amount this isn’t a major issue in the context of game development but working in studio I’d like my visuals to not be buggy and look worse than they would ingame as having to publish and join and test it takes significantly more time then just pressing play within studio.

From further testing this issue only seems to appear in studio when there are several frames using only 4 does not seem to reproduce the same issues

Not 100% sure as I haven’t tested it but maybe try putting the images off screen before they’re needed so they get loaded.

Thanks for the report! I filed a ticket in our internal database.

Hi @TheWorldMachines thanks for the report! Could you create a place file that reproduces the issue for us to investigate?

Yup! Would you like me to physically send the place file I have with the bug or create an isolated one

@TheWorldMachines whatever works easiest for you - if what you have repros the issue then we can work with that!

I just isolated the problem into a new studio sending the file now

Studio:

Live:

File:
forstaff.rbxl (55.1 KB)

Code:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ContentProvider = game:GetService("ContentProvider")

local TestTable = {
	"rbxassetid://82644639143068",
	"rbxassetid://99874917396937",
	"rbxassetid://87137307650557",
	"rbxassetid://140553961525706",
	"rbxassetid://96611592864931",
	"rbxassetid://125141381428947",
	"rbxassetid://79917622814995",
	"rbxassetid://81708519581897",
	"rbxassetid://117392228480097",
	"rbxassetid://109108272005449",
	"rbxassetid://98856720300767",
	"rbxassetid://117076250712214",
	"rbxassetid://114563321233999",
	"rbxassetid://76160112137854",
	"rbxassetid://76160112137854",
	"rbxassetid://86664386918052",
	"rbxassetid://101184079131709",
	"rbxassetid://137931754447276",
	"rbxassetid://109605524268240",
	"rbxassetid://136994427726574",
	"rbxassetid://114835897849285",
	"rbxassetid://76071085296964",
	"rbxassetid://83462914480214",
	"rbxassetid://99944247855056",
	"rbxassetid://111631596797895",
	"rbxassetid://76234194283774",
	"rbxassetid://108075860749380",
	"rbxassetid://87022799227783",
	"rbxassetid://110039772331096",
	"rbxassetid://71546322044893",
	"rbxassetid://117301516167450",
}

ContentProvider:PreloadAsync(TestTable)


local TempStatic = true


while true do
	for _, ID in TestTable do
		if not TempStatic then break end
		script.Parent.Image = ID
		task.wait(1/30)
		print("Is running!")
	end

	script.Parent.Image = ""
end

Hi there,

Images having a short delay before being visible is an intended / inevitable behavior of them being loaded asynchronously. Even though they are cached on disk due to the PreloadAsync call, it still takes time for the images to be loaded from disk into GPU memory for rendering.

Additionally, when a string is passed directly to PreloadAsync, the engine doesn’t really know how the asset is intended to be used, so it can only do some generic loading. The API supports passing an Instance instead, like a Decal or ImageLabel, which allows the asset to be loaded more directly.

For animations, this can be worked around using spritesheets, or this alternative version of your script that uses multiple ImageLabels:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ContentProvider = game:GetService("ContentProvider")

local TestTable = {
	"rbxassetid://82644639143068",
	"rbxassetid://99874917396937",
	"rbxassetid://87137307650557",
	"rbxassetid://140553961525706",
	"rbxassetid://96611592864931",
	"rbxassetid://125141381428947",
	"rbxassetid://79917622814995",
	"rbxassetid://81708519581897",
	"rbxassetid://117392228480097",
	"rbxassetid://109108272005449",
	"rbxassetid://98856720300767",
	"rbxassetid://117076250712214",
	"rbxassetid://114563321233999",
	"rbxassetid://76160112137854",
	"rbxassetid://76160112137854",
	"rbxassetid://86664386918052",
	"rbxassetid://101184079131709",
	"rbxassetid://137931754447276",
	"rbxassetid://109605524268240",
	"rbxassetid://136994427726574",
	"rbxassetid://114835897849285",
	"rbxassetid://76071085296964",
	"rbxassetid://83462914480214",
	"rbxassetid://99944247855056",
	"rbxassetid://111631596797895",
	"rbxassetid://76234194283774",
	"rbxassetid://108075860749380",
	"rbxassetid://87022799227783",
	"rbxassetid://110039772331096",
	"rbxassetid://71546322044893",
	"rbxassetid://117301516167450",
}

local ImageLabelInstances = {}
for _, ID in TestTable do
	local Label = Instance.new("ImageLabel")
	Label.ImageContent = Content.fromUri(ID)
	Label.Size = UDim2.fromScale(1, 1)
	Label.BackgroundTransparency = 1.0
	Label.ImageTransparency = 1.0
	Label.Parent = script.Parent
	table.insert(ImageLabelInstances, Label)
end

ContentProvider:PreloadAsync(ImageLabelInstances)

script.Parent.Visible = true


local TempStatic = true


local LastInst = nil

while true do
	for _, Label in ImageLabelInstances do
		if not TempStatic then break end
		if LastInst then
			LastInst.ImageTransparency = 1.0
		end
		LastInst = Label
		Label.ImageTransparency = 0.0
		task.wait(1/30)
		print("Is running!")
	end

	script.Parent.Image = ""
	print("Looping")
end

With this script, there is a separate ImageLabel created for each frame, which is inserted into the UI and set to be invisible. This will cause all of the labels to be loaded at once. This way, the animation can be played smoothly by marking one label visible at a time.

I’m going to close this as “By Design”.