Skip to main content
Popups are temporary HUD elements that appear in response to events and automatically disappear after a duration. They’re perfect for damage indicators, notifications, quest updates, and any information that should briefly grab the player’s attention.

What is a Popup?

A Popup is a HudObject that:
  • Appears temporarily when triggered by an event
  • Automatically disappears after a configured duration
  • Can be stacked (multiple popups showing simultaneously)
  • Supports animations and movement effects
  • Can be queued when too many appear at once
Unlike Huds, Popups are event-driven and temporary. They show up, animate, then fade away.

Basic Structure

Popups are defined in YAML files in the popups/ directory:
my_popup_name:
  triggers:          # What causes this popup to show
    1:
      class: entity_attack
  layouts:           # What to display
    1:
      name: damage_layout
      gui:
        x: 0
        y: 0
      pixel:
        x: 128
        y: 32
  duration: 20       # How long to display (ticks)

Real Example: Entity Health Popup

Here’s the actual entity health popup from BetterHud’s source:
entity_health_popup:
  move:
    duration: 3
    pixel:
      x-equation: 0
      y-equation: 40t       # Move up 40 pixels per second
  push: true               # Stack multiple popups
  key-mapping: true        # Allow per-entity tracking
  triggers:
    1:
      class: entity_attack  # Show when attacking entity
  layouts:
    1:
      name: entity_health_image
      gui:
        x: 0
        y: 0
      pixel:
        x: 128              # Center of screen
        y: 32               # Near top
    2:
      name: entity_health_text
      gui:
        x: 0
        y: 0
      pixel:
        x: 128
        y: 32
  duration: 20             # Show for 1 second (20 ticks)
This popup:
1

Triggers on attack

When a player attacks an entity, the entity_attack trigger fires
2

Shows health info

Displays the entity’s health using both image and text layouts
3

Moves upward

Animates upward at 40 pixels per second using y-equation: 40t
4

Stacks multiple hits

With push: true, hitting the same entity multiple times shows multiple popups
5

Disappears

After 20 ticks (1 second), the popup fades away
The referenced layouts are defined in layouts/entity-layout.yml:
entity_health_image:
  images:
    1:
      name: player           # Show player head/icon
      y: -20
    2:
      name: entity_health_empty  # Background bar
    3:
      name: entity_health_white  # Bar overlay
    4:
      name: entity_health_red    # Damage indicator

entity_health_text:
  texts:
    1:
      name: entity_font
      pattern: "Health: <#FFD800>[entity_health] // [entity_max_health]"
      placeholder-string-format:
        number: "#,###"      # Format numbers with commas
      y: -16
      x: -32
      scale: 0.5
      align: left
Popups can combine images and texts in their layouts to create rich notifications.

Triggers

Triggers determine when a popup appears:
my_popup:
  triggers:
    1:
      class: entity_attack   # Built-in trigger class
      cooldown: 5           # Minimum ticks between triggers

Common Trigger Classes

TriggerWhen it FiresUse Case
entity_attackPlayer attacks entityDamage indicators
player_deathPlayer diesDeath messages
player_joinPlayer joins serverWelcome messages
player_quitPlayer leaves serverGoodbye messages
commandCommand executedCommand feedback
customAPI callPlugin integration
Use the API to trigger popups programmatically:
popup.show(UpdateEvent.of(player), hudPlayer);

Duration and Timing

Control how long popups display:
my_popup:
  duration: 40        # Display for 40 ticks (2 seconds)
  frame-type: local   # Use popup-local timing (default)

Frame Types

Local Timing

frame-type: local - Each popup has its own animation timeline starting from 0

Global Timing

frame-type: global - All popups share the global tick counter
Local timing is recommended for most popups as it ensures animations play consistently regardless of when the popup was triggered.

Movement and Animation

Popups can move and animate during their lifetime:
my_popup:
  move:
    duration: 3          # Movement speed (higher = slower)
    pixel:
      x-equation: 10t    # Move right 10 pixels per second
      y-equation: -30t   # Move up 30 pixels per second
  layouts:
    # ...

Animation Variables

  • t - Time since popup appeared (0 to duration)
  • Mathematical functions - sin, cos, exp, log, etc.

Movement Examples

move:
  pixel:
    x-equation: 0
    y-equation: -20t  # Negative = upward

Stacking Popups

Control how multiple popups interact:
my_popup:
  max-stack: 5          # Allow up to 5 popups simultaneously
  push: true            # Stack new popups (don't replace old ones)
  group: damage_group   # Group name for organization

Push Behavior

Push Enabled

push: true - New popups stack above old ones. Old popups remain visible.

Push Disabled

push: false - New popups replace old ones in the same group.

Stack Sorting

Control the order of stacked popups:
my_popup:
  push: true
  sort-type: recent     # Most recent on top
  # Options: recent, old
When max-stack is reached, the oldest popup is removed to make room for the new one.
Organize related popups into groups:
damage_popup:
  group: combat_notifications
  max-stack: 3
  # ...

heal_popup:
  group: combat_notifications
  max-stack: 3
  # ...
Popups in the same group:
  • Share the same stack limit
  • Can be hidden/shown together
  • Are positioned relative to each other
Use groups to prevent too many notifications from cluttering the screen. All notifications in a group share the stack limit.

Key Mapping

Track popups per-entity or per-object:
entity_health_popup:
  key-mapping: true     # Each entity gets its own popup
  push: true
  triggers:
    1:
      class: entity_attack
With key-mapping: true:
  • Attacking Entity A and Entity B shows two separate popups
  • Each entity’s popup updates independently
  • Perfect for per-target damage indicators
The “key” is typically the entity UUID or a unique identifier from the trigger event.

Showing Popups via API

Trigger popups programmatically:
import kr.toxicity.hud.api.BetterHud;
import kr.toxicity.hud.api.popup.Popup;
import kr.toxicity.hud.api.update.UpdateEvent;

// Get popup by name
Popup popup = BetterHud.getInstance()
    .getPopupManager()
    .getPopup("my_popup");

// Create update event with custom variables
Map<String, String> variables = new HashMap<>();
variables.put("damage", "15");
variables.put("killer", "Zombie");

UpdateEvent event = UpdateEvent.of(player)
    .withVariables(variables);

// Show popup
if (popup != null) {
    popup.show(event, hudPlayer);
}

With Skript

command /damage:
    trigger:
        set {_vars::damage} to 42
        set {_vars::type} to "critical"
        show popup "damage_popup" to player with variable of {_vars::*}
Variables passed in the UpdateEvent can be used as placeholders in the popup layout.

Hiding Popups

Remove popups programmatically:
// Hide a specific popup
popup.hide(hudPlayer);

// Hide all popups in a group
String groupName = popup.getGroupName();
var group = hudPlayer.getPopupGroupIteratorMap().remove(groupName);
if (group != null) {
    group.clear();
}

Advanced: Conditions

Show popups only when conditions are met:
my_popup:
  conditions:
    - "<player_health> < 5"      # Only show when low health
    - "<player_world> = 'world'"  # Only in specific world
  triggers:
    # ...

Complete Example

A full-featured damage indicator popup:
damage_indicator:
  # Trigger
  triggers:
    1:
      class: entity_attack
      cooldown: 2
  
  # Stacking
  max-stack: 8
  push: true
  sort-type: recent
  key-mapping: true
  group: combat_indicators
  
  # Timing
  duration: 25
  frame-type: local
  
  # Movement
  move:
    duration: 2
    pixel:
      x-equation: 5cos(t * 2)
      y-equation: -40t
  
  # Display
  layouts:
    1:
      name: damage_text
      gui:
        x: 50
        y: 40
      pixel:
        x: 0
        y: 0
With the layout:
damage_text:
  texts:
    1:
      name: damage_font
      pattern: "<red>-[damage]"
      scale: 1.5
      align: center
  animations:
    duration: 25
    x-equation: 0
    y-equation: 0

Best Practices

  • Limit max-stack to reasonable numbers (5-10)
  • Use appropriate duration values (don’t make them too long)
  • Add cooldown to frequently-triggered popups
  • Don’t overwhelm players with too many popups
  • Use movement to direct attention (up = good, down = bad)
  • Keep popup text concise
  • Use groups to organize related notifications
  • Test animations at different frame rates
  • Ensure popups don’t obscure important UI elements
  • Use consistent styling across popup types

Next Steps

Triggers

Learn about all available trigger types

Layouts

Configure text and image layouts

API: Popups

Trigger popups programmatically

Huds

Learn about persistent HUD displays

Build docs developers (and LLMs) love