Sending Messages
ImmersiveMessage is the main class for creating on-screen text displays. This page covers creating messages, configuring them, and sending them to players.
Package: net.tysontheember.emberstextapi.immersivemessages.api
The Simplest Message
Section titled “The Simplest Message”import net.tysontheember.emberstextapi.EmbersTextAPI;import net.tysontheember.emberstextapi.immersivemessages.api.ImmersiveMessage;import net.minecraft.network.chat.Component;
ImmersiveMessage msg = new ImmersiveMessage(Component.literal("Hello, World!"), 100f);EmbersTextAPI.sendMessage(serverPlayer, msg);The duration is in ticks (20 ticks = 1 second). 100f = 5 seconds.
On Fabric, use EmbersTextAPIFabric.sendMessage() instead.
Creating Messages
Section titled “Creating Messages”From a Component
Section titled “From a Component”ImmersiveMessage msg = new ImmersiveMessage(Component.literal("Hello!"), 100f);From Markup
Section titled “From Markup”ImmersiveMessage msg = ImmersiveMessage.fromMarkup(150f, "<neon r=2><rainbow><bold>Welcome!</bold></rainbow></neon>");From a Plain String
Section titled “From a Plain String”ImmersiveMessage msg = ImmersiveMessage.builder(100f, "Simple message");From Pre-Built TextSpans
Section titled “From Pre-Built TextSpans”List<TextSpan> spans = MarkupParser.parse("<rainbow>Hello!</rainbow> normal text");ImmersiveMessage msg = ImmersiveMessage.fromSpans(200f, spans);Configuration Methods
Section titled “Configuration Methods”All configuration methods return this for fluent chaining.
Positioning
Section titled “Positioning”msg.anchor(TextAnchor.MIDDLE) // Default: TOP_CENTERmsg.align(TextAlign.CENTER) // Default: LEFTmsg.offset(0f, -30f) // Pixel offset from anchor (x, y)msg.scale(1.5f) // Default: 1.0Fade Animations
Section titled “Fade Animations”msg.fadeInTicks(20) // Fade in over 1 secondmsg.fadeOutTicks(30) // Fade out over 1.5 secondsShadow
Section titled “Shadow”msg.shadow(true) // Default: truemsg.shadow(false) // Disable shadowBackground
Section titled “Background”// Simple on/offmsg.background(true)
// With colors (ImmersiveColor uses 0xAARRGGBB format)msg.backgroundColors( new ImmersiveColor(0x60000000), // bg: 37% opaque black new ImmersiveColor(0x80FFFFFF), // border start: 50% opaque white new ImmersiveColor(0x80FFFFFF) // border end)
// Background gradientmsg.backgroundGradient("60000040", "60400000") // Hex stringsText Color Gradient
Section titled “Text Color Gradient”Use the <grad> markup tag on your spans instead:
List<TextSpan> spans = MarkupParser.parse("<grad from=FF0000 to=0000FF>Hello!</grad>");// Multi-stop:List<TextSpan> spans = MarkupParser.parse("<grad from=FF0000 via=FFFF00 to=00FF00>Hello!</grad>");Typewriter
Section titled “Typewriter”msg.typewriter(0.5f) // 0.5 characters per tickmsg.typewriter(0.5f, true) // With center-aligned revealWrapping
Section titled “Wrapping”msg.wrap(200) // Max 200 pixels wide before wrappingTexture Backgrounds
Section titled “Texture Backgrounds”Use a custom texture as the message background instead of a solid color. Texture backgrounds are Java API-only — there is no markup tag equivalent.
import net.minecraft.resources.ResourceLocation;
// Simple — uses a 256x256 texture at full sizemsg.textureBackground(ResourceLocation.parse("mymod:textures/gui/panel.png"));
// Specify texture dimensionsmsg.textureBackground(ResourceLocation.parse("mymod:textures/gui/panel.png"), 128, 64);
// Full atlas control — UV offset, region size, atlas sizemsg.textureBackground( ResourceLocation.parse("mymod:textures/gui/atlas.png"), 0, 0, // u, v offset 64, 32, // region width, height 256, 256 // atlas width, height);Configuration methods (all return this for chaining):
// Scale the texture (uniform or per-axis)msg.textureBackgroundScale(2.0f);msg.textureBackgroundScale(1.5f, 2.0f); // scaleX, scaleY
// Add padding around the text areamsg.textureBackgroundPadding(8.0f);msg.textureBackgroundPadding(10.0f, 5.0f); // paddingX, paddingY
// Override the rendered size (ignores scale)msg.textureBackgroundSize(200f, 100f);msg.textureBackgroundWidth(200f);msg.textureBackgroundHeight(100f);
// Sizing mode: how the texture fills the background areamsg.textureBackgroundMode(ImmersiveMessage.TextureSizingMode.STRETCH); // Defaultmsg.textureBackgroundMode(ImmersiveMessage.TextureSizingMode.CROP);| Method | Description |
|---|---|
textureBackground(ResourceLocation) | Set texture (assumes 256x256 atlas) |
textureBackground(ResourceLocation, width, height) | Set texture with dimensions |
textureBackground(ResourceLocation, u, v, regionW, regionH, atlasW, atlasH) | Full atlas UV control |
textureBackgroundScale(float) | Uniform scale multiplier |
textureBackgroundScale(float, float) | Per-axis scale (X, Y) |
textureBackgroundPadding(float) | Uniform padding around text |
textureBackgroundPadding(float, float) | Per-axis padding (X, Y) |
textureBackgroundSize(float, float) | Override rendered width and height |
textureBackgroundWidth(float) | Override rendered width only |
textureBackgroundHeight(float) | Override rendered height only |
textureBackgroundMode(TextureSizingMode) | STRETCH (default) or CROP |
See TextureSizingMode for sizing mode details.
Full Example
Section titled “Full Example”import net.tysontheember.emberstextapi.EmbersTextAPI;import net.tysontheember.emberstextapi.immersivemessages.api.*;import net.tysontheember.emberstextapi.immersivemessages.util.ImmersiveColor;
// Build spans from markupList<TextSpan> spans = MarkupParser.parse( "<neon r=2><rainbow><bold>Welcome!</bold></rainbow></neon> " + "<color value=#AAAAAA>Enjoy your stay.</color>");
// Create and configure the messageImmersiveMessage msg = new ImmersiveMessage(spans, 200f) .anchor(TextAnchor.MIDDLE) .scale(1.3f) .background(true) .backgroundColors( new ImmersiveColor(0x60000020), new ImmersiveColor(0xAAFFFFFF), new ImmersiveColor(0xAA000000) ) .fadeInTicks(30) .fadeOutTicks(30);
// Send (must be called on server thread)EmbersTextAPI.sendMessage(player, msg);Sending Methods
Section titled “Sending Methods”import net.tysontheember.emberstextapi.EmbersTextAPI;
// Simple send (generates UUID automatically)EmbersTextAPI.sendMessage(serverPlayer, message);import net.tysontheember.emberstextapi.fabric.EmbersTextAPIFabric;
// Simple sendEmbersTextAPIFabric.sendMessage(serverPlayer, message);For advanced control (update or close messages by ID), see Networking.
Open / Update / Close Pattern
Section titled “Open / Update / Close Pattern”For messages that persist and need to be updated or closed programmatically (e.g., a progress bar, a running timer), use the explicit Open/Update/Close API via NetworkHelper.
import net.tysontheember.emberstextapi.platform.NetworkHelper;
NetworkHelper net = NetworkHelper.getInstance();String messageId = "my-progress-bar";
// Open a message with an explicit IDnet.sendOpenMessage(player, message); // generates UUID internally
// Later: update it before it expiresnet.sendUpdateMessage(player, messageId, updatedMessage);
// Later: close it explicitlynet.sendCloseMessage(player, messageId);
// Emergency: close everythingnet.sendCloseAllMessages(player);See the full Networking page for all available methods.
Sending Message Queues from Java
Section titled “Sending Message Queues from Java”import net.tysontheember.emberstextapi.platform.NetworkHelper;import java.util.List;
NetworkHelper net = NetworkHelper.getInstance();
// Build steps: each step is a list of simultaneous messagesImmersiveMessage step1a = ImmersiveMessage.fromMarkup(100f, "<rainbow>Step 1 message A</rainbow>");ImmersiveMessage step1b = ImmersiveMessage.fromMarkup(100f, "<wave>Step 1 message B</wave>");ImmersiveMessage step2 = ImmersiveMessage.fromMarkup(80f, "Step 2");
List<List<ImmersiveMessage>> steps = List.of( List.of(step1a, step1b), // Step 1: both show simultaneously List.of(step2) // Step 2: plays after step 1 finishes);
net.sendQueue(player, "my-channel", steps);Important Notes
Section titled “Important Notes”- Always send messages from the server thread. Never construct or send messages from the client side.
- Duration is in ticks:
20f= 1 second,200f= 10 seconds. - Messages are automatically removed when their duration expires. To remove early, use
sendCloseMessage(). - Do not send a new message every tick for updates — use
sendUpdateMessage()instead.