Building an Interactive Fortnite Map

with Mapbox GL JS, Next and TileServer GL

Timothy Krechel
5 min readAug 21, 2018

TL;DR

I built a map application that displays Fortnite challenges on a map and in this article, I am writing about the approach. Here’s a demo!

The motivation

It’s the end of the semester — in the middle of final exams — and that’s always the time I get this itch to create something! Spending the days studying somehow does not satisfy me at all. I feel unproductive, but getting actual work done feels wrong as well.
Some of you may know it: The desparate need to distract oneself with a quick side project

At work, I’ve been playing around with lots of map related tools, especially with Mapbox GL JS, GeoJSON, .mbtiles, QGIS and the likes. And lately, after a mixed start, Fortnite kinda grew on me. I figured it could probably be a fun little project to use some of the stuff I learned over the last couple months, so I went ahead and defined the minimum requirements of what this thing is supposed to be: A map view showing the season 5 Fortnite map and a sidebar showing the locations of the challenges. I decided to skip the lama proposal part for now because of the stuff that’s required to pull that off.

The tools needed

So: Which tools and assets are needed? They are:

  • A high res image of the season 5 map
  • A tileset of that map
  • A map client and
  • a Front-End-Framework to build out the UI

Luckily, there is a very high res map posted in r/FortNiteBR. For it to be used Mapbox GL JS, I needed a way to convert the image to raster mbtiles. I found a guide online which explained how to pull that off with the help of QGIS and Maperitive. But since Maperitive is Windows only I chose the QTiles Plugin for QGIS. At work, I was mainly using QGIS3, but since QTiles is only available for QGIS2 I needed to download that version.

Preparing the .mbtiles file

I needed to set referencing points using QGIS’ Georeferencing plugin. I could have gone the random way and just use numbers that were convenient, but instead I saw the opportunity to step up the game a bit:
There’s a reddit post where someone calculated the area of the Fortnite map by approximating the size of one building block (3.40m) and the amount of building blocks (49) that fit each of the 10 map tiles. Using these numbers, I calculated a coordinate system that will roughly match the actual dimensions of the Fortnite map. This might come in handy way in the future when calculating distances, but has the added bonus of accurate map behavior in the map client.

Georeferenced .png file in QGIS 2

The process of georeferencing and exporting the mbtiles was not exactly straightforward, but after some playing around with the export settings, I got the results I needed. I used MapTiler to check the outcome.

Serving the mbtiles

Next up is choosing a server to serve up the mbtiles for my Front-End application. I chose TileServer GL because it seemed straight forward and painless — turns it out, it actually was! I specified the directory containing my .mbtiles file to my docker command and it just did what it was supposed to do. That’s it for the server!

Side note — I eventually wrapped all this in a docker-compose file to make deploying to AWS a breeze.

Setting up the Front End

For the web application, I chose Next.js due to its convenience, React.js to build the UI and, as mentioned, Mapbox GL JS as the map client. I also added the UI Component library antd in order of having some premade components speeding up development, knowing I might want to customize the UI later on.

Figuring out how to add Raster Tiles to Mapbox GL JS required consulting their docs and playing around a bit. But after a few minutes (and solving a problem caused by trying to server-side render Mapbox GL JS), I was at least able to get everything to render and display nicely.
Panning and zooming around on my own Fortnite map instance was pretty sweet!

The .mbtiles neatly rendered in the client

The next step was to create classes for the cities (I guess you’d call them that?) containing their name as well as center coordinates and coordinates serving as the text anchor. This was a cumbersome process, extracting those coordinates out of my own map and copy/pasting them into my City class instances.
I then created classes for weeks and challenges containing all the necessary info, implementing a system of challenges:

  • Challenges with multiple precise locations
  • Challenges with one precise location
  • Challenges with a given area
  • Challenges without a location reference

The instances of the Week and Challenge classes were used to display the points and areas on the map as well as stuffing them into a list in a sidebar component.
To make things user-selectable, I used React’s new Context API to hold the current Week as the app’s state and have it fetch the respective week’s data.

I then added some styling to the list to make it look much more like the in-game UI.

The final style of the app’s UI.

Making it more interactive

In that state, the app faced the problem of not really showing which item in the list belongs to which layer on the map.
To solve that, I came up with a highlighting system where everything is controlled by an array of Challenge IDs in the app’s state. In a touch environment, the highlights are controlled by touches and additional messages are displayed to enhance usability.
On the desktop, highlights are controlled by hovering for more fluid interactions.

Displaying notifications on Mobile Devices vs. hovering gestures on the Desktop.

Ideas for the future

This is far from complete and it should at least display environmental features such as Rift Portals, Chest Spawns etc.
There should also be feature suggestion functionality, maybe note taking and exporting capabilities.
But for its most simple use case to have a quick look at a week’s challenges while playing or in between rounds, the current version should suffice.

The project kind of deviated from its original intention to make in-game Lamas easier to find, but serves a broader purpose this way.

Contribute!

If you like the project and want to contribute or want to host it on your own, feel free to do so: You can find the source code here!

--

--