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.
Setup
Adding the Dependency
Add Embers Text API to your mod's dependencies:
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
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
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
Use EmbersTextAPI.sendMessage() to send messages to players:
ServerPlayer player = // get your player
ImmersiveMessage message = ImmersiveMessage.builder(100, "Welcome!")
.build();
EmbersTextAPI.sendMessage(player, message);
Builder Methods
Position and Alignment
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()
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()
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
color()
Set a solid color (hex or integer):
.color(0xFF6B6B) // Hex color
.color(16737643) // Integer color
ImmersiveMessage message = ImmersiveMessage.builder(100, "Red text")
.color(0xFF0000)
.build();
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
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();
0.5f- Slow, dramatic1.0f- Natural reading pace2.0f- Quick5.0f+- Very fast
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()
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
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
backgroundColor()
Set solid background color:
.backgroundColor(int color)
ImmersiveMessage message = ImmersiveMessage.builder(100, "With background")
.backgroundColor(0x000000) // Black background
.build();
backgroundGradient()
Add gradient border to background:
.backgroundGradient(int... colors)
ImmersiveMessage message = ImmersiveMessage.builder(100, "Fancy border")
.backgroundColor(0x000000)
.backgroundGradient(0xFF0000, 0x0000FF)
.build();
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
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()
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()
Add drop shadow:
.shadow(boolean enabled)
ImmersiveMessage message = ImmersiveMessage.builder(100, "With shadow")
.shadow(true)
.build();
Message Management
Tracked Messages
Use EmbersMessages to create, update, and close messages:
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()
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()
Close a specific tracked message:
EmbersMessages.close(ServerPlayer player, String messageId)
EmbersMessages.close(player, "quest_objective");
closeAll()
Close all messages for a player:
EmbersMessages.closeAll(ServerPlayer player)
EmbersMessages.closeAll(player);
Complete Examples
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
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
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
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
Embers Text API uses a SimpleChannel for client-server communication. Messages are automatically synchronized when using EmbersTextAPI.sendMessage().
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 directly
Direct packet manipulation is not recommended. Use the provided API methods for best compatibility.
Best Practices
Performance
-
Reuse tracked messages instead of creating new ones continuously
// Good - updates existing message
EmbersMessages.update(player, "score", newMessage);
// Bad - creates new message every tick
EmbersTextAPI.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
- 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
-
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
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
- Reduce number of simultaneous messages
- Use simpler effects (avoid multiple shake animations)
- Close unused tracked messages
- Optimize typewriter speed for longer text
Build Errors
- Verify correct dependency version
- Check Maven repository is accessible
- Ensure proper deobfuscation in build.gradle (
fg.deobf())
Version Compatibility
v1 (Current - Stable)
All features documented above are available in v1. This is the current production version.
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.
Next Steps
- Explore Styling & Effects for visual design tips
- Review NBT Configuration for command-based alternatives
- Check Examples for more use cases
- Join the community for support and updates