Ember’s Text API lets your mod display polished, animated text overlays without building a custom renderer. Messages can include gradients, backgrounds, fonts, typewriter effects, and shake animations, all controlled through a fluent builder API.
Immersive Messaging API(which this was built to replace) uses her lib, txnilib, which jar-in-jars(aka has another mod inside her mod) Forgified Fabric API, making all of his FORGE mods have FABRIC overhead. That, along with the features I want that IM didn't have(like multiple attributes working together like obfuscation and typewriter, and gradients), made me want to make this, so... cheers 🍻
- Fluent Builder: Create
ImmersiveMessageinstances with chaining (gradient,background,typewriter,shake,wrap, etc.). - Client Networking:
EmbersTextAPI.sendMessage(ServerPlayer, ImmersiveMessage)packs the message and sends it over aSimpleChannel. - Demo Command:
/emberstextapi test <id>showcases nine sample effects out of the box. - Custom Fonts & Backgrounds: Place font files under
assets/emberstextapi/font/, toggle tooltip-style backgrounds with gradient borders, or layer textured backgrounds with configurable scaling and padding.
ImmersiveMessage msg = ImmersiveMessage.builder(80f, "Hello world") .anchor(TextAnchor.CENTER_CENTER) .offset(0f, -20f) .gradient(0xFF0000, 0x00FF00) .background(true) .typewriter(2f, true) .fadeInTicks(10) .fadeOutTicks(20) .shake(ShakeType.WAVE, 1.5f);EmbersTextAPI.sendMessage(player, msg);| Method | Description |
|---|---|
anchor(TextAnchor) / align(TextAnchor) | Screen anchor vs. text alignment |
offset(float x, float y) | Move from anchor point |
scale(float size) | Uniform size multiplier |
color(int/String/ChatFormatting) | Single color |
gradient(int... or String...) | Multi-stop text gradient |
background(true) / bgColor(...) | Tooltip-style background (solid/gradient) |
textureBackground(...) | Draw a textured quad behind text using the supplied sprite |
textureBackgroundScale(...) | Scale U/V sampling before drawing (stretch vs. tile density) |
textureBackgroundPadding(...) | Adjust empty space around the textured background quad |
textureBackgroundSize/Width/Height(...) | Override draw dimensions separate from text bounds |
textureBackgroundMode(...) | Choose stretching, cropping, or tiling behavior for the texture |
borderGradient(int start, int end) | Gradient border colors |
wrap(int width) | Line wrapping width |
typewriter(speed [,center]) | Typewriter animation (chars per tick) |
shake(ShakeType, float) / charShake(...) | Whole-text or per-character shaking |
Custom fonts require both a .json and font file in src/main/resources/assets/emberstextapi/font/.
| Command | Purpose |
|---|---|
/emberstextapi test <id> | Play built-in demonstration messages |
/emberstextapi send <player> <duration> [fadeIn] [fadeOut] <text> | Send a basic message |
/emberstextapi sendcustom <player> <nbt> <duration> <text> | Full control via NBT tags |
| Tag | Purpose | Usage Example |
|---|---|---|
fadeIn, fadeOut |
Fade durations before and after the main display (ticks). | {fadeIn:10,fadeOut:20} |
font |
Apply a specific font resource to the message. | {font:"modid:font_name"} |
bold, italic, underlined, strikethrough, obfuscated |
Enable text style flags. Set to true to apply. |
{bold:true,italic:true} |
color |
Set a single text color by name ("red") or hex ("#FF0000"). |
{color:"#FFAA00"} |
gradient |
Apply a multi-stop text gradient (list or {start,end}). |
{gradient:["#FF0000","#00FF00"]} or {gradient:{start:"#FF0000",end:"#00FF00"}} |
bgGradient |
Gradient fill for the background frame. Uses list or {start,end}; enables background automatically. |
{bgGradient:{start:"#FF000080",end:"#0000FF80"}} |
borderGradient |
Gradient for the background border. | {borderGradient:["#FF0000","#00FF00"]} |
bgColor |
Solid background color (implies background). | {bgColor:"#333333CC"} |
borderColor |
Solid color for the border (implies background). | {borderColor:"#FFFFFF"} |
textureBackground |
Apply a textured background. String form uses a single ResourceLocation; compound form supports:texture (sprite id), u/v, width/height, atlas textureWidth/textureHeight, per-axis paddingX/paddingY, scaleX/scaleY, sizeX/sizeY (drawWidth/drawHeight), and mode/resize for stretch vs. crop.Examples: {textureBackground:"modid:textures/gui/panel.png"}, {textureBackground:{texture:"modid:textures/gui/panel.png",mode:"STRETCH"}}, {textureBackground:{texture:"modid:textures/gui/panel.png",mode:"CROP",sizeX:120,sizeY:40}} |
{textureBackground:{texture:"modid:textures/gui/panel.png",paddingX:6,paddingY:4,scaleX:0.5,scaleY:0.5}} |
size |
Uniform scale multiplier for text. | {size:1.5} |
typewriter & center |
Animate text appearing at a given speed; optional center keeps text centered during animation. |
{typewriter:2.0,"center":true} |
background |
Toggle background frame on/off. | {background:true} |
bgAlpha |
Background opacity (0–1). | {bgAlpha:0.5} |
wrap |
Wrap text at the given pixel width. | {wrap:120} |
obfuscate & obfuscateSpeed |
Gradually reveal obfuscated text using mode (LEFT, RIGHT, CENTER, RANDOM) and optional speed. |
{obfuscate:"LEFT",obfuscateSpeed:0.1} |
anchor |
Anchor screen position; values from TextAnchor (e.g., TOP_LEFT, CENTER_CENTER). |
{anchor:"CENTER_CENTER"} |
align |
Text alignment relative to anchor (same enum as anchor). |
{align:"CENTER_CENTER"} |
offsetX, offsetY |
Pixel offsets from anchor point. | {offsetX:10,offsetY:-20} |
shadow |
Enable or disable drop shadow. | {shadow:true} |
shakeWave (wave*) |
Wave-like whole-message shake amplitude. | {shakeWave:1.5} |
shakeCircle (circle*) |
Circular whole-message shake amplitude. | {shakeCircle:1.0} |
shakeRandom (random*) |
Random jitter whole-message shake amplitude. | {shakeRandom:0.8} |
charShakeWave (waveChar*) |
Wave shake per character. | {charShakeWave:1.0} |
charShakeCircle (circleChar*) |
Circular shake per character. | {charShakeCircle:1.0} |
charShakeRandom (randomChar*) |
Random jitter per character. | {charShakeRandom:1.0} |
*Deprecated tags still work, but with log warnings.
ImmersiveMessage msg = ImmersiveMessage.builder(60f, "Boss Approaches!")
.fadeInTicks(10)
.fadeOutTicks(20);
EmbersTextAPI.sendMessage(player, msg);Command variant:
/immersivemessages sendcustom @p {text:"Boss Approaches!",duration:60,fadeIn:10,fadeOut:20}
UUID id = EmbersMessages.open(player,
ImmersiveMessage.builder(100f, "⚔ Boss Appears")
.anchor(TextAnchor.TOP_CENTER)
.build());
EmbersMessages.update(player, id,
ImmersiveMessage.builder(100f, "🔥 Phase 2: Enrage")
.shake(ShakeType.RANDOM, 1.2f)
.build());
EmbersMessages.close(player, id);
// Or clear everything:
EmbersMessages.closeAll(player);