LED-Matrix With Web Server




Introduction: LED-Matrix With Web Server

In my first Instructable we will build a 16x16 LED matrix. In the end you will have

  • obviously a LED matrix with 256 LEDs that are all individually controllable
  • a web page hosted on a microcontroller which allows you to
    • create pixel art live from the web page on the matrix
    • save creations
    • display all previous creations in a loop

I started this project in October 2020, I bought all the parts and was looking forward to laser cutting the wood in my local FabLab. Unfortunately there were new lock downs due to the pandemic in my country and later I almost lost sight of the project. But this summer break I finally got started!

If you just want to see the instructions and materials skip to step 8 :)

Step 1: Which LEDs to Use?

For this project I decided to use a WS2815 LED-strip with 60 LEDs/m.

  • Each LED has a small IC, so we can control every LED's color and brightness individually using the data lines and an Arduino library like "FastLED"
  • With the LEDs being in a strip we basically don't have to solder
  • They are supplied with 12V DC. This is better than cheaper alternatives like the WS2812B because you need a power supply with less amperage (more in the next step)
  • There is a backup data line, if a LED breaks

If you find a suitable power supply (see next step) you could theoretically also use the cheaper WS2812B LED-strip. This has the advantage, that you can power the microcontroller directly and don't need a buck converter for that, but I would recommend using WS2815 so I based my code and instructions on them.

Step 2: Power Supply

Well, these small LEDs will draw quite a lot of current when using white color and full brightness. According to the manufacturer one LED will need around 0.3 Watts max. Having 16*16=256 LED's, we need a power supply with 256*0.3W=76.8 Watts. With a voltage of 12V this means one with 76.8W/12V=6.4A. To have some safety margin I picked up a laptop style power supply with 12V 7A. You could probably get away with much less when limiting the brightness in the software, but I prefer being on the safe side.

To come back to the WS2812B stripes, they also consume around 0.3 Watts per LED. When we divide our 76.8 Watt by 5V to get the required current we see that this would be around 15.36A!

Step 3: Microcontroller

I used a NodeMCU board for this project. It has WiFi, USB to UART (you can program it via USB), and an on-board voltage regulator, so it's fairly easy to work with it. Unfortunately it can't be powered by 12V, so I needed a buck converter to regulate the voltage. In my cased I used one with an USB-output, so i can just use a USB-cable to connect the board.

Along with the NodeMCU I used a SD-card with the corresponding reader to store:

  • the HTML/CSS/js of the web page
  • the saved pixel arts that I created using the web app
  • the names of the pixel arts so I can select them on the web page

Step 4: Do Some Testing

To finish the list of materials I needed to test two things:

  • what to use as a diffuser for the LEDs
  • distance from the LED to the diffuser plate

Step 5: Diffuser

First I tested 3 mm thick opal polystyrene. But as you can see on the first photo, the lines of the grid were blurry and not as sharp as I hoped. I then tried 1 mm thick normal polystyrene, it looked great, but it absorbed the light too much so we would have to have the LEDs on full brightness all the time.(2nd photo) In the end I bought some acrylic glass and used very fine sandpaper to make it look frosted.(4th photo) In my opinion it looked the best from all.

Step 6: Distance Between Diffuser and LED

Having the right distance between LED and diffuser is crucial. If the distance is too big, we lose brightness, if the distance is too small the pixel will not be filled out completely and have round edges in the corners. I 3D printed some test pieces and really liked the look of the one with 14 mm distance (2nd from left).

Step 7: CAD

Based on this design choices and some additional measurements I designed the whole matrix in Fusion 360. If you want to edit something yourself or just want to see how it looks you can find the file in the google drive link with the rest of the necessary files I will provide during this Instructable.

Finally we can make our list of materials and start building!

Step 8: Supplies


Materials from hardware store:

  • 3 mm thick MDF for the box (size depends on the working space of the laser cutter and the arrangement)
  • 3 mm thick MDF for the spacer (30 cm x 30 cm)
  • 3 mm thick MDF for the grid (30 cm x 30 cm)
  • 2x 4 mm thick MDF for the grid (30 cm x 30 cm)
  • frosted glass (29 cm x 29 cm please refer to "Diffuser" step)
  • some 1 cm x 1 cm squared wood


  • soldering iron
  • laser cutter (maybe get in contact with your local FabLab/ hackerspace/ laser cut service)
  • 3D printer


Step 9: Laser Cutting

You will need just 3 files:

  1. 1x The led spacer will hold the led strips in place (3 mm MDF)
  2. 2x the grid which will give us the tested distance between led and diffuser (4mm MDF)
  3. 1x the grid with a black coating (I used 3mm), so the bars you see through the frosted glass are dark. You can also use 4mm normal MDF again.
  4. Box (3 mm MDF)

I used a 60W laser with a working space of 60x40 cm at full power. For 4 mm MDF it needed 2-3 repetitions.

Step 10: Glue the Case

Now start by laying the front part of the box down and put the side panels on. Unfortunately they weren't very tight, so I took some wood glue to secure them to each other. We will deal with the back panel later, so let's give the glue time to dry and move on to the next step for now.

Step 11: Mounting the LEDs

Start by cutting the LED strip in 16 parts with 16 LEDs each. Then use the connectors to link the strips. It is much easier to insert them if you bend the pins of the connector up a bit. When you don't have the connectors you would have to solder the strips now. Be aware that they have to be connected in the right direction. A little arrow next to each led tells you the direction of the dataline. It has to be continuous in a serpentine/snake like shape and start in the bottom left corner, else the code won't work (photo). Be careful no to short anything, the connectors aren't color coded right.

After that start in the bottom left corner to put the LEDs in the holes. I used some tape to hold them down. This process can be a bit fiddly, but after this a big part is already done.

I recommend soldering two wires to + and - on the top of the strip (marked on the photo with a black arrow) so we are feeding current in on the top and bottom for even brightness and less problems with heating up of the LEDs and wires.

Step 12: Make It Fit the Case

The case is designed very tight (it isn't a bug, it's a feature) so we can't fit the plate with the connectors in right now, because the cables of the connectors are in the way. For that i designed a small 3D printed part that we glue the connectors on at an angle. Start by securing the 3D printed part to the wood and then use some (hot) glue to secure the connectors. By doing this the plate with the LEDs will finally fit into the case and the LED strips are secured.

I have a rather large 3D printer so I was able to print the 29cm part in one go, but I also included a file where it is split in two smaller parts.

Step 13: Putting Everything Together

Finaaaally we can put all these laser cut/printed parts together. Start by inserting the laser cut pieces in the following order into the box:

  1. frosted glass
  2. grid with black coating (3mm)
  3. grid (4mm)
  4. grid (4mm)
  5. led spacer with the glued on led strips

To hold these parts in place I used some 1 cm quadratic wood pieces and hot glue. (photo)

That's the hardware part all done, so let's look at the electronics:

Step 14: Connect the SD Card

I split the electronics part into connecting the SD card to the NodeMCU and connecting the power supply with the LEDs.

We will connect the SD card as follows:

  • SD card ➞ NodeMCU
  • GND ➞ GND
  • 3.3V ➞ 3V
  • CS ➞ D8
  • MOSI ➞ D7
  • SCK ➞ D5
  • MISO ➞ D6

I used female - female jumper cables for the connections.

Step 15: Connect the LEDs

Let's deal with the LEDs. Connecting them is pretty straight forward:

12V to the + terminal of the DC-Jack

GND to the - terminal of the DC-Jack and GND of the NodeMCU

DI (Data In) and BI (Backup In) to Pin 3 of the NodeMCU

Important: Make sure that the NodeMCU and the LEDs have a common ground, else the data signal won't work because you know, closed circuit etc. That's why we connect the GND of the LEDs to GND of the NodeMCU.

To mount the DC Jack in the case I drilled a hole in the case and inserted it. Where you drill the hole is up to your use case. I drilled it on the bottom, because i want to hang it on a wall, but if you want to let it stand on the desk you can also drill it in the back.

Step 16: Powering the MCU

To power the NodeMCU directly you would need a 3.3V supply. The other way is to power it via 5V on the microUSB port. Either way we will need a step down. I chose the second option and went with a HW-676 featuring an USB output. I connected the + to the 12V of the supply , - to GND and used a short USB cable to connect the NodeMCU.

This already rounds up the electronics part (see the mess i created on the picture above), which only leaves us one thing:

Step 17: The Software

Yeyyyyy, coding time... I started by thinking about a design for the website and the functionality it should have. Using this article on how to make a pixel art editor as a starting point I was able to work from that. I tried to comment the HTML/CSS/javascript/arduino code as good as I can and add some explanation if you want to take a look at the code or add functionality later. Then I used the ESP8266Webserver library to code a simple web server, which can parse POST and GET requests from the js of the website and control the LEDs according to that. After googling trivial things, visiting StackOverflow not only once and many many chrome tabs I really liked the result even if it is improvable a lot.

Step 18: Flash the NodeMCU and Prepare the SD Card

Preparing the SD card is very simple: just copy the index.html (can't upload it here, so please use the drive link) into the root directory of the SD card. Flashing is not that straight forward:

  1. Because the NodeMCU is no official Arduino board you have to add external boardmanagers. If you never used an ESP8266 before or don't even have the ArduinoIDE yet, follow this tutorial: https://create.arduino.cc/projecthub/najad/using-...
  2. Open the sketch and change the SSID and the password on the top to your WIFI credentials
  3. Choose the right port under "tools" and hit flash!
  4. Check the serial monitor for the IP address under which you can find the web app.
  5. If you encounter any errors feel free to comment, I'll answer asap

Step 19: Short Introduction to the Web App

When you open the website on the given port you will see this UI. I will give a short explanation of the buttons and functions:

  • pen: left click to draw a pixel with the selected color
  • eraser: left click to erase a pixel
  • bucket: left click to fill areas of the same color with the selected color (wait till it's finished on the matrix before using it again)
  • bin: clears the canvas
  • save: click to save the current picture
  • WIFI: toggles between two modes:
    • sync drawing on the web app live to the canvas
    • don't sync drawing and display all saved pictures in a loop
  • load: select a pattern to be loaded on the web app and matrix
  • delete a pattern from the SD card

Step 20: Wrap It Up

Now you only have to glue the back plate on the case and we are ready!

Step 21: Inspiration and Ideas to Expand the Project

Now it's you turn, if you want to expand your matrix , here are a few ideas:

  • make it faaaster
  • make it responsible and compatible for touch devices
  • add a feature to make animations
  • add a feature to play games like snake
  • let it display something according to the weather
  • make it a statusbar for octoprint
  • add a motion sensor
  • and what else comes to your mind!

Step 22: Credits

At the end i want to thank Werner and Nigel from my local FabLab for helping me with this project. Especially for processing the same part with the laser over and over again, because it wasn't cut through yet...

I hope you liked this project and my Instructable. If you have feedback or questions feel free to leave a comment. It's my first Instructable so feedback is much appreciated. Thanks guys for reading through this and see you next time!

First Time Author Contest

First Prize in the
First Time Author Contest

1 Person Made This Project!


  • Back to School: Student Design Challenge

    Back to School: Student Design Challenge
  • Plywood Contest

    Plywood Contest
  • Halloween Contest

    Halloween Contest



Question 5 months ago

exelente proyecto, me encanto, una pregunta es compatible con el esp 32


6 months ago

Hi brocki,
I am really sorry to disturb you again, I have this error when I connect the data cable to d3 I get no response from the websever, the only time I get a response is when I define the data pin as data pin 5 and then connect to D1, but even then only the fill colour works and it fills it the wrong colour.
I was thinking maybe I am using the wrong version of the esp8266 or fast led libary. If you could please let me know which versions you have used, thanks appreciate the help.


Question 7 months ago

amazing work, everything seems to be working fine except when uploading code I get this error, initialization failed and HTTP server does not start?
Any ideas were I couldve gone wrong?


Answer 7 months ago

Yeah, this indicates that your SD card can't be initialized. Maybe I should have made the error message more clear lol. Anyway, you could check your wiring and try to test the connection of the SD card by uploading one of the examples found under File->Examples->SD in your Arduino IDE. Hope this somewhat helps.


Reply 6 months ago

Thanks brocki the sd card reader I was using wasn't compatible, I replaced it and it now works!!


Question 12 months ago


Nice work. I have a question, I use this 16 x 16 matrix https://fr.aliexpress.com/item/1005001382981170.ht... and I have a problem of mirror horizontally. I have used this matrix for anothor project and I have use the fastled.h parameter bool gReverseDirection = false; to resolve. But it does not work when I added in your code. Do you have and idea to resolved the problem ? Thank you.


Answer 11 months ago

I got to admit that I haven't heard of "gReverseDirection" yet. To mirror it you could either change the code how the array is created in the Javascript or (I think easier) change the "showPattern" function of the .ino to something along the line of

for(int i=0; i<16; i++){ //for the y axis
for(int j=15; j>=0; j++){ //for the x axis
leds[i*16+j] = pattern[i*15+j];

This should (fingers crossed) mirror the image.

Reply 11 months ago

I Finally fine the problem and modify the index.html :

in fucntion function draw(x,y,drawColor,post) replace the next value

if(y%2 == 0){
var index = 255-(y*16+(x));
var index = 255-(y*16+(15-x));

It will necessary to modify to load and save too.


Reply 11 months ago

Thank you for your reply, but with showPartern modification it is no effect on mirror effect. Very strange, and when I try to load some backup since SD Card it does not work. Very strange. I will try to modify your program when I will have free time. Anyway thank you for you help and very good job.

Reply 12 months ago

Thank you so much!


12 months ago on Step 22

@lamp contest

(you should enter this in it)


Reply 12 months ago

Naaah, already entered the First time author contest but thank you!


Question 1 year ago on Step 21

Great work, was planning on doing something like this myself, but this is more than I would be capable of. Will give it a try, only problem for me is that I cannot locate the "drive link" in order to get the html files. Can you advise?
Robert N.


Answer 1 year ago

To answer my own question, found it under the list of hardware!


1 year ago

This is awesome work, great job man! I got it uploaded to my nodemcu and working great. My only problems are involving the matrixes I used. Vertically they map to yours fine, but horizontally they are mirrored. It's not a huge deal, and I can fix that by reversing my sprites before drawing them into the webpage. My second, larger problem is that I cannot seem to find a way to make the matrix larger. Specifically I wanted to do a 32x16 matrix instead of a 16x16. I have tried editing the INO itself but the webpage still shows the 16x16 matrix. I don't have any experience with HTML if it's something in there, would it be possible to get a customized index.html or explain the options I should change by hand? Much appreciated any help and again, wonderful work on this project.


Reply 1 year ago

That they are mirrored probably is because you wired them differently? If you look on the matrix from the back the first LED should be on the bottom left corner. If you used already wired matrices there will probably be no way around a. changing software or b. having the drawback that you have to draw them mirrored.

Oh well, haven't considered the possibility that questions like this will come, so I used bad and evil magic numbers for the size of the matrix in my code.
I took some time updating the code now. When you open index.html now you should see a size_x variable right at the top. Changing it to 32 should give you a 32x16 canvas. (I really hope you meant 32 pixels on the x Axis... If not I will have to look back into it, because changing size_y doesn't work yet) If you need help changing the Arduino code feel free to leave another comment.

Have a nice day and thank you for the feedback!


Reply 1 year ago

I didn't make my matrix by hand is the issue :) I bought extra premade for another project and am trying to use that. Super trivial fix with the mirroring I can handle during sprite creation though. Thank you so much for changing the html, I have 0 clue involving it. I did unfortunately mean 32 vertical and 16 horizontal though :) The reason for that is NES sprites are created at 16x16 resolution, so for things like "super" mario or Link from Links Adventure are 2 of those stacked on top of each other. Alright after trying the new html it shows the grid perfectly, but since my matrix are wired differently the pattern is not matching what is drawn. I think instead of making you do more work, I will just do a 16x16 version for now that I can always upgrade in the future :) So thank you very much for all the extra help and again thanks for making this project and uploading it so anybody can make one. I will do my very best to get my make uploaded as soon as I 3d print some sort of case for it :) Also for a future reference, there is an arduino library written for use with fastled & matrixes here at https://github.com/AaronLiddiment/LEDMatrix Thank you again for the hard work! I voted for you for the contest :)
Also after testing the new index.html with a 16x16 matrix I'm seeing some artifacts where I cannot make some of the pixels colored. I have switched back to the original and everything seems to be working beautifully.


Question 1 year ago on Step 22

I have a raspberry Pi which have inbuilt card reader and wifi ... Can I use this instead of node mcu ?


Answer 1 year ago

Thank you for your interest. Unfortunately you won't be able to run the code I wrote on it, because it isn't based on a chip, that you can program with the ArduinoIDE. So you would have to write your own code.