< Personal Project / >


Back to Explore Projects
npm run case_study

An experiment in creating a 3D game where you can only interact over API.

In this physics-based open-world desktop game you play as a Dodecahedron, a twelve-sided convex polyhedron. The aim of the game is to "level up" by moving your Dodecahedron to the next milestone. The catch? There are no mouse or keyboard controls - you can only interact through API requests.

To begin with you can only move a small amount in each direction, by calling a /push endpoint. As the game progresses, you unlock additional API endpoints that give you more flexibility in traversing the 3D world, such as /crater , /spawn , and physics controls like /slowmo .

Visual aid for the case study.
A simple brand for the game’s loading screen.

For the sake of having a clean window and installer, I went with Electron to create a desktop application package. The API was created using Express, which ran a localhost server for API requests from within Electron’s background process. The game itself was programmed using ThreeJS and some Vue for supporting 2D user interface elements.

Within ThreeJS is where most of the fun happened. The first step was to setup an object model representing the player (a twelve-sided dodecahedron) and getting the convex physics body of that to collide correctly with the concave terrain and other objects. Once that was in place, I used Electron’s IPC communication flow to capture API requests and pipe then through to the renderer, where ThreeJS could listen and apply physics updates accordingly.

Visual aid for the case study.
A slide-in side panel that displayed object properties and recent API requests made against it.

The terrain was partly procedural, but with artistic direction provided by an input heightmap. The heightmap file was pixel-mapped in from a PNG file, and then each local area was split into “chunks”, and dynamically loaded at runtime to support large, sprawling landscapes. With this approach, mountains and valleys could be painted in.

A LOD (level-of-detail) approach was developed, to only load every n vertices at varying depths from the camera, and to hide terrain behind the camera (which is called “Frustum Culling”) to keep overall performance snappy while having a detailed, distant horizon.

In the screenshot above you can see a series of topographical lines on the terrain at each level of “height”. This was due to the pixel depth of the input file, that could only stretch so far vertically using luminance as a height value. I originally planned to smooth this out procedurally, but actually ended up keeping the effect, as the physics body worked better when the dodecahedron’s flat sides had levels of flat ground to collide with. This is similar to why I went with a dodecahedron in the first place, and not a sphere - to have the object’s natural shape resist continued motion, making it more challenging to get around.

Visual aid for the case study.
A glimpse into some of the code that pre-generated the chunks of terrain for runtime usage.

While I had no real avenue to distribute the game (it wouldn’t be able to compete with games made with Unity or Unreal Engine, for example) I wanted to experiment with the idea and perhaps use it as a teaching tool in the future, or as a proof-of-concept for interacting with a self-hosted API server within an Electron app. Several of the creative techniques developed for Dodecahedron have been utilized in recent commercial projects since putting it down.