JelloUI public API documentation for Minecraft Fabric addon developers.
JelloUI profiles are named documents used for module/settings data and addon
sections; keybinds are saved through the client configuration path. HUD
layout is not currently persisted by the public HUD registry. Addons that
keep their own profile state register a
ProfileSectionCodec; addons that ship presets register ProfileTemplates.
A ProfileSectionCodec should read and write only your addon’s section of
a profile document. Register a ProfileProvider wrapping the codec:
api.profiles().register(new ProfileProvider(owner,
JelloId.of("example", "state_codec"),
new ProfileSectionCodec() {
@Override public void load(ProfileData data) {
JsonObject section = data.section("example");
int saved = section.has("counter")
? section.get("counter").getAsInt() : 0;
myState.set(saved);
}
@Override public void save(ProfileData data) {
JsonObject section = data.section("example");
section.addProperty("counter", myState.get());
}
}));
load(ProfileData) and save(ProfileData) are invoked in registration
order on the host’s calling thread and are exception-isolated per codec.ProfileData exposes the full root document and does not technically
enforce owner scoping. As an addon contract, read and write only
data.section(owner.namespace()) and never mutate another namespace.Trigger a save or reload from code:
api.profiles().saveActive(); // writes codec state into the in-memory document
api.profiles().loadActive(); // reads codecs from the in-memory document
These methods do not perform file I/O themselves. Normal JelloUI profile save/load flows place the disk document into the registry or retrieve it after invoking codecs. Calling either method directly only processes the currently active in-memory document.
A ProfileTemplate is a named preset the Profiles screen lists under “add
profile”. Picking one imports a fresh document as a new local profile. This
replaced the former remote preset download - templates are entirely local.
api.profiles().registerTemplate(new ProfileTemplate(
owner, JelloId.of("example", "example_defaults"),
"Example Defaults",
() -> {
JsonObject section = new JsonObject();
section.addProperty("counter", 5);
JsonObject root = new JsonObject();
root.add("example", section);
return root;
}));
The content factory must return a fresh document per call: the user can import the same template many times, and each import becomes an independent profile. A factory that returns null or throws is reported through the error handler and only that import is skipped.
Module documents are complete replacements by default, so modules omitted from
the mods array are disabled when the profile is selected. A template that must
change only its own modules can add "jelloui:preserve_unlisted_modules": true
at the document root. In that mode, omitted modules keep their current enabled
state and settings.
JelloUI persists the user’s keybind bindings and restores them on startup. You register the definition once; the user’s rebindings are stored under the keybind id and reapplied. The action always remains the one the addon supplied. See 04-surfaces for how to register and rebind.
The keybind registry exposes and changes the current binding:
api.keybinds().binding(id); // Optional<InputBinding>
api.keybinds().setBinding(id, binding); // rebinds in memory
The normal client configuration save later writes the live binding.
setBinding throws ApiUsageException when the id is not registered.
New module and setting profile entries include stable ids. The loader first matches those ids and falls back to case-insensitive display names only for legacy entries that lack ids. This fallback preserves old profiles; it does not make display names safe identity. Never change a released id. See 02-registration.