How holograms work
You do not need this page to get started — but it helps when something looks wrong, or when you choose between line types.
Normal entities vs packets
In vanilla Bukkit, if you spawn an Armor Stand, the server tracks it like any other entity. That costs memory and tick time, especially with many holograms.
HoloEasy instead:
- Keeps hologram data in memory (location, lines, who should see what)
- Uses PacketEvents to send “spawn / update / destroy entity” packets only to the players who should see them
From the player’s point of view it looks like a real floating entity. From the server’s point of view it is mostly packets.
The main objects
| Object | Role |
|---|---|
HoloEasy | Library entry point. Holds pools and registers click packet listening. |
Hologram | One hologram at one location. You subclass it. |
Line | One row of content (text, item, block, click hitbox, …). |
IHologramPool | Manages many holograms and who can see them. |
Lifecycle in plain English
- Plugin loads → create PacketEvents +
new HoloEasy(plugin) - Plugin enables →
PacketEvents.getAPI().init(), optionallystartPool(...) - You create a hologram subclass and call
show(player)orshow(pool) - HoloEasy sends spawn packets for each line
- When values change, you call
update/updateAllon lines - Plugin disables →
destroyPools()+ PacketEventsterminate()
Per-player content
Many line helpers take a Function<Player, …> (or a Kotlin lambda). That function runs when HoloEasy needs the value for that player.
Example: "Welcome, " + player.getName() shows a different name for each viewer.
Version notes
HoloEasy picks behavior from the server version. Broadly:
- Armor-stand style lines (
TextLine,BlockLine, …) work on older versions - Display entity lines (
DisplayTextLine,DisplayBlockLine) need 1.19.4+ - Interaction click hitboxes need 1.19.4+
Details for each type are on the Lines page.