World Map Project

World Map

I recently finished building a large wooden map that hangs on my wall and decided to capture some thoughts about what it was like to build this project. My hope is that this will inspire others to go and finish the creative projects that they have started.



  • Measures 6' x 3'
  • 578 LED lights
  • More than 4 dozen laser-cut islands and land masses
  • Powered by an ESP8266 running the FastLED library
  • Weighs 15 lbs


I'd been wanting to put up a hand-made world map on my wall ever since I saw the photo of the world made via the Wallz Kickstarter project. Inspired by that, I went through a few iterations of planning different types of projects until I finally settled on using a laser cutter to create wood continents that could be hung from my wall.

Choosing a template

Finding a template was considerably harder than I thought it would be. Wikipedia has several good SVG maps that aren't colorized or labeled. I no longer have the source, but think I finally settled on using this one. The Robinson projection looks pretty cool.

This highly-detailed SVG had a couple of problems:

  1. All of the polygons are per-country, not per-continent.
  2. There are a billion microscopic islands that are smaller than the size of the laser beam. If I tried to cut them out, I'd probably just end up with ash.

To solve this problem, I removed the country borders and exported the image from Inkscape as a high-resolution .png file (10K x 5K pixels). I imported that into Paint.Net and used a combination of flood-fill and an eraser to eradicate most of the tiny islands. Finally, I re-imported the image back into Inkscape and traced the outlines to generate the continents.

There were several iterations of the previous steps using different resolutions after I discovered that polygons with very high vector counts have a tendency to crash Visio. This is what the template ended up looking like:


Here's a comparison between the original SVG and actual cut of South America's southern peninsula. Notice how the border between Chile and Argentina accidentally made it into the template! You can also see how the width of the laser beam actually made many of the features smaller. I didn't compensate for kerf when generating the template.

Original SVG:

South America Peninsula SVG

Simplified Template:

South America Peninsula PNG

Wood cut:

South America Peninsula Wood

Once I had all of the polygons for the land masses defined I scaled all of them such that the largest one (Asia) would fit inside the 24x18" laser bed.

The decision to add lights

I had originally intended to just stick the continents on the wall, but my obsession with LED backlighting eventually infected this project. The decision to add backlights converted this from a 2-day project into a multi-month undertaking. Adding lights requires creating and gluing supports for the continents, wiring and soldering, and eventually programming an Arduino to drive them. I didn't think that through at the time.

Some examples of LED light strips used for indirect lighting:

LED Lights LED Lights LED Lights

Creating the supports

Creating the supports for the continents was really easy. I used Inkscape's Inset command to create a shape that was slightly smaller than the actual continent

I was concerned that the supports might not be deep enough and would thus expose the LED lights when viewing the map head-on, so I first cut out and added some lights to South America to see what it would look like. I was satisfied with how it looked, so I then preceded to laser cut everything else. This sample also showed that I had somehow miscalculated how many support frames I needed: 2 pieces of wood were the exact width of the LED strip.

Cutting South America and it's supports:

South America being cut

Testing with an LED light strip:

South America with lights

One of my goals was to have a map that was relatively accurate when it came to the alignment of islands relative to their larger masses. The wooden sheets that the land masses were cut out of were kept around because they served as natural alignment guides when gluing the islands. With enough foresight, I would have also created crude macro-level alignment pieces so that the large land masses would be accurately placed relative to each other. Since I didn't create those, I eyeballed that part instead.

The Asia supports were split into three sections so that they wouldn't waste as much wood when being cut out.

Template for Asia and its supports:

Asia support template

Wood cuts of Asia:

Asia support wooden pieces

Unfortunately most of the supports ended up with some pretty pointy edges that made it harder for the light strips to stick to them. So I ended up sanding many of these jagged points off the outer edges of the support frames in order to create smoother surfaces. It would have been quicker to remove those points in software beforehand.

Cut panels

Building the backboard

As much as I like the Robinson projection, the land masses don't look good without an actual oval around them representing the outline of the world. The top in particular looks squished, and Australia and it's neighbors look pretty skewed.

Land Masses

After seeing the pieces arranged as they were above, I decided to also create a backboard that would serve as the world's outline. Some rough measurements in Inkscape told me that actual shape of the panel should conveniently be 6' x 3'. I used the laser to cut a quick template of the curve out of cardboard and used that in each of the corners to create an outline on the board.

The plywood I used for the backboard was pretty thin and bendy, so I also built a wooden frame for it.


Here's what it looked like after staining it blue:

Backboard stained

Adding the lights

I was originally planning on using NeoPixels but managed to snag some WS2812B light strips during the 11.11 sale. At a final price of $4.14/meter, this is significantly cheaper than Adafruit's equivalent. I did have to wait a few weeks for them to arrive from China. I also purchased a generic 10A power supply for under $10 to drive these lights but was soon convinced by my father to get one that is UL-certified. I eventually ended up with this one because it has the proper safety certifications and claims to have very low power consumption with no load. That allows me to keep it on at all times rather than also adding a switch in front of it that is driven by the Arduino.

The entire project uses just shy of 10 meters worth of LEDs split into 19 segments. That took many nights to solder.

Lights Lights Lights Lights

Sturdier supports

At this point, I naively thought that I was nearing completion of the project: it would just be a little gluing, drilling holes for the wires, and the soldering all of the wires together. So I carefully arranged all of the major land masses, glued their supports onto the backboard and put some weights on top.

Gluing to backboard

After waiting for a day, I picked up the project and immediately all of the landmasses fell off! The glue didn't even leave a trace on the blue stain. I'm now well aware that the "waterproof" label on the stain also means "glue-proof".

To ensure that this wouldn't happen again, I had to secure the support frames into place via a combination of screws and nails. Since I could use beefier screws where the top supports also aligned with the backboard's support frame, this made the entire project significantly sturdier.

Red dots indicate screws, purple dots indicate nails:

Holding the world together

Midpoint: New Years Eve

I got close to giving up on the project several times throughout this process because of the amount of time that it was taking to complete. Having all of the supports connected and in place made it easier to see the final product. Each of the landmasses had a few pegs that allowed me to stick them to the supports and remove them at will.

Power & data wires soldered:

Power & data wires soldered

All of the lights work!

Lights work

Temporarily adding the front panels

Added front panels


Imagine an interactive map that would respond to your gestures and touches. It would glow brighter when a person was in the room and blush if somebody walked up close to it. You could change the color of any continent and change the light show just by touching it. If you hooked up a speaker, you could even treat it as a drum kit.

That sounded good in my head and I thought it would be a good application for my Bare Conductive Touch Board. Rather than using conductive paint, I ran copper ribbon around the inside of each support structure and wired them back to the Arduino. I also ran a ribbon around the outside of the blue backboard which would function as a proximity sensor for people in the room and primary power switch if somebody touched it.

Copper ribbon

I didn't find out until I finished that this experiment was largely a failure. There is too much crosstalk between the different channels, making it difficult to discern if you put your hand close to North America or South America. And the large "proximity" border doesn't actually pick up if people are nearby. But that one still fires if somebody touches it, so I plan on keeping that as the on/off trigger.

Calculating the light positions

This was the part of the project that I was most looking forward to: figuring out where every one of the 581 lights were and mapping them to 2D coordinates.

I thought this would be a nontrivial amount of work, but it took less than two hours to whip up a python script that use image processing to do this work. The script would:

  1. Instruct the Arduino to turn on a particular light
  2. Take a picture of the map
  3. Use image processing to find the position of the LED And repeated for every LED. Once complete, it would then scale the coordinates into a 1-byte by 1-byte range and emit the coordinates as an array in a C header file.

Capture in progress:

Capturing LED positions

The image processing was really simple thanks to the power of OpenCV. I would convert the image to B&W, blur it to reduce noise, and then use the cv2.minMaxLoc() function to get the X/Y coordinates of the brightest pixel.

Step 1: Capture


Step 2: Blur


Step 3: Calculate X/Y

Calculate XY

I was originally worried that scaling the final coordinates into a 1-byte by 1-byte coordinate system would be too inaccurate. On the x-axis, assuming it was 5' (60") wide, a range of 0-255 would translate into about a quarter inch of accuracy per light. To visualize what that would look like, I updated the script to show the original light positions along with the scaled positions. The green circles pinpoint the original coordinates and the red circles pinpoint the compressed coordinates.

Compressed coordinates

Once I had the coordinates of these lights, I could begin experimenting with visualizations that were spacially-aware. My first attempt was a rainbow that traversed the globe horizontally.

Horizontal rainbow

Adding the Islands

Despite having culled out many of the microscopic islands in the template, I still had several dozen little land masses that needed to be secured in place. I used small wooden cylindars as their supports and glued them to the backboard after sanding away the stain in those areas. The original panels that these land masses had been cut from were used for alignment.

Adding islands Spot sander Island alignment Island support pillars

Adding Antarctica

I originally hadn't intended to create Antarctica because without the oval outline it looks really weird. But with the oval outline it's absence is quite noticeable. There was too much blank space in the bottom 1/3 of the map. Fortunately I now had quite a bit of experience creating and adding land masses, so it didn't take very long to create a template of the continent and add it to the project.

Cutting Antarctica Adding the ribbon On the wall

When I tried to compile the Arduino program for more lights, I ran into a problem: the Touch board doesn't have enough memory for the array of light colors. So I had to swap out the Touch board for a standard Arduino that apparently has significantly more memory.

Tweaking the Algorithm

In the attempt to capture the light's coordinates, I took the photos with the front panels not yet attached. At this point they were all glued on and the additional light diffusion made it trickier for the algorithm to pinpoint where the lights should be.

Light diffusion Light diffusion Light diffusion

Since I had all of the pictures, the simplest way to solve the problem was to modify some of them to make it more obvious where the bright spot should be and then re-run the image processing algorithm. The source pictures don't look as pretty, but the results are what I wanted.

Algorithm hint Algorithm hint Algorithm hint

The final result:

Light positions

Not enough RAM

Once I extended my Ardunio sketch to include the lights for Antarctica, I ran into loads of problems getting it uploaded and running. After a few nights of trying things and bashing my head against the table, I finally figured out that the global variables in the sketch were larger than the RAM of the Ardunio. Unfortunately the Ardunio IDE doesn't detect this condition, so the process of trying to upload and run an invalid sketch results in nondeterministic failures somewhere in the process. I swapped out the Ardunio for a $2 ESP8266 and managed to get things working agin. Eventually I may try to take advantage of the ESP8266's WiFi capabilities and hook the map up to the network.


Finishing up

The 22 AWG wire I had run from the power supply to the lights got a little warm after they had been running for a while, so I replaced it with a much beefier wire that was originally one of those cheap extension cords.

The backside is a mess of power, data and proximity wires. I tried gluing some of them down to make things look nicer, but that was significantly more effort than it's worth.

View of the back

There were a few folks who loaned me tools or gave advice, so I crafted a handful of 12" miniature maps to give them as a way of saying thank you. These ended up looking beautiful.

Miniature maps

Good luck with your own projects!