Currently, the only way to render graphical interfaces on Roblox is by placing it under the PlayerGui instance that is (usually) automatically created under every Player instance.
This has many downsides with relation to developer ergonomics and performance, namely:
The GUIs get unnecessarily replicated for every player, but only when their character spawns. This makes working with GUIs before a character has spawned hard to pull off.
To have your GUI components dispatched, you must put it inside the StarterGui singleton. This is also the only place where they will render inside studio, which makes its runtime behavior seem unintuitive.
The existence of both the PlayerGui and its intended contents are not determined, because they are cloned based on character spawning. This leads to ugly and very hard-to-debug :WaitForChild chains.
Among many other problems. Because of this, I believe introducing a new, separate singleton will help mitigate these issues and make GUIs a little less of a hassle to manage both internally and programmatically.
The Proposal
Add a new service, named something like Graphics or Interface, which acts similar to a PlayerGui. When a client connects, the contents of this service will be replicated before any local scripts run.
Every GUI component in this container will be rendered, just like they are in PlayerGui. These components will also render in the Studio viewport, just like if they were in StarterGui. Changes on the server will be attempted to be replicated on the client like any other replicated container.
Because you shouldn’t be. Unless you’re maybe trying to control if the client has a gui (and even then there’s better solutions).
Manipulating UI on the server with the expectation it replicates to each client creates ping issues. Its better to send messages down to the client with remote events (or instance changes), and let the client solely handle the UI.
On the main thing, if we have a singleton UI for each player, how do we create UI that is specific to each player, such as the player name?
Yes, I was thinking more about the intuitiveness of that behavior, obviously you should never try to do that. I’ve replaced that with another point.
Scripts would be expected to add and edit things inside this container locally, and that shouldn’t be more awkward to work with because that’s what we essentially do with for GUI currently.
I would want this new singleton to replace StarterGui completely, but if need be, someone could still manually work inside the PlayerGui.
I feel like this entire thing can be replicated by either a remote or something similar that pulls a gui from a place that already exists and then, manually parent’s it to the client’s gui after the character loads. Not sure if I am reading this correctly. It’s a bit confusing to read.
I’m bumping this because working with UI in Roblox is absolutely abhorrent in its current state without this.
Right now, I have a RunContext.Client script that parents the GUI to the LocalPlayer’s PlayerGui when it finally appears. Then I have to make sure nothing resets/destroys the GUI while I’m working with it. So much boilerplate to just properly render a single box or text.
UI should always be static. Needlessly cloning UI components every time the character spawns is unintuitive and should be discouraged. Having a single, static container for UI solves this.
Makes sense, though I always typically just turn off ResetOnSpawn and then there’s no need to worry about your UIs being destroyed when a character spawns. Unless I’m missing something?
EDIT:
The initial cloning of UI is still tied to the character model, which can be annoying.
Have you looked into ReplicatedFirst? you can put a script with ui in it and manually parent the ui to the players PlayerGui all before any character spawning happens. I get some of these issues as I have ran into them before, but there are ways around it without the need for another Ui storage instance StarterGui but d i f f e r e n t
And there’s the problem. Why should developers be forced to constantly work around obvious flaws in the design of how interfaces work with hacky solutions when Roblox should have provided a first-party solution that just worked the way we expected simply to begin with?
I kinda get that I suppose, but I think the real issue with that approach is, if they add new services/“singletons” for every little thing the clutter is going to get out of hand pretty quickly. I think a solution that doesn’t require a new instance of any kind would be better. That would help reduce unnecessary clutter in the explorer and whatnot.
Looking at the actual post of this thread, 2 of the 3 issues can be solved by simply using resources we already have
this can be fixed by using ReplicatedFirst, or StarterPlayerScripts. Instead of placing the gui in StarterGui you use a LocalScript to place it into the player’s PlayerGui for you. Since any gui you are making will almost always need a LocalScript anyway to control that gui, this isn’t a major issue. You already have a LocalScript so it’s a few extra lines of code at most.
This can be fixed by simply setting ResetOnSpawn to false on any ScreenGui. The initial spawn still happens, which again can be avoided with a LocalScript in ReplicatedFirst, or StarterPlayerScripts.
I think a better solution to this issue would perhaps be that ReplicatedFirst would show gui in studio, and have a setting to auto parent any ScreenGui instances to the local player’s PlayerGui. This would solve all 3 issues, without the need of a new instance.
I rarely use LocalScripts anymore and it still boggles my mind why people will insist on using them in scenarios where a RunContext.Client script is obviously the superior option.
UI should be static. Scripts should be static. Input should be static. The StarterGui system is too dynamic and has too many strings attached to properly handle these cases statically. It was designed in 2011 for the simple sandboxed plug-n-play environment Roblox had at the time, but Roblox has grown past that era and now requires more future-proof solutions.
Imagine if RunContext was never added and we were stuck with StarterPlayerScripts and ReplicatedFirst (which was and still is only intended for startup logic, mind you). We would have no way to run verily run client code without having it attached to character spawning or have to deal with stuff not being loaded in. That’s the same problem we have with StarterGui right now.
…Speaking of RunContext, that just gave me an idea. With client scripts, Roblox almost added ReplicatedScriptStorage but made the right decision to go with RunContext instead. Why? Because it gave more freedom to how developers could organize their scripts (even if it acts strange in some places).
I wonder if a similar solution could be adopted for GUI instead, like a RenderContext property that makes a GUI render regardless of where it’s parented to. You could switch between client and even studio-only contexts for plugins, and we would finally get the freedom to store our GUI any way we’d like. No singletons required, either!
I will have to disagree here LocalScript still has many useful cases that keep it relevant, using RunContext.Client is a terrible idea for code you only want to run on a single client (gui, input handling, ect.)
I’m not saying you can’t use RunContext.Client as I agree it is extremely useful for many things, but I don’t think it should be used for every thing.
You do know that ReplicatedFirst does not wait for character spawning yeah? it’s replicated before anything else in the game, hence the name ReplicatedFirst.
I do like this idea however, this could solve alot of issues and allow for more freedom in making gui