Skip to main content
Foundation’s SimpleHologram class provides an easy way to create floating text displays and animated entities without depending on external hologram plugins.

Creating a hologram

Extend SimpleHologram and implement createEntity():
public class FloatingText extends SimpleHologram {

    public FloatingText(Location location) {
        super(location);
        
        setLore(
            "&6&lWelcome",
            "&7to our server!",
            "&eEnjoy your stay"
        );
    }

    @Override
    protected Entity createEntity() {
        ArmorStand stand = (ArmorStand) getLastTeleportLocation()
            .getWorld()
            .spawnEntity(getLastTeleportLocation(), EntityType.ARMOR_STAND);
        
        stand.setVisible(false);
        stand.setGravity(false);
        stand.setCustomNameVisible(true);
        stand.setCustomName("Main Hologram");
        
        return stand;
    }
}

Spawning holograms

Location loc = player.getLocation().add(0, 2, 0);
FloatingText hologram = new FloatingText(loc);
hologram.spawn();

Text lines

Set multiple lines of floating text above the hologram:
public MyHologram(Location location) {
    super(location);
    
    setLore(
        "&6Line 1",
        "&eLine 2",
        "&7Line 3",
        "&cLine 4"
    );
}

Line spacing

Adjust the distance between text lines:
SimpleHologram.setLoreLineHeight(0.30); // Default: 0.26

Animations

Override onTick() to animate your hologram:
public class RotatingHologram extends SimpleHologram {

    private float yaw = 0;

    public RotatingHologram(Location location) {
        super(location);
    }

    @Override
    protected Entity createEntity() {
        ArmorStand stand = (ArmorStand) getLastTeleportLocation()
            .getWorld()
            .spawnEntity(getLastTeleportLocation(), EntityType.ARMOR_STAND);
        
        stand.setVisible(true);
        stand.setGravity(false);
        stand.setHelmet(new ItemStack(Material.DIAMOND_BLOCK));
        
        return stand;
    }

    @Override
    protected void onTick() {
        yaw += 5;
        if (yaw >= 360)
            yaw = 0;
        
        ArmorStand stand = (ArmorStand) getEntity();
        Location loc = getLocation();
        loc.setYaw(yaw);
        stand.teleport(loc);
    }
}

Particles

Add particle effects to your holograms:
public MyHologram(Location location) {
    super(location);
    
    // Simple particle
    addParticleEffect(CompParticle.FLAME);
    
    // Particle with block data
    addParticleEffect(CompParticle.BLOCK_CRACK, CompMaterial.DIAMOND_BLOCK);
    
    // Multiple particles
    addParticleEffect(CompParticle.SPELL_WITCH);
    addParticleEffect(CompParticle.SPELL_MOB);
}

Teleporting

Move holograms to new locations:
Location newLoc = player.getLocation();
hologram.teleport(newLoc);

Getting location

Location current = hologram.getLocation();
Location spawn = hologram.getLastTeleportLocation();

Removing holograms

Remove a specific hologram:
hologram.remove();
Remove all holograms:
SimpleHologram.deleteAll();

Advanced examples

Leaderboard hologram

public class LeaderboardHologram extends SimpleHologram {

    public LeaderboardHologram(Location location) {
        super(location);
        updateLeaderboard();
    }

    @Override
    protected Entity createEntity() {
        ArmorStand stand = (ArmorStand) getLastTeleportLocation()
            .getWorld()
            .spawnEntity(getLastTeleportLocation(), EntityType.ARMOR_STAND);
        
        stand.setVisible(false);
        stand.setGravity(false);
        
        return stand;
    }

    public void updateLeaderboard() {
        List<String> lines = new ArrayList<>();
        lines.add("&6&l━━━━━━━━━━━━━━━━━");
        lines.add("&e&lTOP PLAYERS");
        lines.add("&6&l━━━━━━━━━━━━━━━━━");
        lines.add("");
        
        List<PlayerData> top = PlayerData.getTopPlayers(10);
        for (int i = 0; i < top.size(); i++) {
            PlayerData data = top.get(i);
            lines.add("&7" + (i + 1) + ". &f" + data.getName() + 
                     " &7- &e" + data.getScore());
        }
        
        setLore(lines.toArray(new String[0]));
        
        // Update if already spawned
        if (isSpawned()) {
            removeLore();
            // Lore will be redrawn on next tick
        }
    }
}

Animated floating item

public class FloatingItem extends SimpleHologram {

    private final ItemStack item;
    private double rotation = 0;
    private double bobbing = 0;

    public FloatingItem(Location location, ItemStack item) {
        super(location);
        this.item = item;
        
        setLore(
            "&e&lRare Item!",
            "&7Click to collect"
        );
        
        addParticleEffect(CompParticle.VILLAGER_HAPPY);
        addParticleEffect(CompParticle.SPELL_INSTANT);
    }

    @Override
    protected Entity createEntity() {
        ArmorStand stand = (ArmorStand) getLastTeleportLocation()
            .getWorld()
            .spawnEntity(getLastTeleportLocation(), EntityType.ARMOR_STAND);
        
        stand.setVisible(false);
        stand.setGravity(false);
        stand.setSmall(true);
        stand.setHelmet(item);
        
        return stand;
    }

    @Override
    protected void onTick() {
        // Rotate
        rotation += 5;
        if (rotation >= 360)
            rotation = 0;
        
        // Bob up and down
        bobbing += 0.1;
        double yOffset = Math.sin(bobbing) * 0.1;
        
        Location loc = getLastTeleportLocation().clone();
        loc.setYaw((float) rotation);
        loc.add(0, yOffset, 0);
        
        getEntity().teleport(loc);
    }
}

Information display

public class InfoHologram extends SimpleHologram {

    public InfoHologram(Location location) {
        super(location);
    }

    @Override
    protected Entity createEntity() {
        ArmorStand stand = (ArmorStand) getLastTeleportLocation()
            .getWorld()
            .spawnEntity(getLastTeleportLocation(), EntityType.ARMOR_STAND);
        
        stand.setVisible(false);
        stand.setGravity(false);
        
        return stand;
    }

    @Override
    protected void onTick() {
        // Update info every tick (20 times per second)
        updateInfo();
    }

    private void updateInfo() {
        int players = Bukkit.getOnlinePlayers().size();
        long tps = Remain.getTPS();
        
        setLore(
            "&6&lSERVER INFO",
            "",
            "&7Players: &f" + players + "/" + Bukkit.getMaxPlayers(),
            "&7TPS: &f" + tps,
            "&7Time: &f" + getFormattedTime()
        );
        
        // Update lore
        removeLore();
        // Will be redrawn
    }
    
    private String getFormattedTime() {
        return new SimpleDateFormat("HH:mm:ss").format(new Date());
    }
}

NPC hologram

public class NPCHologram extends SimpleHologram {

    private final String npcName;
    private final String[] dialogue;

    public NPCHologram(Location location, String name, String... dialogue) {
        super(location);
        this.npcName = name;
        this.dialogue = dialogue;
        
        List<String> lore = new ArrayList<>();
        lore.add("&e" + npcName);
        lore.add("");
        lore.addAll(Arrays.asList(dialogue));
        
        setLore(lore.toArray(new String[0]));
    }

    @Override
    protected Entity createEntity() {
        ArmorStand stand = (ArmorStand) getLastTeleportLocation()
            .getWorld()
            .spawnEntity(getLastTeleportLocation(), EntityType.ARMOR_STAND);
        
        stand.setVisible(true);
        stand.setGravity(false);
        stand.setBasePlate(false);
        stand.setArms(true);
        
        // Equip NPC
        stand.setHelmet(new ItemStack(Material.PLAYER_HEAD));
        stand.setChestplate(new ItemStack(Material.DIAMOND_CHESTPLATE));
        stand.setLeggings(new ItemStack(Material.DIAMOND_LEGGINGS));
        stand.setBoots(new ItemStack(Material.DIAMOND_BOOTS));
        stand.setItemInHand(new ItemStack(Material.DIAMOND_SWORD));
        
        return stand;
    }
}

Managing holograms

Get all holograms

Set<SimpleHologram> all = SimpleHologram.getRegisteredItems();

Check if spawned

if (hologram.isSpawned()) {
    // Hologram is active
}

Get entities

Entity mainEntity = hologram.getEntity();
List<ArmorStand> loreStands = hologram.getLoreEntities();

Cleanup

Always remove holograms when your plugin disables:
@Override
protected void onPluginStop() {
    SimpleHologram.deleteAll();
}
Holograms automatically tick and update. The tick rate is 1 tick (50ms) and cannot be changed.
Too many holograms or complex animations can cause performance issues. Use sparingly!

Build docs developers (and LLMs) love