Composite is a Minecraft library mod that brings Jetpack Compose and Material 3 to Minecraft modding. It allows developers to build modern, reactive user interfaces for Minecraft Screens and HUDs using the declarative power of Kotlin and Compose.
Supports both Fabric and NeoForge.
- Jetpack Compose UI: Build Minecraft GUIs using standard Compose code.
- Material 3: Full support for Material Design 3 components and Material Icons Extended.
- Minecraft Integration:
- Screens: Create full-screen UIs with
ComposeScreen. - HUD: Render overlays with
ComposeHudregistered viaComposeHudRegistry. - HUD Layering: Position your HUD before or after any vanilla HUD element using
HudLayerPositionandVanillaHudconstants. - Items: Render Minecraft ItemStacks inside Compose layouts.
- Textures: Render Minecraft textures (Identifier) inside Compose layouts.
- Asset Images: Load and render PNGs from resource packs as Compose
Images. - Translations: Integrated i18n support with rich text styling preservation.
- Screens: Create full-screen UIs with
- Input Handling: Automatic mapping of Minecraft mouse and keyboard events to Compose.
- Multi-loader: Works on both Fabric and NeoForge.
Add the following to your build.gradle.kts:
plugins {
kotlin("jvm") version "2.3.0"
id("org.jetbrains.kotlin.plugin.compose") version "2.3.0"
id("org.jetbrains.compose") version "1.9.3"
}
repositories {
google()
maven("https://jitpack.io")
}
dependencies {
implementation(compose.desktop.currentOs)
implementation(compose.material3)
modImplementation("com.github.apersomany:composite:0.5.0")
}Instantiate ComposeScreen and pass your composable content, then open it with Minecraft.getInstance().setScreen(...).
import dev.aperso.composite.core.ComposeScreen
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import net.minecraft.client.Minecraft
fun openMyScreen() {
Minecraft.getInstance().setScreen(ComposeScreen {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Button(onClick = { println("Clicked!") }) {
Text("Hello from Compose!")
}
}
})
}Register a ComposeHud with ComposeHudRegistry, specifying where it should be rendered relative to a vanilla HUD element using HudLayerPosition and VanillaHud constants.
import dev.aperso.composite.core.ComposeHud
import dev.aperso.composite.hud.ComposeHudRegistry
import dev.aperso.composite.hud.HudLayerPosition
import dev.aperso.composite.hud.VanillaHud
import androidx.compose.material3.Text
import androidx.compose.ui.graphics.Color
import net.minecraft.resources.Identifier
// In your ClientModInitializer (or NeoForge client setup)
ComposeHudRegistry.get().register(
id = Identifier.of("mymod", "my_overlay"),
position = HudLayerPosition.before(VanillaHud.HOTBAR),
layer = ComposeHud {
Text(
text = "HUD Overlay",
color = Color.White
)
}
)Position your HUD layer relative to any vanilla element:
HudLayerPosition.before(VanillaHud.HOTBAR) // render before the hotbar
HudLayerPosition.after(VanillaHud.HEALTH_BAR) // render after the health bar| Constant | Description |
|---|---|
CAMERA_OVERLAYS / MISC_OVERLAYS |
Camera and misc overlays |
CROSSHAIR |
Crosshair |
HOTBAR / SELECTED_ITEM_NAME / HELD_ITEM_TOOLTIP |
Hotbar area |
HEALTH_BAR / ARMOR_BAR / FOOD_BAR / AIR_BAR / MOUNT_HEALTH |
Status bars |
INFO_BAR / EXPERIENCE_LEVEL |
Experience |
MOB_EFFECTS / BOSS_BAR / SLEEP / DEMO_TIMER |
Effects and overlays |
SCOREBOARD / OVERLAY_MESSAGE / TITLE_AND_SUBTITLE |
Text overlays |
CHAT / PLAYER_LIST / SUBTITLES |
Chat and player list |
import dev.aperso.composite.component.Components
import net.minecraft.world.item.Items
import net.minecraft.world.item.ItemStack
// Inside a Composable
Components.Item(ItemStack(Items.DIAMOND_SWORD))import dev.aperso.composite.component.Components
import net.minecraft.resources.Identifier
import androidx.compose.foundation.layout.size
import androidx.compose.ui.unit.dp
// Inside a Composable
Components.Texture(
texture = Identifier.fromNamespaceAndPath("minecraft", "textures/block/dirt.png"),
modifier = Modifier.size(64.dp)
)Load a PNG directly from the resource pack:
import dev.aperso.composite.component.Components
import net.minecraft.resources.Identifier
// Inside a Composable
Components.AssetImage(
identifier = Identifier.fromNamespaceAndPath("mymod", "textures/gui/icon.png"),
modifier = Modifier.size(32.dp)
)import dev.aperso.composite.i18n.translate
import androidx.compose.material3.Text
// Inside a Composable
Text(text = translate("block.minecraft.diamond_block"))
Text(text = translate("death.attack.player", arrayOf("Steve", "Alex")))import dev.aperso.composite.component.Components
// Inside a Composable
Components.TranslatableText(key = "block.minecraft.diamond_block")
Components.TranslatableText(
key = "death.attack.player",
args = arrayOf("Steve", "Alex"),
color = androidx.compose.ui.graphics.Color.Red
)Preserves colors, bold, italic, and other styling from language files:
import dev.aperso.composite.i18n.translateAnnotated
import dev.aperso.composite.component.Components
val annotatedString = translateAnnotated("chat.type.advancement.task", arrayOf("Player", "Advancement!"))
Components.TranslatableAnnotatedText(
key = "chat.type.advancement.task",
args = arrayOf("Player", "Advancement!"),
onClick = { offset -> /* handle click */ }
)Translations automatically update when the player changes their language setting.
- Minecraft 26.1
- Fabric Loader + Fabric API + Fabric Language Kotlin, or NeoForge
MIT License
Copyright (c) 2026 apersomany
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.