How should I manage GUI with Rojo?

My current workflow revolves around creating GUI inside of Studio, and then interacting with those pre-made objects directly. Without Rojo, I would just create scripts underneath each object. With Rojo, I’ve instead managed my GUI through a script in StarterPlayerScripts that gets each object from the player and adds behavior from there. However, I’m starting to become uncertain as to if this is the ‘correct’ way of managing my GUI.

As an example, here’s what my Rojo project would look like:
→ src
→ → StarterPlayer
→ → → StarterPlayerScripts
→ → → → Button.client.lua

-- Button.client.lua
local Players = game:GetService("Players")
local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
local button = PlayerGui:WaitForChild("ScreenGui"):WaitForChild("Button")

→ Roblox Studio
→ → StarterGui
→ → → ScreenGui
→ → → → Button (TextButton)
→ → StarterPlayer
→ → → StarterPlayerScripts
→ → → → Button (LocalScript)

Is there a better way to manage GUI created inside of Studio? Should I instead use a library such as Roact? Thank you!

2 Likes

First of all, don’t worry about a ‘correct’ way of managing GUIs. Obviously though, there are certain methods that are objectively or situationally better or worse than others. Some things you might want to consider:

  • What are the constraints of Rojo?
  • What do you want to do in terms of UI control? Do you want to create everything in Rojo and just use Roblox/Studio for script execution? Do you want to do something else?
  • Is your approach scalable? If no, does it need to be (ex: if your game only has one or two main UI pieces, you might not really care about scalability)
  • How do the other pieces of your project fit together?

Because a lot of the questions (and others you might consider) can be specific to either your project or simply your design approach, I don’t want to recommend an arbitrary approach that might be worse.

If you’re curious about other approaches, I can briefly detail the way I handle UI + Rojo on my current project.

My Current Approach (for my current project)

For context, my game is set up somewhat similarly to Knit Framework (stuff is divided into ‘Services’, ‘Systems’, and ‘Utility Modules’). It also runs with a hard backbone of ProfileService and ReplicaService.

I keep all of my UI elements in a folder accessible to the client with no scripts. I keep the modules which manage each UI elsewhere. When I want to load UI in, I use a service I named UIService, which essentially clones the UI, clones the module, throws the module into the ScreenGui, and requires it (all modules can be set up assuming they will be a direct child of the ScreenGui). It’s set to work from both client and server, which makes it very easy and scalable for me to manage the UI like

UIService:LoadUI("Intro Screen", Player)

--// Some stuff happens here

UIService:UnloadUI("Intro Screen", Player)
UI:Service:LoadUI("Loading Screen", Player)

--// Stuff loads

UIService:UnloadUI("Loading Screen", Player)

UIService:LoadUI("HUD", Player)
UIService:LoadUI("Leaderboard", Player)

I set my UI up like this, because (based on my project structure and anticipated needs), I wanted to be able to control UI from every point in my project beyond simply adjusting visibility when I wanted something to appear or disappear. There’s a variety of other functions that I use in my UIService too, that lets me get useful information for my project.

I would identify how you ideally manage your UI approach to fit in with the rest of your project, what you expect you’ll need from it, etc. and then with your endpoints in mind, consider an efficient and scalable approach to reach those!

8 Likes