GUI Optimization tips?

Really, GUIs aren’t too expensive. Just keep an eye on DrawCalls and focus on following MrRobotChicken’s advice in his optimizations thread here: Real world building and scripting optimization for Roblox - Resources / Roblox Staff - Developer Forum | Roblox

CanvasGroups aren’t bad really in careful use either really. I did find some issues you’ll run into though, so just be mindful that:

  • Low Graphics Settings (1-4) result in blurry GUIs in CanvasGroups (rendering at 480p or lower sometimes)
  • A device running out of memory will fail to render CanvasGroups and instead substiute the contents with a white texture.
  • Most of the time, you can achieve the same thing with regular frames and careful use of UI modifiers and UI layout tools mixed with some careful Luau as you can with Canvases.

Also, most of the GUI Optimization isn’t as much in the design as it is in the programming. It’s also about prioritizing User Experience, Seamelssness and Load Times. You can make use of already included property data from objects within your GUI Hierarchy:

  • UIGridLayout and UIListLayout have AbsoluteContentSize. This is most reliably read after the GUI’s content has changed, or after the GUI is made visible. Otherwise, you can run into times where the property reads (0, 0) because it didn’t get chance to update based on visible content.

  • AbsoluteSize and AbsolutePosition exist too. These are super useful if you’re working with specific pixel offsets or targeting specific devices. Don’t be shy about using them, just know they aren’t as useful as Scale values are.

  • UIScale and UIAspectRatioConstraint are super useful too. If you need to constrain or rescale something, you’re better off with these.

  • If you are looking for the lowest common denominator for what constitutes as a renderable GUI component, use myGuiObject:IsA("GuiObject") in conditionals.

  • If you are trying to make something like a tech tree, or a list of purchasable store items, don’t keep references to them in memory for longer than you absolutely need to. Delete objects and destroy connections for things that assemble from a template.

    • If a GUI is temporary, like a match end screen, you can often just clone and populate a template ending screen, then delete it and disconnect any events once the ending screen container is hidden. Just make sure to nil any temporary runtime references to the screen and any RBXScriptConnections afterwards.
    • If you are animating things with TweenService, You can also manually destroy and nil references to tweens. They are objects too.
  • Multiple scripts per-se aren’t even bad. It’s better to have multiple scripts that control context-specific GUI elements than it is to have a monolithic design.

    • Example: Instead of having a GameplayGuiManager, you can split it up into corresponding components like GameplayMinimapManager, GameplayVitalsManager, GameplayObjectivesManager. It’s common in Unity Engine and Unreal Engine, but becomes extremely useful when quick-debugging. You trade off some extra memory usage, and extra object references in memory for ease-of-navigation and separation of concerns.
  • ROBLOX Primitives (Frames) are faster to render than ImageLabels, even with the use of ContentProvider to preload assets at the loading stage. The content still has to be loaded into memory which takes more time in ROBLOX’s engine. If you can achieve the same results with one or two more frames, and objects like UICorner and UIGradient, it’s better to do that instead because there’s no assets being loaded or unloaded.

    • You can still preload assets with some success to somewhat mitigate loading times for assets, but it’s hit and miss. Sometimes they’ll load faster, sometimes they won’t.
  • A special note needs to be made that ImageLabels with Slice (and possibly Tile) don’t work with UICorner. They result in unique artefacts because of how the engine processes the slices.

  • There’s not much difference between having a pre-assembled GUI and one assembled by a script. This isn’t to say there aren’t advantages to libraries like Roact, ReactLua or Flux, some do fix performance issues with things like ScrollingFrames, but it’s a trade off of maintainability, visual editing and performance.

    • If you prefer visual editing, stick with the Visual Tools. If you prefer literal editing (i.e. script-based), then stick with Luau scripting and/or any libraries you use. It really doesn’t matter to the end user, just to you. So don’t get hung up on the details.
  • If you need to share module scripts with GUIs then for the love of all that is Luau put the module scripts somewhere in ReplicatedStorage, especially if the GUI resets on spawn! ROBLOX treats clones of ModuleScripts as unique instances and caches each require of them separately. Just because it’s the same script doesn’t mean it’s the same instance, and the cached result will stay in memory until the player leaves.

That’s what I’ve run into from personal experience from 5 years of GUI and Tools Programming over 3 engines.

3 Likes