Modular Architecture
The entire HUD system is orchestrated by HudModuleManager. On initialization it registers the 7 built-in modules. Via the eymistaken_hud Fabric entrypoint, third-party addons can register additional modules that are loaded and managed alongside the core ones automatically.
Each module extends HudModule, which handles render position injection, rainbow color cycling, and the context menu settings contract. On each client tick, SimpleCPSClient calls HudModuleManager#tickAll(Minecraft); during HUD rendering, it calls renderAll(GuiGraphicsExtractor, float). The render pipeline runs through the client-side HUD registry — modules receive a GuiGraphicsExtractor context and implement extractRenderState(GuiGraphicsExtractor, float) to draw their content. Automatic stacking is handled for TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, and BOTTOM_RIGHT; CENTER modules are centered rather than stacked, so multiple centered modules can overlap unless your addon offsets them.
Adding the Dependency
Use JitPack to compile your addon mod against Eymistaken's HUD 26.2. Add the following to your build.gradle:
repositories {
maven { url 'https://jitpack.io' }
}
dependencies {
modImplementation 'com.github.Eymistaken:Eymistaken-s-hud:-SNAPSHOT'
}
After reloading your Gradle project, the current 26.2 API classes — including HudModule, IHudElement, HudModuleSetting, and all six setting types — will be available in your development environment.
Creating a Custom Module
Every HUD element must extend HudModule and implement its abstract methods. Below is the minimum required implementation:
import com.eymistaken.simplecps.api.HudModule;
import com.eymistaken.simplecps.SimpleCPSConfig;
import net.minecraft.client.gui.GuiGraphicsExtractor;
public class MyCustomModule extends HudModule {
@Override
public String getName() {
return "My Custom Tracker";
}
@Override
public SimpleCPSConfig.Position getPositionType() {
return SimpleCPSConfig.Position.TOP_LEFT; // Default corner alignment
}
@Override
public int getXOffset() { return 0; }
@Override
public int getYOffset() { return 0; }
@Override
public boolean isEnabled() {
return true; // Tie to your own config
}
@Override
public int getWidth() {
return 100; // Required for stacking layout
}
@Override
public int getHeight() {
return 20;
}
@Override
public void extractRenderState(GuiGraphicsExtractor context, float tickDelta) {
float currentScale = getScale() / 100f;
context.pose().pushMatrix();
context.pose().translate((float) this.x, (float) this.y);
context.pose().scale(currentScale, currentScale);
// After translating, drawing should be done relative to 0,0 (the local origin)
context.text(this.client.font, "Hello World", 0, 0, 0xFFFFFFFF, true);
context.pose().popMatrix();
}
@Override
public void tick(net.minecraft.client.Minecraft client) {
// Optional: runs every client tick (timers, click tracking, etc.)
super.tick(client);
}
}
Important: Always return accurate values from getWidth() and getHeight(). Returning 0 removes your module from the stacking layout and makes it invisible.
Unique Name Requirement: The value returned by the getName() method must be strictly unique. The HudModuleManager uses this name as a key to store bounding boxes in a Map. Use specific names, for example: "MyAddon_Tracker".
Inherited Variables Note: When a module extends the HudModule class, the variables this.client (Minecraft.getInstance()), this.x, and this.y are automatically inherited. Developers do not need to define these manually.
Advanced: Sub-Elements (Complex Modules)
If a module consists of multiple independently draggable parts (such as the ArmorModule), developers can override the getSubElements() method inside HudModule. This method should return a list of objects that implement the IHudElement interface. This allows the HUD Editor to treat these sub-parts as independent draggable elements instead of dragging the entire main module.
@Override
public List<IHudElement> getSubElements() {
// Return a list of independent sub-elements (e.g., Helmet, Chestplate, etc.)
// If empty, the entire module is treated as a single draggable element.
return mySubElementsList;
}
HUD Editor Integration (Drag & Drop)
Override the optional setter methods to allow players to move, scale, and reset your module in the HUD Editor. Important: save all values to your own mod's config — never to SimpleCPSConfig.
// Inside your MyCustomModule class:
@Override
public void setPositionType(SimpleCPSConfig.Position pos) {
MyAddonConfig.anchor = pos; // Save to YOUR config
}
@Override
public void setXOffset(int x) { MyAddonConfig.xOffset = x; }
@Override
public void setYOffset(int y) { MyAddonConfig.yOffset = y; }
@Override
public void setScale(int scale) { MyAddonConfig.scale = scale; }
@Override
public int getScale() { return MyAddonConfig.scale; }
@Override
public void resetToDefaults() {
// Called by "Reset Position" in the context menu
MyAddonConfig.anchor = SimpleCPSConfig.Position.TOP_LEFT;
MyAddonConfig.xOffset = 0;
MyAddonConfig.yOffset = 0;
MyAddonConfig.scale = 100;
}
If you skip these overrides, your module will still render correctly — but players will not be able to move or scale it via the HUD Editor.
When the user drags and drops a module in the HUD Editor screen, the onPositionUpdated() method inside the module is triggered. Developers can override this method to act as a listener, allowing them to automatically save the module's new position to their own config files.
@Override
public void onPositionUpdated() {
// Called when the user releases the mouse after dragging the module in HUD Editor
MyAddonConfig.save();
}
Registering the Plugin
Declare an entrypoint implementing EymistakenHudPlugin in your fabric.mod.json. Your modules will be passed to HudModuleManager#registerModule() and managed alongside the built-in ones from that point forward — no core modification required.
Implementation class:
import com.eymistaken.simplecps.api.EymistakenHudPlugin;
import com.eymistaken.simplecps.HudModuleManager;
public class MyPluginInit implements EymistakenHudPlugin {
@Override
public void registerHudModules(HudModuleManager manager) {
manager.registerModule(new MyCustomModule());
}
}
fabric.mod.json:
"entrypoints": {
"eymistaken_hud": [
"com.myname.myaddon.MyPluginInit"
]
}
The eymistaken_hud entrypoint key is processed by SimpleCPSClient during initialization. Every registered module is automatically included in the tickAll() and renderAll() cycles of HudModuleManager, and becomes fully editable in the in-game HUD Editor.