How It Works
The Fluent API — writing code like a sentence
You might have noticed the code looks like a chain of dot-separated words:
new Button(100, 100, 200, 40)
.text("Save")
.colorScheme(Button.Style.GREEN)
.cornerRadius(8)
.onClick(() -> save());
This is called a Fluent API. It works because every method (like
.text(), .colorScheme()) returns this — meaning
"the same object I'm configuring". So you can keep chaining. Think of it like building a
sentence: "Create a button, with text 'Save', colored green, with rounded corners, that calls
save() when clicked."
You don't have to chain everything. This is exactly equivalent:
Button myButton = new Button(100, 100, 200, 40);
myButton.text("Save");
myButton.colorScheme(Button.Style.GREEN);
myButton.cornerRadius(8);
myButton.onClick(() -> save());
addComponent(myButton);
Coordinates — where things go
Every component takes 4 numbers when you create it: (x, y, width, height).
- x — how far from the left edge of the screen
- y — how far from the top of the screen
- width — how wide the component is
- height — how tall the component is
These numbers are in design pixels — they assume a screen that is 1920 pixels
wide and 1080 pixels tall. So x=960, y=540 is exactly the center of the screen,
regardless of what resolution the player is actually running.
EriAPI automatically converts your design-pixel coordinates to real screen coordinates. If a player runs at 1280x720, EriAPI scales everything down so it still looks correct. You never have to think about this — just design for 1920x1080 and the framework handles the rest.
The component hierarchy
Everything you put on screen is a "component". Components can contain other components (like a panel containing buttons). There are three base types you should know about:
| Class | What it is | When to use |
|---|---|---|
| Component | abstract | The root of everything — all components extend this |
| InteractiveComponent | abstract | Extends Component — adds onClick, onHover, onRelease |
| ContainerComponent | abstract | Extends Component — can hold child components (e.g. ScrollPanel) |
As a beginner, you don't need to worry about extending these yourself. Just use the ready-made components described in the next sections.
EriGuiScreen
EriGuiScreen is the base class for every screen you create with EriAPI.
Think of it as the blank canvas onto which you place your components. By extending it,
you get automatic event handling, rendering, scaling, and keyboard shortcuts (like Escape
to close) for free.
What you need to do
There is only one method you must implement: buildComponents().
This is called once when the screen opens. Inside it, you call addComponent()
for each thing you want to display.
public class MyScreen extends EriGuiScreen {
@Override
protected void buildComponents() {
// Add your components here
addComponent(new Label(760, 500, 400, 30)
.text("Hello, Minecraft!")
.color(Colors.CYAN)
.align(Label.Align.CENTER)
);
}
}
Available methods you can override
-
ABSTRACTbuildComponents()REQUIRED — called when the screen opens. Add all your components here.
-
EVENTonScreenClosed()Optional — called when the player closes the screen (e.g. presses Escape). Use to save data, play sounds, etc.
-
FLUENTaddComponent(Component c)Registers a component so it gets drawn and receives events. Call this inside buildComponents() for every component you create.
Automatic ItemSlot integration
EriGuiScreen automatically manages the complete lifecycle of
ItemSlot components present in the component tree.
No extra configuration is needed.
| EriGuiScreen event | ItemSlot action triggered |
|---|---|
drawScreen(mouseX, mouseY, pt) |
ItemSlot.renderCursorItem(mouseX, mouseY) after all components and notifications |
mouseReleased(x, y, btn) |
ItemSlot.onDragEnd() before propagating to components |
mouseClickMove(x, y, btn, dt) |
slot.checkDragHover(x, y) on every ItemSlot in the tree |
onGuiClosed() |
ItemSlot.clearCursor() to reset the global state |
Components Overview
A "component" is any visual element you place on screen — a button, a piece of text, a rectangle, an input field, etc. Here is a quick summary of all available components. Each one is documented in detail in the sections that follow.
| Component | Category | What it does |
|---|---|---|
| Button | Interaction | A clickable button with 7 color styles |
| TexturedButton | Interaction | A button that shows an image/texture |
| Label | Display | A piece of text, with alignment and scaling |
| Rectangle | Shape | A colored box, optionally with rounded corners |
| Circle | Shape | A circle drawn on screen |
| Triangle | Shape | A triangle pointing up, down, left, or right |
| TextField | Input | A text input box the player can type in |
| NumericField | Input | A text input that only accepts numbers |
| PasswordField | Input | A text input that hides the typed text |
| GridLayout | Layout | Automatically arranges components in a grid |
| ScrollList | Layout | A scrollable list of items with optional search |
| ScrollPanel | Layout | A scrollable container for any components |
| ProgressBar | Control | Shows progress (0% to 100%) |
| Slider | Control | A draggable slider for picking a value |
| Checkbox | Control | A checkbox the player can tick on/off |
| RadioButton | Control | A single selectable option |
| RadioGroup | Control | A group of RadioButtons where only one can be selected |
Background Texture (all components)
All components inherit these texture methods from the base Component class. When a background image is set,
it replaces the color rendering. If no image is set, the classic color behavior applies unchanged.
-
FluentbackgroundImage(ResourceLocation image)Background image for the component. Replaces the background color when set. Works on Button, TextField, Panel, ScrollList, ScrollPanel, ContainerComponent, ProgressBar, etc.
-
FluentscaleMode(ScaleMode mode)Texture scaling mode:
STRETCH,FIT,FILL,TILE,NINE_SLICE. -
FluentimageTint(int argb)ARGB tint applied to the texture.
0xFFFFFFFF= no tint (default). -
FluentnineSliceBorder(int pixels)Border size for
NINE_SLICEmode (in texture pixels). Corners are preserved, edges are stretched. -
FluentimageUV(int u, int v, int uW, int vH, int texW, int texH)Sub-region of a spritesheet. Allows using a single image containing multiple textures.
ResourceLocation panelTex = new ResourceLocation("mymod", "textures/gui/panel.png");
// Works on ScrollPanel, ScrollList, ContainerComponent, Panel...
ScrollPanel panel = new ScrollPanel()
.originalPos(100, 50)
.originalSize(300, 200)
.backgroundColor(Colors.PANEL_BG); // fallback if no texture
panel.backgroundImage(panelTex);
panel.scaleMode(ScaleMode.NINE_SLICE);
panel.nineSliceBorder(8);
// Also works on TextField, Button, etc.
TextField tf = new TextField()
.originalPos(100, 260)
.originalSize(200, 20)
.placeholder("Textured input...");
tf.backgroundImage(new ResourceLocation("mymod", "textures/gui/input.png"));
tf.scaleMode(ScaleMode.NINE_SLICE);
tf.nineSliceBorder(4);
If backgroundImage is not set, the component behaves exactly as before (color rendering).
No existing code is broken by the texture support addition.
Button
A Button is exactly like a button in any app — the player clicks it and something happens.
You decide what happens by passing a function to .onClick(). EriAPI handles
everything else: drawing, hover effects, press animation, and disabled states.
Basic example
// new Button(x, y, width, height)
// x=760, y=400 means: 760 pixels from the left, 400 from the top (in design space)
addComponent(new Button(760, 400, 400, 40)
.text("Click Me") // Text shown on the button
.colorScheme(Button.Style.CYAN) // Color style (see the 7 styles below)
.onClick(() -> { // Code that runs when clicked
System.out.println("Button was clicked!");
})
);
The 7 color styles
Pass one of these to .colorScheme() to change the button's look.
All styles automatically handle hover and pressed states.
| Style constant | Color |
|---|---|
| Button.Style.CYAN | Cyan / light blue |
| Button.Style.PURPLE | Purple / violet |
| Button.Style.GREEN | Green |
| Button.Style.RED | Red |
| Button.Style.ORANGE | Orange |
| Button.Style.GRAY | Dark gray (neutral) |
| Button.Style.WHITE | White / light |
All methods
-
FLUENTtext(String text)Sets the text displayed on the button.
-
FLUENTcolorScheme(Button.Style style)Sets the color style. Default is CYAN.
-
FLUENToutlined(boolean outlined)If true, the button is transparent with a colored border instead of a filled background. Great for secondary actions.
-
FLUENTcornerRadius(int radius)Rounds the corners of the button. 0 = sharp corners, 8 = nicely rounded. Default is 4.
-
EVENTonClick(Runnable action)The code that runs when the button is clicked. Use a lambda:
() -> doSomething(). -
FLUENTenabled(boolean enabled)If false, the button is grayed out and cannot be clicked. Useful for preventing actions until a condition is met.
-
FLUENTvisible(boolean visible)If false, the button is completely hidden (not drawn, not clickable).
-
FLUENTtextScale(float scale)Changes the size of the text inside the button. Default is 1.0.
Advanced example — multiple buttons
// A primary "Save" button, filled cyan with rounded corners
addComponent(new Button(760, 500, 180, 44)
.text("Save")
.colorScheme(Button.Style.GREEN)
.cornerRadius(10)
.onClick(() -> savePlayerData())
);
// A secondary "Cancel" button, outlined style
addComponent(new Button(960, 500, 180, 44)
.text("Cancel")
.colorScheme(Button.Style.GRAY)
.outlined(true) // Transparent background, just a border
.cornerRadius(10)
.onClick(() -> mc.displayGuiScreen(null)) // null closes the screen
);
// A "Delete" button that starts disabled
// (you'd enable it later based on game logic)
addComponent(new Button(1160, 500, 180, 44)
.text("Delete")
.colorScheme(Button.Style.RED)
.cornerRadius(10)
.enabled(false) // Grayed out — player can't click yet
.onClick(() -> deleteItem())
);
You can store the button in a variable and call myButton.enabled(false)
later in your code to disable it dynamically. For example, disable "Buy" if the player
doesn't have enough gold.
Texture Support (per-state)
Button supports different textures for each visual state.
The backgroundImage inherited from Component serves as the default texture (normal state).
hoverImage and pressedImage change the appearance on hover and click.
-
FluenthoverImage(ResourceLocation image)Texture displayed when the mouse hovers over the button. Falls back to
backgroundImageif not set. -
FluentpressedImage(ResourceLocation image)Texture displayed when the button is clicked/pressed. Falls back to
hoverImageorbackgroundImage.
ResourceLocation btnNormal = new ResourceLocation("mymod", "textures/gui/btn.png");
ResourceLocation btnHover = new ResourceLocation("mymod", "textures/gui/btn_hover.png");
ResourceLocation btnPressed = new ResourceLocation("mymod", "textures/gui/btn_pressed.png");
Button btn = new Button("Buy")
.originalPos(100, 200)
.originalSize(200, 40)
.hoverImage(btnHover)
.pressedImage(btnPressed)
.textColor(Colors.WHITE);
btn.backgroundImage(btnNormal);
btn.scaleMode(ScaleMode.NINE_SLICE);
btn.nineSliceBorder(6);
Priority order: pressedImage > hoverImage > backgroundImage.
If no texture is set, the classic color rendering applies (full backwards compatibility).
TexturedButton
A TexturedButton is a button that shows an image (a texture from your mod's resource pack) instead of a colored box. Think of icon buttons in games — a gear icon for settings, an X icon to close a panel, etc. You can also add an optional text label on top of the texture.
Basic example
// First, create the ResourceLocation that points to your image file.
// The image must be in: src/main/resources/assets/yourmod/textures/gui/mybutton.png
ResourceLocation myIcon = new ResourceLocation("yourmod", "textures/gui/mybutton.png");
addComponent(new TexturedButton(900, 400, 64, 64) // 64x64 button
.texture(myIcon) // The image to display
.hoverTint(0x44FFFFFF) // A slight white tint when hovered (ARGB)
.pressedTint(0x66000000) // A dark tint when pressed (ARGB)
.onClick(() -> openSettings()) // Action when clicked
);
All methods
-
FLUENTtexture(ResourceLocation texture)The image to draw as the button background. Must be a valid resource location pointing to a PNG file in your mod's assets.
-
FLUENThoverTint(int argbColor)A color overlay applied when the mouse hovers over the button. Use a semi-transparent color like
0x44FFFFFF(44 = alpha, white tint). -
FLUENTpressedTint(int argbColor)A color overlay applied when the button is being pressed/clicked. Typically a dark tint like
0x66000000. -
FLUENTlabel(String text)Optional text drawn on top of the texture. Useful for labeled icon buttons.
-
EVENTonClick(Runnable action)Code that runs when the button is clicked.
Colors in EriAPI use the format 0xAARRGGBB where AA is the alpha
(transparency: 00 = fully transparent, FF = fully opaque), RR is red, GG is green,
and BB is blue. Example: 0x80FF0000 is semi-transparent red.
Label
A Label displays text on screen. It supports alignment (left, center, right), scaling (making text bigger or smaller), drop shadows, and clipping (trimming text with "..." if it's too long to fit). Labels can also scroll their text when hovered.
Basic example
// new Label(x, y, width, height)
addComponent(new Label(400, 200, 600, 30)
.text("Welcome to my mod!") // The text to show
.color(Colors.WHITE) // Text color
.align(Label.Align.CENTER) // Center-align within the width
.scale(1.5f) // 1.5x bigger than default text
.shadow(true) // Draw a drop shadow behind the text
);
All methods
-
FLUENTtext(String text)The text to display. You can update this at any time by calling it again.
-
FLUENTcolor(int argbColor)The text color. Use a constant from
Colors(e.g.Colors.WHITE) or write an ARGB hex like0xFFFF0000for red. -
FLUENTalign(Label.Align alignment)Text alignment:
Label.Align.LEFT,Label.Align.CENTER, orLabel.Align.RIGHT. -
FLUENTscale(float scale)Text size multiplier. 1.0 = normal, 2.0 = double size, 0.5 = half size.
-
FLUENTshadow(boolean shadow)If true, a drop shadow is drawn behind the text, improving readability.
-
FLUENTclip(boolean clip)If true and the text is too long to fit in the label's width, it is clipped with "..." at the end.
-
FLUENTscrollOnHover(boolean scroll)If true, when the player hovers over the label, the text scrolls horizontally to reveal the full content.
-
FLUENTscaleToFit(boolean enabled)If
true, instead of truncating text with "...", automatically reduces the text scale so it fits exactly within the component width. Mutually exclusive withwrapped()at render time — if both are active,wrappedtakes priority. -
FLUENTwrapped(boolean enabled)If
true, text wraps to multiple lines at word boundaries instead of being truncated. If the wrapped content exceeds the component height, vertical mouse scroll is enabled (scissor clipped). Mutually exclusive withscaleToFit()—wrappedwins if both are active.
Advanced example
// A big title, centered, with a shadow
addComponent(new Label(400, 100, 1120, 60)
.text("Player Statistics")
.color(0xFFFFFFFF) // Fully opaque white
.align(Label.Align.CENTER)
.scale(2.5f)
.shadow(true)
);
// A subtitle in muted cyan
addComponent(new Label(400, 170, 1120, 30)
.text("Your progress so far")
.color(Colors.CYAN_DIM)
.align(Label.Align.CENTER)
.scale(1.2f)
);
// A long description that clips with "..." if too long
addComponent(new Label(400, 300, 500, 24)
.text("This is a very long text that might not fit in the available space.")
.color(Colors.LIGHT_GRAY)
.clip(true) // Cut off with "..."
.scrollOnHover(true) // Scroll when hovered to show full text
);
// Auto-shrink text to fit within the width (scaleToFit)
addComponent(new Label(400, 340, 200, 24)
.text("VeryLongPlayerNameThatDoesNotFit")
.color(Colors.GRAY)
.scaleToFit(true) // Reduces font scale to fit in 200px
);
// Multi-line wrapped text with scroll if it overflows
addComponent(new Label(400, 380, 500, 80)
.text("This is a long description that will automatically wrap at word boundaries when it exceeds the component width. If the wrapped text exceeds the component height, the player can scroll with the mouse wheel.")
.color(Colors.LIGHT_GRAY)
.wrapped(true) // Word-wrap instead of truncating
);
Rectangle
A Rectangle draws a colored box on screen. You can fill it with a solid color, add a border, and optionally round the corners. Rectangles are great for panels, backgrounds, dividers, and decorative elements.
Basic example
// Draw a semi-transparent dark background panel
addComponent(new Rectangle(300, 150, 800, 500)
.fillColor(0xCC101020) // Dark blue-ish, 80% opaque (CC = 204/255)
.borderColor(0xFF2255FF) // Bright blue border
.borderThickness(2) // 2-pixel border
.cornerRadius(12) // Nicely rounded corners
);
All methods
-
FLUENTfillColor(int argbColor)The inside color of the rectangle. Use
0x00000000for transparent (no fill). -
FLUENTborderColor(int argbColor)The color of the border around the rectangle. You don't have to set this — by default there is no border.
-
FLUENTborderThickness(int thickness)How thick (in design pixels) the border is. Ignored if no borderColor is set.
-
FLUENTcornerRadius(int radius)How round the corners are. 0 = sharp right-angle corners, higher values = rounder. Try values between 4 and 16.
Components are drawn in the order you call addComponent(). So add background
rectangles first, then labels and buttons on top. Later-added components
appear in front of earlier ones.
Circle
Draws a filled circle on screen. Good for status indicators, avatars, decorative dots, or anything that needs to be round. The position is the top-left corner of the bounding box, and width/height should be equal to make a perfect circle.
Basic example
// Draw a green circle — "online" indicator
// Position: x=850, y=450. Size: 40x40 (equal width and height = perfect circle)
addComponent(new Circle(850, 450, 40, 40)
.fillColor(0xFF00CC44) // Bright green, fully opaque
.borderColor(0xFF009933) // Darker green border
);
All methods
-
FLUENTfillColor(int argbColor)The color that fills the inside of the circle.
-
FLUENTborderColor(int argbColor)Optional outline color around the circle.
Triangle
Draws a triangle pointing in one of four directions: up, down, left, or right. Useful for arrows, expand/collapse indicators, dropdown arrows, pagination buttons, etc.
Basic example
// A downward-pointing arrow, like a dropdown indicator
addComponent(new Triangle(920, 440, 40, 24)
.direction(Triangle.Direction.DOWN) // UP, DOWN, LEFT, or RIGHT
.fillColor(0xFFCCCCCC) // Light gray
);
All methods
-
FLUENTdirection(Triangle.Direction dir)Which way the triangle points. Options:
Triangle.Direction.UP,DOWN,LEFT,RIGHT. -
FLUENTfillColor(int argbColor)The color that fills the triangle.
TextField
A TextField is a box the player can click on and type into — like a search bar or a name input. It handles everything automatically: cursor blinking, text scrolling when the text gets long, keyboard shortcuts (Ctrl+C to copy, Ctrl+V to paste, Ctrl+X to cut), and focus management (clicking another text field deselects this one).
Basic example
// Keep a reference to read the text later
TextField nameField = new TextField(600, 400, 400, 36)
.placeholder("Enter your username...") // Gray hint text shown when empty
.maxLength(32) // Maximum 32 characters allowed
.onTextChanged(text -> { // Called every time the text changes
System.out.println("Text is now: " + text);
});
addComponent(nameField);
// Later (e.g. in your save button's onClick), read the text:
// String enteredName = nameField.getText();
All methods
-
FLUENTplaceholder(String hint)Gray hint text displayed when the field is empty. Disappears when the player starts typing.
-
FLUENTmaxLength(int max)Maximum number of characters the player can type. The field stops accepting input once this limit is reached.
-
EVENTonTextChanged(Consumer<String> callback)A function called every time the text changes. The new text is passed as a parameter.
-
GETTERgetText()Returns the text currently typed in the field. Call this when the player submits a form.
-
FLUENTsetText(String text)Programmatically sets the content of the field. Useful to pre-fill with existing data.
-
FLUENTsetFocused(boolean focused)Manually give or remove keyboard focus. When focused, keyboard input goes to this field.
TextField automatically supports: Ctrl+C (copy), Ctrl+V (paste), Ctrl+X (cut), Home/End (jump to start/end), Arrow keys (move cursor). You don't need to add any code for these.
NumericField
A NumericField is like a TextField but it only accepts numbers. The player cannot type letters or symbols. You can set a minimum and maximum value, allow or disallow decimal numbers, and allow or disallow negative numbers. Perfect for quantity selectors, price inputs, or any numeric setting.
Basic example
NumericField quantityField = new NumericField(700, 400, 200, 36)
.placeholder("Quantity") // Hint text when empty
.min(1) // Minimum allowed value
.max(64) // Maximum allowed value (one stack)
.decimal(false) // Only whole numbers (no decimals)
.negative(false); // No negative numbers
addComponent(quantityField);
// Later, get the value:
// double qty = quantityField.getValue();
All methods
-
FLUENTmin(double minimum)The smallest value the field will accept. The field clamps to this if the player types something lower.
-
FLUENTmax(double maximum)The largest value the field will accept.
-
FLUENTdecimal(boolean allow)If true, decimal numbers (like 3.14) are allowed. If false, only whole numbers.
-
FLUENTnegative(boolean allow)If true, negative numbers are allowed. If false, only zero and positive.
-
GETTERgetValue()Returns the current numeric value as a
double. Cast tointif you need a whole number.
PasswordField
A PasswordField is a text input where every character is hidden behind a bullet symbol (like ••••••). This prevents someone looking over the player's shoulder from reading the password. It can optionally show a "reveal" toggle button.
Basic example
PasswordField passField = new PasswordField(700, 450, 400, 36)
.placeholder("Enter password...")
.bulletChar('*') // The character used to hide each letter. Default is '•'
.toggleReveal(true); // Show an eye icon to reveal/hide the password
addComponent(passField);
// Read the actual password (not the bullet characters):
// String password = passField.getText();
All methods
-
FLUENTbulletChar(char bullet)The character shown in place of each typed character. Default is the bullet '•'. You can use '*' for a more classic look.
-
FLUENTtoggleReveal(boolean show)If true, a small eye icon appears at the right of the field. Clicking it toggles between showing and hiding the text.
-
GETTERgetText()Returns the actual text typed (not the bullet characters). Use this to validate the password.
MultiLineField
A multi-line text input with vertical scrolling, optional line numbers, and full multi-line selection. Ideal for consoles, code editors, or long text areas.
2
3
4
System.out.println(
"Hello EriAPI!"
);
MultiLineField editor = new MultiLineField()
.originalPos(50, 50)
.originalSize(300, 150)
.placeholder("Enter your code here...")
.showLineNumbers(true)
.maxLines(100)
.tabSize(4)
.onTextChanged(text -> System.out.println("Text changed"));
Keyboard shortcuts
| Shortcut | Action |
|---|---|
Enter | New line |
Backspace (at col 0) | Merge with previous line |
Delete (at end of line) | Merge with next line |
↑ / ↓ | Vertical navigation (column memory) |
Home / End | Start / end of line |
Ctrl+Home / End | Start / end of document |
Shift+arrows | Multi-line selection |
Ctrl+A / C / V / X | Select all / Copy / Paste / Cut |
Tab | Insert spaces (configurable via tabSize) |
Fluent API
| Method | Description |
|---|---|
.placeholder(String) | Text shown when field is empty |
.maxLength(int) | Max total character count |
.maxLines(int) | Max line count (0 = unlimited) |
.showLineNumbers(boolean) | Show line numbers |
.tabSize(int) | Number of spaces for Tab (default: 4) |
.lineHeight(int) | Line height in pixels |
.scrollSpeed(int) | Vertical scroll speed |
.onTextChanged(Consumer<String>) | Callback when text changes |
.backgroundColor(int) | Background color |
.textColor(int) | Text color |
.cursorColor(int) | Cursor color |
.selectionColor(int) | Selection color |
.lineNumberColor(int) | Line number color |
Useful methods
| Method | Description |
|---|---|
getText() | Returns all text (lines joined by \n) |
setText(String) | Replaces all text |
getLineCount() | Current line count |
isFocused() | Whether the field has focus |
AutoCompleteField
A text input with auto-complete suggestions displayed in a dropdown.
Extends TextField — same editing behavior, plus a suggestion dropdown overlay.
AutoCompleteField field = new AutoCompleteField()
.originalPos(100, 50)
.originalSize(200, 16)
.placeholder("Command...")
.suggestions("help", "give", "gamemode", "gamerule", "tp", "time")
.onSuggestionAccepted(s -> System.out.println("Accepted: " + s));
AutoCompleteField field = new AutoCompleteField()
.originalPos(100, 50)
.originalSize(200, 16)
.placeholder("Search player...")
.suggestionSupplier(query -> {
// Dynamic search based on typed text
return playerList.stream()
.filter(p -> p.toLowerCase().startsWith(query.toLowerCase()))
.collect(Collectors.toList());
})
.maxSuggestions(6)
.filterContains(true);
Dropdown navigation
| Shortcut | Action |
|---|---|
↑ / ↓ | Navigate suggestions |
Enter | Accept selected suggestion |
Tab | Accept suggestion (or the only remaining one) |
Escape | Close dropdown (keep focus) |
Fluent API
| Method | Description |
|---|---|
.suggestions(String...) | Static suggestion list |
.suggestions(List<String>) | Static suggestion list |
.suggestionSupplier(Function<String, List<String>>) | Dynamic suggestion supplier |
.maxSuggestions(int) | Max displayed suggestions (default: 8) |
.caseSensitive(boolean) | Case-sensitive filtering (default: false) |
.filterContains(boolean) | true = contains, false = startsWith (default) |
.onSuggestionAccepted(Consumer<String>) | Callback when a suggestion is accepted |
.dropdownBackground(int) | Dropdown background color |
.dropdownBorder(int) | Dropdown border color |
.dropdownHoverColor(int) | Dropdown hover color |
.dropdownTextColor(int) | Dropdown text color |
.dropdownItemHeight(int) | Dropdown item height |
RenderUtil.pauseScissor() to render
on top of parent containers (ScrollPanel, etc.), ensuring visibility even in complex layouts.
GridLayout
A GridLayout automatically arranges components into a grid — rows and columns. Instead of calculating x/y coordinates for each button yourself, you just add them to the grid and it places them evenly. Think of a hotbar grid, a 3x3 option panel, or a card layout.
Basic example
// Create a 2-column grid starting at x=400, y=300, total size 800x400
GridLayout grid = new GridLayout(400, 300, 800, 400)
.columns(2) // 2 columns side by side
.spacing(16) // 16-pixel gap between items
.padding(24); // 24-pixel padding inside the grid borders
// Add buttons — they are placed automatically left-to-right, then wrap to next row
grid.add(new Button(0, 0, 0, 44).text("Option 1").colorScheme(Button.Style.CYAN));
grid.add(new Button(0, 0, 0, 44).text("Option 2").colorScheme(Button.Style.PURPLE));
grid.add(new Button(0, 0, 0, 44).text("Option 3").colorScheme(Button.Style.GREEN));
grid.add(new Button(0, 0, 0, 44).text("Option 4").colorScheme(Button.Style.RED));
// Don't forget to add the grid itself to the screen
addComponent(grid);
When adding components to a GridLayout, the x/y coordinates you pass to each component's
constructor are ignored — the grid calculates the correct position automatically. Just
pass 0, 0 for x and y. The width and height still matter for items that
don't auto-fill (like labels), but the grid overrides the cell dimensions.
All methods
-
FLUENTcolumns(int count)How many columns the grid has. Components wrap to the next row after this many columns.
-
FLUENTrows(int count)Optional: explicitly set how many rows. Usually you let the grid calculate this from the number of items.
-
FLUENTspacing(int pixels)Gap (in design pixels) between each cell.
-
FLUENTpadding(int pixels)Empty space around the inside edge of the grid.
-
FLUENTadd(Component component)Adds a component to the next available cell in the grid.
ScrollList
A ScrollList is a list of items that the player can scroll through. Think of a server player list, an item catalog, a friend list, or a list of available quests. It optionally shows a search bar at the top so the player can filter items by name. The list renders a scrollbar automatically when there are more items than fit on screen.
Basic example
// ScrollList(x, y, width, height)
ScrollList myList = new ScrollList(300, 200, 600, 500)
.showSearch(true) // Show a search box at the top
.itemHeight(40) // Each item is 40 pixels tall
.showScrollbar(true); // Show the scrollbar on the right
// Add items to the list (see ListItem section for creating custom items)
myList.addItem(new MyCustomItem("Steve"));
myList.addItem(new MyCustomItem("Alex"));
myList.addItem(new MyCustomItem("Creeper"));
addComponent(myList);
All methods
-
FLUENTaddItem(ListItem item)Adds one item to the list. Items are displayed in the order they are added.
-
FLUENTshowSearch(boolean show)If true, a search field appears above the list. Items are filtered in real time as the player types.
-
FLUENTshowScrollbar(boolean show)If true, a scrollbar appears on the side when there are more items than fit.
-
FLUENTitemHeight(int pixels)How tall each item row is in design pixels.
-
FLUENTclearItems()Removes all items from the list. Useful when refreshing the list with new data.
Texture support
The list background uses the inherited backgroundImage from Component.
Items and the scrollbar thumb can also receive their own textures.
-
FLUENTitemBackgroundImage(ResourceLocation texture)Background texture for each item (normal state). Replaces
itemBackgroundColorwhen set. -
FLUENTitemHoverImage(ResourceLocation texture)Background texture on hover. Falls back to
itemBackgroundImageif not set. -
FLUENTitemSelectedImage(ResourceLocation texture)Background texture for the selected item. Falls back to
itemBackgroundImageif not set. -
FLUENTitemImageScaleMode(ScaleMode mode)How the item textures are scaled.
-
FLUENTitemImageTint(int argb)ARGB tint applied on the item textures.
-
FLUENTitemSliceBorder(int pixels)9-slice border for item textures (when
itemImageScaleModeisNINE_SLICE). -
FLUENTthumbImage(ResourceLocation texture)Texture for the scrollbar thumb (the draggable handle).
-
FLUENTthumbScaleMode(ScaleMode mode)How the thumb texture is scaled.
-
FLUENTthumbImageTint(int argb)ARGB tint applied on top of the thumb texture.
ListItem
ListItem is an abstract class you extend to create your own custom rows for a ScrollList.
Each item has an ID (a unique number), a display name (used for search filtering), and a
render() method where you draw whatever you want inside the row.
How to create a custom list item
// Create a file PlayerListItem.java
public class PlayerListItem extends ListItem {
// The player name this item represents
private final String playerName;
// Constructor — takes an ID (unique number) and the player name
public PlayerListItem(int id, String playerName) {
super(id, playerName); // "playerName" is also the search display name
this.playerName = playerName;
}
// This is called by ScrollList to draw your row.
// x, y = top-left corner of this row on screen
// width, height = dimensions of the row on screen
@Override
public void render(int x, int y, int width, int height, int mouseX, int mouseY) {
// Draw a simple gray background for each row
RenderUtil.drawRect(x, y, width, height, 0x33FFFFFF);
// Draw the player name on the left
RenderUtil.drawText(playerName, x + 10, y + height / 2 - 4, 0xFFFFFFFF, false);
// You can draw anything here: icons, health bars, item icons, etc.
}
// Optional: called when the player clicks on this row
@Override
public void onClick() {
System.out.println("Player clicked on: " + playerName);
}
}
Methods to implement
-
ABSTRACTrender(int x, int y, int width, int height, int mouseX, int mouseY)REQUIRED — draw your row content here. x/y is where this row starts on screen. Draw everything relative to x and y.
-
EVENTonClick()Optional — called when the player clicks on this row. Override it to handle selection.
-
GETTERgetId()Returns the unique ID of this item (set in the constructor).
-
GETTERgetDisplayName()Returns the name used for search filtering.
ListRenderContext
ListRenderContext is a render helper for ListItem rows. It wraps
the row coordinates (x, y, width, height) and the mouse position, and exposes ready-to-use
methods for drawing design-scaled text, Minecraft item icons, and computing dimensions
proportional to the row size.
Without this helper, drawing vertically-centered text inside a row whose height changes with
the window quickly becomes painful. With ListRenderContext, you express vertical
offsets in permil (1/1000) of the row height — the layout stays correct at every
resolution.
import fr.eri.eriapi.gui.components.ListItem;
import fr.eri.eriapi.gui.components.ListRenderContext;
public class RecipeItem extends ListItem {
private final ItemStack icon;
private final String name, cost, status;
public RecipeItem(String id, ItemStack icon, String name, String cost, String status) {
super(id, name);
this.icon = icon; this.name = name; this.cost = cost; this.status = status;
}
@Override
public void render(int x, int y, int width, int height, int mouseX, int mouseY, float pt) {
ListRenderContext ctx = ListRenderContext.of(x, y, width, height, mouseX, mouseY);
int gap = ctx.gap();
// Item icon on the left, size auto-proportional to the row height
int iconSize = ctx.drawItem(icon, gap * 2, 0);
int textX = gap * 2 + iconSize + gap;
// Status on the right
int statusW = ctx.textWidth(status);
int statusOffsetX = width - gap * 2 - statusW;
int textMaxW = statusOffsetX - textX - gap;
// Text with PROPORTIONAL vertical offset (drawTextProp)
ctx.drawTextProp(name, textX, -150, textMaxW, 0xFFFFFFFF);
ctx.drawTextProp(cost, textX, +150, textMaxW, 0xFF4ADE80);
ctx.drawTextProp(status, statusOffsetX, -150, statusW + gap, 0xFFBB55FF);
}
@Override public String getSearchText() { return name; }
}
Public fields
-
FIELDfinal int x, y, width, heightRow position and size in screen pixels.
-
FIELDfinal int mouseX, mouseYMouse position in screen pixels.
Construction
-
STATICstatic ListRenderContext of(int x, int y, int width, int height, int mouseX, int mouseY)Creates a context from the parameters of
ListItem.render().
Proportional sizing
-
METHODint propW(int permil)Returns a width proportional to the row width (permil: 1000 = full width). Minimum 1 pixel.
-
METHODint propH(int permil)Returns a height proportional to the row height. Minimum 1 pixel.
-
METHODint gap()Standard gap proportional to the row width (minimum 2 pixels).
Positioning
-
METHODint midY()Vertical center of the row (
y + height / 2). -
METHODint centerY(int elementHeight)Y to vertically center an element of the given height.
-
METHODint rightX(int offset)X measured from the right edge, inset by
offsetscreen pixels (x + width - offset). -
METHODboolean isHover(int rx, int ry, int rw, int rh)Checks whether the mouse is inside the given screen-pixel rectangle.
Drawing
-
METHODint drawItem(ItemStack stack, int offsetX, int offsetY)Draws a Minecraft item icon. Size is proportional to the row height (
height - 6px). WhenoffsetY = 0, the icon is vertically centered. Returns the icon size in screen pixels. -
METHODvoid drawText(String text, int offsetX, int offsetY, int maxWidth, int color)Draws design-scaled text.
offsetYis in raw screen pixels from the row's vertical center. WhenmaxWidth > 0, the text is clipped to fit. -
METHODvoid drawTextProp(String text, int offsetX, int offsetYPermil, int maxWidth, int color) v1.6.1Variant of
drawTextwhere the vertical offset is expressed in permil of the row height (1/1000). Essential for layouts that need to stay correct at any window size. Example:offsetYPermil = -150places text 15% of the row height above center;+150places it 15% below. -
METHODvoid drawRect(int rx, int ry, int rw, int rh, int color)Draws a filled rectangle (badges, inline buttons).
-
METHODvoid drawCenteredText(String text, int rx, int ry, int rw, int rh, int color)Draws text centered inside a rectangle.
Measurement
-
METHODint textWidth(String text)Text width in screen pixels (design-scaled).
-
METHODint textHeight()Single text line height in screen pixels (design-scaled).
ScrollPanel
A ScrollPanel is a container that lets you place any EriAPI components inside it and makes the content scrollable. Unlike ScrollList (which requires custom ListItem classes), ScrollPanel works with anything: labels, buttons, shapes, other layouts, etc. Think of it like a div with overflow: scroll in web design.
Basic example
// Create a panel that is 600x400 on screen but holds up to 1200px of content
ScrollPanel panel = new ScrollPanel(300, 200, 600, 400);
// Add any components INSIDE the panel
// The y coordinates are relative to the panel's content area, not the screen
panel.addChild(new Label(0, 0, 580, 30).text("Section 1").color(Colors.CYAN));
panel.addChild(new Label(0, 40, 580, 60).text("Long description text...").color(Colors.LIGHT_GRAY));
panel.addChild(new Button(0, 110, 200, 36).text("Action 1").colorScheme(Button.Style.CYAN));
panel.addChild(new Label(0, 170, 580, 30).text("Section 2").color(Colors.CYAN));
// ... add as many as you want, the panel will scroll
addComponent(panel);
The player can scroll the panel content using the mouse wheel. A scrollbar is automatically rendered on the right side. The player can also click and drag the scrollbar handle. All of this is handled automatically.
Methods
-
FLUENTaddChild(Component component)Adds a component inside the scrollable content area. Position coordinates are relative to the panel's content origin (0, 0 = top-left of content).
Texture support
The panel background uses the inherited backgroundImage from Component.
The scrollbar thumb can also receive its own texture.
-
FLUENTthumbImage(ResourceLocation texture)Texture for the scrollbar thumb.
-
FLUENTthumbScaleMode(ScaleMode mode)How the thumb texture is scaled.
-
FLUENTthumbImageTint(int argb)ARGB tint applied on top of the thumb texture.
TabView
A TabView is like the tabs in your browser — you click a tab at the top and the content below changes. It lets you pack several distinct "pages" into one compact area of your GUI without the player having to open a second screen. Each tab has a title shown in the header bar, and its own Panel (a simple container) that becomes visible when the tab is selected.
Tab is a tiny data object that holds a title, a reference to its
Panel, and whether it is currently active. Panel is a lightweight
container you fill with components. TabView is the visible widget
that manages them all and handles clicks. You mostly only interact with
TabView directly.
Basic example
// 1. Build the content for each tab using Panel
Panel inventory = new Panel()
.add(new Label("My items").originalPos(110, 90).originalSize(200, 14));
Panel stats = new Panel()
.add(new ProgressBar().originalPos(110, 90).originalSize(200, 14).progress(0.7f));
// 2. Create the TabView, give it a position and size
TabView tabs = new TabView()
.originalPos(100, 50)
.originalSize(300, 200)
.addTab("Inventory", inventory) // first tab
.addTab("Stats", stats) // second tab
.selected(0) // start on the first tab (index 0)
.onTabChange(index -> System.out.println("Tab " + index));
// 3. Register it like any other component
addComponent(tabs);
Panel is a plain container with no scrolling. If you need scrollable
content inside a tab, add a ScrollPanel as a child of your
Panel instead of adding components directly.
Tab — data class
A simple record that glues a title string, a Panel, and an active flag together. You
will rarely create Tab objects directly — TabView.addTab()
creates them for you.
-
Tab(String title, Panel content)Creates a Tab.
titleis what appears on the clickable header button.contentis the Panel displayed when this tab is selected. -
GETTERisActive()Returns
trueif this tab is the one currently shown.
Panel — content container
A Panel is a ContainerComponent convenience subclass. It has no visual
decoration of its own — it is just a transparent box you fill with components. The
TabView will show or hide it depending on which tab is selected.
-
FLUENTadd(Component component)Adds a child component into this Panel. Coordinates on the child are relative to the Panel's own origin.
TabView methods
-
FLUENTaddTab(String title, ContainerComponent content)Registers a new tab. The
titlestring appears on the clickable header button.contentis the Panel (or any ContainerComponent) that will be shown when this tab is selected. Tabs are displayed in the order they are added. -
FLUENTselected(int index)Selects a tab by its zero-based index. Calling
selected(0)shows the first tab you added,selected(1)the second, and so on. -
FLUENTselectByTitle(String title)Selects the tab whose title matches the given string exactly. Useful when you want to jump to a specific tab by name without tracking its index.
-
FLUENTonTabChange(Consumer<Integer> callback)Registers a callback that fires every time the player switches tabs. The integer passed to the callback is the newly selected tab's index. Use a lambda:
.onTabChange(i -> doSomething(i)). -
GETTERgetSelectedIndex()Returns the zero-based index of the currently active tab.
-
GETTERgetSelectedTitle()Returns the title string of the currently active tab.
-
FLUENTtabHeight(int h)Sets the height of the tab header bar in design pixels. Increase this if you want larger clickable header buttons.
-
FLUENTtabBgColor(int argbColor)Background color of inactive tab header buttons.
-
FLUENTactiveTabBgColor(int argbColor)Background color of the currently selected tab header button.
-
FLUENTtabTextColor(int argbColor)Text color of inactive tab labels.
-
FLUENTactiveTabTextColor(int argbColor)Text color of the active tab label.
-
FLUENThighlightColor(int argbColor)Color of the thin indicator bar drawn below the active tab button. This accent line helps players see at a glance which tab is selected.
-
FLUENTcontentBgColor(int argbColor)Background color of the content area (the rectangle below the tab headers where the Panel is rendered).
-
FLUENTcontentBorderColor(int argbColor)Border color drawn around the content area. Set to
0x00000000(fully transparent) to hide the border entirely.
Texture support
Inactive tab headers, the active tab header, and the content area can each display a texture independently of their background colours.
-
FLUENTtabImage(ResourceLocation texture)Texture for inactive tab header buttons.
-
FLUENTactiveTabImage(ResourceLocation texture)Texture for the currently selected tab header button.
-
FLUENTcontentImage(ResourceLocation texture)Texture for the content area (the rectangle below the tab headers).
-
FLUENTtabImageScaleMode(ScaleMode mode)Scale mode for both tab (active and inactive) textures.
-
FLUENTcontentImageScaleMode(ScaleMode mode)Scale mode for the content area texture.
-
FLUENTtabImageTint(int argb)ARGB tint applied on tab textures.
-
FLUENTcontentImageTint(int argb)ARGB tint applied on the content area texture.
-
FLUENTcontentSliceBorder(int pixels)Corner size in pixels for
NINE_SLICEmode on the content texture.
Chart — abstract base class
Chart is the common foundation that every chart type in EriAPI is built on.
You will never create a Chart directly — instead you create a
LineChart, BarChart, or PieChart. But all of them
share the methods listed here, which control things like the title, axis labels, grid
lines, and background color.
Think of it like this: Chart is the "blank canvas and frame" that every
chart type inherits. The specific chart type then decides how to draw the data inside
that frame.
Position and size your chart with the usual .originalPos(x, y) and
.originalSize(w, h) methods inherited from Component.
EriAPI's scaling system converts them to screen pixels automatically.
Default values
Every chart comes pre-configured with sensible defaults so it looks good out of the box with no extra setup:
- Background — deep navy
0xFF1A1A2A - Grid lines — 5 horizontal guide lines, color
0xFF303045 - Axes — drawn in
0xFF505070 - Text — white
- Border —
0xFF404060 - Chart padding — 25 design pixels on each side
- Title height — 12 design pixels
- Show grid — true
Shared methods (available on every chart)
-
FLUENTtitle(String text)Sets the chart title displayed at the very top of the component. Leave it empty if you do not need a title.
-
FLUENTxLabel(String text)Label drawn below the horizontal axis. Use it to describe what the X axis represents (e.g.
"Time (seconds)"or"Player name"). -
FLUENTyLabel(String text)Label drawn along the vertical axis. Use it to describe what the Y axis represents (e.g.
"Score"or"Kills"). -
FLUENTchartPadding(int pixels)Internal padding between the chart border and the actual data area, in design pixels. Default is 25. Increase it if axis labels are being clipped.
-
FLUENTtitleHeight(int pixels)Height reserved at the top of the chart for the title text, in design pixels. Default is 12.
-
FLUENTgridLines(int count)Number of horizontal grid lines drawn inside the chart area. Default is 5. Set to 0 to disable them entirely.
-
FLUENTshowGrid(boolean show)Toggles grid line rendering.
showGrid(false)hides all grid lines without changing thegridLinescount. -
FLUENTbackgroundColor(int argbColor)Fill color of the chart's background rectangle. Use the
0xAARRGGBBformat. Default is0xFF1A1A2A. -
FLUENTgridColor(int argbColor)Color of the horizontal grid lines. Default is
0xFF303045. -
FLUENTaxisColor(int argbColor)Color of the X and Y axes. Default is
0xFF505070. -
FLUENTtextColor(int argbColor)Color used for all text drawn on the chart (title, axis labels, tick values). Default is white.
-
FLUENTborderColor(int argbColor)Color of the thin border drawn around the chart. Default is
0xFF404060. Set alpha to 0 to hide it.
LineChart
A LineChart draws one or more lines across a coordinate plane, where the
horizontal axis is X and the vertical axis is Y. It is perfect for showing how a value
changes over time — for example, a player's ping history, a server's TPS over the last
minute, or the progress of a stat as a player levels up.
You can add multiple datasets — each dataset is a named series of (x, y) data points drawn as its own colored line. A legend can be shown so players know which line belongs to which dataset.
LineChart.DataPoint is a tiny helper class that holds exactly two
numbers: an x value and a y value. You create one like
this: new LineChart.DataPoint(3.0f, 47.5f). The chart figures out
the scale automatically based on all the points you provide.
Basic example
import java.util.Arrays;
import java.util.List;
// 1. Build a list of data points (x, y pairs)
List<LineChart.DataPoint> pingData = Arrays.asList(
new LineChart.DataPoint(0, 42),
new LineChart.DataPoint(1, 38),
new LineChart.DataPoint(2, 55),
new LineChart.DataPoint(3, 60),
new LineChart.DataPoint(4, 47)
);
// 2. Create the chart
LineChart ping = new LineChart()
.originalPos(50, 50)
.originalSize(300, 180)
.title("Ping over time")
.xLabel("Seconds")
.yLabel("ms")
.addDataset("My ping", pingData) // add the dataset with a name
.datasetColor("My ping", 0xFF00CFFF) // give it a color
.showLegend(true) // show the legend
.showDots(true) // draw a dot at each data point
.showGrid(true)
.gridLines(4);
// 3. Register it
addComponent(ping);
Multiple datasets example
List<LineChart.DataPoint> redTeam = Arrays.asList(
new LineChart.DataPoint(0, 10),
new LineChart.DataPoint(1, 15),
new LineChart.DataPoint(2, 12)
);
List<LineChart.DataPoint> blueTeam = Arrays.asList(
new LineChart.DataPoint(0, 8),
new LineChart.DataPoint(1, 20),
new LineChart.DataPoint(2, 18)
);
LineChart scores = new LineChart()
.originalPos(50, 50)
.originalSize(300, 180)
.title("Team Scores")
.addDataset("Red Team", redTeam)
.datasetColor("Red Team", 0xFFFF4455)
.addDataset("Blue Team", blueTeam)
.datasetColor("Blue Team", 0xFF4488FF)
.showLegend(true)
.showDots(false); // lines only, no dots
addComponent(scores);
LineChart methods
These are in addition to all the Chart base methods.
-
FLUENTaddDataset(String name, List<DataPoint> data)Adds a new line to the chart.
nameis used as the legend label and as the key fordatasetColor()andremoveDataset().datais the list of (x, y) points. -
FLUENTdatasetColor(String name, int argbColor)Assigns a color to the dataset identified by
name. If you do not call this, EriAPI picks a default color automatically. -
FLUENTremoveDataset(String name)Removes the dataset with the given name from the chart. Useful for dynamically updating which data series are displayed.
-
FLUENTclearDatasets()Removes all datasets at once. Call this before loading a completely fresh set of data.
-
FLUENTshowLegend(boolean show)Shows or hides the legend box that maps each colored line to its dataset name. Turn it on when you have more than one dataset.
-
FLUENTshowDots(boolean show)When
true, a small filled circle is drawn at every data point on the line, making individual values easier to spot. Default istrue. -
FLUENTlineWidth(int pixels)Thickness of the drawn lines in screen pixels. Default is 1. Use 2 or 3 for bolder, more visible lines.
DataPoint — inner helper class
A simple object that pairs an X value with a Y value. Both are float
numbers, so you can use decimals (e.g. 3.5f). You will always create
these inline when building your dataset list.
-
DataPoint(float x, float y)Creates a point at coordinate (x, y). The chart automatically determines the min/max range from all points in all datasets.
BarChart
A BarChart displays data as vertical bars standing side by side. Each bar
has a text label below it (shown on the X axis) and a numeric value that controls its
height. Bar charts are great for comparing things at a glance — top players on a
leaderboard, item counts per category, kills per round, and so on.
You can give every bar its own color, or set one default color for all bars. When the player hovers over a bar, it can highlight with a different color to make the interface feel responsive.
Basic example
// 1. Create the chart and add bars one by one
BarChart leaderboard = new BarChart()
.originalPos(50, 50)
.originalSize(300, 180)
.title("Top Players")
.yLabel("Kills")
.addBar("Alice", 42)
.addBar("Bob", 37)
.addBar("Carol", 55)
.addBar("Dave", 28)
.barColor(0xFF4488FF) // default color for all bars
.hoverBarColor(0xFF66AAFF) // color when the player hovers a bar
.showValues(true) // draw the numeric value above each bar
.showLabels(true) // draw the text label below each bar
.showGrid(true);
// 2. Register it
addComponent(leaderboard);
Per-bar colors example
BarChart stats = new BarChart()
.originalPos(50, 50)
.originalSize(300, 180)
.title("Resource Usage")
// addBar(label, value, color) — third argument overrides the default color
.addBar("CPU", 72f, 0xFFFF6644)
.addBar("RAM", 55f, 0xFF44AAFF)
.addBar("Disk", 30f, 0xFF44DD88)
.showValues(true)
.valueFormat("%.0f%%"); // format: "72%", "55%", etc.
addComponent(stats);
BarChart methods
These are in addition to all the Chart base methods.
-
FLUENTaddBar(String label, float value)Adds a bar with the given label and height value. The bar uses the default
barColor. Bars are rendered in the order they are added. -
FLUENTaddBar(String label, float value, int argbColor)Adds a bar with its own individual color, overriding the chart's default
barColorfor this bar only. -
FLUENTupdateBar(String label, float value)Updates the value of an existing bar identified by its label. Use this to refresh data without rebuilding the entire chart.
-
FLUENTclearBars()Removes all bars. Call this before reloading a completely fresh set of data.
-
FLUENTbarColor(int argbColor)Default fill color applied to every bar that does not have its own individual color. Default is a soft blue.
-
FLUENThoverBarColor(int argbColor)Color applied to whichever bar the player's mouse is currently hovering over. Gives the chart a responsive feel.
-
FLUENTbarSpacing(int pixels)Gap between adjacent bars in design pixels. Increase this if bar labels overlap each other.
-
FLUENTshowValues(boolean show)When
true, the numeric value of each bar is drawn just above its top edge. Formatted withvalueFormat. -
FLUENTshowLabels(boolean show)When
true, the text label of each bar is drawn below the bar along the X axis. -
FLUENTvalueFormat(String format)A
String.formatpattern used to format the numeric value displayed above each bar whenshowValues(true)is set. Examples:"%.0f"→ whole numbers,"%.1f"→ one decimal,"%.0f%%"→ percentage sign.
PieChart
A PieChart divides a circle into colored slices, where each slice's size
is proportional to its value relative to the total. It is ideal for showing how a whole
is split into parts — for example, the percentage of players in each team, the breakdown
of items in a chest, or how time is distributed across activities.
Each slice has a label and a value. You can optionally show the percentage each slice represents, and display a legend that maps colors to labels.
You do not need to calculate percentages yourself. You simply provide raw values
(e.g. 42, 18, 30) and the chart automatically
works out what fraction of the circle each slice occupies. The total can be anything.
Basic example
// 1. Create the chart and add slices
PieChart distribution = new PieChart()
.originalPos(50, 50)
.originalSize(200, 200) // square looks best for pie charts
.title("Team Distribution")
.addSlice("Red Team", 42, 0xFFFF4455)
.addSlice("Blue Team", 38, 0xFF4488FF)
.addSlice("Green Team", 20, 0xFF44CC66)
.showLegend(true) // show color-to-label legend
.showPercentage(true) // draw "42%" inside or near each slice
.segments(64); // smoothness of slice edges (higher = smoother circle)
// 2. Register it
addComponent(distribution);
Auto-color example
// If you don't provide a color, EriAPI picks one automatically
PieChart inventory = new PieChart()
.originalPos(50, 50)
.originalSize(200, 200)
.title("Inventory Contents")
.addSlice("Swords", 5) // no third argument → auto color
.addSlice("Armor", 12)
.addSlice("Food", 30)
.addSlice("Misc", 8)
.showLegend(true)
.showPercentage(false);
addComponent(inventory);
PieChart methods
These are in addition to all the Chart base methods.
-
FLUENTaddSlice(String label, float value, int argbColor)Adds a slice with an explicit color. The slice occupies a portion of the circle proportional to
valuerelative to the sum of all slice values. -
FLUENTaddSlice(String label, float value)Adds a slice and lets EriAPI automatically assign a color from a built-in palette. Convenient when you don't need precise color control.
-
FLUENTclearSlices()Removes all slices. Use this before providing a completely fresh dataset.
-
FLUENTshowLegend(boolean show)Shows or hides a legend alongside the pie that maps each color to its slice label. Recommended when
showPercentageis off or when slices are very small. -
FLUENTshowPercentage(boolean show)When
true, the calculated percentage (e.g."42%") is drawn on or near each slice. Slices that are too small to fit the text are skipped automatically. -
FLUENTsegments(int count)Number of OpenGL triangle segments used to draw each slice. Higher values produce a smoother circular edge. Default is 64. Values below 16 will look noticeably faceted.
ProgressBar
A ProgressBar shows how much of something is complete — experience points, a loading bar, health remaining, a quest objective. It takes a value between 0.0 (empty) and 1.0 (full) and draws a colored fill accordingly. It can optionally animate the fill and show the percentage as text.
Basic example
// A health bar: 70% full
addComponent(new ProgressBar(400, 300, 600, 24)
.progress(0.7f) // 0.0 = empty, 1.0 = full. 0.7 = 70%
.fillColor(0xFF22CC44) // Green fill
.backgroundColor(0xFF333333) // Dark gray empty part
.cornerRadius(6) // Rounded ends
.showPercentage(true) // Show "70%" text over the bar
.animated(true) // Smoothly animate fill changes
);
All methods
-
FLUENTprogress(float value)Sets the fill level. Must be between 0.0 and 1.0. Call this whenever you want to update the bar (e.g. when player gains XP).
-
FLUENTfillColor(int argbColor)The color of the filled portion of the bar.
-
FLUENTbackgroundColor(int argbColor)The color of the empty (background) portion of the bar.
-
FLUENTcornerRadius(int radius)Rounds the ends of the progress bar.
-
FLUENTshowPercentage(boolean show)If true, draws the percentage (e.g. "70%") as text centered over the bar.
-
FLUENTanimated(boolean animate)If true, the bar fill transitions smoothly when
progress()is called with a new value, instead of jumping instantly.
Texture support
In addition to flat colours, you can skin the bar with textures. The fill texture
(fillImage) is clipped via scissor so it follows the progress level exactly.
The inherited backgroundImage from Component covers the empty
(background) portion of the bar.
ProgressBar bar = new ProgressBar()
.originalPos(100, 50)
.originalSize(200, 16)
.progress(0.7f)
.fillImage(new ResourceLocation("mymod", "textures/gui/fill.png"))
.fillScaleMode(ScaleMode.NINE_SLICE)
.fillSliceBorder(4);
// Background texture (inherited from Component)
bar.backgroundImage(new ResourceLocation("mymod", "textures/gui/bar_bg.png"));
-
FLUENTfillImage(ResourceLocation texture)Texture for the filled portion of the bar. Clipped by scissor to match the current progress level.
-
FLUENTfillScaleMode(ScaleMode mode)How the fill texture is stretched:
STRETCH,NINE_SLICE,TILE, orFIT. -
FLUENTfillImageTint(int argb)ARGB tint applied on top of the fill texture. Defaults to
0xFFFFFFFF(no tint). -
FLUENTfillSliceBorder(int pixels)Corner size in pixels for
NINE_SLICEmode.
Slider
A Slider lets the player drag a handle along a track to pick a value within a range. Think of a volume slider, a render distance slider, or a brightness control. The player clicks and drags the handle. EriAPI handles all the math and mouse tracking.
Basic example
Slider volumeSlider = new Slider(400, 400, 500, 32)
.value(0.5) // Starting value (range: min to max)
.range(0.0, 1.0) // Min and max values
.step(0.05) // Snap to increments of 0.05 (5%)
.showValue(true) // Display the current value as text
.onValueChange(v -> { // Called every time the slider moves
System.out.println("Volume: " + (int)(v * 100) + "%");
});
addComponent(volumeSlider);
// Read the current value later:
// double vol = volumeSlider.getValue();
All methods
-
FLUENTvalue(double initialValue)The starting value of the slider when the screen opens.
-
FLUENTrange(double min, double max)The minimum and maximum values. The slider's handle moves between these two extremes.
-
FLUENTstep(double step)The snap increment. For example, step(1.0) makes the slider jump between whole numbers. Use 0 for continuous (no snapping).
-
FLUENTshowValue(boolean show)If true, the current value is displayed as text next to the slider handle.
-
EVENTonValueChange(Consumer<Double> callback)Called every time the slider value changes. The new value is passed as a parameter.
-
GETTERgetValue()Returns the current value of the slider as a
double.
Texture support
The track and the thumb (handle) can each receive an independent texture.
-
FLUENTtrackImage(ResourceLocation texture)Texture for the track (the rail the handle slides along).
-
FLUENTtrackScaleMode(ScaleMode mode)How the track texture is scaled.
-
FLUENTtrackImageTint(int argb)ARGB tint applied on top of the track texture.
-
FLUENTtrackSliceBorder(int pixels)Corner size for
NINE_SLICEmode on the track texture. -
FLUENTthumbImage(ResourceLocation texture)Texture for the slider handle (the knob the player drags).
-
FLUENTthumbScaleMode(ScaleMode mode)How the thumb texture is scaled.
-
FLUENTthumbImageTint(int argb)ARGB tint applied on top of the thumb texture.
Checkbox
A Checkbox is a small square the player can tick on or off. It's for toggling options — like "Enable notifications", "Show online players only", or "Agree to terms". It has a label displayed next to it and fires a callback when toggled.
Basic example
Checkbox notifCheck = new Checkbox(400, 350, 300, 30)
.label("Enable notifications") // Text shown next to the checkbox
.checked(true) // Start as checked (ticked)
.onToggle(isChecked -> { // Called when player clicks it
System.out.println("Notifications enabled: " + isChecked);
});
addComponent(notifCheck);
// Read the current state later:
// boolean enabled = notifCheck.isChecked();
All methods
-
FLUENTlabel(String text)The text displayed to the right of the checkbox box.
-
FLUENTchecked(boolean state)The initial checked state. true = ticked, false = unticked.
-
EVENTonToggle(Consumer<Boolean> callback)Called when the player clicks the checkbox. The new state (true = checked) is passed as a parameter.
-
GETTERisChecked()Returns the current checked state as a boolean.
Texture support
The box and the checkmark can each have their own texture. checkImage uses
ScaleMode.FIT by default to preserve the icon's aspect ratio.
-
FLUENTboxImage(ResourceLocation texture)Texture for the checkbox square (the box background).
-
FLUENTcheckImage(ResourceLocation texture)Texture for the checkmark shown when the box is ticked. Default scale mode:
ScaleMode.FIT. -
FLUENTboxScaleMode(ScaleMode mode)How the box texture is scaled.
-
FLUENTboxImageTint(int argb)ARGB tint applied on top of the box texture.
RadioButton
A RadioButton is like a checkbox but part of a group where only one can be selected at a time. Think of a "Difficulty: Easy / Medium / Hard" selection — you can only pick one. On its own, a RadioButton is just a visual element; you put it inside a RadioGroup to enforce the "only one selected" behavior.
Basic example (single, standalone)
// A single radio button (see RadioGroup for the proper group usage)
RadioButton easyOption = new RadioButton(400, 300, 200, 30)
.label("Easy") // Text shown next to the radio button
.selected(true) // This one is selected by default
.onSelect(() -> { // Called when this option is selected
System.out.println("Difficulty: Easy");
});
addComponent(easyOption);
All methods
-
FLUENTlabel(String text)The text label shown next to the radio circle.
-
FLUENTselected(boolean state)Whether this button is selected (filled circle) or not (empty circle).
-
EVENTonSelect(Runnable callback)Called when the player clicks this radio button to select it.
-
GETTERisSelected()Returns true if this radio button is currently selected.
RadioGroup
A RadioGroup holds multiple RadioButtons and ensures that when you click one, the others
are automatically deselected. This is the correct way to create "pick one from a list"
selections. Use getSelected() to find out which option the player chose.
Basic example
// Create the group — it manages the selection state
RadioGroup difficultyGroup = new RadioGroup(400, 300, 300, 130)
.onSelect(selectedId -> { // Called when any button in the group is clicked
System.out.println("Selected option ID: " + selectedId);
});
// Add radio buttons to the group
// The first argument to add() is a unique ID string for that option
difficultyGroup.add("easy", new RadioButton(0, 0, 280, 36).label("Easy"));
difficultyGroup.add("medium", new RadioButton(0, 0, 280, 36).label("Medium"));
difficultyGroup.add("hard", new RadioButton(0, 0, 280, 36).label("Hard"));
// Select one as the default
difficultyGroup.select("easy");
// Add the group to the screen — this also adds all its radio buttons
addComponent(difficultyGroup);
// Read the selection on a button click:
// String chosen = difficultyGroup.getSelected(); // returns "easy", "medium", or "hard"
All methods
-
FLUENTadd(String id, RadioButton button)Adds a radio button to the group with a unique string ID. The ID is what you get back from
getSelected(). -
FLUENTselect(String id)Programmatically selects the option with the given ID (and deselects all others).
-
EVENTonSelect(Consumer<String> callback)Called whenever the player changes the selection. The selected option's ID is passed as a parameter.
-
GETTERgetSelected()Returns the ID string of the currently selected option, or null if nothing is selected.
Easing
The Easing enum defines interpolation functions for animations.
Each function transforms a linear progression (0→1) into a more natural curve.
Easing.LINEAR // t → linear progression
Easing.EASE_IN // t² → slow start
Easing.EASE_OUT // t(2-t) → slow end
Easing.EASE_IN_OUT // smoothstep → slow at both ends
Easing.EASE_IN_CUBIC // t³ → very slow start
Easing.EASE_OUT_CUBIC // (t-1)³+1 → very slow end
Easing.BOUNCE // bouncing decay
Easing.ELASTIC // dampened oscillation
float result = Easing.EASE_OUT.apply(0.5f); // → 0.75
Animation
The Animation class represents an active animation.
It interpolates a value between from and to over a duration in ticks (20 ticks = 1 second).
import fr.eri.eriapi.gui.anim.*;
Animation anim = Animation.create(0, 1, 20) // 0 to 1 in 1 second
.easing(Easing.EASE_OUT)
.delay(5) // wait 5 ticks before starting
.onUpdate(value -> myComponent.setOpacity(value))
.onComplete(() -> System.out.println("Done!"));
AnimationManager.getInstance().play(anim);
anim.pause();
anim.resume();
anim.stop();
AnimationManager
The AnimationManager is a singleton that manages all active animations.
It is automatically integrated into EriGuiScreen's render loop —
just call play().
AnimationManager manager = AnimationManager.getInstance();
manager.play(Animation.create(0, 100, 20).easing(Easing.BOUNCE));
int count = manager.activeCount();
manager.stopAll();
Built-in Animations
Every Component has built-in animation methods.
They automatically create and play the animation — just call the method.
button.fadeIn(10); // fade in over 0.5 seconds
panel.fadeOut(15); // fade out over 0.75 seconds
button.slideIn(Component.Direction.LEFT, 60, 12);
panel.slideIn(Component.Direction.DOWN, 40, 14).easing(Easing.BOUNCE);
label.slideOut(Component.Direction.RIGHT, 80, 10);
button.scaleIn(10); // scale from 0 to 1
panel.scaleOut(8); // scale from 1 to 0
button.shake(10); // horizontal oscillation
public class MyGui extends EriGuiScreen {
@Override
protected void buildGui() {
GuiFramework.getInstance().setDesignResolution(this.width, this.height);
ContainerComponent panel = new ContainerComponent()
.originalPos(100, 100).originalSize(300, 200)
.backgroundColor(Colors.PANEL_BG);
Button btn = new Button("Click me!")
.originalPos(150, 200).originalSize(120, 30)
.colorScheme(0xFF1A8FA0);
add(panel, btn);
// Entry animations
panel.fadeIn(12);
btn.slideIn(Component.Direction.DOWN, 40, 15);
}
}
Tooltip
Any component can display a tooltip by calling .tooltip("text").
Tooltips are rendered automatically by EriGuiScreen — no extra setup required.
They appear after a configurable hover delay and reposition themselves to stay within screen edges.
.tooltip() is defined on the base Component class,
so it is available on Button, Label, TextField,
Slider, and every other component in the framework.
Key features
| Feature | Details |
|---|---|
| Single-line tooltip | .tooltip("text") |
| Multi-line tooltip | Use \n in Java strings or literal \\n from .lang files — both work automatically |
| Configurable delay | .tooltipDelay(ticks) — default 15 ticks (0.75 s) |
| Auto-positioning | Repositions automatically to avoid screen edges |
| Automatic rendering | Rendered by EriGuiScreen — zero boilerplate |
new Button("Buy")
.originalPos(100, 50)
.originalSize(120, 30)
.onClick(() -> buyItem())
.tooltip("Buy the selected item\nPrice: 100 coins");
// In en_US.lang: tooltip.item.info=Line 1\nLine 2\nLine 3
// The literal \\n from .lang files is automatically normalized to real newlines
new Button("Info")
.originalPos(100, 50)
.originalSize(120, 30)
.tooltip(I18n.format("tooltip.item.info")); // Renders as 3 lines
// Custom delay: 40 ticks = 2 seconds
new Label("Info")
.originalPos(50, 50)
.originalSize(80, 10)
.tooltip("Additional details")
.tooltipDelay(40);
Notification
Notifications are transient messages that slide in from the edge of the screen and automatically disappear after a configurable duration. They come in four types, each with a distinct color and icon.
Notification types
| Type | Color | Use case |
|---|---|---|
Notification.Type.SUCCESS | Green | Action completed successfully |
Notification.Type.ERROR | Red | Something went wrong |
Notification.Type.INFO | Blue | General information |
Notification.Type.WARNING | Orange/Yellow | Something needs attention |
Behaviour
| Property | Value |
|---|---|
| Default duration | 60 ticks (3 seconds) |
| Maximum visible at once | 5 notifications |
| Entry / exit animation | Slide in / slide out |
| Rendering | Automatic via EriGuiScreen |
NotificationManager.success("Purchase complete!");
NotificationManager.error("Insufficient balance.");
NotificationManager.info("Welcome to the server.");
NotificationManager.warning("Low stock!");
// 100 ticks = 5 seconds
NotificationManager.notify(Notification.Type.INFO, "Custom message", 100);
Texture support
The notification background can be replaced by a texture. By default NINE_SLICE
with a 4 px border is used so the texture scales gracefully with different message lengths.
notification
.bgImage(new ResourceLocation("mymod", "textures/gui/notif_bg.png"))
.bgScaleMode(ScaleMode.NINE_SLICE)
.bgSliceBorder(4);
-
FLUENTbgImage(ResourceLocation texture)Background texture for the notification. Replaces the flat background colour.
-
FLUENTbgScaleMode(ScaleMode mode)How the background texture is scaled (default:
NINE_SLICE). -
FLUENTbgSliceBorder(int pixels)Corner size for
NINE_SLICEmode (default: 4).
GradientRectangle
A rectangle component filled with a two-color gradient — either vertical (top to bottom) or horizontal (left to right). The direction and both colors are set via fluent methods.
fr.eri.eriapi.gui.components.GradientRectangle
Constructor
-
FluentGradientRectangle()Creates an empty gradient rectangle. Set position and size with
originalPos(x, y)andoriginalSize(w, h)(inherited fromComponent), then configure the gradient with.vertical()or.horizontal().
API
-
Fluentvertical(int topColor, int bottomColor)Sets the gradient direction to
Direction.VERTICALwith the given top and bottom ARGB colors. Returnsthisfor chaining. -
Fluenthorizontal(int leftColor, int rightColor)Sets the gradient direction to
Direction.HORIZONTALwith the given left and right ARGB colors. Returnsthisfor chaining. -
FluentcornerRadius(int px)Rounds all four corners by
pxdesign pixels.
Direction enum
| Constant | Description |
|---|---|
GradientRectangle.Direction.VERTICAL | Gradient flows from top color to bottom color |
GradientRectangle.Direction.HORIZONTAL | Gradient flows from left color to right color |
// Dark vertical gradient (header fade)
GradientRectangle header = new GradientRectangle()
.originalPos(0, 0)
.originalSize(1920, 120)
.vertical(0xFF1A1A3E, 0x001A1A3E) // opaque top, transparent bottom
.cornerRadius(0);
root.add(header);
// Horizontal color bar
GradientRectangle bar = new GradientRectangle()
.originalPos(200, 500)
.originalSize(600, 8)
.horizontal(0xFF00E5FF, 0xFF9B59FF)
.cornerRadius(4);
root.add(bar);
Aurora
An animated aurora borealis background effect. You add up to 10 color bands; each band is a sinusoidal ribbon that drifts slowly across the component. Ideal as a full-screen background layer.
fr.eri.eriapi.gui.components.Aurora — maximum 10 bands per instance.
Constructor
-
FluentAurora()Creates an aurora effect with no bands. Configure position and size with
originalPos(x, y)andoriginalSize(w, h), then add bands withaddBand().
API
-
FluentaddBand(int color, float frequency, float amplitude, int height, int yOffset)Adds an aurora band.
color: ARGB color (semi-transparent values recommended);frequency: wave frequency — higher = more waves across the width (e.g. 0.02);amplitude: wave height oscillation in design pixels (e.g. 40.0f);height: band thickness in design pixels;yOffset: vertical offset from the top of the component. Maximum 10 bands per instance. -
Fluentspeed(float speed)Animation speed multiplier. Default is 1.0. Higher values make bands drift faster.
-
Fluentsegments(int count)Number of horizontal segments per wave. Higher values produce smoother curves at higher rendering cost.
Aurora aurora = new Aurora()
.originalPos(0, 0)
.originalSize(1920, 1080)
.addBand(0x440088FF, 0.015f, 60f, 220, 200) // blue band
.addBand(0x3300FF88, 0.02f, 45f, 180, 380) // green band
.addBand(0x33AA44FF, 0.012f, 80f, 200, 550) // purple band
.speed(0.6f)
.segments(120);
root.add(aurora);
Starfield
An animated field of twinkling background stars with optional shooting stars. Stars are randomly distributed across the component area. Designed as a full-screen background layer.
fr.eri.eriapi.gui.components.Starfield — maximum 3 simultaneous shooting stars.
Constructor
-
FluentStarfield()Creates a starfield with default settings. Set position and size with
originalPos(x, y)andoriginalSize(w, h).
API
-
FluentstarCount(int count)Total number of background stars to render.
-
FluentstarColor(int argbColor)Base ARGB color for background stars. Individual star brightness varies around this base value.
-
FluentshootingStarChance(float chance)Probability per tick that a new shooting star spawns (0.0 to 1.0). A maximum of 3 shooting stars can be active simultaneously. Set to 0.0 to disable shooting stars entirely.
Starfield stars = new Starfield()
.originalPos(0, 0)
.originalSize(1920, 1080)
.starCount(200)
.starColor(0xCCFFFFFF)
.shootingStarChance(0.003f); // roughly one shooting star every ~6 seconds
root.add(stars);
ParticleSystem
A 2D particle emitter. Particles are spawned at the component origin (or along its edges) and drift according to speed, spread, and lifecycle parameters. Suitable for magic sparkles, fire embers, confetti, and similar effects.
fr.eri.eriapi.gui.components.ParticleSystem
Constructor
-
FluentParticleSystem()Creates an empty particle system. Configure with the fluent methods below, then set position/size with
originalPos(x, y)andoriginalSize(w, h).
API
-
FluentmaxParticles(int max)Maximum number of simultaneously active particles.
-
FluentspawnRate(float perTick)Particles spawned per tick. Can be fractional (e.g. 0.5 = one every 2 ticks).
-
FluentparticleLife(int minMs, int maxMs)Lifetime range per particle in milliseconds. Each particle gets a random value in [minMs, maxMs].
-
FluentparticleSize(int startPx, int endPx)Particle size in design pixels at birth (
startPx) and at death (endPx). Linearly interpolated. -
FluentparticleColor(int argbColor)Base ARGB color. Alpha is respected and combined with fade-in/fade-out.
-
Fluentdrift(float dx, float dy)Average velocity in design pixels per tick. Positive
dydrifts downward. -
Fluentspread(float radius)Random velocity spread (pixels/tick radius) added to the base drift direction.
-
FluentfadeIn(float ratio)Fraction of the particle lifetime (0.0–1.0) during which it fades in from transparent.
-
FluentfadeOut(float ratio)Fraction of the particle lifetime during which it fades out to transparent. E.g. 0.3 = starts fading at 70% of its life.
-
FluentspawnOnEdges(boolean enable)If
true, particles spawn along the component's edges instead of at the center.
ParticleSystem sparkles = new ParticleSystem()
.originalPos(860, 480)
.originalSize(200, 120)
.maxParticles(80)
.spawnRate(1.5f)
.particleLife(600, 1400)
.particleSize(3, 1)
.particleColor(0xFFFFD700)
.drift(0.0f, -0.8f) // float upward
.spread(1.2f)
.fadeIn(0.15f)
.fadeOut(0.35f)
.spawnOnEdges(false);
root.add(sparkles);
SmokeFog
A procedural Perlin-noise fog/smoke overlay rendered in real time. The noise field scrolls continuously and can be given a wind direction. Useful for atmospheric backgrounds, mist over a landscape, or dark smoke layers.
fr.eri.eriapi.gui.components.SmokeFog
Constructor
-
FluentSmokeFog()Creates a smoke/fog effect with default parameters. Set position and size with
originalPos(x, y)andoriginalSize(w, h).
API
-
Fluentcolor(int rgb)Base RGB color of the fog (no alpha — opacity is controlled by
intensity). Example:0x888888for grey smoke. -
Fluentintensity(float value)Maximum opacity of the fog (0.0 to 1.0). Higher values produce denser, more opaque fog.
-
Fluentscale(float value)Spatial scale of the noise pattern. Larger values produce bigger, smoother wisps; smaller values produce fine-grained turbulence.
-
Fluentspeed(float value)How fast the noise pattern scrolls over time. Default is 1.0.
-
Fluentwind(float wx, float wy)Wind direction vector. The fog scrolls in this direction at the configured speed. E.g.
wind(1.0f, 0.2f)drifts mostly to the right with a slight downward angle. -
Fluentoctaves(int count)Number of noise octaves (1–8). More octaves add fine detail at higher rendering cost. Default is 4.
-
Fluentpersistence(float value)Contribution of each successive octave (0.0–1.0). Higher values produce more turbulent, cloud-like patterns.
-
FluentcellSize(int pixels)Resolution of the noise sampling grid in design pixels. Larger cells are cheaper to render but produce blockier fog.
SmokeFog fog = new SmokeFog()
.originalPos(0, 600)
.originalSize(1920, 480)
.color(0x1A1A2E)
.intensity(0.55f)
.scale(2.5f)
.speed(0.4f)
.wind(0.8f, 0.15f)
.octaves(4)
.persistence(0.5f)
.cellSize(8);
root.add(fog);
NotificationManager
NotificationManager is a global singleton that manages all active notifications.
Its tick() and render() methods are called automatically by
EriGuiScreen — you never need to wire them up manually.
API
| Method | Description |
|---|---|
NotificationManager.success(String) | Show a SUCCESS notification |
NotificationManager.error(String) | Show an ERROR notification |
NotificationManager.info(String) | Show an INFO notification |
NotificationManager.warning(String) | Show a WARNING notification |
NotificationManager.notify(Type, String, int) | Show a notification with a custom duration (ticks) |
NotificationManager.clearAll() | Dismiss all active notifications immediately |
NotificationManager.activeCount() | Returns the number of currently visible notifications |
tick() | Advances all notification timers — called by EriGuiScreen |
render(int, int, float) | Renders all visible notifications — called by EriGuiScreen |
public class MyGui extends EriGuiScreen {
@Override
protected void buildGui() {
GuiFramework.getInstance().setDesignResolution(this.width, this.height);
Button buyBtn = new Button("Buy")
.originalPos(100, 50)
.originalSize(120, 30)
.tooltip("Buy the selected item\nPrice: 100 coins")
.onClick(() -> {
if (hasEnoughBalance()) {
processTransaction();
NotificationManager.success("Purchase complete!");
} else {
NotificationManager.error("Insufficient balance.");
}
});
add(buyBtn);
}
}
EriGuiScreen already calls NotificationManager.tick() and
NotificationManager.render() on every frame. Just call the static methods
anywhere in your GUI logic — the notifications will appear automatically.
Network GUI
Client ↔ server communication for EriAPI GUIs — sending actions, receiving data, and opening screens from the server — is covered in the dedicated Network GUI documentation page.
See network.html for the full reference:
GuiNetworkHandler (all static methods),
IGuiDataReceiver (onDataUpdate(String, String, String)),
packet format tables, and a complete client/server shop example.
Colors
The Colors class is a collection of ready-to-use color constants and helper
methods. Instead of memorizing hex codes, you can write Colors.WHITE or
Colors.CYAN. All colors are in ARGB format (0xAARRGGBB).
Color palette
Helper methods
-
STATICColors.withAlpha(int color, int alpha)Takes an existing color and changes its transparency. Alpha: 0 = invisible, 255 = fully opaque. Example:
Colors.withAlpha(Colors.RED, 128)= semi-transparent red. -
STATICColors.fromHex(String hex)Creates a color from a hex string like
"#FF0000"(red) or"#80FF0000"(semi-transparent red). The leading # is optional. -
STATICColors.lerp(int colorA, int colorB, float t)Blends between two colors. t=0.0 returns colorA, t=1.0 returns colorB, t=0.5 returns an equal mix. Great for gradient effects or color transitions.
-
STATICColors.of(int r, int g, int b)Creates an ARGB color from individual red, green, blue values (0-255 each). Automatically sets alpha to 255 (fully opaque).
-
STATICColors.of(int r, int g, int b, int a)Creates an ARGB color with a custom alpha.
Usage examples
// Use a predefined color constant
label.color(Colors.CYAN);
// Use a raw ARGB hex value
label.color(0xFF00DDFF); // same as Colors.CYAN
// Semi-transparent red (AA=80 = about 50% opacity)
rectangle.fillColor(0x80FF0000);
// Create a color from RGB components (fully opaque)
int myColor = Colors.of(100, 200, 50); // a lime green
// Create from a hex string
int fromHex = Colors.fromHex("#FF8800"); // orange
// Blend two colors — useful for hover animations
int blended = Colors.lerp(Colors.GRAY, Colors.CYAN, 0.3f); // 30% towards cyan
// Make a color semi-transparent
int semiRed = Colors.withAlpha(Colors.RED, 128); // 128/255 = ~50% opaque
RenderUtil
RenderUtil is a collection of static drawing methods. You use these when you want
to draw something custom — for example, inside a ListItem.render()
or a component's custom draw code. For most regular use, you don't need to call RenderUtil
directly — the built-in components handle their own drawing.
When you use RenderUtil inside a ListItem.render(), the x/y coordinates
you receive are already in screen pixels (not design pixels). Pass them directly to
RenderUtil — no conversion needed.
Drawing methods
-
STATICRenderUtil.drawRect(int x, int y, int w, int h, int color)Draws a filled rectangle. All coordinates are in screen pixels. Color is ARGB.
-
STATICRenderUtil.drawRoundRect(int x, int y, int w, int h, int radius, int color)Draws a filled rectangle with rounded corners.
-
STATICRenderUtil.drawCircle(int cx, int cy, int radius, int color)Draws a filled circle. cx/cy is the center point.
-
STATICRenderUtil.drawGradient(int x, int y, int w, int h, int colorTop, int colorBottom)Draws a rectangle with a vertical gradient blending from colorTop at the top to colorBottom at the bottom.
-
STATICRenderUtil.drawText(String text, int x, int y, int color, boolean shadow)Draws a string of text at the given position. shadow=true adds a drop shadow.
-
STATICRenderUtil.drawCenteredText(String text, int x, int y, int width, int color, boolean shadow)Draws text horizontally centered within the given width, starting at x.
-
STATICRenderUtil.drawScissor(int x, int y, int w, int h)Enables a clipping region — anything drawn outside this rectangle will be invisible. Call
RenderUtil.stopScissor()when done. -
STATICRenderUtil.stopScissor()Disables the active scissor (clipping) region. Always call this after
drawScissor(). -
STATICRenderUtil.drawTexture(ResourceLocation texture, int x, int y, int w, int h)Draws an image (texture) from your mod's resources at the given position and size.
Example — custom ListItem using RenderUtil
@Override
public void render(int x, int y, int width, int height, int mouseX, int mouseY) {
// Draw a hover highlight if mouse is over this row
boolean hovered = mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height;
if (hovered) {
RenderUtil.drawRect(x, y, width, height, 0x22FFFFFF); // Subtle white tint
}
// Draw a colored dot on the left (status indicator: green = online)
RenderUtil.drawCircle(x + 16, y + height / 2, 6, 0xFF22CC44); // Green circle
// Draw the player name
RenderUtil.drawText(playerName, x + 32, y + height / 2 - 4, 0xFFFFFFFF, true);
// Draw the player's level on the right side, right-aligned
String levelText = "Lv. " + playerLevel;
// Offset from right edge
RenderUtil.drawText(levelText, x + width - 60, y + height / 2 - 4, 0xFFCCCCCC, false);
}
SoundManager
SoundManager is the UI sound manager for EriAPI. It plays vanilla Minecraft
sounds for common interface actions (clicks, hovers, toggles, focus, notifications, etc.)
through a simple static API. A global volume and mute flag let you control the audio
experience at the application level.
Most sounds are triggered automatically by built-in components — you
rarely need to call SoundManager directly unless you want a custom sound
or need to silence a specific component.
Pre-made sound methods
-
STATICSoundManager.playClick()Plays a standard button-click sound. Vanilla:
UI_BUTTON_CLICK. Triggered automatically byInteractiveComponenton click. -
STATICSoundManager.playHover()Plays a subtle hover sound (high pitch, low volume). Vanilla:
UI_BUTTON_CLICK. Triggered automatically on mouse enter. -
STATICSoundManager.playFocus()Plays a soft focus sound when a text field gains keyboard focus. Vanilla:
UI_BUTTON_CLICK. Triggered automatically byTextField. -
STATICSoundManager.playTick()Plays a tick sound during drag or slide interactions. Vanilla:
BLOCK_NOTE_HAT. Useful forSliderstep feedback. -
STATICSoundManager.playSuccess()Plays a positive validation sound. Vanilla:
ENTITY_EXPERIENCE_ORB_PICKUP. Use after successful form submission or confirmation. -
STATICSoundManager.playError()Plays a low-pitched error sound. Vanilla:
BLOCK_NOTE_BASS. Use when an action fails or input validation is rejected. -
STATICSoundManager.playNotification()Plays a notification pop sound. Vanilla:
BLOCK_NOTE_PLING. Triggered automatically when a notification component is created. -
STATICSoundManager.playToggle()Plays a toggle sound for on/off state changes. Vanilla:
UI_BUTTON_CLICK. Triggered automatically byCheckboxandRadioButton. -
STATICSoundManager.playOpen()Plays a sound when a panel or overlay opens. Vanilla:
UI_BUTTON_CLICK. -
STATICSoundManager.playClose()Plays a sound when a panel or overlay closes. Vanilla:
UI_BUTTON_CLICK.
Global configuration
-
STATICSoundManager.setMuted(boolean muted)Enables or disables all UI sounds globally. When muted, no sound method produces any output.
-
STATICSoundManager.setVolume(float volume)Sets the global volume multiplier, between
0.0(silent) and1.0(full volume). Applies to every subsequent sound call. -
STATICSoundManager.toggleMute()Toggles the mute state on/off. Convenient for a settings button that lets the player silence the UI.
-
STATICSoundManager.play(SoundEvent event, float volume, float pitch)Plays any vanilla
SoundEventdirectly with explicit volume and pitch values. The global volume multiplier and mute flag still apply.
Automatic integration with components
The following components trigger sounds automatically, with no extra code needed on your side:
- InteractiveComponent — click →
playClick(), mouse enter →playHover() - Checkbox / RadioButton — toggle →
playToggle() - TextField — focus gained →
playFocus() - Notification — on creation →
playNotification()
To silence a specific component, call .sound(false) on it.
Usage examples
// Global mute toggle (e.g. settings button)
SoundManager.setMuted(true); // Disable all UI sounds
SoundManager.setVolume(0.5f); // Half volume globally
SoundManager.toggleMute(); // Switch mute on/off
// Play a custom vanilla sound with explicit pitch
SoundManager.play(SoundEvents.ENTITY_EXPERIENCE_ORB_PICKUP, 0.6f, 1.2f);
// Silence sounds on a specific component only
new Button("Silent Action").sound(false);
// Play feedback sounds manually after server-side validation
if (success) {
SoundManager.playSuccess();
} else {
SoundManager.playError();
}
ColorWheel
A ColorWheel renders an interactive HSB (Hue / Saturation / Brightness) color
disc. The player clicks or drags inside the circle to pick a color. The component fires a
callback every time the selection changes, giving you the selected color as an ARGB
int.
The outer ring represents hue (the color family — red, green, blue…) and
the saturation increases towards the edge of each segment. A separate
BrightnessSlider is normally placed below the wheel to
control the brightness dimension, or you can wire it yourself via brightness(float).
Basic example
ColorWheel wheel = new ColorWheel()
.originalPos(50, 50) // Top-left corner in design pixels
.originalSize(100, 100) // Width and height (should be equal for a perfect circle)
.defaultColor(0xFFFF0000) // Start with red selected
.onColorChange(color -> { // Called every time the user moves the selection
System.out.println("Selected color: #" + Integer.toHexString(color));
});
addComponent(wheel);
// Read the current selection programmatically at any time:
int currentColor = wheel.getSelectedColor();
float hue = wheel.getHue(); // 0.0 – 360.0
float saturation = wheel.getSaturation(); // 0.0 – 1.0
float brightness = wheel.getBrightness(); // 0.0 – 1.0
All methods
-
FLUENTdefaultColor(int argb)Sets the initially selected color in ARGB format. The wheel converts it to HSB internally and positions the selector accordingly.
-
EVENTonColorChange(Consumer<Integer> callback)Called every time the user moves the selection inside the wheel. The new color is passed as an ARGB
int. -
FLUENTradius(int radius)Overrides the radius of the wheel in design pixels. Useful when you want a circular component without specifying equal width/height.
-
FLUENTbrightness(float value)Programmatically sets the brightness dimension (0.0 = black, 1.0 = full color). Used by BrightnessSlider to stay in sync with the wheel.
-
GETTERgetSelectedColor()Returns the currently selected color as an ARGB
int(alpha is always 0xFF). -
GETTERgetHue()Returns the hue component of the selected color in degrees (0.0 – 360.0).
-
GETTERgetSaturation()Returns the saturation component of the selected color (0.0 – 1.0).
-
GETTERgetBrightness()Returns the brightness component of the selected color (0.0 – 1.0).
BrightnessSlider
BrightnessSlider extends Slider and is specifically
designed to work alongside a ColorWheel. Instead of a plain
colored track it renders a gradient that goes from black on the left to the
pure hue currently selected in the wheel on the right. Dragging the handle
adjusts the brightness of the selected color in real time.
You pass the linked ColorWheel to the constructor — the slider keeps itself in
sync automatically. No extra wiring needed.
If you just need a full color-selection UI, use ColorPicker
instead — it bundles a ColorWheel, a BrightnessSlider, a hex
input field, and a preview swatch into a single component.
Basic example
// First create the wheel
ColorWheel wheel = new ColorWheel()
.originalPos(50, 50)
.originalSize(100, 100)
.defaultColor(0xFF00AAFF);
// Then create the slider and link it to the wheel via the constructor
BrightnessSlider slider = new BrightnessSlider(wheel)
.originalPos(50, 160) // Positioned just below the wheel
.originalSize(100, 14); // Thin horizontal strip
addComponent(wheel);
addComponent(slider);
Inherited methods (from Slider)
BrightnessSlider inherits all of Slider's fluent methods. The most relevant
ones in this context are:
-
EVENTonValueChange(Consumer<Double> callback)Called whenever the brightness changes. The value is in the range 0.0 (black) to 1.0 (full brightness). In most cases you can rely on the ColorWheel's
onColorChangecallback instead. -
GETTERgetValue()Returns the current brightness as a
doublebetween 0.0 and 1.0.
ColorPicker
ColorPicker is a self-contained color-selection widget. It bundles four
sub-components into one:
- A ColorWheel for hue and saturation selection
- A BrightnessSlider below the wheel for brightness
- A hex TextField for direct hex input (e.g.
FF00AAFF) - A small color preview swatch showing the current color
All four are kept in bidirectional sync: editing the hex field updates the wheel, and
dragging the wheel updates the hex field. You only need one onChange callback
to receive the final color.
Basic example
ColorPicker picker = new ColorPicker()
.originalPos(50, 50) // Top-left corner in design pixels
.originalSize(120, 170) // Width x height — the sub-components lay out automatically
.defaultColor(0xFF00AAFF) // Initial color (ARGB)
.backgroundColor(0xFF2A2A2A) // Background behind the whole picker
.onChange(color -> { // Called whenever any sub-component changes the color
System.out.println("Color changed: #" + Integer.toHexString(color));
});
addComponent(picker);
// Read the currently selected color at any time:
int selectedColor = picker.getColor();
All methods
-
FLUENTdefaultColor(int argb)The color that is selected when the picker first appears. Applied to the wheel, the slider, and the hex field simultaneously.
-
FLUENTbackgroundColor(int argb)The background fill drawn behind the entire picker (wheel, slider, hex field, and swatch). Defaults to a dark grey.
-
EVENTonChange(Consumer<Integer> callback)Called whenever the selected color changes, regardless of which sub-component triggered the change. The new color is passed as an ARGB
int. -
GETTERgetColor()Returns the currently selected color as an ARGB
int.
The recommended minimum size is 120 × 170 design pixels. Below that the
hex field becomes too narrow to be usable. The wheel and slider automatically resize to
fill the available space, so you can scale the whole picker up without any extra work.
Dropdown
A Dropdown (or "select") allows the player to choose a value from a drop-down list.
It supports text search filtering and scrolling when the list is long.
Example
import fr.eri.eriapi.gui.components.Dropdown;
// new Dropdown(x, y, width, height)
Dropdown dd = new Dropdown(660, 400, 300, 40)
.placeholder("Choose a rank...")
.searchable(true)
.maxVisibleItems(8)
.onChange(val -> applyRank(val));
dd.addOption("Member", "member");
dd.addOption("Officer", "officer");
dd.addOption("Leader", "leader");
root.add(dd);
-
MethodaddOption(String label, String value)Adds an entry to the drop-down list.
labelis the displayed text,valueis the string returned bygetSelected(). -
FluentsetSelected(String value)Programmatically selects an entry by its value. If the value does not exist, the state falls back to the placeholder.
-
GetterString getSelected()Returns the currently selected value, or
nullif nothing is selected. -
EventonChange(Consumer<String> callback)Called every time the selection changes. Receives the newly selected value.
-
Fluentplaceholder(String text)Text displayed when no value is selected (e.g. "Choose..."). Rendered greyed-out and in italics.
-
FluentmaxVisibleItems(int n)Maximum number of entries visible before the list becomes scrollable. Default: 6.
-
Fluentsearchable(boolean enabled)Enables a search field at the top of the drop-down list. The typed text filters entries in real time.
Deferred rendering
The Dropdown uses deferred rendering: its list is drawn AFTER all other
components, ensuring it always appears on top. Click handling works even when the
Dropdown is inside a ScrollPanel.
If you use EriGuiScreen, everything is automatic. However, if you
override drawScreen() or mouseClicked() without calling super,
you must manually add these calls:
-
Staticstatic void Dropdown.renderDeferredDropdown()Draws the open drop-down list. Called automatically by
EriGuiScreen.drawScreen()after root rendering. Only call manually if you overridedrawScreen()withoutsuper. -
Staticstatic boolean Dropdown.handleDeferredClick(int mouseX, int mouseY, int mouseButton)Handles clicks on the open drop-down list. Called automatically by
EriGuiScreen.mouseClicked()before root click handling. Returnstrueif the click was consumed. Only call manually if you overridemouseClicked()withoutsuper. -
Staticstatic void Dropdown.resetState()Resets the internal Dropdown state (closes the list). Called automatically by
EriGuiScreen.onGuiClosed(). Only call manually if you handle GUI closing yourself.
ToggleSwitch
A ToggleSwitch is a visual ON/OFF switch — the modern equivalent of a Checkbox,
with a knob that slides horizontally when toggling. Ideal for enabling or disabling an option clearly.
Example
import fr.eri.eriapi.gui.components.ToggleSwitch;
// new ToggleSwitch(x, y, width, height)
ToggleSwitch toggle = new ToggleSwitch(860, 500, 60, 30)
.label("Show Mana HUD")
.setState(true)
.activeColor(0xFF00E5FF)
.onToggle(on -> manaBarMod.setEnabled(on));
root.add(toggle);
// Read state from another component:
boolean active = toggle.getState();
-
FluentsetState(boolean state)Sets the initial or programmatic state of the switch.
true= active (knob on the right),false= inactive. -
Getterboolean getState()Returns the current state of the switch.
-
EventonToggle(Consumer<Boolean> callback)Called every time the user toggles the switch. Receives the new state (
true= active). -
Fluentlabel(String text)Text displayed to the right of the switch. Clicking the label also toggles the switch.
-
FluentactiveColor(int argb)Track background color when the switch is active. Default: cyan (
0xFF00E5FF). -
FluentinactiveColor(int argb)Track background color when the switch is inactive. Default: dark grey.
Modal / Dialog
Modal is an overlay dialog box. It displays a semi-transparent dark backdrop
behind a central "liquid glass" panel, with a fade + scale animation on opening.
The Escape key automatically closes the modal. Interactions with the background are blocked while open.
Static methods
-
Staticstatic void Modal.confirm(String title, String msg, Runnable onConfirm, Runnable onCancel)Displays a confirmation dialog with two buttons: "Confirm" (green) and "Cancel" (grey). Calls
onConfirmoronCanceldepending on the choice. -
Staticstatic void Modal.alert(String title, String msg, Runnable onClose)Displays an alert dialog with a single "OK" button. Calls
onCloseon close (button or Escape). -
Staticstatic ContainerComponent Modal.custom(String title, int width, int height)Creates an empty modal and returns its inner
ContainerComponent. You can add any component to it to fully customise the content.
Example
import fr.eri.eriapi.gui.components.Modal;
// Confirmation dialog — irreversible action
Modal.confirm(
"Dissolve the faction?",
"This action is irreversible. All members will be kicked.",
() -> factionManager.dissolve(player), // Confirm
() -> {} // Cancel (do nothing)
);
// Simple alert dialog
Modal.alert(
"Permission denied",
"You do not have the rights to perform this action.",
() -> {}
);
// Custom modal with free components
ContainerComponent content = Modal.custom("Advanced settings", 600, 400);
content.add(new Label(20, 20, 560, 30, "Choose an option:"));
content.add(new Dropdown(20, 60, 560, 40)
.addOption("Option A", "a")
.addOption("Option B", "b"));
All modals share the same style: 0x80000000 overlay backdrop, translucent liquid glass panel,
fadeIn + scaleIn animation on opening, closed by Escape or button.
PlayerHead
PlayerHead renders a player's 3D head directly inside a GUI — full skin with hat layer,
configurable orientation. Useful for profiles, leaderboards, and member previews.
Example
import fr.eri.eriapi.gui.components.PlayerHead;
import com.mojang.authlib.GameProfile;
// From a GameProfile (connected player)
PlayerHead head = new PlayerHead(860, 300, 80, player.getGameProfile())
.setRotation(-20f, 15f) // yaw, pitch
.showHat(true);
root.add(head);
// From a UUID (offline / stored player)
UUID uuid = UUID.fromString("069a79f4-44e9-4726-a5be-fca90e38aaf5"); // Notch
PlayerHead headByUuid = new PlayerHead(960, 300, 80, uuid)
.showHat(false);
-
ConstructorPlayerHead(int x, int y, int size, GameProfile profile)Creates a head render from a
GameProfile. The skin is loaded automatically. -
ConstructorPlayerHead(int x, int y, int size, UUID uuid)Creates a head render from a UUID. The skin is fetched asynchronously.
-
FluentsetProfile(GameProfile profile)Changes the rendered profile (useful for dynamic lists).
-
FluentsetRotation(float yaw, float pitch)Orients the head in degrees. Yaw = left/right rotation, pitch = up/down. E.g.
(-20f, 15f)for a three-quarter front angle. -
FluentshowHat(boolean enabled)Shows or hides the second skin layer (hat, accessories). Default:
true.
ItemStackRenderer
ItemStackRenderer renders a Minecraft ItemStack (with its 2D icon,
enchantment glint, stack count and tooltip) directly inside an EriAPI GUI.
Example
import fr.eri.eriapi.gui.components.ItemStackRenderer;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
// new ItemStackRenderer(x, y, size, stack)
ItemStackRenderer renderer = new ItemStackRenderer(
900, 400, 32, new ItemStack(Items.DIAMOND_SWORD))
.showTooltip(true) // Show vanilla tooltip on hover
.showCount(false) // Hide the stack count
.scale(1.5f); // Enlarge the icon by 50%
root.add(renderer);
// Change the item dynamically (e.g. inventory slot)
renderer.setStack(player.getHeldItemMainhand());
-
FluentsetStack(ItemStack stack)Replaces the rendered ItemStack. Can be called every tick for a dynamic render.
-
FluentshowTooltip(boolean enabled)Displays the vanilla tooltip (name, lore, enchantments) when the mouse hovers over the component. Default:
true. -
FluentshowCount(boolean enabled)Displays the item count text as an overlay (bottom-right corner). Default:
true. Independent fromshowDurability()— you can hide the count while keeping the durability bar. -
FluentshowDurability(boolean enabled)Displays the durability bar below the icon (for items with durability). Default:
true. Independent fromshowCount()— for example,showCount(false).showDurability(true)renders the durability bar without the count text. -
Fluentscale(float factor)Icon scale factor.
1.0f= normal size (16x16),2.0f= double. Default:1.0f.
ItemSlot
ItemSlot is a Minecraft inventory slot component with full vanilla interactions:
shared cursor, drag-and-drop, shift+click, double-click. It faithfully reproduces the behavior
of GuiContainer while integrating into any EriGuiScreen.
The component supports three distinct modes depending on the GUI architecture (client-only, server-authoritative or direct take).
Example — simple client inventory
import fr.eri.eriapi.gui.components.ItemSlot;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
// Empty interactive slot
ItemSlot slot = new ItemSlot()
.originalPos(100, 100)
.originalSize(48, 48)
.onSlotChanged((s, stack) -> System.out.println("Contents: " + stack.getDisplayName()));
// Pre-filled slot with a diamond
ItemSlot slotDia = new ItemSlot(new ItemStack(Items.DIAMOND, 32))
.originalPos(160, 100)
.originalSize(48, 48)
.slotId("chest:0") // logical identifier for the server
.onSlotChanged((s, stack) -> saveToServer(stack))
.onShiftClick((s, stack) -> transferToPlayer(stack));
root.add(slot, slotDia);
Example — server-only mode (server inventory)
// All slots target the server — no local manipulation
for (int i = 0; i < 27; i++) {
final int idx = i;
ItemSlot slot = new ItemSlot()
.originalPos(80 + (i % 9) * 54, 200 + (i / 9) * 54)
.originalSize(48, 48)
.serverOnly(true) // server-authoritative mode
.slotId("chest:" + idx) // identifier sent to the server in the drag callback
.onAnyClick((s, button) -> {
// Called for every simple click. button: 0=left, 1=right, 2=shift+left
sendClickPacket(idx, button, ItemSlot.getCursorStack());
})
.onDoubleClick((s, type) -> {
// type 0 = double-click collect, type 3 = shift+double-click
sendDoubleClickPacket(idx, type);
});
root.add(slot);
}
// Register the drag callback (one global callback for the whole GUI)
ItemSlot.setServerDragCallback((button, targetSlotIds) -> {
sendDragPacket(button, targetSlotIds);
});
Example — takeOnly mode (showcase)
// The player can take the item but cannot deposit another one
ItemSlot showcase = new ItemSlot(new ItemStack(Items.DIAMOND_SWORD))
.originalPos(200, 300)
.originalSize(48, 48)
.takeOnly(true)
.onSlotChanged((s, taken) -> giveTo(player, taken));
Click behavior (normal mode)
| Action | Behavior |
|---|---|
| Left click — empty cursor | Picks up the full slot contents into the cursor |
| Left click — cursor has item | Deposits / merges / swaps with the slot |
| Right click — empty cursor | Picks up half the stack |
| Right click — cursor has item | Deposits one item into the slot |
| Shift + left click | Triggers onShiftClick (bulk transfer delegated to caller) |
| Left drag | Distributes the cursor stack evenly across hovered slots |
| Right drag | Deposits 1 item per hovered slot |
| Left double-click | Triggers onDoubleClick (type 0 — collect all matching items) |
| Shift + double-click | Triggers onDoubleClick (type 3 — transfer all matching items) |
Server-only flow — one action per physical click
In serverOnly mode, no action is fired on mouseDown. All logic
is decided at mouseUp (via onDragEnd()): if drag slots were
accumulated, it is a drag — otherwise it is a simple click. Only one callback is ever
triggered, never two.
-
ConstructorItemSlot()Creates an empty slot.
-
ConstructorItemSlot(ItemStack stack)Creates a pre-filled slot with the provided ItemStack.
-
Fluentstack(ItemStack s)Sets or replaces the slot's ItemStack. Pass
nullto clear the slot. -
Fluentinteractive(boolean b)Enables or disables interactions. A non-interactive slot is rendered but does not respond to clicks. Default:
true. -
FluenttakeOnly(boolean b)Direct-take mode — a click takes the item without going through the cursor. The player cannot deposit items into this slot.
-
FluentserverOnly(boolean b)Server-authoritative mode — no local manipulation. Clicks and drags are delegated to callbacks; the server responds with the new state. Automatically enables
interactive(true). -
FluentslotId(String id)Logical identifier of the slot (e.g.
"chest:5","player:12"). Used by the server-only drag to identify slots in the packet sent to the server. -
Fluentfilter(Predicate<ItemStack> f)Filter accepted items. Returning
falseblocks the item from being deposited into this slot. -
FluentbgColor(int color)Background color of the slot at rest (ARGB). Default:
0x20FFFFFF. -
FluenthoverColor(int color)Background color when the mouse hovers over the slot (ARGB). Default:
0x40FFFFFF. -
FluentslotBorderColor(int color)Border color of the slot (ARGB). Set to
0to remove the border. Default:0x15FFFFFF. -
FluentcornerRadius(int r)Rounded corner radius in design pixels. Default:
4. -
FluentonSlotChanged(SlotAction action)Callback called when the slot's contents change. Receives the slot and the new ItemStack (empty if the slot is cleared). Signature:
(ItemSlot slot, ItemStack stack) -> void. -
FluentonShiftClick(SlotAction action)Callback called on Shift+left click. Receives the slot and its current ItemStack. Use to implement bulk transfer (e.g. chest → player inventory).
-
FluentonRightClick(SlotAction action)Callback called on right click when the cursor is empty (picking up half the stack).
-
FluentonAnyClick(ClickAction action)Generic callback called on any simple click in
serverOnlymode. Signature:(ItemSlot slot, int button) -> void.buttonis 0 (left), 1 (right) or 2 (shift+left). -
FluentonDoubleClick(DoubleClickAction action)Callback called on left double-click in
serverOnlymode. Signature:(ItemSlot slot, int type) -> void.typeis 0 (collect) or 3 (Shift+double-click transfer).
Static methods
-
StaticItemSlot.getCursorStack()Returns the ItemStack currently held by the cursor (shared across all slots of the GUI).
-
StaticItemSlot.setCursorStack(ItemStack s)Forces the cursor contents (useful for applying the server response).
-
StaticItemSlot.clearCursor()Clears the cursor and resets all drag state. Called automatically by
EriGuiScreen.onGuiClosed(). -
StaticItemSlot.renderCursorItem(int mouseX, int mouseY)Renders the item held by the cursor at the mouse position. Called automatically by
EriGuiScreen.drawScreen()after all components. -
StaticItemSlot.setServerDragCallback(ServerDragCallback cb)Registers the global drag callback for server-only mode. Signature:
(int button, List<String> targetSlotIds) -> void. One callback is sufficient for the entire GUI. -
StaticItemSlot.onDragEnd()Finalizes the current drag and fires the appropriate callbacks. Called automatically by
EriGuiScreen.mouseReleased(). Never call manually.
EriGuiScreen automatically handles the full lifecycle of ItemSlot
components: drawScreen() calls renderCursorItem() after all
components, mouseReleased() calls onDragEnd() before propagating
to components, mouseClickMove() propagates checkDragHover() to
every slot in the tree, and onGuiClosed() calls clearCursor().
You never need to wire anything manually.
The item is automatically scaled via GL to fill the slot area. You can use a slot of 32x32, 48x48 or 64x64 design pixels — the icon always adapts cleanly, regardless of the player's actual screen resolution.
TexturedRect
TexturedRect renders a PNG texture (via ResourceLocation) within the
component bounds. It supports a color tint, a grayscale mode and sub-pixel rendering
via the Tessellator for precise floating-point coordinates.
Works equally well inside an EriGuiScreen or an OverlayMod.
Example
import fr.eri.eriapi.gui.components.TexturedRect;
import net.minecraft.util.ResourceLocation;
// Color icon 64x64
TexturedRect icon = new TexturedRect(
new ResourceLocation("eriniumfaction", "textures/gui/faction_icon.png"))
.originalPos(40, 40)
.originalSize(64, 64)
.tint(0xFFFFFFFF); // white = no tint
root.add(icon);
// Desaturated (grayscale) icon for an inactive element
TexturedRect iconGray = new TexturedRect(
new ResourceLocation("eriniumfaction", "textures/gui/faction_icon.png"))
.originalPos(120, 40)
.originalSize(64, 64)
.grayscale(true);
root.add(iconGray);
// Colored semi-transparent tint
TexturedRect tinted = new TexturedRect(
new ResourceLocation("eriniumfaction", "textures/gui/banner.png"))
.originalPos(0, 0)
.originalSize(1920, 1080)
.tint(0x80FF6600) // orange 50% transparent
.textureSize(256, 128); // actual PNG image size
root.add(tinted);
// Update dynamically
icon.setGrayscale(true);
icon.setTint(0x80FFFFFF);
-
ConstructorTexturedRect(ResourceLocation texture)Creates a component that renders the specified PNG texture. The texture must be on the mod's classpath (inside the
assets/folder). -
Fluenttexture(ResourceLocation tex)Replaces the rendered texture. Can be called dynamically to change the displayed image.
-
Fluenttint(int color)Applies an ARGB tint to the texture.
0xFFFFFFFF= no tint (default). The tint alpha multiplies the component's opacity. -
Fluentgrayscale(boolean gray)Enables grayscale rendering (applies a neutral color
(0.35, 0.35, 0.35)). Useful for disabled elements or inactive icons. Default:false. -
FluenttextureSize(int w, int h)Declares the actual PNG image resolution (in pixels). Informs the render engine about the UV proportions of the texture. Default:
64x64. -
SettersetGrayscale(boolean g)Non-fluent equivalent of
grayscale()— useful for toggling the mode from a callback. -
SettersetTint(int c)Non-fluent equivalent of
tint()— useful for animating the tint from anonColorUpdate(). -
GettergetTexture()Returns the
ResourceLocationof the currently displayed texture.
TexturedRect uses the Tessellator with float coordinates
for precise sub-pixel positioning. Unlike Gui.drawTexturedModalRect()
which rounds to integers, this component aligns perfectly with the ScaleManager even
at non-integer scales.
Divider
A Divider is a horizontal or vertical separator line. It can be solid color or gradient,
with configurable margins, and integrates into any panel to visually separate sections.
Example
import fr.eri.eriapi.gui.components.Divider;
// new Divider(x, y, length) — horizontal by default
root.add(new Divider(60, 200, 500)
.gradient(0x4400E5FF, 0x00000000) // Cyan to transparent
.thickness(1)
.margin(20));
// Solid vertical separator
root.add(new Divider(960, 100, 800)
.vertical()
.color(0x33FFFFFF)
.thickness(2));
-
Fluenthorizontal()Horizontal mode (default). The
lengthparameter is the width. -
Fluentvertical()Vertical mode. The
lengthparameter becomes the height. -
Fluentcolor(int argb)Solid color for the line. Replaces any previously defined gradient.
-
Fluentthickness(int px)Line thickness in design pixels. Default:
1. -
Fluentgradient(int startColor, int endColor)Applies a linear gradient from
startColortoendColoralong the line. Replaces the solid color. -
Fluentmargin(int px)Transparent empty space at the start and end of the line. Useful to add breathing room relative to panel edges.
Badge
A Badge is a compact pill-shaped tag — perfect for displaying categories, ranks,
statuses or short labels (e.g. "Combat", "Leader", "Online"). Auto-sized based on its content.
Example
import fr.eri.eriapi.gui.components.Badge;
// new Badge(x, y, text) — auto-size calculated from text
root.add(new Badge(200, 150, "Combat")
.color(0x206B2FA0, 0xFF9B4FCF) // (bgColor, textColor)
.outlined(true));
// Badge with icon
root.add(new Badge(300, 150, "Leader")
.color(0x20FFD700, 0xFFFFD700)
.icon(new ResourceLocation("eriniumfaction", "textures/gui/icon_crown.png"))
.cornerRadius(4));
// Solid badge (not outlined)
root.add(new Badge(400, 150, "Online")
.color(0xFF1A6B3C, 0xFF2ECC71)
.scale(0.75f));
-
Fluentcolor(int bgColor, int textColor)Background color and text color in ARGB. The background accepts a low alpha value for a translucent effect.
-
Fluentoutlined(boolean enabled)Outline mode: transparent background, colored border using
bgColor. -
FluentcornerRadius(int px)Corner radius in design pixels. Default:
999(perfect pill). Use4for a rounded-rectangle look. -
Fluenticon(ResourceLocation texture)16x16 icon displayed to the left of the text. The badge width adjusts automatically.
-
Fluentscale(float factor)Text scale of the badge. Default:
0.8f. Reduce for very compact badges.
Accordion
An Accordion is a list of collapsible sections. Each section has a clickable header
that expands or collapses its content with an animated height transition. The singleMode option
ensures only one section is open at a time.
Example
import fr.eri.eriapi.gui.components.Accordion;
// new Accordion(x, y, width)
Accordion acc = new Accordion(660, 300, 600)
.singleMode(true); // Only one section open at a time
acc.addSection("Information", section -> {
section.add(new Label(10, 10, 580, 20,
"Name: " + faction.getName()));
section.add(new Label(10, 35, 580, 20,
"Members: " + faction.getMemberCount()));
});
acc.addSection("Statistics", section -> {
section.add(new Label(10, 10, 580, 20,
"Wins: " + faction.getWins()));
section.add(new Label(10, 35, 580, 20,
"Losses: " + faction.getLosses()));
});
acc.addSection("Members", section -> {
for (String member : faction.getMembers()) {
section.add(new Label(10, 10 + i * 25, 580, 20, member));
}
});
root.add(acc);
-
MethodaddSection(String title, Consumer<ContainerComponent> builder)Adds a section with the header
title. The lambda receives the contentContainerComponent— add your components inside it. -
MethodexpandAll()Expands all sections. Ignores
singleMode. -
MethodcollapseAll()Collapses all sections.
-
FluentsingleMode(boolean enabled)When active, opening a section automatically closes any other open section. Default:
false.
Carousel
A Carousel is a horizontal scroll container that displays multiple elements side by side.
It supports arrow navigation, dot indicators, and auto-scrolling.
Ideal for card previews, rewards, or faction showcases.
Example
import fr.eri.eriapi.gui.components.Carousel;
// new Carousel(x, y, width, height)
Carousel car = new Carousel(200, 300, 1520, 400)
.setVisibleCount(3) // 3 cards visible simultaneously
.showArrows(true) // < and > navigation buttons
.showDots(true) // Indicator dots at the bottom
.autoScroll(100); // Auto-scroll every 100 ticks (5 sec)
// Add items (any Component)
for (FactionCard card : factionCards) {
ContainerComponent cardComp = new ContainerComponent(0, 0, 480, 380);
cardComp.add(new Rectangle(0, 0, 480, 380)
.fillColor(0xCC1A1A2E).cornerRadius(12));
cardComp.add(new Label(20, 20, 440, 30, card.getName())
.scale(2.0f).color(0xFFFFFFFF));
car.addItem(cardComp);
}
root.add(car);
-
MethodaddItem(Component component)Adds an element to the carousel. Each item is any
Component— typically aContainerComponent. -
FluentsetVisibleCount(int n)Number of items displayed simultaneously. The available space is divided equally. Default:
1. -
FluentshowArrows(boolean enabled)Displays left/right arrow buttons on the sides of the carousel.
-
FluentshowDots(boolean enabled)Displays indicator dots at the bottom of the carousel (one dot per item, the active one is highlighted).
-
FluentautoScroll(int intervalTicks)Enables automatic scrolling every
intervalTicksticks. Pass0to disable.
ProgressBarEnhanced
ProgressBarEnhanced is an advanced progress bar supporting 9 geometric shapes,
gradients, segments, smooth animations and a centered label. Use it instead of the standard
ProgressBar when you need circular, hexagonal, or segmented rendering.
Available shapes — enum BarShape
| Constant | Render | Typical use |
|---|---|---|
| BarShape.HORIZONTAL | Left-to-right bar | XP, health, mana |
| BarShape.VERTICAL | Bottom-to-top bar | Water level, heat |
| BarShape.CIRCULAR | Ring (arc) | Cooldown, stamina |
| BarShape.PIE | Filled pie chart | Resource share |
| BarShape.DIAMOND | Diamond shape | PvP stats |
| BarShape.PENTAGON | Pentagon | Overall score |
| BarShape.HEXAGON | Hexagon | Abilities, rank |
| BarShape.OCTAGON | Octagon | Shield, defense |
| BarShape.SQUARE | Square with corners | Compact bar |
Fill direction — enum FillDirection
| Constant | Direction |
|---|---|
| FillDirection.LEFT_TO_RIGHT | Left to right (horizontal default) |
| FillDirection.RIGHT_TO_LEFT | Right to left |
| FillDirection.BOTTOM_TO_TOP | Bottom to top (vertical default) |
| FillDirection.TOP_TO_BOTTOM | Top to bottom |
| FillDirection.CLOCKWISE | Clockwise (circular shapes) |
| FillDirection.COUNTERCLOCKWISE | Counter-clockwise |
Examples
import fr.eri.eriapi.gui.components.ProgressBarEnhanced;
import fr.eri.eriapi.gui.components.ProgressBarEnhanced.BarShape;
import fr.eri.eriapi.gui.components.ProgressBarEnhanced.FillDirection;
// Circular ring for a cooldown
ProgressBarEnhanced ring = new ProgressBarEnhanced(860, 440, 200, 200)
.shape(BarShape.CIRCULAR)
.value(0.72f)
.barWidth(18)
.gradientFill(0xFF00E5FF, 0xFF6B2FA0)
.backgroundColor(0xFF1A1A2E)
.showPercentage(true)
.animate(true);
root.add(ring);
// Segmented XP bar old-school style
ProgressBarEnhanced bar = new ProgressBarEnhanced(100, 50, 400, 20)
.shape(BarShape.HORIZONTAL)
.value(0.5f)
.segments(10)
.segmentGap(2)
.fillColor(0xFF00D4FF)
.cornerRadius(4)
.animate(true)
.animationSpeed(10); // Transition over 10 ticks (0.5 sec)
root.add(bar);
-
Fluentshape(BarShape shape)Sets the geometric shape of the bar. See the
BarShapetable above. -
Fluentvalue(float v)Fill value between
0.0(empty) and1.0(full). Ifanimateis active, the transition is animated. -
FluentfillColor(int argb)Solid fill color. Replaces any defined gradient.
-
FluentbackgroundColor(int argb)Color of the empty area (bar background).
-
FluentbarWidth(int px)Ring or outline thickness for circular and polygonal shapes.
-
FluentgradientFill(int startColor, int endColor)Linear gradient fill. For CIRCULAR/PIE, the gradient follows the arc.
-
Fluentsegments(int n)Divides the bar into
nseparated segments. Very useful for RPG-style health bars. -
FluentsegmentGap(int px)Spacing in design pixels between segments.
-
Fluentdirection(FillDirection dir)Fill direction. See the
FillDirectiontable above. -
Fluentanimate(boolean enabled)Enables animated transitions when the value changes via
value(). -
FluentanimationSpeed(int ticks)Transition duration in ticks. Default:
10(0.5 sec). Requiresanimate(true). -
FluentshowPercentage(boolean enabled)Displays the percentage ("72%") centered on the component.
-
Fluentlabel(String text)Centered text displayed as an overlay. Overrides the percentage if
showPercentageis also active. -
FluentcornerRadius(int px)Corner radius for HORIZONTAL, VERTICAL and SQUARE shapes.
GUI Showcase — Page 2: Textures
The demo GUI (opened with /skyapitest) now has two pages,
navigated with the header buttons:
- Components — All standard components (buttons, inputs, charts, ColorPicker, etc.)
- Textures — Live demo of texture support for ProgressBar, Slider, Checkbox, ScrollPanel, ScrollList, TabView, ContextMenu, and Notification.
The "Components" and "Textures" buttons in the showcase header let you switch between pages. The active page is highlighted on the button.