FancyInnovations
FancyHologramsAPIHolograms

Block Holograms

Creating and managing block display holograms

Block holograms display 3D blocks in the world. They support all Minecraft blocks including full block states (waterlogged, powered, facing directions, etc.).

Creating a block hologram

Using the builder

The recommended way to create block holograms is using the BlockHologramBuilder:

import de.oliver.fancyholograms.api.data.BlockHologramData;
import de.oliver.fancyholograms.api.data.builder.BlockHologramBuilder;
import de.oliver.fancyholograms.api.hologram.Hologram;
import de.oliver.fancyholograms.api.FancyHolograms;
import org.bukkit.Location;
import org.bukkit.Material;

Location location = new Location(world, 100, 64, 200);

BlockHologramData data = BlockHologramBuilder.create("my_block_hologram", location)
    .block(Material.DIAMOND_BLOCK)
    .scale(2.0f)  // Make it larger
    .billboard(Display.Billboard.FIXED)  // Keep block orientation
    .persistent(true)
    .build();

Hologram hologram = FancyHolograms.get().getHologramManager().create(data);
FancyHolograms.get().getHologramRegistry().register(hologram);

Direct instantiation

You can also create BlockHologramData directly:

BlockHologramData data = new BlockHologramData("my_block_hologram", location);
data.setBlock(Material.GOLD_BLOCK);
data.setScale(1.5f);

Setting the displayed block

Simple blocks

// Display ore blocks
data.setBlock(Material.DIAMOND_ORE);
data.setBlock(Material.EMERALD_ORE);
data.setBlock(Material.ANCIENT_DEBRIS);

// Display building blocks
data.setBlock(Material.STONE_BRICKS);
data.setBlock(Material.QUARTZ_BLOCK);
data.setBlock(Material.PRISMARINE);

// Display decorative blocks
data.setBlock(Material.GLOWSTONE);
data.setBlock(Material.SEA_LANTERN);
data.setBlock(Material.BEACON);

Blocks with block data

For blocks that have directional states or other properties:

import org.bukkit.block.data.BlockData;

// Directional blocks (stairs, logs, etc.)
BlockData stairsData = Bukkit.createBlockData(Material.OAK_STAIRS, "[facing=north,half=top]");
data.setBlockData(stairsData);

// Powered blocks
BlockData leverData = Bukkit.createBlockData(Material.LEVER, "[powered=true]");
data.setBlockData(leverData);

// Waterlogged blocks
BlockData slabData = Bukkit.createBlockData(Material.OAK_SLAB, "[waterlogged=true]");
data.setBlockData(slabData);

// Lit furnace
BlockData furnaceData = Bukkit.createBlockData(Material.FURNACE, "[lit=true]");
data.setBlockData(furnaceData);

Complex block states

// Chest facing south
BlockData chestData = Bukkit.createBlockData(Material.CHEST, "[facing=south,waterlogged=false]");
data.setBlockData(chestData);

// Extended piston
BlockData pistonData = Bukkit.createBlockData(Material.PISTON, "[extended=true,facing=up]");
data.setBlockData(pistonData);

// Redstone wire with power
BlockData redstoneData = Bukkit.createBlockData(Material.REDSTONE_WIRE,
    "[east=side,north=none,power=15,south=up,west=side]");
data.setBlockData(redstoneData);

Display properties

Scale

Control the size of the displayed block:

// Default size
data.setScale(1.0f);

// Double size
data.setScale(2.0f);

// Miniature
data.setScale(0.3f);

// Massive
data.setScale(10.0f);

// Get current scale
float scale = data.getScale();

Rotation

Rotate the block display:

import org.joml.Vector3f;

// Rotate 45 degrees on Y axis
data.setRotation(new Vector3f(0, 45, 0));

// Rotate on multiple axes
data.setRotation(new Vector3f(15, 90, 30));

// Upside down
data.setRotation(new Vector3f(180, 0, 0));

// Get current rotation
Vector3f rotation = data.getRotation();

Billboard mode

Control how the block faces the player:

import org.bukkit.entity.Display;

// Fixed orientation (recommended for blocks)
data.setBillboard(Display.Billboard.FIXED);

// Always face player
data.setBillboard(Display.Billboard.CENTER);

// Face player vertically only
data.setBillboard(Display.Billboard.VERTICAL);

// Face player horizontally only
data.setBillboard(Display.Billboard.HORIZONTAL);

Glow effect

Add a glowing outline:

// Enable glow
data.setGlowing(true);
data.setGlowColor(ChatColor.AQUA);

// Disable glow
data.setGlowing(false);

// Check if glowing
boolean glowing = data.isGlowing();

Complete examples

Example: Ore markers

public class OreMarkers {

    public void markOreVein(Location location, Material oreType) {
        BlockHologramData data = BlockHologramBuilder.create(
            "ore_marker_" + location.hashCode(),
            location.clone().add(0.5, 2, 0.5)
        )
        .block(oreType)
        .scale(0.5f)
        .billboard(Display.Billboard.CENTER)
        .glowing(true)
        .glowColor(getOreColor(oreType))
        .persistent(false)
        .build();

        Hologram hologram = FancyHolograms.get().getHologramManager().create(data);
        FancyHolograms.get().getHologramRegistry().register(hologram);

        // Remove after 30 seconds
        Bukkit.getScheduler().runTaskLater(plugin, () -> {
            FancyHolograms.get().getHologramRegistry().unregister(hologram);
        }, 600L);
    }

    private ChatColor getOreColor(Material ore) {
        return switch (ore) {
            case DIAMOND_ORE, DEEPSLATE_DIAMOND_ORE -> ChatColor.AQUA;
            case EMERALD_ORE, DEEPSLATE_EMERALD_ORE -> ChatColor.GREEN;
            case GOLD_ORE, DEEPSLATE_GOLD_ORE -> ChatColor.YELLOW;
            case IRON_ORE, DEEPSLATE_IRON_ORE -> ChatColor.WHITE;
            case ANCIENT_DEBRIS -> ChatColor.RED;
            default -> ChatColor.GRAY;
        };
    }
}

Example: Rotating beacon

public class RotatingBeacon {

    private Hologram beaconHologram;
    private float rotation = 0;

    public void create(Location location) {
        BlockHologramData data = BlockHologramBuilder.create("rotating_beacon", location)
            .block(Material.BEACON)
            .scale(2.0f)
            .billboard(Display.Billboard.FIXED)
            .glowing(true)
            .glowColor(ChatColor.AQUA)
            .persistent(false)
            .build();

        beaconHologram = FancyHolograms.get().getHologramManager().create(data);
        FancyHolograms.get().getHologramRegistry().register(beaconHologram);

        // Start rotation
        startRotation();
    }

    private void startRotation() {
        Bukkit.getScheduler().runTaskTimer(plugin, () -> {
            if (beaconHologram == null) return;

            rotation += 3;
            if (rotation >= 360) rotation = 0;

            BlockHologramData data = (BlockHologramData) beaconHologram.getData();
            data.setRotation(new Vector3f(0, rotation, 0));

            FancyHolograms.get().getHologramController().refreshHologram(beaconHologram);

        }, 0L, 1L);
    }
}

Example: Waypoint markers

public class WaypointMarkers {

    public void createWaypoint(Location location, String name, Material blockType) {
        // Floating block marker
        BlockHologramData blockData = BlockHologramBuilder.create(
            "waypoint_block_" + name,
            location.clone().add(0, 3, 0)
        )
        .block(blockType)
        .scale(1.5f)
        .billboard(Display.Billboard.CENTER)
        .glowing(true)
        .glowColor(ChatColor.YELLOW)
        .persistent(true)
        .build();

        // Waypoint name
        TextHologramData textData = TextHologramBuilder.create(
            "waypoint_text_" + name,
            location.clone().add(0, 4.5, 0)
        )
        .text(
            "<yellow><bold>" + name + "</bold></yellow>",
            "<gray>Waypoint</gray>"
        )
        .scale(0.8f)
        .textShadow(true)
        .billboard(Display.Billboard.CENTER)
        .persistent(true)
        .build();

        // Register both
        FancyHolograms api = FancyHolograms.get();
        api.getHologramRegistry().register(api.getHologramManager().create(blockData));
        api.getHologramRegistry().register(api.getHologramManager().create(textData));
    }
}

Example: Building preview

public class BuildingPreview {

    public void showBuildingPreview(Player player, Location corner1, Location corner2) {
        // Get all blocks in the region
        List<Location> blockLocations = getBlocksInRegion(corner1, corner2);

        for (Location loc : blockLocations) {
            Block block = loc.getBlock();
            if (block.getType().isAir()) continue;

            // Create hologram for each block
            BlockHologramData data = BlockHologramBuilder.create(
                "preview_" + loc.hashCode(),
                loc.clone().add(0.5, 0, 0.5)
            )
            .blockData(block.getBlockData())
            .scale(1.0f)
            .billboard(Display.Billboard.FIXED)
            .persistent(false)
            .visibilityDistance(100)
            .build();

            Hologram hologram = FancyHolograms.get().getHologramManager().create(data);
            FancyHolograms.get().getHologramRegistry().register(hologram);

            // Show only to this player
            FancyHolograms.get().getHologramController().showHologramTo(hologram, player);
        }

        player.sendMessage("§aShowing building preview...");
    }

    private List<Location> getBlocksInRegion(Location corner1, Location corner2) {
        List<Location> locations = new ArrayList<>();

        int minX = Math.min(corner1.getBlockX(), corner2.getBlockX());
        int maxX = Math.max(corner1.getBlockX(), corner2.getBlockX());
        int minY = Math.min(corner1.getBlockY(), corner2.getBlockY());
        int maxY = Math.max(corner1.getBlockY(), corner2.getBlockY());
        int minZ = Math.min(corner1.getBlockZ(), corner2.getBlockZ());
        int maxZ = Math.max(corner1.getBlockZ(), corner2.getBlockZ());

        for (int x = minX; x <= maxX; x++) {
            for (int y = minY; y <= maxY; y++) {
                for (int z = minZ; z <= maxZ; z++) {
                    locations.add(new Location(corner1.getWorld(), x, y, z));
                }
            }
        }

        return locations;
    }
}

Example: Portal frame

public class PortalFrame {

    public void createPortalFrame(Location center) {
        List<Location> frameLocations = getFrameLocations(center);

        for (int i = 0; i < frameLocations.size(); i++) {
            Location loc = frameLocations.get(i);

            BlockHologramData data = BlockHologramBuilder.create(
                "portal_frame_" + i,
                loc
            )
            .block(Material.CRYING_OBSIDIAN)
            .scale(1.0f)
            .billboard(Display.Billboard.FIXED)
            .glowing(true)
            .glowColor(ChatColor.LIGHT_PURPLE)
            .persistent(true)
            .build();

            Hologram hologram = FancyHolograms.get().getHologramManager().create(data);
            FancyHolograms.get().getHologramRegistry().register(hologram);
        }

        // Create portal effect in center
        createPortalEffect(center);
    }

    private List<Location> getFrameLocations(Location center) {
        List<Location> locations = new ArrayList<>();

        // Create a 3x3 frame (8 blocks)
        for (int x = -1; x <= 1; x++) {
            for (int z = -1; z <= 1; z++) {
                if (x == 0 && z == 0) continue;  // Skip center
                locations.add(center.clone().add(x, 0, z));
            }
        }

        return locations;
    }

    private void createPortalEffect(Location center) {
        BlockHologramData data = BlockHologramBuilder.create("portal_center", center)
            .block(Material.NETHER_PORTAL)
            .scale(0.5f)
            .glowing(true)
            .glowColor(ChatColor.LIGHT_PURPLE)
            .persistent(true)
            .build();

        Hologram hologram = FancyHolograms.get().getHologramManager().create(data);
        FancyHolograms.get().getHologramRegistry().register(hologram);
    }
}

Example: Resource node

public class ResourceNode {

    public void createNode(Location location, Material resourceType, int amount) {
        // Main resource block (larger)
        BlockHologramData mainData = BlockHologramBuilder.create(
            "node_main_" + location.hashCode(),
            location
        )
        .block(resourceType)
        .scale(1.8f)
        .billboard(Display.Billboard.FIXED)
        .glowing(true)
        .glowColor(ChatColor.YELLOW)
        .persistent(false)
        .build();

        // Orbiting mini blocks
        for (int i = 0; i < 3; i++) {
            double angle = (360.0 / 3) * i;
            double x = Math.cos(Math.toRadians(angle)) * 1.5;
            double z = Math.sin(Math.toRadians(angle)) * 1.5;

            BlockHologramData orbitData = BlockHologramBuilder.create(
                "node_orbit_" + location.hashCode() + "_" + i,
                location.clone().add(x, 0, z)
            )
            .block(resourceType)
            .scale(0.5f)
            .billboard(Display.Billboard.CENTER)
            .persistent(false)
            .build();

            FancyHolograms.get().getHologramRegistry().register(
                FancyHolograms.get().getHologramManager().create(orbitData)
            );
        }

        // Amount label
        TextHologramData amountData = TextHologramBuilder.create(
            "node_amount_" + location.hashCode(),
            location.clone().add(0, 2, 0)
        )
        .text(
            "<gold><bold>x" + amount + "</bold></gold>",
            "<gray>Resources Available</gray>"
        )
        .scale(0.7f)
        .textShadow(true)
        .build();

        // Register main block and text
        FancyHolograms api = FancyHolograms.get();
        api.getHologramRegistry().register(api.getHologramManager().create(mainData));
        api.getHologramRegistry().register(api.getHologramManager().create(amountData));
    }
}

Updating block holograms

Change the displayed block

Hologram hologram = FancyHolograms.get().getHologramRegistry()
    .get("my_block_hologram").orElse(null);

if (hologram != null && hologram.getData() instanceof BlockHologramData blockData) {
    // Change to a different block
    blockData.setBlock(Material.EMERALD_BLOCK);

    // Or change with block data
    BlockData newData = Bukkit.createBlockData(Material.CHEST, "[facing=north]");
    blockData.setBlockData(newData);

    // Refresh for all viewers
    FancyHolograms.get().getHologramController().refreshHologram(hologram);
}

Cycle through blocks

public class BlockCycler {

    private final List<Material> blocks = Arrays.asList(
        Material.DIAMOND_BLOCK,
        Material.EMERALD_BLOCK,
        Material.GOLD_BLOCK,
        Material.IRON_BLOCK
    );

    private int currentIndex = 0;

    public void startCycling(Hologram hologram) {
        Bukkit.getScheduler().runTaskTimer(plugin, () -> {
            if (!(hologram.getData() instanceof BlockHologramData blockData)) {
                return;
            }

            // Cycle to next block
            currentIndex = (currentIndex + 1) % blocks.size();
            blockData.setBlock(blocks.get(currentIndex));

            FancyHolograms.get().getHologramController().refreshHologram(hologram);

        }, 0L, 40L);  // Change every 2 seconds
    }
}

Special block effects

Animated redstone lamp

public void createFlashingLamp(Location location) {
    BlockHologramData data = BlockHologramBuilder.create("flashing_lamp", location)
        .block(Material.REDSTONE_LAMP)
        .scale(1.5f)
        .persistent(false)
        .build();

    Hologram hologram = FancyHolograms.get().getHologramManager().create(data);
    FancyHolograms.get().getHologramRegistry().register(hologram);

    // Toggle between lit and unlit
    Bukkit.getScheduler().runTaskTimer(plugin, new Runnable() {
        boolean lit = false;

        @Override
        public void run() {
            BlockData lampData = Bukkit.createBlockData(
                Material.REDSTONE_LAMP,
                "[lit=" + lit + "]"
            );

            ((BlockHologramData) hologram.getData()).setBlockData(lampData);
            FancyHolograms.get().getHologramController().refreshHologram(hologram);

            lit = !lit;
        }
    }, 0L, 10L);  // Flash every 0.5 seconds
}

On this page