Hi, I’m Ryan Exner. A full-stack engineer who ships and runs my own products.
I write Java and Spring Boot on the backend, along with React and TypeScript on the front end. On my own time, I run GardensMC, a Minecraft community with 736 registered players. I also built the plugins behind it and the website builder that hosts its site.
The plugin stores only the blocks the map camera can see, plus small images for zoomed-out views. Up close, the browser’s GPU draws each tile from its block data. The map is served by the plugin itself or through the server’s EnderBeam site, and players and mobs stream in over Server-Sent Events.
Hard problems
Deep zoom without huge storage. Detailed web maps usually save a rendered image for every zoom level, which takes a lot of disk. EnderMap saves block data instead, about 10 KB per 128×128-block tile, and the GPU draws close-ups from it. Images are used only for zoomed-out views.
Hosted on EnderBeam. Servers can show the map on their EnderBeam site without opening a port. EnderBeam caches the files over one outbound WebSocket, so each file leaves the server once, and the map stays up while the server is down.
Drawing without sorting. The GPU works out what’s in front, so players hide behind trees, walls, and roofs with a faint outline.
Edits show up fast. Blocks placed or broken appear for everyone within a few hundred milliseconds.
Looks like the game. Textures, animated water, mob models, and the day-night sky all come from the game’s own files and the server’s resource pack.
Hosted websites for Minecraft servers. Owners install a plugin, drag modules onto a page, and publish a site that connects to their server, Discord, and store.
There are two apps: an editor where owners build their site, and a renderer that shows the finished site to visitors. Both read the same site schema and use the same set of modules, so a new module shows up in both at once. A Spring Boot backend stores every site in PostgreSQL, syncs live edits over WebSockets, and receives data from each server's plugin.
Hard problems
Cheap multi-tenant hosting. One renderer build and one backend serve every site. A new customer is simply a database row instead of a new app.
Keeping three apps in sync. The editor, renderer, and backend share one versioned schema. Older sites upgrade automatically when they load.
Editing together. Several people can edit a site at once, with drafts, publishing, and undo.
One plugin for every server. Server owners install one jar that runs on Spigot and Paper, with Velocity and BungeeCord versions for networks. Optional bridges pull in data from LuckPerms, VotingPlugin, LiteBans, and more.
Safe deploys. Every release is tested against a copy of the production schema, then goes live with no downtime.
A survival Minecraft community I run, with 736 registered players and 300+ active each month across Java and Bedrock. Nearly all of its gameplay runs on four plugins I wrote.
The custom block framework the other plugins build on.
Placed furniture lives in chunk data instead of a database, so it loads with the world.
Custom blocks are drawn by rewriting outgoing chunk and block packets. Chunk packets are patched off the main thread, so players don’t get ping spikes.
Writes are batched per chunk to keep world generation fast.
Bedrock players see the same furniture through Geyser.
Farming with planters, sprinklers, and harvest golems.
Growth runs from a queue that handles at most 100 planters every half second, so big farms don’t cause lag spikes.
Nearby chunks load asynchronously before planters are queued. Planters in unloaded chunks wait instead of forcing a load.
Offline growth is simulated. When a chunk loads again, crops and sprinklers catch up from the days since they last ran, so unloaded farms never need to tick.
Bedrock players connect through GeyserGardens, my fork of Geyser that adds custom blocks in a thin shim so upstream releases merge cleanly. Across the suite: 36 test classes, CI on every push, and automatic deploys.