Skip to content

Embers Text API Integration

Matthiesen Lib provides a platform-agnostic compatibility layer for Ember’s Text API. It works identically on both Fabric and NeoForge, abstracting away platform differences and version variations in the Ember API.

Access the compatibility layer through the parser system:

MatthiesenLibTextParser parser = MatthiesenLib.getTextParser(MatthiesenLibBuiltInTextParsers.EMBER);
MatthiesenLibEmbersTextParserCompat compat = parser.getEmbersCompat();
if (compat != null) {
compat.sendMessage(player, "Hello World", 100f);
}

This sends a simple text message to the player for 100 ticks (5 seconds).

The Ember’s Text API compatibility layer is accessed through the text parser system:

MatthiesenLibTextParser parser = MatthiesenLib.getTextParser(MatthiesenLibBuiltInTextParsers.EMBER);
MatthiesenLibEmbersTextParserCompat compat = parser.getEmbersCompat();

Important: Always check that the result is not null before using it:

if (compat != null) {
// Use compat layer...
} else {
// Ember's Text API is not installed
// Fall back to vanilla chat or other notification method
}
MatthiesenLibTextParser parser = MatthiesenLib.getTextParser(MatthiesenLibBuiltInTextParsers.EMBER);
MatthiesenLibEmbersTextParserCompat compat = parser.getEmbersCompat();
if (compat != null) {
compat.sendMessage(player, "Customized Message", 100f, builder -> builder
.anchor(MatthiesenLibImmersiveMessageBuilder.TextAnchor.TOP_CENTER)
.align(MatthiesenLibImmersiveMessageBuilder.TextAlign.CENTER)
.scale(1.5f)
.shadow(true)
.fadeInTicks(10)
.fadeOutTicks(20));
}

The builder -> ... overload creates a new builder internally so you do not need to pre-create one.

Main interface for sending immersive messages.

MethodDescription
sendMessage(ServerPlayer, Component, float)Send a message using a Minecraft Component
sendMessage(ServerPlayer, String, float)Send a message using plain text (string)
MethodDescription
sendMessage(ServerPlayer, Component, float, Builder)Send a Component message with custom formatting via builder
sendMessage(ServerPlayer, Component, float, Consumer<Builder>)Send a Component message with inline builder configuration (builder -> ...)
sendMessage(ServerPlayer, String, float, Builder)Send a message with custom formatting via builder
sendMessage(ServerPlayer, String, float, Consumer<Builder>)Send a message with inline builder configuration (builder -> ...)
MethodDescription
sendUpdateMessage(ServerPlayer, String, Component, float)Update an existing message by ID using a Component
sendUpdateMessage(ServerPlayer, String, Component, float, Builder)Update a Component message with custom formatting
sendUpdateMessage(ServerPlayer, String, Component, float, Consumer<Builder>)Update a Component message with inline builder configuration
sendUpdateMessage(ServerPlayer, String, String, float)Update an existing message by ID using plain text
sendUpdateMessage(ServerPlayer, String, String, float, Builder)Update an existing message with custom formatting
sendUpdateMessage(ServerPlayer, String, String, float, Consumer<Builder>)Update a message with inline builder configuration
MethodDescription
sendCloseMessage(ServerPlayer, String)Close a specific message by ID
sendCloseAllMessages(ServerPlayer)Close all active messages for a player

Fluent builder for configuring message appearance and behavior.

MatthiesenLibImmersiveMessageBuilder builder = MatthiesenLibImmersiveMessageBuilder.create();
MethodParameter(s)DescriptionDefault
anchor(TextAnchor)Screen positionWhere the message appearsTOP_CENTER
align(TextAlign)Horizontal alignmentText alignment relative to anchorCENTER
offset(float, float)X, Y pixelsPixel offset from anchor point(0, 55)
scale(float)Scale multiplierText size (1.0 = normal)1.0
shadow(boolean)Enable/disableRender text shadowstrue
background(boolean)Enable/disableShow background panelfalse
fadeInTicks(int)Ticks (20 = 1s)Duration to fade in0
fadeOutTicks(int)Ticks (20 = 1s)Duration to fade out0
typewriter(float)Chars/tickTypewriter effect speedDisabled
typewriter(float, boolean)Speed, centerTypewriter with centeringDisabled
wrap(int)Width in pixelsText wrap widthDisabled

Screen positions (3×3 grid):

  • TOP_LEFT, TOP_CENTER, TOP_RIGHT
  • MIDDLE_LEFT, MIDDLE, MIDDLE_RIGHT
  • BOTTOM_LEFT, BOTTOM_CENTER, BOTTOM_RIGHT

Horizontal alignment relative to anchor:

  • LEFT – align text left
  • CENTER – center text (default)
  • RIGHT – align text right
MatthiesenLibTextParser parser = MatthiesenLib.getTextParser(MatthiesenLibBuiltInTextParsers.EMBER);
MatthiesenLibEmbersTextParserCompat compat = parser.getEmbersCompat();
if (compat != null) {
compat.sendMessage(player, "Your quest has been updated!", 80f);
}

Appears at the top-center by default.

Example 2: Large, Centered, Glowing Message

Section titled “Example 2: Large, Centered, Glowing Message”
MatthiesenLibTextParser parser = MatthiesenLib.getTextParser(MatthiesenLibBuiltInTextParsers.EMBER);
MatthiesenLibEmbersTextParserCompat compat = parser.getEmbersCompat();
if (compat != null) {
MatthiesenLibImmersiveMessageBuilder builder = MatthiesenLibImmersiveMessageBuilder.create()
.anchor(MatthiesenLibImmersiveMessageBuilder.TextAnchor.MIDDLE)
.scale(2.0f)
.shadow(true)
.fadeInTicks(5)
.fadeOutTicks(10);
compat.sendMessage(player, "Victory!", 120f, builder);
}

Appears at the center with double size, fades in/out gracefully.

Example 3: Styled Component Message with Inline Builder

Section titled “Example 3: Styled Component Message with Inline Builder”
MatthiesenLibTextParser parser = MatthiesenLib.getTextParser(MatthiesenLibBuiltInTextParsers.EMBER);
MatthiesenLibEmbersTextParserCompat compat = parser.getEmbersCompat();
if (compat != null) {
Component msg = Component.literal("Dungeon Cleared!")
.withStyle(ChatFormatting.GOLD)
.withStyle(ChatFormatting.BOLD);
compat.sendMessage(player, msg, 120f, builder -> builder
.anchor(MatthiesenLibImmersiveMessageBuilder.TextAnchor.MIDDLE)
.scale(1.8f)
.fadeInTicks(6)
.fadeOutTicks(10));
}
MatthiesenLibTextParser parser = MatthiesenLib.getTextParser(MatthiesenLibBuiltInTextParsers.EMBER);
MatthiesenLibEmbersTextParserCompat compat = parser.getEmbersCompat();
if (compat != null) {
MatthiesenLibImmersiveMessageBuilder builder = MatthiesenLibImmersiveMessageBuilder.create()
.typewriter(0.5f, true) // 0.5 chars per tick, centered while typing
.offset(0f, 150f)
.anchor(MatthiesenLibImmersiveMessageBuilder.TextAnchor.BOTTOM_CENTER);
compat.sendMessage(player, "A mysterious force awakens...", 200f, builder);
}
MatthiesenLibTextParser parser = MatthiesenLib.getTextParser(MatthiesenLibBuiltInTextParsers.EMBER);
MatthiesenLibEmbersTextParserCompat compat = parser.getEmbersCompat();
if (compat != null) {
// Send initial message with an ID
compat.sendMessage(player, "progress_message", "Loading: 0%", 100f);
// Later, update the message
compat.sendUpdateMessage(player, "progress_message", "Loading: 50%", 100f);
// Close the message when done
compat.sendCloseMessage(player, "progress_message");
}
MatthiesenLibTextParser parser = MatthiesenLib.getTextParser(MatthiesenLibBuiltInTextParsers.EMBER);
MatthiesenLibEmbersTextParserCompat compat = parser.getEmbersCompat();
if (compat != null) {
// Title message at center
compat.sendMessage(player, "Boss Defeated!", 140f, builder -> builder
.anchor(MatthiesenLibImmersiveMessageBuilder.TextAnchor.MIDDLE)
.scale(2.5f)
.fadeInTicks(10)
.fadeOutTicks(20));
// Subtitle message below center
compat.sendMessage(player, "+500 XP", 120f, builder -> builder
.anchor(MatthiesenLibImmersiveMessageBuilder.TextAnchor.MIDDLE)
.offset(0f, 50f)
.scale(1.2f)
.fadeInTicks(15)
.fadeOutTicks(15));
}

Since Ember’s Text API is an optional dependency, always check if the compatibility layer is available:

MatthiesenLibEmbersTextParserCompat compat = MatthiesenLib.getTextParser(MatthiesenLibBuiltInTextParsers.EMBER).getEmbersCompat();
if (compat != null) {
// Use Ember's Text API
} else {
// Fall back to vanilla chat messages
player.sendSystemMessage(Component.literal("Your message here"));
}
  • Short notifications (80-100 ticks / 4-5 seconds): Quick status updates
  • Medium messages (120-160 ticks / 6-8 seconds): Quest updates, achievements
  • Long messages (200+ ticks / 10+ seconds): Important story beats, tutorials

Add fade effects to make messages feel more polished:

builder -> builder
.fadeInTicks(10) // 0.5 second fade in
.fadeOutTicks(20) // 1 second fade out
  • TOP_CENTER: Status updates, quest notifications
  • MIDDLE: Critical announcements, boss defeats, story beats
  • BOTTOM_CENTER: Hints, tips, subtitles
  • TOP_LEFT/RIGHT, BOTTOM_LEFT/RIGHT: Persistent HUD elements

When you need to update a message multiple times, use a unique ID:

String messageId = "player_status_" + player.getUUID();
compat.sendMessage(player, messageId, "Health: 20/20", 100f);
// Later...
compat.sendUpdateMessage(player, messageId, "Health: 15/20", 100f);
Learn how to set up Matthiesen Lib in your development environment with the Installation Guide.
Explore the Registry Builder API to see how to register content from common code.
Check out the Commands page to learn how to create cross-platform commands.
Find out how to implement permissions with the Permissions system.
Discover how to register client-side features like screens and renderers in the Client-Side Features section.
Utilize helpful utilities like the ItemBuilder in the Utilities section.