Vexel is a modern, declarative GUI library for Minecraft mods that simplifies interface creation. Built on top of NanoVG, it offers both high-level declarative components and low-level rendering capabilities. Heavily inspired by Elementa, Vexel provides a clean API for creating responsive, animated user interfaces.
Have questions? Join our discord!
- Declarative UI: Build interfaces by describing what you want, not how to position it
- Layout System: Position and sizing with automatic calculations
- Animation Support: Built-in animations with presets
- Component Library: Pre-built elements like buttons, inputs, sliders, and more
- NanoVG Integration: Direct access to powerful vector graphics rendering
Add Vexel to your build.gradle.kts:
dependencies {
// mc-version: Your minecraft version, refer to the images above for the supported versions
// loader: Your mod loader, refer to the images above for the supported mod loaders
// version: The vexel version, use the number in the image above without the character "v", so like 106
modImplementation(include("xyz.meowing:vexel-<mc-version>-<loader>:<version>")!!)
// ONLY FORGE 1.8.9 - In your ModInitializer class, call Vexel.init() like:
class MyMod {
@Mod.EventHandler
fun init(event: FMLInitializationEvent) {
Vexel.init()
/* other code */
}
}
// It is highly recommended that you use Deftu's Gradle Toolkit but if you use any other GT,
// you may also need to add the following to your build script's repositories:
repositories {
maven("https://maven.deftu.dev/snapshots")
maven("https://maven.deftu.dev/releases")
}
}Create a simple screen with Vexel:
class MyScreen : VexelScreen() {
override fun afterInitialization() {
Button("Click me!")
.setSizing(100f, Size.Pixels, 30f, Size.Pixels)
.setPositioning(50f, Pos.ParentPixels, 50f, Pos.ParentPixels)
.onClick { mouseX, mouseY, button ->
println("Button clicked!")
true // indicates the event was handled
}
.childOf(window)
}
}Elements can also be manually rendered outside of the standard screen hierarchy using .drawAsRoot().
This is useful for rendering custom overlays such as scoreboards, HUD elements, or menus that appear on top of the game without pausing it.
val square = Rectangle()
.backgroundColor(0xFFFF0000.toInt())
.setSizing(100f, Size.Pixels, 100f, Size.Pixels)
.setPositioning(0f, Pos.ParentCenter, 0f, Pos.ParentCenter)
fun someEvent() {
square.drawAsRoot()
}All UI elements extend VexelElement<T>, providing:
- Positioning: Flexible layout system
- Sizing: Auto, percentage, or pixel-based dimensions
- Event Handling: Mouse and keyboard interaction support
- Parent-Child Relationships: Hierarchical organization
- Animation Support: Built-in animation capabilities
Vexel uses positioning and sizing methods for layout control:
element
.setSizing(200f, Size.Pixels, 100f, Size.Pixels)
.setPositioning(10f, Pos.ParentPixels, 20f, Pos.ParentCenter)ParentPixels: Offset in pixels from parentScreenPixels: Absolute screen coordinatesParentPercent: Percentage of parent dimensionsScreenPercent: Percentage of screen dimensionsParentCenter: Centered within parentScreenCenter: Centered on screenAfterSibling: After the previous sibling elementMatchSibling: Match position of previous sibling
Pixels: Fixed pixel sizeParentPerc: Percentage of parent size, or screen size if no parentAuto: Automatic sizing based on content
Vexel provides a comprehensive animation system:
// Basic animations
element.animatePosition(100f, 50f, 500, EasingType.EASE_OUT)
element.animateSize(200f, 100f, 300, EasingType.EASE_IN_OUT)
// Animation presets
element.fadeIn(duration = 300)
element.slideIn(fromX = -100f, duration = 500)
element.bounceScale(scale = 1.2f, duration = 200)Vexel provides comprehensive event handling:
element
.onMouseEnter { mouseX, mouseY ->
// Mouse entered element
}
.onMouseExit { mouseX, mouseY ->
// Mouse left element
}
.onClick { mouseX, mouseY, button ->
// Element clicked
true // Return true if handled
}
.onScroll { mouseX, mouseY, horizontal, vertical ->
// Scroll event
true
}
.onCharType { keyCode, scanCode, char ->
// Character typed
true
}
.onValueChange { value ->
// Value changed for input elements
}