Portable Studio Light

by Arnov Sharma in Circuits > LEDs

198 Views, 3 Favorites, 0 Comments

Portable Studio Light

39.gif
35.gif
40.gif
47.gif

Greetings everyone and welcome back. Here's something super bright.

The Portable Studio Light is an ultra-compact RGB lighting solution intended to improve video production and visual aesthetics. With a sleek 3D-printed housing and a custom-engineered lens, it diffuses brilliant light from just four WS2812B LEDs.

The Studio light, powered by an ESP8266 microcontroller, links smoothly to a browser-based web app, allowing for exact color choices and dynamic control directly from your phone or laptop.

The Portable Studio Light was created to address an actual problem: I just relocated and found myself frequently hopping between two workplaces. I needed a lighting setup that was portable, easy to mount anyplace, and strong enough to enhance my video output.

Our Setup is powered by an ESP8266, with a custom 3D-printed lens and enclosure to make the most of only four WS2812B LEDs. The web app is where the magic happens: it's simple, responsive, and works on any device. I've used my phone, laptop, and ROG Ally to control it. Simply select a hue and it refreshes instantaneously, allowing us complete creative freedom no matter where I am working.

This whole Instructables is about the build process of this project and how you can make it in a few easy steps, so let's get started with the build.

Supplies

These are the components required in this build:

  1. Custom PCBs (Provided by HQ NEXTPCB)
  2. RGB WS2812B LEDs
  3. ESP12F Module
  4. 10K Resistor 0805 Package
  5. SMD Push Button
  6. Type C Port
  7. Right Angle Push Button
  8. 100 nF Capacitor 0603 Package
  9. AMS1117
  10. 10 uF Capacitor 1206
  11. 1uF Capacitor 1296
  12. M7 Diode
  13. 3D-printed parts
  14. LiPo Cell 3.7V 2000mAh

Previous Build

46.gif

Previously, I created a similar Studio light that was far bigger and more powerful in terms of both light and battery capacity. In the initial version, I used two PCBs connected by a 3D printed bracket and a long PCB standoff. The two PCBs consisted of an LED board and a control board. The LED board contains all of the non-addressable SMD RGB 5050 LEDs, including Warm White and Cool White LEDs.

The Control board included a PICO 2 with a display, a few buttons, an integrated power source, and two 8205S Mosfets as a switch setup that we linked to the LED board to turn on and off the Warm and Cool white LEDs.

One major issue with the project was its size, and I chose to use the WS2811 chip instead of an RGB addressable LED. I connected more than ten LEDs in parallel with the WS2811 IC, but the maximum current the WS2811 can sustain is roughly 20 mA per channel, causing all LEDs to flash very dimly in all R G and B modes.

The new portable version resolved the current issue by replacing the WS2811 IC with higher-quality WS2812B LEDs.

You can check out the previous project from here—

https://www.instructables.com/PICO-Studio-Light/

3D DESIGN

untitled.120.png
untitled.126.png
untitled.111.png
untitled.119.png
Screenshot 2025-07-15 172014.jpg
Screenshot 2025-07-15 172124.jpg
Screenshot 2025-07-15 172207.jpg
Screenshot 2025-05-23 162123.png
Screenshot 2025-05-23 164804.png
Screenshot 2025-07-15 171806.jpg
Screenshot 2025-07-15 171917.jpg
Screenshot 2025-07-15 172032.jpg
Screenshot 2025-07-15 172112.jpg
Screenshot 2025-07-15 172220.jpg
Screenshot 2025-07-15 172251.jpg
Screenshot 2025-07-15 172309.jpg
Screenshot 2025-07-15 172337.jpg
Screenshot 2025-07-15 172357.jpg
untitled.113.png

The 3D design of this project began with creating a proper-sized model of the lens that will be used in this build. The idea here was to place a PCB on the backside of the lens and then create an enclosure around it to house the batteries and electronics. The entire device will have a Stand Holder component that will be used to attach the device to any tripod or pipe.

The enclosure was designed in two halves: the front body and the lid section.

The front body has a huge opening in its center where the lens will be secured. The circuit was then modeled and connected to the lens, which is kept in place by a hole in the middle into which we will insert an M2.5 nut and bolt.

The lid is attached to the front body from the back and held in place with four M2 screws. The Lid Part also houses the Stand Holder Part.

We have created a 20mm DIA hole on the Stand Holder for attaching a tripod with this arrangement. We also constructed a slit and provided a hole and slot for installing an M6 nut and bolt; by tightening these nuts and bolts, the 20mm dia. hole size drops to 19.5 or less, allowing our device to be fastened securely with a tripod.

After preparing the 3D model, we exported the mesh files for all of the parts and 3D printed them on our K10 Max 3D printer with white Hyper PLA.

PCB Design

SCH_page-0001.jpg
Screenshot 2025-07-11 001736.jpg
Screenshot 2025-07-11 001712.jpg

Let's have a look at the schematic for this project, which is divided into four primary parts, one of which is the microcontroller section, which in our case is the ESP12F setup. Here, we've connected the ESP12F module to a few 10K resistors in the minimal configuration required for the ESP12F to work. We also included a CON6 Header pin connector that connects to the TX, RX, GPIO 0, RESET, VCC, and GND pins of the ESP12F Module; this connector will be used to flash the ESP chip using a UART adapter.

Next, we have the Power source section, which is the IP5306 Power management IC Setup, which we have previously used in many of our battery-related projects. This SOIC8 Package IC can provide a stable 5V 2.4A from a 3.7V Lithium Ion or LIPO Cell and also includes many important functions such as overcharging protection, overdischarge, battery fuel level, and charging status.

Below is its datasheet if you want more info on this IC.

https://www.skytech.ir/DownLoad/File/2566_IP5306.pdf

Our ESP12F is a 3.3V device; however, the IP5306 provides 5V, which will easily destroy our ESP12F setup. To avoid this issue, we used an AMS1117 3.3V Voltage Regulator, which takes the 5V from the IP5306 IC and lowers it to 3.3V so that our ESP12F setup can function properly.

Finally, we have the RGB LED Array, which consists of four WS2812B LEDs linked together to make a four-chain addressable LED. We have also included four 100 nF decoupling capacitors, which will be placed near the VCC and GND pins of each SMD LED.

After finalizing the schematic, we prepared the PCB Design, which was really simple. We began by creating the board outline using a DWG file exported from our Fusion360 model, which we then used to construct the PCB outline in our PCB cad software. We placed all of the SMD components on the top side of the PCB except for the ESP12F module due to space constraints; all SMD components were extremely small and could easily be placed on the top side, but our ESP12F module occupied a larger area, so we had to move it to the bottom layer.

All of the through-hole components, including the Type C Port and Right angle Push button, were installed to the bottom side according to the mounting dimensions provided in the design. The mounting hole in the middle was also added by following the dimensions from the 3D model, as was the placement of RGB LEDs.

NextPCB PCB Service

IMG_6460.JPG
02.gif
01.gif

After completing the PCB Design, Gerber Data was sent to HQ NextPCB, and two orders were placed in a white solder mask with black silkscreen.

After placing the order, the PCBs were received within a week, and the PCB quality was pretty great.

In addition, I have to bring in HQDFM to you, which helped me a lot through many projects. Huaqiu’s in-house engineers developed the free Design for Manufacturing software, HQDFM, revolutionizing how PCB designers visualize and verify their designs.

Take advantage of NextPCB's Accelerator campaign and get 2 free assembled RP2040-based PCBs for your innovative projects.

https://www.nextpcb.com/blog/rp2040-free-pcba-prototypes-nextpcb-accelerator

This offer covers all costs, including logistics, making it easier and more affordable to bring your ideas to life. SMT services can be expensive, but NextPCB is here to help you overcome that hurdle. Simply share your relevant project, and they'll take care of the rest. Don't miss out on this amazing opportunity to advance your tech creations!

HQDFM: Free Online Gerber Viewer and DFM Analysis Tool

Screenshot 2025-07-20 001319.jpg

Also, NextPCB has its own Gerber Viewer and DFM analysis software.

Your designs are improved by their HQDFM software (DFM) services. Since I find it annoying to have to wait around for DFM reports from manufacturers, HQDFM is the most efficient method for performing a pre-event self-check.

This is what I see in the online Gerber Viewer. It's decent for a quick look, but not entirely clear. For full functionality—like detailed DFM analysis for PCBA—you’ll need to download the desktop software. The web version only offers a basic DFM report.

With comprehensive Design for Manufacture (DFM) analysis features, HQDFM is a free, sophisticated online PCB Gerber file viewer.

With over 15 years of industry experience, it offers valuable insights into advanced manufacturing processes. If you’re looking for reliable PCB services at a budget-friendly price, HQ NextPCB is definitely worth checking out.

PCB ASSEMBLY

03.gif
04.gif
05.gif
06.gif
07.gif
08.gif
09.gif
10.gif
11.gif
  1. The PCB assembly process begins by applying solder paste to each SMD component pad one at a time with a solder paste dispensing needle; we are using 63/37 Sn/Pb solder paste here.
  2. Next, we use an ESD tweezer to choose and arrange all SMD components on the top side of the board.
  3. We pick the circuit and place it on the Reflow hotplate, which heats the PCB to the solder paste melting temperature, causing all SMD components to permanently solder to their pads.
  4. Next, we begin assembly on the bottom side of the board, beginning with the placement of the ESP12F Module.
  5. Because we are soldering on the other side of the board, we must use a soldering iron. We begin by soldering the first pad of the ESP model, which secures it in place and allows us to begin soldering the pins.
  6. Now come the through-hole components; we begin by installing the Push Switch, followed by the type C Port.

Flashing the ESP12F & MAIN CODE

12.gif
IMG_6689.JPG

Next is the Flashing process of the main circuit's ESP12F Module.

The usual FTDI board method, which requires connecting a flashing button between GPIO 0 and the GND Port, is being used to program the ESP12F Module. During uploading, the ESP12F enters programming mode by long pressing the Flash button first, followed by the reset button.

Here's an article about programming ESP12F with FTDI Board for more details:

https://www.instructables.com/Program-ESP8266-With-NodeMCU/

Here's the code that was used in this project and it's a simple one.

#include <Adafruit_NeoPixel.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
// WiFi credentials
const char* ssid = "URSSID";
const char* password = "URPASS";
// Web server
ESP8266WebServer server(80);
// NeoPixel setup
#define NeoPIN 14
#define NUM_LEDS 4
int brightness = 250;
//Use GRB ordering for WS2812B
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, NeoPIN, NEO_GRB + NEO_KHZ800);
const int led = 13;
void setup() {
Serial.begin(115200);
strip.setBrightness(brightness);
strip.begin();
strip.show();
delay(10);
Serial.println("NeoPixel initialized");
pinMode(led, OUTPUT);
digitalWrite(led, LOW);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi: ");
Serial.println(ssid);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.print("Connected to: ");
Serial.println(ssid);
Serial.print("Web App IP Address: ");
Serial.println(WiFi.localIP().toString());
if (MDNS.begin("esp8266")) {
Serial.println("MDNS responder started");
}
server.on("/", handleRoot);
server.onNotFound(handleNotFound);
server.begin();
Serial.println("HTTP server started");
}
void loop() {
server.handleClient();
}
void handleRoot() {
digitalWrite(led, HIGH);
String color = server.arg("c");
if (color.length() == 7 && color[0] == '#') {
setNeoColor(color);
}
int sec = millis() / 1000;
int min = sec / 60;
int hr = min / 60;
char clr[7] = "FFFFFF";
if (color.length() == 7) {
color.toCharArray(clr, 7);
}
// Reduced buffer size for safety
char webpage[1200];
snprintf(webpage, sizeof(webpage),
"<!DOCTYPE html>\n<html>\n\
<head>\n\
<title>STUDIO LIGHT MINI</title>\n\
<meta name='viewport' content='width=device-width, initial-scale=1.0'>\n\
<style>\n\
body { background-color:#111; color:#00ffe7; font-family:Arial; text-align:center; margin:0; padding:0; }\n\
h1 { margin-top:20px; font-size:2em; }\n\
input[type=color] { margin-top:20px; padding:10px; border:none; border-radius:6px; background:#222; color:#fff; }\n\
.btn { font-size:16pt; margin:20px; padding:10px 20px; background:#00ffe7; color:#111; border-radius:8px; cursor:pointer; }\n\
.btn:hover { background:#00ccbb; }\n\
</style>\n\
</head>\n\
<body>\n\
<h1>STUDIO LIGHT MINI</h1>\n\
<p>Uptime: %02d:%02d:%02d</p>\n\
<form method='post'>\n\
<input type='color' name='c' value='#%s' onchange='this.form.submit();'>\n\
<div class='btn' onclick='this.closest(\"form\").submit();'>CHANGE</div>\n\
</form>\n\
</body>\n</html>",
hr, min % 60, sec % 60, clr);
server.send(200, "text/html", webpage);
digitalWrite(led, LOW);
}
void handleNotFound() {
digitalWrite(led, HIGH);
String message = "File Not Found\n\n";
message += String("URI: ") + server.uri() + "\n";
message += String("Method: ") + (server.method() == HTTP_GET ? "GET" : "POST") + "\n";
message += "Arguments: " + String(server.args()) + "\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
digitalWrite(led, LOW);
}
void setNeoColor(String value) {
int number = (int) strtol(&value[1], NULL, 16);
int r = number >> 16;
int g = number >> 8 & 0xFF;
int b = number & 0xFF;
Serial.printf("RGB: %d %d %d\n", r, g, b);
//Send colors as GRB, matching hardware expectations
for (int i = 0; i < NUM_LEDS; i++) {
strip.setPixelColor(i, strip.Color(g, r, b));
}
strip.show();
delay(10);
Serial.println("Color updated.");
}

Let's have a closer look at the code for this project.

Library

#include <Adafruit_NeoPixel.h> // Controls WS2812B LEDs via simple API
#include <ESP8266WiFi.h> // Handles WiFi connection
#include <ESP8266WebServer.h> // Creates lightweight HTTP server
#include <ESP8266mDNS.h> // Enables access via esp8266.local

const char* ssid = "URSSID";
const char* password = "URPASS";

These libraries are the backbone: NeoPixel handles the RGB LEDs, ESP8266WiFi brings it online, WebServer lets it serve pages and handle user input, and mDNS adds that nice touch of accessing the ESP via a human-readable name instead of an IP address.

Neopixel and Web Server Configuration

ESP8266WebServer server(80); // Listens on port 80 — standard for HTTP
#define NeoPIN 14 // GPIO pin connected to data line of LEDs
#define NUM_LEDS 4 // Total LED count
int brightness = 250; // Max is 255

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, NeoPIN, NEO_GRB + NEO_KHZ800);

const int led = 13; // Optional status LED (visible blink on actions)

This section sets up the LED strip with the correct pin, pixel order (GRB), and signal frequency. The strip object lets us talk to all four LEDs with just a few commands. The led pin is a handy debug indicator that shows when something’s happening—useful for visual feedback without the Serial Monitor.

Setup Function

void setup() {
Serial.begin(115200); // Enables logging via USB serial

// Initialize LED strip
strip.setBrightness(brightness);
strip.begin();
strip.show(); // Clears the strip to off

// Prepare status LED
pinMode(led, OUTPUT);
digitalWrite(led, LOW);

// Connect to WiFi network
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500); // Wait until connected
}

// Optional: local DNS name
MDNS.begin("esp8266");

// Define HTTP routes
server.on("/", handleRoot); // Main page
server.onNotFound(handleNotFound); // 404 page
server.begin(); // Start server
}

This section gets everything live: Serial monitor for debugging, LED setup, WiFi connection, MDNS (so users can type esp8266.local instead of IP), and defines web routes so visitors know where to land and what to expect.

Loop Function

void loop() {
server.handleClient(); // Checks for incoming HTTP requests
}

This maintains the ESP responsive to web traffic. It is a non-blocking function that allows the ESP to process user input without freezing or requiring reboots.

handleRoot

void handleRoot() {
digitalWrite(led, HIGH); // Turns on debug/status LED

String color = server.arg("c"); // Get chosen color value
if (color.length() == 7 && color[0] == '#') {
setNeoColor(color); // Apply color to LEDs
}

// Uptime calculation
int sec = millis() / 1000;
int min = sec / 60;
int hr = min / 60;

// Prepare current color string
char clr[7] = "FFFFFF";
if (color.length() == 7) {
color.toCharArray(clr, 7);
}

// HTML page buffer
char webpage[1200];
snprintf(webpage, sizeof(webpage),
"<!DOCTYPE html> ...", hr, min % 60, sec % 60, clr);

server.send(200, "text/html", webpage); // Send HTML content to browser
digitalWrite(led, LOW);
}

This part block responds to users when they visit the ESP in a browser. It serves a functional color picker UI, calculates and displays uptime, and applies any color sent via the form. Simple, clean, and interactive.

handleNotFound

void handleNotFound() {
digitalWrite(led, HIGH); // Blink to indicate an error
String message = "File Not Found\n\n";
message += "URI: " + server.uri() + "\n";
message += "Method: " + (server.method() == HTTP_GET ? "GET" : "POST") + "\n";
message += "Arguments: " + String(server.args()) + "\n";

for (uint8_t i = 0; i < server.args(); i++) {
message += server.argName(i) + ": " + server.arg(i) + "\n";
}

server.send(404, "text/plain", message);
digitalWrite(led, LOW);
}

This Section keeps the server polished even when users mistype URLs. Instead of crashing or freezing, it gives useful debug info about what went wrong.

setNeoColor

void setNeoColor(String value) {
int number = (int) strtol(&value[1], NULL, 16); // Skip '#' and convert hex to int
int r = number >> 16;
int g = number >> 8 & 0xFF;
int b = number & 0xFF;

Serial.printf("RGB: %d %d %d\n", r, g, b); // Debug print

for (int i = 0; i < NUM_LEDS; i++) {
strip.setPixelColor(i, strip.Color(g, r, b)); // GRB order
}
strip.show(); // Push colors to LED
delay(10);
Serial.println("Color updated.");
}

This function is the heart of our system's response. It decodes the hex string (like #34D2FF) into individual RGB components, converts them for our hardware's GRB needs, and applies them across the LED strip. That’s what makes the lights react instantly when someone clicks a color.

Power Source

14.gif
15.gif

This project's power source is a 3.7V 2000mAh LiPo cell. We begin the power source assembly process by connecting the Lipo cell's positive and negative terminals to the Battery CON2 port of the IP5306 IC.

We plug a type C charger into our circuit, and the blue lights begin to flash, indicating that this setup is functional. When the blinking becomes stable, the battery has been fully charged.

Lens Assembly Process

16.gif
17.gif
18.gif

Here's the lens we're using in this project; it's a special one that I got on Amazon. These lenses are actually used in commercial streetlights and have a light spread of 50 to 90 degrees, making them more suitable for applications that require floodlighting.

For the assembly of the lens with our completed circuit, we just added the circuit to the back of the lens; our circuit was developed based on the lense cad model, thus we included a mounting hole for the lens in the center.

We used an M2.5 nut and bolt to secure the lens and circuit together.

Enclosure Assembly Process

21.gif
22.gif
23.gif
24.gif
25.gif
26.gif
27.gif
28.gif
29.gif
30.gif
  1. The Circuit-Lens Assembly is now inserted into the Front Enclosure and pressure fitted in place.
  2. We attached double-sided thermal tape to the rear side of the circuit, which has an exposed ESP12F module, to isolate it from the battery, as the battery is located on the back side of the circuit.
  3. We now take the Stand Holder portion and attach an M6 nut to the backside of the Holder, where we have modeled a cavity for the nut. From the other side, we install the M6 Bolt, which is then Tightened with the M5 Nut. When fitted on any cylindrical pipe, this part effectively tightens the Stand Holder.
  4. The Stand Holder is then installed on the backside of the Lid and tightened with four M2 screws.
  5. We then mount the antenna to the battery.
  6. The lid is then fitted on the backside of the front enclosure and tightened with four M2 screws.

The assembly process has now been completed.

RESULT

38.gif
45.gif
47.gif
48.gif
49.gif

Here's the end result of this build, the Portable Studio Light, a fully functional, travel-friendly RGB lighting solution designed for creatives who move between workspaces. Built from the ground up with an ESP8266 microprocessor, four WS2812B LEDs, a custom-designed 3D-printed body, and a unique lens.

To turn on this device, hit the Right Angle Push button once; multiple tapping turns it off.

After turning on the ESP12F, it connects to our network, and we can browse the webapp using the IP address we obtained in the Serial Monitor during the code uploading and testing process.

The web app provides a built-in color palette that allows us to quickly select and apply any color we desire. It's a simple and easy approach to managing lighting in real time.

I tested the Studio Light Mini by illuminating objects in my workspace. I first used it to highlight my ROG Ally, then as a facial light source. It performed great in both circumstances, providing smooth and vivid illumination.

CONCLUSION

35.gif
42.gif
31.gif

The Studio Light Mini demonstrates that portability does not have to compromise performance. Through smart engineering, thoughtful design, and real-world testing, this compact RGB light delivers powerful results in any setting—from workspace demos to personal filming setups.

The Studio Light Mini's tiny form allows it to be readily mounted or positioned anywhere, whether overhead or on a tripod. During testing, we used a tripod and the web app to experiment with different colors. Each adjustment was quickly updated, resulting in studio-quality lighting without the need for bulky equipment.

This project began as a practical answer to a personal problem and has grown into something truly useful, enjoyable, and portable. It serves as a reminder that even tiny ideas, when executed with care and purpose, can have a significant impact. If you enjoy small electronics, creative interfaces, or simply want studio-grade lighting that fits in your pocket, this is an interesting pick.

Overall, this project is completed and requires no revisions.

Special thanks to HQ NextPCB for providing components that I've used in this project; check them out for getting all sorts of PCB or PCBA-related services for less cost.

Thanks for reaching this far, and I will be back with a new project soon