A Minecraft library for rendering geometric shapes using TextDisplay entities. Supports both direct Bukkit entity manipulation and packet-based rendering via EntityLib.
- Multiple Shape Types: Triangle, Line, Polyline, Parallelogram
- Three Rendering Modes:
- Paper Mode: Direct entity manipulation using Paper's Adventure API, visible to all players
- Spigot Mode: Direct entity manipulation compatible with Spigot servers, visible to all players
- Packet Mode: EntityLib-based, only visible to specified viewers
- Modular Design: Platform-agnostic API module can be reused across Bukkit, Fabric, Minestom, etc.
- Customizable: Color, brightness, transparency, double-sided rendering
- Display Control: Adjustable view range (
viewRange) - Line Roll Angle: Rotate lines around their length axis for visibility from any angle
TextDisplayShapes/
├── api/ Platform-agnostic interfaces & math utilities (JOML only)
├── paper/ Paper implementation (uses Adventure API)
├── spigot/ Spigot implementation (compatible with Spigot servers)
└── packet/ Packet-based implementation using EntityLib/PacketEvents
| Module | Artifact ID | Description |
|---|---|---|
| API | textdisplayshape-api |
Core interfaces (Shape, ShapeBuilder) and math utilities. No platform dependencies. |
| Paper | textdisplayshape-paper |
Paper implementation using Adventure API for text rendering. |
| Spigot | textdisplayshape-spigot |
Spigot-compatible implementation using standard Bukkit API. |
| Packet | textdisplayshape-packet |
Packet-based implementation using EntityLib + PacketEvents. |
<repository>
<id>twme-repo-snapshots</id>
<name>TWME Repository</name>
<url>https://repo.twme.dev/snapshots</url>
</repository>Paper mode (recommended for Paper servers):
<dependency>
<groupId>dev.twme</groupId>
<artifactId>textdisplayshape-paper</artifactId>
<version>2.0.1-SNAPSHOT</version>
</dependency>Spigot mode (for Spigot servers):
<dependency>
<groupId>dev.twme</groupId>
<artifactId>textdisplayshape-spigot</artifactId>
<version>2.0.1-SNAPSHOT</version>
</dependency>Packet mode:
<dependency>
<groupId>dev.twme</groupId>
<artifactId>textdisplayshape-packet</artifactId>
<version>2.0.1-SNAPSHOT</version>
</dependency>API only (for custom platform implementations):
<dependency>
<groupId>dev.twme</groupId>
<artifactId>textdisplayshape-api</artifactId>
<version>2.0.1-SNAPSHOT</version>
</dependency>Note: When providing a
Locationas the origin, please avoid including the pitch and yaw (set them to 0). Passing a location with rotation data (e.g.,player.getLocation()) may cause unexpected behavior in shape orientation.
Both Paper and Spigot modules share the same BukkitShapeFactory API. Simply depend on the appropriate module for your server platform.
BukkitShapeFactory bukkit = new BukkitShapeFactory();
// Triangle
Shape triangle = bukkit.triangle(spawnLocation, p1, p2, p3)
.color(Color.fromARGB(150, 50, 100, 100))
.doubleSided(true)
.build();
triangle.spawn();
// Line
Shape line = bukkit.line(spawnLocation, p1, p2, 0.1f)
.rollDegrees(90f) // Rotate for visibility from different angles
.viewRange(1.0f)
.doubleSided(true)
.build();
line.spawn();
// Polyline (connected line segments)
List<Vector3f> points = Arrays.asList(
new Vector3f(0, 0, 0),
new Vector3f(5, 0, 0),
new Vector3f(5, 5, 0),
new Vector3f(0, 5, 0)
);
Shape polyline = bukkit.polyline(spawnLocation, points, 0.1f)
.closed(true) // Connect last point to first
.build();
polyline.spawn();
// Parallelogram
Shape parallelogram = bukkit.parallelogram(spawnLocation, p1, p2, p3)
.build();
parallelogram.spawn();
// Remove shape
triangle.remove();Requires EntityLib and PacketEvents.
// Initialize EntityLib first
SpigotEntityLibPlatform platform = new SpigotEntityLibPlatform(plugin);
APIConfig settings = new APIConfig(PacketEvents.getAPI())
.tickTickables()
.trackPlatformEntities();
EntityLib.init(platform, settings);
PacketShapeFactory packet = new PacketShapeFactory();
// Create shape
Shape line = packet.line(spawnLocation, p1, p2, 0.1f)
.color(Color.RED)
.viewRange(1.0f)
.build();
// Add viewers by UUID (only these players will see the shape)
line.addViewer(player.getUniqueId());
line.spawn();
// Remove viewer
line.removeViewer(player.getUniqueId());
// Remove shape
line.remove();| Method | Description |
|---|---|
spawn() |
Spawn the shape into the world |
remove() |
Remove the shape from the world |
isSpawned() |
Check if the shape is spawned |
addViewer(UUID) |
Add a viewer by UUID (packet mode only) |
removeViewer(UUID) |
Remove a viewer by UUID (packet mode only) |
getViewerUUIDs() |
Get UUIDs of all viewers |
getEntityUUIDs() |
Get UUIDs of all entities in this shape |
teleportOrigin(double x, double y, double z) |
Teleport origin to prevent view-range issues |
| Method | Description |
|---|---|
.color(int argb) |
Set background color as ARGB integer |
.color(Color) |
Set background color using Bukkit Color (Paper/Spigot/Packet builders) |
.doubleSided(boolean) |
Enable double-sided rendering |
.brightness(int block, int sky) |
Set brightness (0-15) |
.seeThrough(boolean) |
Make visible through blocks |
.viewRange(float) |
Set entity view range |
.roll(float) |
Line roll angle in radians |
.rollDegrees(float) |
Line roll angle in degrees |
.closed(boolean) |
Close polyline (connect last to first) |
.rootAnchor(boolean) |
Enable root-anchor mode (packet mode only) |
The 2.0 release includes breaking API changes:
| 1.x | 2.0 |
|---|---|
TextDisplayShapes.bukkit().line(...) |
new BukkitShapeFactory().line(...) |
TextDisplayShapes.packet().line(...) |
new PacketShapeFactory().line(...) |
shape.addViewer(Player) |
shape.addViewer(player.getUniqueId()) |
shape.removeViewer(Player) |
shape.removeViewer(player.getUniqueId()) |
shape.getViewers() |
shape.getViewerUUIDs() |
shape.teleportOrigin(Location) |
shape.teleportOrigin(x, y, z) |
.color(Color) (API) |
.color(int argb) (API), .color(Color) still available in builders |
Single TextDisplayShape artifact |
Separate textdisplayshape-api, textdisplayshape-paper, textdisplayshape-spigot, textdisplayshape-packet |
Why UUID instead of Player? Bukkit invalidates
Playerobjects on respawn, creating new instances with different hash codes. StoringPlayerreferences in aSetcauses memory leaks and silent removal failures. UsingUUIDavoids these issues entirely.
Since version 2.0, the project is modularized. You can find the JavaDocs for each module below:
- Paper 1.21+ (for paper module) or Spigot 1.21+ (for spigot module)
- PacketEvents (for packet mode)
- EntityLib (for packet mode)
- WorldEditDisplay: Renders WorldEdit selections using TextDisplayShapes
Apache License Version 2.0