Iris IMGUI for Roblox
repository·main·Indexed 43 days ago
https://github.com/sirmallard/irisAn Immediate Mode GUI (IMGUI) library for Roblox inspired by Dear ImGui. Designed for high-performance visualization, debugging, and data input tools, Iris allows developers to declare UI widgets every frame without the overhead of the standard Roblox UI API. It supports customizable themes, global and per-widget configuration, and integrates with various Roblox GUI containers including PlayerGui, CoreGui, and PluginGui.
What's inside Iris
- Iris is an Immediate Mode GUI (IMGUI) library for Roblox, inspired by Dear ImGui. It is designed for high-productivity UI creation, specifically for visualization, debugging, and data input tools. Unlike traditional Roblox UI libraries that wrap the Roblox UI API, Iris provides its own streamlined Immediate-Mode paradigm and set of widgets to simplify the development of developer tools.
Explore Iris extensions and libraries
mainIris can be extended with specialized libraries to add advanced functionality like 2D graphing or 3D gizmo rendering. Notable extensions include:
- ImPlot: A range of 2D graphing and plotting widgets (LinusKat/ImPlot).
- Ceive ImGizmo: A 3D gizmo rendering library (JakeyWasTaken/CeiveImGizmo).
Additionally, projects like Rocket use Iris under-the-hood with custom theming to provide visual user interfaces for Roblox Studio plugins.
What is Iris and how does it work?
mainIris is an Immediate mode GUI (IMGUI) library for Roblox, inspired by Dear ImGui. It is designed for building debug, visualization, and content-creation tools.
Key Concepts
- Immediate Mode Paradigm: Unlike conventional Roblox UI libraries where you maintain references to UI elements, in Iris you declare the UI you want to appear every single frame. Iris handles the layout, arrangement, and rendering based on these declarations.
- Declarative UI: You describe what you want to see (e.g., a window with a button) rather than how to construct and position it. This allows for rapid iteration of developer tools.
- State Management: Iris provides mechanisms to bridge your game variables with UI widgets, allowing you to control and modify game state directly through the interface.
How the Immediate Mode (IMGUI) paradigm works in Iris
mainIris is an Immediate Mode GUI library. Unlike Retained Mode UI (where you create an object once and update its properties later), in Immediate Mode:
- You call a widget function (like
Iris.Button) every frame. - You check for interactions (like clicks) immediately via the function's return value.
- You do not need to manage UI instances, cleanup, or persistent references; Iris handles the lifecycle of the UI elements automatically based on what you declare in the current frame.
This makes Iris ideal for rapid development of visualization, debugging, and data input tools.
- You call a widget function (like
Where to use Iris in Roblox
mainIris is highly portable and can be used within any Roblox UI container. It is compatible with:
PlayerGuiCoreGuiBillboardGuiSurfaceGuiPluginGui
How Iris configuration scoping works
mainIris uses two levels of configuration: Global and Per-Widget.
- Global Configuration: Managed via
Iris.UpdateGlobalConfig(). It sets the baseline for the entire UI. Changes here are heavy as they trigger a full UI redraw. - Per-Widget Configuration: Managed via a stack using
Iris.PushConfig()andIris.PopConfig(). This allows for local overrides. Because the configuration is stacked, you can nest different styles for parent and child widgets.
Configuration values are stored in a global table accessible via
Iris.Internal._configfor debugging or reference.- Global Configuration: Managed via
Use WeakState to disconnect widgets
mainAWeakStatebehaves like a standardState, but provides a mechanism to clear all connections. When you call the state by ID usingIris.WeakState(), all connected widgets and functions are removed, but the underlying value is preserved. This is useful when you want to stop UI elements from updating based on a specific state without losing the data itself.How State works in Iris
mainAn Iris State object is a table containing a value and an array of connected widgets. It acts as a reference-like object in Luau to allow reactive UI updates.
Key behaviors:
- Get/Set: You can retrieve or update the value. Setting the value automatically updates all connected widgets' UIs.
- Reactivity: Functions can be connected to a state so they fire whenever the value changes.
- Reference Pattern: Because Luau tables are passed by reference, State objects allow different parts of your code to share and react to the same underlying data.
Understand the event firing lifecycle
mainIris events typically fire one frame after the initial user action. This delay ensures that state changes (like visual toggles) have time to propagate through the UI system before the event logic is processed.
For example, with a checkbox:
- The user interacts with the widget (e.g., releases a mouse button).
- On the subsequent frame, the visual state updates (e.g., the checkmark appears).
- The event method (e.g.,
.checked()) returnstrueon that same frame where the visual change is finalized.
How the Iris lifecycle works
mainIris operates on a frame-based lifecycle called a 'cycle'. During each cycle, Iris updates global variables and cleans up unused widgets. This process is similar to
ImGui::EndFrame()in Dear ImGui.To function correctly, all Iris UI code must be executed every frame and before the cycle event occurs. If you run Iris code after the cycle event, the UI state may not update or clean up properly.
By default, Iris uses the Roblox
RunService.Heartbeatevent as its cycle. This means any Iris code must run beforeHeartbeatfires in the Roblox task scheduler. While you can change the cycle event during initialization,RunService.Heartbeatis the recommended default for most use cases.How widgets and widget classes work together
mainIn Iris, a widget is a simple table of data containing properties like
ID,type,tick,events,arguments,zindex,parent widget, andgui instance. It contains no logic itself.Functionality is provided by a widget class using a factory pattern. A widget class is a table of functions that are applied to a widget instance to modify it. To define a new type of widget, you must construct a widget class using
WidgetConstructor: (type: string, widgetClass: WidgetClass) -> ()fromIris.Internal.-- Example of the conceptual relationship -- WidgetConstructor is used to register the class Iris.Internal.WidgetConstructor("MyWidgetType", myWidgetClass) -- When the widget is called in the UI loop, Iris applies the class functions -- to the widget data table.How the Iris Widget API works
mainThe Iris API is consistent across all widgets. Every widget follows a specific pattern involving Children, Arguments, States, and Events.
1. Children
If a widget is marked as
hasChildren = true, you must callIris.End()after the widget call to close the scope of that widget.2. Arguments
Arguments are passed as an array (table with integer indices). The first index is typically a required value (like a
Title), while subsequent indices are optional configuration flags.3. States
States allow for two-way data binding. They are used for properties that can be both read from and written to by the widget (e.g., a window's
positionorsize). States are passed as a dictionary where the key is the state name (string) and the value is anIris.Stateobject.4. Events
Events are functions called on the widget instance that return a boolean. They allow you to react to user interactions (e.g.,
.clicked()or.opened()) during the frame the interaction occurs.local window = Iris.Window({"Window"}) -- Check events if window.opened() and window.uncollapsed() then if Iris.Button({"Click me"}).clicked() then -- Handle click end end Iris.End()