Write Minecraft GUI screens in HTML and CSS. TesseraUI parses them at runtime and renders native widgets — no JavaScript, no browser engine.
Everything that's painful to build in NeoForge GUI (flexbox layout, hover transitions, @keyframes animations, drag & drop, item pickers, virtual lists, i18n) is handled for you. Use HTML templates or the programmatic Java API — your choice.
Grab the latest tesseraui-x.x.x.jar from the Releases page or from CurseForge.
Drop the jar in your libs/ folder, then in build.gradle:
dependencies {
implementation files('libs/tesseraui-1.1.jar')
}src/main/resources/META-INF/neoforge.mods.toml:
[[dependencies.yourmod]]
modId = "tesseraui"
type = "required"
versionRange = "[1.0,)"
ordering = "NONE"
side = "CLIENT"If you prefer Gradle dependency management:
repositories {
maven { url "https://cursemaven.com" }
}
dependencies {
implementation fg.deobf("curse.maven:tesseraui-<file-id>:latest")
}Replace <file-id> with the file ID from the CurseForge project page.
assets/yourmod/ui/my_screen.html
<col>
<h2 data-i18n="ui.yourmod.title">Settings</h2>
<p>Hello, {{ player.name }}!</p>
<row>
<button onclick="save" data-i18n="ui.yourmod.save">Save</button>
<button onclick="cancel" data-i18n="ui.yourmod.cancel">Cancel</button>
</row>
</col>assets/yourmod/ui/my_screen.css
col { background: #1A1208; padding: 12px; gap: 8px; }
h2 { color: #F0B27A; font-size: 10px; }
p { color: #F3E7D3; font-size: 7px; }
button {
background: #5C3A1E;
color: #F0B27A;
width: 80px; height: 16px;
transition: background 200ms ease-out;
}
button:hover { background: #7C5A2E; }public class MyScreen extends TesseraScreen {
private TesseraPanel root;
public MyScreen() { super(Component.literal("My Screen")); }
@Override
protected void init() {
TesseraModel model = TesseraModel.of(Map.of(
"player.name", Minecraft.getInstance().player.getName().getString()
));
int pw = Math.min(width, 300), ph = Math.min(height, 200);
root = TesseraTemplateRenderer.build(
TesseraTemplate.load("yourmod:ui/my_screen"),
model,
Map.of("save", this::onSave, "cancel", this::onCancel),
(width - pw) / 2, (height - ph) / 2, pw, ph
);
root.layout();
}
@Override protected TesseraPanel tesseraRoot() { return root; }
}No HTML file needed. Every feature is available directly in Java.
// Keyframe animation
TesseraKeyframes pulse = TesseraKeyframes.builder("pulse")
.from(s -> { s.background = 0xFF1a2a1a; s.borderColor = 0xFF22c55e; })
.at(50, s -> { s.background = 0xFF14532d; s.borderColor = 0xFF4ade80; })
.to(s -> { s.background = 0xFF1a2a1a; s.borderColor = 0xFF22c55e; })
.build();
TesseraPanel card = TesseraPanel.column(x, y, 120, 60)
.padding(8).gap(4)
.animate(pulse, 1500, TesseraEasing.EASE_IN_OUT) // infinite loop
.hoverTransition("border-color", 150, TesseraEasing.EASE_OUT, 0xFF22c55e, 0xFF4ade80);
// v-for / v-if helpers
panel.addFor(playerList, p ->
new TesseraLabel(0, 0, 120, 10, p.getName()).color(TesseraPalette.CREAM));
panel.addIf(isAdmin, () -> buildAdminPanel());| Feature | HTML | Java API |
|---|---|---|
| Flexbox & grid layout | ✓ | ✓ |
CSS variables, @media queries |
✓ | — |
| Hover transitions | ✓ | ✓ |
@keyframes animations |
✓ | ✓ |
Data binding {{ }}, v-for, v-if |
✓ | ✓ |
Component system <template> / <slot> |
✓ | — |
i18n data-i18n / {{ t:key }} |
✓ | ✓ |
| Drag & Drop | ✓ | ✓ |
| Item slots & inventory picker | ✓ | ✓ |
| Virtual list (large datasets) | ✓ | ✓ |
| Tabs | ✓ | ✓ |
| Hot reload from disk | ✓ | ✓ |
Full reference on the GitHub Wiki:
| Page | |
|---|---|
| Getting Started | Installation and first screen |
| HTML Tags | All supported elements |
| CSS Reference | Every supported property |
| CSS Animations | transition and @keyframes |
| Layout System | Flexbox and grid |
| Data Binding | {{ }}, v-for, v-if |
| Programmatic API | Full Java API |
| Item Slots | Item display and inventory picker |
| Drag and Drop | Draggable widgets |
| Localization | i18n integration |
| Hot Reload | Development workflow |
LGPL-3.0 — you can use TesseraUI in any mod (open-source or closed-source, free or paid) without restrictions. If you modify TesseraUI itself, those modifications must be published under LGPL-3.0.