Bringing anime girls holding programming books straight onto your Minecraft maps!
This is a Spigot/Bukkit plugin that lets you fetch images from the web, including random anime girls holding programming books from the AGHPB API, and render them onto in-game Minecraft maps.
It supports splitting a single image across a grid of multiple maps (auto-scaling to fit), permanently persists rendered maps across server restarts, caches downloaded images locally to avoid redundant network calls, and lets you pick from a list of known AGHPB instances or supply your own.
Written entirely in Kotlin with zero external dependencies beyond the Kotlin standard library and the Spigot API itself -> no image libraries, no HTTP clients, no JSON parsers.
Pick the closest instance to you for FASTER ANIME GIRLS! Configurable via config.yml or in-game with
/aghpb instance.
| Country | URL | Hosted by | Notes |
|---|---|---|---|
| 🇬🇧 | https://api.devgoldy.xyz/aghpb/v1 |
DevGoldy | ⭐ Official Instance (default) |
| 🇸🇪 | https://aghpb.zeeraa.net |
Zeeraa | Backup |
You can also point the plugin at a self-hosted instance, or any other AGHPB-compatible server, via
/aghpb instance set <url>.
- Any image, any URL -> render any web-hosted image onto maps, not just AGHPB books (
aghpb.urlpermission required) - Random AGHPB books -> fetch a random book, optionally filtered by category
- Configurable map grids -> split a single image across a
W x Hgrid of maps (up to a configurable maximum), or keep it to a single 128×128 map; images are automatically scaled and letterboxed to fit - True persistence -> rendered maps survive server restarts by saving each tile to disk and actively reattaching renderers on startup, not relying on unreliable Bukkit map-load events
- Local image cache -> downloaded images are cached to disk (SHA-256 keyed, with configurable TTL) so repeat fetches of the same URL don't hit the network again
- Named map items -> each map item is labeled with the book/image name, with grid position suffixed when split across multiple maps
- Instance selection -> switch between configured AGHPB instances or supply a custom base URL per-player
- Optimized rendering -> uses direct pixel writes (
MapCanvas.setPixelColor) instead of legacy palette-matched image drawing, scaling much better on large grids - No external dependencies -> HTTP via
java.net.HttpURLConnection, images viajavax.imageio, both bundled with the JVM
- Download or build
aghpb-1.0.0.jar(see Building below) - Drop it into your server's
plugins/folder - Restart or start your Spigot 1.21.x server
- Edit
plugins/AGHPB/config.ymlto taste, then/aghpb reload
- Spigot/Paper 1.21.x
- Java 21+
All commands require the aghpb.use permission (default: op).
| Command | Description |
|---|---|
/aghpb random [category] [WxH] |
Fetch a random book, optionally by category, rendered across an optional WxH map grid |
/aghpb url <imageUrl> [WxH] |
Render any image from a URL onto a map grid (requires aghpb.url) |
/aghpb instance list |
List configured AGHPB instances and which one is currently active |
/aghpb instance set <index|url> |
Switch to a listed instance by index, or supply your own custom base URL |
/aghpb categories |
List all available book categories from the current instance |
/aghpb info |
Show stats about the current instance (book count, version, repo hash, etc.) |
/aghpb reload |
Reload config.yml (requires aghpb.admin) |
/aghpb version |
Show the plugin's version and server's Bukkit version |
/aghpb about |
Show credits and plugin information |
/aghpb help |
Show the command list |
Grid format is WxH, e.g. 2x3 = 2 maps wide, 3 maps tall (256×384 pixels total). Each individual map is 128×128
pixels.
/aghpb random
/aghpb random rust 2x2
/aghpb url https://example.com/image.png 3x2
/aghpb instance list
/aghpb instance set 1
/aghpb instance set https://my-self-hosted-aghpb.example.com
| Permission | Description | Default |
|---|---|---|
aghpb.use |
Use /aghpb commands |
op |
aghpb.admin |
Reload the config | op |
aghpb.url |
Fetch images from arbitrary custom URLs (not just AGHPB) | op |
plugins/AGHPB/config.yml:
# Default grid size for image rendering.
# Each map is 128x128 pixels. A 2x2 grid = 256x256 total.
default-grid:
width: 1 # Number of maps horizontally
height: 1 # Number of maps vertically
# Maximum allowed grid size (to prevent abuse)
max-grid:
width: 8
height: 8
# Timeout in milliseconds for HTTP requests
http-timeout-ms: 8000
# Known AGHPB public instances.
# The first entry is used as default.
# Players can also supply a custom URL via command.
aghpb-instances:
- name: "Official (UK)"
url: "https://api.devgoldy.xyz/aghpb/v1"
- name: "Zeeraa (SE)"
url: "https://aghpb.zeeraa.net"
# Default instance index (0-based, refers to list above)
default-instance: 0
# Local disk cache for downloaded images (avoids re-downloading identical URLs).
image-cache:
enabled: true
ttl-minutes: 1440 # 0 = never expire
# Persisted maps (rendered tiles saved to disk, restored on server restart)
persistence:
enabled: true- An image is fetched, either a random AGHPB book via
AGHPBClient, or an arbitrary URL viaImageFetcher(checkingImageCachefirst) ImageScalerscales the source image to fit the requestedW x Hgrid (letterboxed, aspect-ratio preserved) and slices it into 128×128 tiles- On the main thread, one
MapViewis created per tile viaBukkit.createMap(), with anImageMapRendererattached that writes pixels directly viaMapCanvas.setPixelColor - Each map item is named after the source image/book, suffixed with its grid position when tiled (e.g.
Some Book [2,1 of 2x2]) - Maps are given to the player's inventory, overflow dropped on the ground
Bukkit doesn't serialize custom MapRenderer instances across restarts, and MapInitializeEvent only fires the first time a map is ever loaded into memory -> it's not a reliable "server just started" signal. To work around this, every rendered tile is saved to disk as a PNG keyed by map ID (plugins/AGHPB/cache/maps/<id>.png), and on plugin startup MapPersistence.restoreAll() actively looks up every persisted map via Bukkit.getMap(id) and reattaches its renderer -> guaranteeing your maps come back exactly as rendered, every restart.
Downloaded image bytes are cached on disk under plugins/AGHPB/cache/images/, keyed by the SHA-256 hash of the source URL, with a configurable TTL. Random AGHPB fetches are intentionally not cached, since each request is meant to return a different book.
- Clone the repo
git clone https://github.com/thenolle/aghpb.mc && cd aghpb.mc
- Build with Maven
mvn clean package
- Grab the shaded jar
cp target/aghpb-1.0.0.jar /path/to/server/plugins/
- AGHPB API by DevGoldy -> the API this plugin wraps
- Anime Girls Holding Programming Books repo by cat-milk -> the source material
- Built on the Spigot/Bukkit API
WTFPL - Do whatever the f*ck you want