The GUI API provides utilities for creating Elementa-based user interfaces with Essential’s pre-built components and styling.
Overview
Essential provides two main GUI utilities:
- EssentialComponentFactory - Factory for creating pre-styled Elementa components
- EssentialGUI - Base class for creating consistent GUI screens
Getting the component factory
val factory = EssentialAPI.getEssentialComponentFactory()
EssentialComponentFactory factory = EssentialAPI.getEssentialComponentFactory();
EssentialComponentFactory
The component factory creates pre-styled Elementa components used throughout Essential.
Emulated player
Render a 3D player model like the one in Essential’s character customizer:
val player = factory.buildEmulatedPlayer {
profile = gameProfile
showCape = true
draggable = true
renderNameTag = false
}
EmulatedPlayerBuilder properties
The player’s game profile to render
wrappedProfileState
State<WrappedGameProfile?>
Reactive state for the wrapped game profile (recommended over profileState)
Whether to render the player’s cape if present
Reactive state for cape visibility
Whether the player model can be rotated with the mouse
Reactive state for draggable setting
Whether to render the player’s name tag
Reactive state for name tag rendering
Example
import gg.essential.api.EssentialAPI
import gg.essential.api.gui.buildEmulatedPlayer
import gg.essential.elementa.state.BasicState
val profileState = BasicState<GameProfile?>(null)
val playerComponent = EssentialAPI.getEssentialComponentFactory().buildEmulatedPlayer {
wrappedProfileState = profileState.map { it?.wrapped() }
showCape = true
draggable = true
renderNameTag = true
}
// Update the player later
profileState.set(someGameProfile)
Use wrappedProfileState instead of profileState for better equality comparisons, as GameProfile has a broken equals() implementation.
Confirmation modal
Create confirmation dialogs like those in Essential’s friends menu:
val modal = factory.buildConfirmationModal {
text = "Are you sure?"
secondaryText = "This action cannot be undone."
confirmButtonText = "Delete"
denyButtonText = "Cancel"
onConfirm = { userInput ->
// Handle confirmation
}
onDeny = {
// Handle denial
}
}
ConfirmationModalBuilder properties
Additional descriptive text shown below the primary text
Placeholder text for an optional input field
Text for the confirm button
onConfirm
(String) -> Unit
default:"{}"
Callback invoked when the confirm button is clicked. Receives user input if an input field was shown.
Callback invoked when the deny button is clicked
val deleteModal = factory.buildConfirmationModal {
text = "Delete world?"
secondaryText = "Type the world name to confirm deletion."
inputPlaceholder = "World name"
confirmButtonText = "Delete"
denyButtonText = "Cancel"
onConfirm = { userInput ->
if (userInput == worldName) {
deleteWorld()
EssentialAPI.getNotifications().push(
"Success",
"World deleted"
)
} else {
EssentialAPI.getNotifications().push(
"Error",
"World name doesn't match"
)
}
}
}
EssentialGUI
A base WindowScreen class with Essential’s styling and layout structure. Provides a consistent foundation for custom GUIs.
Creating a custom GUI
import gg.essential.api.gui.EssentialGUI
import gg.essential.elementa.ElementaVersion
import gg.essential.elementa.components.UIText
import gg.essential.elementa.dsl.childOf
import gg.essential.elementa.dsl.constrain
import gg.essential.elementa.dsl.pixels
class MyCustomGUI : EssentialGUI(
version = ElementaVersion.V2,
guiTitle = "My Custom Menu",
discordActivityDescription = "Configuring settings"
) {
init {
UIText("Hello, Essential!")
.constrain {
x = 10.pixels
y = 10.pixels
} childOf content
}
}
// Display the GUI
EssentialAPI.getGuiUtil().openScreen(MyCustomGUI())
Constructor parameters
Elementa version for improved behavior (use ElementaVersion.V2)
Title displayed in the GUI’s title bar
GUI scale override. Defaults to Essential’s configured scale.
restorePreviousGuiOnClose
Whether to restore the previous screen when this GUI is closed
discordActivityDescription
Description shown in Discord Rich Presence (e.g., “Customizing their character”, “Browsing screenshots”)
Properties
Main content container where you should add your GUI elements
The title bar container at the top of the GUI
Whether the back button is visible
Methods
setTitle
Update the GUI title:
fun setTitle(newTitle: String)
Override to customize back button behavior:
override fun backButtonPressed() {
// Custom logic before going back
saveSettings()
super.backButtonPressed() // or restorePreviousScreen()
}
Customizing colors
Override color methods to customize the GUI appearance:
class MyCustomGUI : EssentialGUI(ElementaVersion.V2, "Custom Colors") {
override fun getTitleBackgroundColor() = Color(0x1a1a1a)
override fun getBackgroundColor() = Color(0x0d0d0d)
override fun getTextColor() = Color(0x00ff00)
}
Available color methods:
getTitleBackgroundColor()
getTitleEdgesColor()
getBackgroundColor()
getContentEdgesColor()
getButtonColor()
getButtonHighlightColor()
getTextColor()
getTextHighlightColor()
Complete example
import gg.essential.api.EssentialAPI
import gg.essential.api.gui.EssentialGUI
import gg.essential.api.gui.buildEmulatedPlayer
import gg.essential.elementa.ElementaVersion
import gg.essential.elementa.components.*
import gg.essential.elementa.constraints.*
import gg.essential.elementa.dsl.*
import java.awt.Color
class PlayerViewerGUI(private val gameProfile: GameProfile) : EssentialGUI(
version = ElementaVersion.V2,
guiTitle = "Player Viewer",
discordActivityDescription = "Viewing player profile"
) {
init {
// Add player model
val playerModel = EssentialAPI.getEssentialComponentFactory().buildEmulatedPlayer {
profile = gameProfile
showCape = true
draggable = true
renderNameTag = true
}.constrain {
x = CenterConstraint()
y = CenterConstraint()
width = 200.pixels
height = 300.pixels
} childOf content
// Add player name
UIText(gameProfile.name).constrain {
x = CenterConstraint()
y = 10.pixels
color = Color.WHITE.toConstraint()
} childOf content
}
override fun backButtonPressed() {
// Return to main menu
restorePreviousScreen()
}
}
Best practices
Always use ElementaVersion.V2 when creating new GUIs for improved layout behavior and bug fixes.
Use reactive states (State<T>) for dynamic properties in emulated players and other components to automatically update when data changes.
Add all custom components to the content container, not directly to the window. This ensures proper layout and styling.