About six years ago I wrote up Six Months of voxel.js (mid-2014) on my efforts to build out voxel.js as a powerful voxel engine platform. I had big ideas: a highly customizable platform with a plugin system to rival modded Minecraft, all easily accessible within your web browser.
But as a hobbyist side project, after three years of solid development, it wasn’t reaching where I wanted it to be and alas, real life took over, and the project became inactive. However it was always in the back of my mind, so with the clarity of hindsight, I figured it would be worthwhile to take a look back and see what went wrong.
First, the good news is the main “Voxel Metaverse” project with all the plugins still works, even on modern browsers from 2021. You can play with it here:
Live demo: http://voxel.github.io/voxelmetaverse/
If it works, you’ll be spawned in the air and dropped into a procedurally-generated world to mine and craft in, something like this:
Tips for new users: click the canvas to activate mouse look, use WASD to move, space to jump. If you just want to freely build, type “.” to bring up the console then enter .creative, press E to open the inventory. Otherwise you’re in survival mode by default. Open the keys control to see all shortcuts, most should be familiar. A bunch of plugins are enabled by default. Core plugins:
- voxel-engine-stackgl: An experimental port of voxel-engine replacing three.js with stackgl
- voxel-registry: A shared registry for managing item and block IDs
- voxel-stitch: Stitches a set of block textures together into a texture atlas
- voxel-shader: Shader for use with voxel-mesher
- voxel-mesher: A voxel mesher for ndarrays that handles ambient occlusion and transparency
- game-shell-fps-camera: First person shooter style camera controls for game-shell
Additional plugins:
- voxel-artpacks: Artpack selector dialog
- voxel-wireframe: Shows a wireframe around the voxels
- voxel-chunkborder: Show borders around the outline of chunks
- voxel-outline: Show an outline around the player’s currently targeted block
- voxel-carry: Adds a player inventory for carrying items
- voxel-bucket: Adds buckets to pickup and place fluids
- voxel-fluid: Fluid registry
- voxel-skyhook: A block that can be placed in mid-air, no other block required in the world to be placed against
- voxel-bedrock: Bedrock block
- voxel-recipes: Provides access to craftingrecipes
- voxel-quarry: Automated mining quarry
- voxel-measure: Tape measure tool to measure distance between blocks
- voxel-webview: Embed webpages in a voxel.js world using CSS 3D
- voxel-vr: WebVR voxel.js plugin
- voxel-workbench: A workbench block to access a 3x3 crafting grid
- voxel-furnace: A furnace block for smelting items
- voxel-chest: Chests to store your items
- voxel-inventory-hotbar: Adds a hotbar to view and select a subset of player inventory
- voxel-inventory-crafting: A player inventory and crafting dialog
- voxel-voila: Show name of block highlighted at your cursor
- voxel-health: Stores player health value
- voxel-health-bar: Player health bar display
- voxel-food: Adds food you can eat to improve your health
- voxel-scriptblock: A block to run player-defined JavaScript code
- voxel-sfx: Play sound effects on events
- voxel-flight: Double-tap jump to toggle flight mode, then use jump/crouch to adjust altitude, and land if you hit the ground
- voxel-gamemode: Toggle between a creative/survival game modes
- voxel-sprint: Double-tap the forward key (default ‘W’) to sprint
- voxel-decals: Adds textured planes on the side of blocks
- voxel-mine: Mine blocks of variable hardness, hold down the left mouse button to mine
- voxel-harvest: Add mined blocks from voxel-mine to an inventory
- voxel-use: Use items and blocks
- voxel-reach: Listen for fire/firealt events, raycast the voxel within reach, and send mining/interact events for the hit voxel
- voxel-pickaxe: Adds pickaxe tools to help you mine faster
- voxel-hammer: Adds a hammer tool to mine blocks in a 3x3x1 area
- voxel-wool: Colored wool blocks
- voxel-pumpkin: Carvable pumpkin blocks, a directional block metadata demonstration
- voxel-blockdata: Store arbitrary per-block data in chunks
- voxel-glass: Glass blocks
- voxel-land: A terrain generator combining several landform features: grass, dirt, stone, trees
- voxel-flatland: Simple flat land terrain generator
- voxel-decorative: Decorative blocks you can craft
- voxel-inventory-creative: Inventory dialog with an infinite supply of all items and blocks
- voxel-console: Text console widget
- voxel-commands: A few basic commands for voxel-console
- voxel-drop: Drag and drop various types of files to load them into your game
- voxel-zen: Hide distracting UI elements
- camera-debug: Adjustable camera debug datgui settings for voxel-shader
- voxel-plugins-ui: A graphical interface for voxel-plugins using dat-gui
- voxel-fullscreen: Toggle fullscreen with a hotkey
- voxel-keys: Events for key bindings
- kb-bindings-ui: A graphical interface for configuring kb-bindings or game-shell using dat-gui.
The source code is available at:
What broke? ProgrammerArt resource pack
Not everything survived the past six years. The minimal voxel-example broke due to an expired link to the default resource pack hosted on Dropbox. Lesson learned: don’t host resources on external servers. To fix this, I changed it to embed the zip locally, like I did with voxelmetaverse (which I also just moved into the voxel organization).
ProgrammerArt is my artwork pack for voxel games, in several formats:
- ResourcePack: compatible with MC 1.9, 1.8, 1.7, 1.6
- TexturePacks: compatible with MC 1.5
- StitchPack: compatible with MC ≤1.4, pre-stitched texture atlases
This is my most popular repo, with 64 stars and 7 forks:
I maintained it 2013–2016 as a freely redistributable (CC-BY 4.0) resource, to serve as a quick placeholder until better graphics are freely available. Coincidentally, in 2019 with the 1.14 update, Mojang redesigned their textures and renamed their old assets to “Programmer Art” (no relation), so my ProgrammerArt project will probably need a new name:
The original textures (with the exception of leather horse armor) are available as a resource pack/texture pack built in-game[Java Edition only] or as a separate download[Bedrock Edition only] (named “Programmer Art” in Java Edition, and “Classic Textures” in Bedrock Edition).
The multitude of JavaScript voxel engines
How about the engine itself?
The original (2012–2015) is maxogden/voxel-engine:
My contribution in 2014-2016 was completing a port from THREE.js to stackgl to create voxel-engine-stackgl, covered at the end of Six Months of voxel.js, and used in voxelmetaverse.
Meanwhile, @joshmarinacci created voxeljs-next (2019–2020+) based on the original voxel-engine, modernizing it to use ES6, update to the latest THREE.js, latest WebGL2, and AR/VR support:
I haven’t looked into it much but it seems cool. Unfortunately, old voxel.js plugins, including all plugins described herein, are not compatible.
@vogonistic created mineflayer-voxel in 2013 to visualize the JavaScrpt mineflayer bot client, using voxel.js:
and in 2020 @Karang created a new prismarine-viewer from scratch as part of the PrismarineJS project, though more of an interactive 3D map viewer than an interactive client:
@andyhall’s noa (2015–2020+) is perhaps the most successful JavaScript-based voxel engine, in that it powers the official 0.0.23a_01 “Minecraft Classic” site, though distinct from Java Edition Classic (2009):
For voxelmetaverse, I used voxel-engine-stackgl, which has some advantages:
Notable features: plugin system
A major design goal, which turned out reasonably well, was a highly flexible but simple plugin system (voxel-plugins) loosely inspired by modded Minecraft. In fact, all gameplay functionality is implemented in the form of plugins.
Each plugin can be enabled or disabled, at runtime, through the plugins UI (shown to the left). This “meta-game” of plugins allows creating an arbitrary voxel game meeting the creator’s requirements.
I was most interested for voxelmetaverse in developing a survival mode, adding a challenge to the game beyond the unlimited resources available in what is known as creative mode. Mining, crafting, workbenches, furnaces, chests are all there: finite resources and constraints creating creativity.
The goal wasn’t to replicate vanilla, yet to build a platform to foster the creation of a diversive, collaborative, Cambrian explosion community of plugins. Voxel engines are a blank slate, an open canvas for free artistic and technical expression. What kind of virtual world can you envision?
My world consisted of bits and pieces inspired directly by modded Minecraft, especially mods found in Feed the Beast modpacks of the era:
- voxel-webview (2014–2016) is perhaps the neatest tech demo, built on gl-css3d (demo): embedding a fully-fledged web page in the voxel world. It is a real <iframe>, transformed using CSS 3D transforms, a natural fit for a web-based world. I was inspired bymontoyo’s Web Displays mod (2013), an old mod he since updated in 2018. Web Displays in contast embeds a full web browser, whereas voxel-webview reuses the same browser stack.
- voxel-hammer (2014), an item mining blocks in a 3x3 area (vs 1x1 with the pickaxe), inspired by mdiyo’s Tinkers’ Construct hammer.
- voxel-skyhook (2014), a block you can place in the sky, inspired by RWTema’s Extra Utilities’ Angel Block.
- voxel-quarry (2014), an automated mining quarry, inspired by SpaceManiac’s BuildCraft’s quarry.
I had a blast developing these plugins to add new and fun features, which you can read more about in Six Months of voxel.js, but unfortunately I was not able to complete implementing the more basic features: saving the world (#55), and multiplayer servers (#26).
Server software
Persisting the world is an essential feature of any voxel platform. Other voxel.js projects have had success with storing the world in a local database: voxel-level (2013), or a custom server: voxel-server (2014–2016). For voxelmetaverse, I had some success running it through NodeJS as a server, but wanted to try a different approach: leveraging existing voxel server software.
To this end, I developed voxel-clientmc, a plugin to connect to Minecraft-compatible servers over WebSockets, through a WebSocket-Minecraft proxy: wsmc. voxel-clientmc uses PrismarineJS’s mineflayer as the client. It sorta worked:
but wasn’t complete enough for real-world usage. Nonetheless, this path led to a detour to several interesting projects.
Glowstone++ is now Glowstone
While searching for server software to use as a backend for my frontend, I stumbled across SpaceManiac’s Glowstone. Written in Java, it supports Bukkit plugins, so I could use it to load my WSMC proxy (which I originally wrote in JavaScript, but then rewrote in Java for this purpose) to provide access to voxel-clientmc.
When I found it, there were a bunch of open pull requests for Glowstone and an eager community, but they were waiting for its creator SpaceManiac to come back, his last commit in 2015, 16cb7d5 Fixed incorrect reference in ToolType.:
I wanted to see the project develop further, so I started merging the pull requests in my own branch and experimenting with the improvements. Other users were interested, so later in 2015 I released my changes in a fork of Glowstone (itself a fork of Graham Edgecomb’s Lightstone), I called Glowstone++:
Looking at the status of this project now, I am glad to see Glowstone++ has now become Glowstone proper, and it remains active to this day: https://github.com/GlowstonePlusPlus/GlowstonePlusPlus redirects to https://github.com/GlowstoneMC/Glowstone, and the 2010–2015 project was archived at https://github.com/GlowstoneMC/Glowstone-Legacy. Thanks to @mastercoms and others for continually developing and maintaining Glowstone, it is reassuring the project can march on without me, hopefully my changes which sparked Glowstone++ were useful in reviving the project, kicking it back into gear where it can live a long and fruitful life.
There was a decisive decision I made in creating this temporary fork, worth discussing further:
Bukkit’s API lineage, Glowkit and Spigot
In the aftermath of Bukkit (2010–2014), Glowstone decided to continue the legacy of this API in their Glowkit fork. The strategy was to maintain compatibility with Bukkit but develop new APIs for new functionality in the game, such as banners. Bukkit only supported up to 1.7.10, so Glowstone devs would develop their own new APIs for features added post-1.7.10.
This was a reasonable choice, but there was another development: Spigot began also maintaining a fork of Bukkit (which they maintain to this day), with their own API enhancements, for their own project. Spigot Resources hosts tens of thousands of compatible plugins with a vibrant community, so I figured it would be a better idea to rebase Glowkit on Spigot-Bukkit, gaining potential compatibility with these plugins.
Glowstone++ still had its own Glowkit API, but where there were conflicts with Spigot’s Bukkit, I chose Spigot. This was actually the main impetus for Glowstone++ since although it creates potential incompatibility with Glowstone-Legacy (in practice, few Glowstone-specific plugins) it opens up a new world of Spigot plugins (more than 47,000+ now).
Nowadays there’s also Paper, an enhanced Spigot fork. So we have:
- Bukkit → SpigotMC/Bukkit → PaperMC/Bukkit → Glowkit
A good API for your plugins
It is interesting to step back and appreciate the longevity of the Bukkit API, a sign of a good API. The original official developers only developed it for 4 years, but it survives in one form today, more than a decade after inception.
Back then I was surveying the existing voxel APIs to investigate for voxel.js:
Glowstone and Spigot are still going strong. MCServer is now Cuberite, also under active development. PrismarineJS as well, which I held a special interest in because it is written in JavaScript, potentially allowing easier integration with voxel.js (and I used via mineflayer for voxel-clientmc).
Sponge is alive too, founded in 2014 as a new API to replace Bukkit. In my WSMC plugin, I wanted to also support Sponge servers, but it is not clear if the API has significantly deviated by now to where it is no longer compatible. I started Bukkit2Sponge (2015–2016), a bridge to allow loading Sponge plugins on Bukkit servers—it worked well enough for WSMC at the time, but not much else, and is stuck on Sponge 6.0.0 (latest at the time of this writing: 7.3.0), with breaking changes in newer versions. A contemporary project, Pore, performed the opposite function as Bukkit2Sponge: bridging Sponge servers to Bukkit plugins, but is was also discontinued in 2016.
And yet, the Bukkit API keeps keeping on.
Sponge was designed to be a better API for Forge servers, and maybe it is, but I was surprised to see Bukkit is still actively used with Forge (as opposed to using Sponge with Forge). Back around the time I was working on voxel.js, the landscape looked something like this:
- BukkitForge 1.3.2-1.5.2 (2012-2013)
- MCPC 1.2.5 and earlier (2012 and earlier)
* MCPC+ 1.4.5 to 1.5.2 (2013)
* Cauldron 1.6.4 (2014), 1.7.10 (2015)
The descendants of Cauldron have since continued, and exploded, at least:
and even new projects for updated versions of modded Minecraft:
I started an attempt at a new implementation of Bukkit: BedrockAPI (2014), generated based on javadoc documentation, but it is not clear it was a viable approach. The name also I later learned collided with the name Bedrock Edition. More contemporary thoughts I posted on /r/admincraft: [Discussion] Minecraft Server Modding in a Post-CraftBukkit Era: An Overview of the Pros and Cons of The Paths Ahead (2014).
Either way, we can see now Bukkit as an API clearly has staying power. So one may ask, can we use Bukkit in the browser, for client plugins?
My attempt at achieving this was Junket (2014), a minimal implementation of the Bukkit API but with no server, it was able to at least load plugins and it ran in the browser using the doppio JVM in TypeScript, but Bukkit is focused on server plugins, not client-side or client/server mods.
NOVA (Neatly Organized Voxel API) (2015–2019) looked promising back then, with the noble goal of abstracting the API to support “almost any voxel game”, and with Forge support. It progressed quite a bit, but the last commit at the time of this writing is from 2019, and there is an open issue asking if development stopped, with some problems related to Java versioning.
Anyways, that’s enough in our detour into servers and APIs. I never did finish a solution, again, the biggest failure of my project. Moving on, what else?
Code organization
Monorepo or many repos
Built on top of NPM, I split my code for voxel.js into many small little modules, as was the fashion in JavaScript programming at the time.
Each of these modules reside in their own GitHub repositories, most under the voxel organization. voxelmetaverse includes each of the modules as deps.
Another approach is to create one big repo containing multiple modules, aka a “monorepo”, as suggested in issue #11 perhaps managed using Lerna. If I had to do it again this is how I’d prefer to have organized the project, in retrospect.
To manage updating projects split across multiple repos, I wrote lmno-cl, Linked Modules for Node.js of your Own, Change Log generator (2015). This would generate a more informative git commit history for downstream projects, including the commit messages instead of update to version X, but it did not alleviate the spam of committing and pushing to each repo. I may have noticed a few interested users unfollowing my account on GitHub because of the spam generated by massive wide-ranging updates (ES6) across too many projects. Definitely should have gone with a monorepo instead!
Modularity or monolith
There’s also the question of granularity, the boundaries where to split code into modules, how far is too far? — especially after the left-pad debacle (2016). My most popular module on https://www.npmjs.com/~deathcap, by far, is ucfirst:
32,995 downloads/week. The entirety of this module is only these five lines:
‘use strict’;
module.exports = function ucfirst(s) {
return s.charAt(0).toUpperCase() + s.substr(1);
};
I created it since I wanted to capitalize inventory item names in voxel.js, inspired by the ucfirst function in Perl. Cool to see it take off!, but I question whether these small modules are really the right way to structure software.
On the other hand, I believe having small plugins is useful to allow adding, removing, and swapping out game functionality. Jury’s still out on this one.
Technology stack
The web is a challenging yet exciting platform to develop for. I strived to use the most cutting-edge features available at the time, but there are newer better technologies available today.
Language choice
voxel.js is written in JavaScript, as the name implies. JavaScript is widely supported but has some rough edges, such that Douglas Crockford wrote JavaScript: The Good Parts (2008) covering a useful subset.
Allured by a less error-prone and cleaner syntax, early in the project I flirted with Jeremy Ashkenas’s CoffeeScript. This introduced a compilation step, annoying but worth it, so I thought. But then ECMAScript 6 was finalized in 2015, and gained widespread browser support the year after, so I then converted from CoffeeScript to the ES6 version of “JavaScript” in voxel.js modules, now 100% transpile-free (2016).
ES6 is an improvement, but JavaScript still can be difficult to use for large projects. TypeScript could be a good choice to mitigate some of the structural challenges, introduced in 2012 and maintained to this day, only growing in popularity.
Beyond JavaScript
However there’s a bigger problem with all of these JavaScript extension languages or compiles-to-JavaScript languages: garbage collection. I would notice FPS drops periodically when GC triggers. This is a showstopper for realtime games.
It is possible to carefully write JS to avoid GC. stackgl uses mikolalysenko’s ndarray implementation for Cache oblivious array operations (2013), another example of carefully constructed high-performance JavaScript code, and this was one reason for migrating the engine to stackgl from THREE.js. JS can be fast because browsers perform sophisticated optimizations, but V8 will deoptimize less optimal code, a fine line to walk for a JS game programmer.
The situation has since improved with the development of WebAssembly (2017+). It didn’t exist yet when I was working on voxel.js, the closest was its predecessor asm.js (2013), but without widespread explicit browser support, though Firefox was working on something…nowadays WebAssembly is widely supported, a great boon to non-GC programming on the web.
But you don’t write WebAssembly bytecode directly, it is meant to be compiled from a compiled language. C/C++ were among the first languages supported for this purpose. Sounds like a significant departure from the world of JavaScript, but then AssemblyScript (2017+) arrived on the scene: a new language made for WebAssembly, a variant of TypeScript. I haven’t used it but it appears to be a promising language for modern web app development.
Of course, using a new language wouldn’t have solved the fundamental missing functionality which wasn’t implemented, for one reason or another.
Conclusions
Creating a viable competitor to modded Minecraft is hard. 3 years wasn’t enough time to create a suitable platform, not to mention technology limitations of the time and my design mistakes.
The end result was a curiosity, you can still play online at:
Live demo: http://voxel.github.io/voxelmetaverse/
but only a curiosity, it has not reached activation energy to truly take off.
Nonetheless I still think there is an opportunity out there. Mojang created a singular genre-defining voxel game, but hasn’t really embraced it as a modding platform. A voxel game could be so much more. In fact, all of the projects discussed in this article to allow extending Minecraft are the creations of independent third parties. It could be argued they succeeded on Minecraft despite Mojang, not necessarily because of it.
Instead of focusing on building out a platform for developers to build on, over the years Mojang has developed Minecraft as game, adding new content and gameplay features themselves.
Drew DeVault’s TrueCraft (2014-2017) attempts to replicate the magic in 1.7.3 beta (2011), claiming “Most of what Mojang has added since beta 1.7.3 is fluff, life support for a game that was ‘done’ years ago. This is my attempt to get back to the original spirit of Minecraft, before there were things like the End, or all-in-one redstone devices, or village gift shops. A simple sandbox where you can build and explore and fight with your friends. I miss that.”
I’m not sure what to believe. Personally I’m partial to 1.7.10 (2014), but this may because it is contemporary to my voxel.js-based projects, but it is also a favorite version for modding. It was also released near the peak of popularity according to Google Trends:
Voxelmetaverse was an attempt at implementing a different vision than Mojang: a minimal voxel engine, where all game content is in the form of optional plugins. Build your own game from plugins, ala modpack creation, which can be a fun metagame in itself. All with effortless delivery to your browser through the web platform.
Perhaps a completely new and open voxel platform will rise and challenge Minecraft. Or voxel.js and voxelmetaverse still exist and are functional, if anyone wants to pick up where I and other developers left off.