This is documentation for EmbersTextAPI 2.9.4. View the latest version

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


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.


ImmersiveMessage msg = new ImmersiveMessage(Component.literal("Hello!"), 100f);
ImmersiveMessage msg = ImmersiveMessage.fromMarkup(150f,
"<neon r=2><rainbow><bold>Welcome!</bold></rainbow></neon>"
);
ImmersiveMessage msg = ImmersiveMessage.builder(100f, "Simple message");
List<TextSpan> spans = MarkupParser.parse("<rainbow>Hello!</rainbow> normal text");
ImmersiveMessage msg = ImmersiveMessage.fromSpans(200f, spans);

All configuration methods return this for fluent chaining.

msg.anchor(TextAnchor.MIDDLE) // Default: TOP_CENTER
msg.align(TextAlign.CENTER) // Default: LEFT
msg.offset(0f, -30f) // Pixel offset from anchor (x, y)
msg.scale(1.5f) // Default: 1.0
msg.fadeInTicks(20) // Fade in over 1 second
msg.fadeOutTicks(30) // Fade out over 1.5 seconds
msg.shadow(true) // Default: true
msg.shadow(false) // Disable shadow
// Simple on/off
msg.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 gradient
msg.backgroundGradient("60000040", "60400000") // Hex strings

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>");
msg.typewriter(0.5f) // 0.5 characters per tick
msg.typewriter(0.5f, true) // With center-aligned reveal
msg.wrap(200) // Max 200 pixels wide before wrapping

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 size
msg.textureBackground(ResourceLocation.parse("mymod:textures/gui/panel.png"));
// Specify texture dimensions
msg.textureBackground(ResourceLocation.parse("mymod:textures/gui/panel.png"), 128, 64);
// Full atlas control — UV offset, region size, atlas size
msg.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 area
msg.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 area
msg.textureBackgroundMode(ImmersiveMessage.TextureSizingMode.STRETCH); // Default
msg.textureBackgroundMode(ImmersiveMessage.TextureSizingMode.CROP);
MethodDescription
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.


import net.tysontheember.emberstextapi.EmbersTextAPI;
import net.tysontheember.emberstextapi.immersivemessages.api.*;
import net.tysontheember.emberstextapi.immersivemessages.util.ImmersiveColor;
// Build spans from markup
List<TextSpan> spans = MarkupParser.parse(
"<neon r=2><rainbow><bold>Welcome!</bold></rainbow></neon> " +
"<color value=#AAAAAA>Enjoy your stay.</color>"
);
// Create and configure the message
ImmersiveMessage 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);

import net.tysontheember.emberstextapi.EmbersTextAPI;
// Simple send (generates UUID automatically)
EmbersTextAPI.sendMessage(serverPlayer, message);

For advanced control (update or close messages by ID), see Networking.


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 ID
net.sendOpenMessage(player, message); // generates UUID internally
// Later: update it before it expires
net.sendUpdateMessage(player, messageId, updatedMessage);
// Later: close it explicitly
net.sendCloseMessage(player, messageId);
// Emergency: close everything
net.sendCloseAllMessages(player);

See the full Networking page for all available methods.


import net.tysontheember.emberstextapi.platform.NetworkHelper;
import java.util.List;
NetworkHelper net = NetworkHelper.getInstance();
// Build steps: each step is a list of simultaneous messages
ImmersiveMessage 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);

  • 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.