Developer API Reference
This guide covers how to integrate Embers Text API into your Minecraft mod, using the fluent builder pattern and message management system.
Adding the Dependency
Section titled “Adding the Dependency”Add Embers Text API to your mod’s dependencies:
build.gradle
Section titled “build.gradle”repositories { maven { url = "https://www.cursemaven.com" content { includeGroup "curse.maven" } }}
dependencies { implementation fg.deobf("curse.maven:embers-text-api-1345948:FILE_ID")}Replace FILE_ID with the latest file ID from CurseForge.
Importing Classes
Section titled “Importing Classes”import com.emberstextapi.EmbersTextAPI;import com.emberstextapi.message.ImmersiveMessage;import com.emberstextapi.message.EmbersMessages;import com.emberstextapi.util.TextAnchor;import com.emberstextapi.util.TextAlignment;import com.emberstextapi.util.ShakeType;Creating Messages
Section titled “Creating Messages”Basic Message Builder
Section titled “Basic Message Builder”The ImmersiveMessage.builder() method uses a fluent builder pattern for creating messages:
ImmersiveMessage message = ImmersiveMessage.builder(100, "Hello, World!") .build();Parameters:
duration(int) - Display duration in tickstext(String) - The message to display
Sending Messages to Players
Section titled “Sending Messages to Players”Use EmbersTextAPI.sendMessage() to send messages to players:
ServerPlayer player = // get your playerImmersiveMessage message = ImmersiveMessage.builder(100, "Welcome!") .build();
EmbersTextAPI.sendMessage(player, message);Builder Methods
Section titled “Builder Methods”Position and Alignment
Section titled “Position and Alignment”anchor()
Section titled “anchor()”Set where the message appears on screen:
.anchor(TextAnchor.CENTER_CENTER)Available Anchors:
TOP_LEFT,TOP_CENTER,TOP_RIGHTCENTER_LEFT,CENTER_CENTER,CENTER_RIGHTBOTTOM_LEFT,BOTTOM_CENTER,BOTTOM_RIGHT
ImmersiveMessage message = ImmersiveMessage.builder(100, "Centered!") .anchor(TextAnchor.CENTER_CENTER) .build();align()
Section titled “align()”Set text alignment relative to anchor:
.align(TextAlignment.CENTER)Available Alignments:
LEFT- Text extends right from anchorCENTER- Text centers on anchorRIGHT- Text extends left from anchor
ImmersiveMessage message = ImmersiveMessage.builder(100, "Right aligned") .anchor(TextAnchor.TOP_RIGHT) .align(TextAlignment.RIGHT) .build();offset()
Section titled “offset()”Fine-tune position with pixel offsets:
.offsetX(10).offsetY(-20)ImmersiveMessage message = ImmersiveMessage.builder(100, "Offset text") .anchor(TextAnchor.CENTER_CENTER) .offsetX(50) .offsetY(30) .build();Colors and Gradients
Section titled “Colors and Gradients”color()
Section titled “color()”Set a solid color (hex or integer):
.color(0xFF6B6B) // Hex color.color(16737643) // Integer colorImmersiveMessage message = ImmersiveMessage.builder(100, "Red text") .color(0xFF0000) .build();gradient()
Section titled “gradient()”Create multi-stop gradients:
.gradient(int... colors)Two-color gradient:
ImmersiveMessage message = ImmersiveMessage.builder(100, "Gradient text") .gradient(0xFF0000, 0x0000FF) // Red to blue .build();Multi-stop gradient:
ImmersiveMessage message = ImmersiveMessage.builder(100, "Rainbow!") .gradient(0xFF0000, 0xFFFF00, 0x00FF00, 0x00FFFF, 0x0000FF) .build();Animations
Section titled “Animations”typewriter()
Section titled “typewriter()”Create a typing animation effect:
.typewriter(float speed, boolean center)Parameters:
speed- Characters per tick (1.0f = 1 char/tick, 2.0f = 2 chars/tick)center- If true, re-centers text as it types
ImmersiveMessage message = ImmersiveMessage.builder(200, "Typing effect...") .typewriter(2.0f, true) .anchor(TextAnchor.CENTER_CENTER) .build();shake()
Section titled “shake()”Add whole-text shake effects:
.shake(ShakeType type, float intensity)Shake Types:
ShakeType.WAVE- Smooth wave motionShakeType.CIRCULAR- Circular movementShakeType.RANDOM- Random jitter
ImmersiveMessage message = ImmersiveMessage.builder(100, "Shaking!") .shake(ShakeType.WAVE, 1.5f) .build();Per-character shake:
.charShake(ShakeType type, float intensity)ImmersiveMessage message = ImmersiveMessage.builder(100, "Each letter shakes!") .charShake(ShakeType.RANDOM, 2.0f) .build();obfuscate()
Section titled “obfuscate()”Add obfuscation with optional reveal:
.obfuscate(String revealMode)Reveal Modes:
"NONE"- Always obfuscated"LEFT_TO_RIGHT"- Reveals from left"RIGHT_TO_LEFT"- Reveals from right"CENTER_OUT"- Reveals from center"RANDOM"- Random character reveal
ImmersiveMessage message = ImmersiveMessage.builder(150, "Secret message") .obfuscate("LEFT_TO_RIGHT") .build();Fade Effects
Section titled “Fade Effects”fadeIn() / fadeOut()
Section titled “fadeIn() / fadeOut()”Control fade timing:
.fadeIn(int ticks).fadeOut(int ticks)ImmersiveMessage message = ImmersiveMessage.builder(200, "Smooth entrance") .fadeIn(40) // 2 second fade in .fadeOut(40) // 2 second fade out .build();Backgrounds
Section titled “Backgrounds”backgroundColor()
Section titled “backgroundColor()”Set solid background color:
.backgroundColor(int color)ImmersiveMessage message = ImmersiveMessage.builder(100, "With background") .backgroundColor(0x000000) // Black background .build();backgroundGradient()
Section titled “backgroundGradient()”Add gradient border to background:
.backgroundGradient(int... colors)ImmersiveMessage message = ImmersiveMessage.builder(100, "Fancy border") .backgroundColor(0x000000) .backgroundGradient(0xFF0000, 0x0000FF) .build();background()
Section titled “background()”Use a textured background:
.background(String texture, String mode, int width, int height, int paddingX, int paddingY)Modes:
"STRETCH"- Stretch texture to fit"CROP"- Crop texture to fit"TILE"- Tile texture
ImmersiveMessage message = ImmersiveMessage.builder(100, "Textured!") .background("minecraft:textures/gui/demo_background.png", "STRETCH", 256, 64, 10, 5) .build();Text Formatting
Section titled “Text Formatting”font()
Section titled “font()”Use custom fonts:
.font(String fontId)ImmersiveMessage message = ImmersiveMessage.builder(100, "Custom font") .font("minecraft:uniform") .build();Built-in Fonts:
"minecraft:default"- Standard Minecraft font"minecraft:uniform"- Uniform spacing"minecraft:alt"- Alternative font- Custom fonts in
assets/emberstextapi/font/
wrap()
Section titled “wrap()”Enable text wrapping at pixel width:
.wrap(int maxWidth)ImmersiveMessage message = ImmersiveMessage.builder(200, "This is a very long message that will wrap to multiple lines") .wrap(200) .build();shadow()
Section titled “shadow()”Add drop shadow:
.shadow(boolean enabled)ImmersiveMessage message = ImmersiveMessage.builder(100, "With shadow") .shadow(true) .build();Message Management
Section titled “Message Management”Tracked Messages
Section titled “Tracked Messages”Use EmbersMessages to create, update, and close messages:
open()
Section titled “open()”Create a tracked message with an ID:
EmbersMessages.open(ServerPlayer player, String messageId, ImmersiveMessage message)ImmersiveMessage message = ImmersiveMessage.builder(1000, "Quest: Find the treasure") .anchor(TextAnchor.TOP_CENTER) .build();
EmbersMessages.open(player, "quest_objective", message);update()
Section titled “update()”Update an existing tracked message:
EmbersMessages.update(ServerPlayer player, String messageId, ImmersiveMessage newMessage)ImmersiveMessage updated = ImmersiveMessage.builder(1000, "Quest: Return to village") .anchor(TextAnchor.TOP_CENTER) .color(0x00FF00) .build();
EmbersMessages.update(player, "quest_objective", updated);close()
Section titled “close()”Close a specific tracked message:
EmbersMessages.close(ServerPlayer player, String messageId)EmbersMessages.close(player, "quest_objective");closeAll()
Section titled “closeAll()”Close all messages for a player:
EmbersMessages.closeAll(ServerPlayer player)EmbersMessages.closeAll(player);Complete Examples
Section titled “Complete Examples”Quest Notification System
Section titled “Quest Notification System”public class QuestNotifier {
public void showQuestStart(ServerPlayer player, String questName) { ImmersiveMessage message = ImmersiveMessage.builder(200, "New Quest: " + questName) .anchor(TextAnchor.CENTER_CENTER) .gradient(0xFFD700, 0xFFA500) .typewriter(2.0f, true) .fadeIn(20) .fadeOut(20) .backgroundColor(0x000000) .shadow(true) .build();
EmbersTextAPI.sendMessage(player, message); }
public void showQuestObjective(ServerPlayer player, String objective) { ImmersiveMessage message = ImmersiveMessage.builder(Integer.MAX_VALUE, objective) .anchor(TextAnchor.TOP_CENTER) .color(0xFFFFFF) .offsetY(20) .shadow(true) .build();
EmbersMessages.open(player, "current_quest", message); }
public void updateQuestObjective(ServerPlayer player, String newObjective) { ImmersiveMessage message = ImmersiveMessage.builder(Integer.MAX_VALUE, newObjective) .anchor(TextAnchor.TOP_CENTER) .color(0xFFFFFF) .offsetY(20) .shadow(true) .build();
EmbersMessages.update(player, "current_quest", message); }
public void completeQuest(ServerPlayer player) { EmbersMessages.close(player, "current_quest");
ImmersiveMessage completion = ImmersiveMessage.builder(100, "Quest Complete!") .anchor(TextAnchor.CENTER_CENTER) .gradient(0x00FF00, 0xFFFF00) .shake(ShakeType.WAVE, 1.0f) .fadeOut(30) .build();
EmbersTextAPI.sendMessage(player, completion); }}Boss Health Display
Section titled “Boss Health Display”public class BossHealthDisplay {
public void showBossHealth(ServerPlayer player, String bossName, int health, int maxHealth) { float healthPercent = (float) health / maxHealth; int barLength = 20; int filledBars = (int) (healthPercent * barLength);
StringBuilder healthBar = new StringBuilder(); for (int i = 0; i < barLength; i++) { healthBar.append(i < filledBars ? "█" : "░"); }
String display = String.format("%s\n%s %d/%d", bossName, healthBar.toString(), health, maxHealth);
int color = healthPercent > 0.5 ? 0xFF0000 : healthPercent > 0.25 ? 0xFF6B00 : 0x8B0000;
ImmersiveMessage message = ImmersiveMessage.builder(Integer.MAX_VALUE, display) .anchor(TextAnchor.TOP_CENTER) .align(TextAlignment.CENTER) .color(color) .offsetY(30) .shadow(true) .build();
EmbersMessages.update(player, "boss_health", message); }
public void hideBossHealth(ServerPlayer player) { EmbersMessages.close(player, "boss_health"); }}Cinematic Dialogue
Section titled “Cinematic Dialogue”public class CinematicDialogue {
public void playDialogueSequence(ServerPlayer player) { scheduleMessage(player, 0, "A mysterious voice echoes...", 3.0f); scheduleMessage(player, 100, "You shouldn't be here...", 2.0f); scheduleMessage(player, 200, "Turn back while you still can!", 2.5f); }
private void scheduleMessage(ServerPlayer player, int delay, String text, float typeSpeed) { // Use your preferred scheduling system (Minecraft tick scheduler, etc.) server.schedule(() -> { ImmersiveMessage message = ImmersiveMessage.builder(150, text) .anchor(TextAnchor.BOTTOM_CENTER) .align(TextAlignment.CENTER) .typewriter(typeSpeed, true) .gradient(0xAAAAAA, 0xFFFFFF) .fadeIn(10) .fadeOut(20) .backgroundColor(0x000000) .offsetY(-50) .build();
EmbersTextAPI.sendMessage(player, message); }, delay); }}Warning System
Section titled “Warning System”public class WarningSystem {
public void showCriticalWarning(ServerPlayer player, String warning) { ImmersiveMessage message = ImmersiveMessage.builder(80, "⚠ " + warning + " ⚠") .anchor(TextAnchor.CENTER_CENTER) .color(0xFF0000) .shake(ShakeType.RANDOM, 2.0f) .shadow(true) .backgroundColor(0x330000) .backgroundGradient(0xFF0000, 0x660000) .build();
EmbersTextAPI.sendMessage(player, message); }
public void showPersistentAlert(ServerPlayer player, String alert) { ImmersiveMessage message = ImmersiveMessage.builder(Integer.MAX_VALUE, alert) .anchor(TextAnchor.TOP_CENTER) .color(0xFFFF00) .charShake(ShakeType.WAVE, 0.5f) .offsetY(10) .shadow(true) .build();
EmbersMessages.open(player, "persistent_alert", message); }
public void clearAlert(ServerPlayer player) { EmbersMessages.close(player, "persistent_alert"); }}Networking
Section titled “Networking”Embers Text API uses a SimpleChannel for client-server communication. Messages are automatically synchronized when using EmbersTextAPI.sendMessage().
Custom Packets (Advanced)
Section titled “Custom Packets (Advanced)”If you need to send custom packet data:
// This is handled internally by EmbersTextAPI// You typically don't need to interact with the network layer directlyBest Practices
Section titled “Best Practices”Performance
Section titled “Performance”-
Reuse tracked messages instead of creating new ones continuously
// Good - updates existing messageEmbersMessages.update(player, "score", newMessage);// Bad - creates new message every tickEmbersTextAPI.sendMessage(player, newMessage); -
Clean up messages when no longer needed
EmbersMessages.close(player, "temporary_message"); -
Use appropriate durations - don’t set infinite duration unless necessary
User Experience
Section titled “User Experience”- Don’t overlap too many messages - screen space is limited
- Use fade effects for smooth transitions
- Match anchor and alignment for intuitive positioning
- Test readability with different backgrounds and screen sizes
Compatibility
Section titled “Compatibility”-
Check if API is loaded before sending messages
if (ModList.get().isLoaded("emberstextapi")) {EmbersTextAPI.sendMessage(player, message);} -
Handle null players gracefully
if (player != null && player.connection != null) {EmbersTextAPI.sendMessage(player, message);}
Troubleshooting
Section titled “Troubleshooting”Messages Not Appearing
Section titled “Messages Not Appearing”- Verify the player is online and connected
- Check that duration > 0
- Ensure message isn’t off-screen (check anchor/offset)
- Verify mod is loaded on both client and server
Performance Issues
Section titled “Performance Issues”- Reduce number of simultaneous messages
- Use simpler effects (avoid multiple shake animations)
- Close unused tracked messages
- Optimize typewriter speed for longer text
Build Errors
Section titled “Build Errors”- Verify correct dependency version
- Check Maven repository is accessible
- Ensure proper deobfuscation in build.gradle (
fg.deobf())
Version Compatibility
Section titled “Version Compatibility”v1 (Current - Stable)
Section titled “v1 (Current - Stable)”All features documented above are available in v1. This is the current production version.
v2 (In Development)
Section titled “v2 (In Development)”v2 will introduce major architectural changes:
Span-Based Effects System:
- Apply effects to specific text segments (words, characters, ranges)
- Use animations in quest descriptions, item lore, chat, and tooltips
- Universal text styling system beyond just overlays
- Per-segment effect control
New Rendering Types:
- Item rendering inline with text
- Entity rendering in messages
- Advanced texture rendering
- Multiple simultaneous renders
Enhanced Configuration:
- More granular effect control
- Improved animation timing and easing
- Better effect composition
Inspiration: v2 draws inspiration from Snownee’s Text Animator mod
Migration Path: When v2 releases, v1 APIs will be deprecated but continue to function through a compatibility layer. The shift to span-based effects represents a fundamental architectural change that will enable more powerful and flexible text styling throughout Minecraft.