FakeRing: How I Turned My Monitor Into a $10 Ring Light
My webcam's brightness failed me during a crucial meeting. Instead of buying a ring light, I built one using Go, Wails v3, and some Win32 magic.
I have a problem: My room is dark, and my webcam isโฆ well, temperamental. ๐ก
A few days ago, I was hopping into a meeting and my webcam decided it didnโt want to adjust its brightness. I looked like a silhouette in a witness protection program. I didnโt have any lamps nearby, so in a moment of desperation, I opened a blank Chrome tab with about:blank.
Suddenly, my face was illuminated. It worked. Wait, I thought, why donโt I just make this a real thing?
And thatโs how FakeRing was born.

๐๏ธ The Tech Stack: Go meets the Desktop
Iโve been playing around with Go and Wails v3 recently. If you havenโt tried Wails, itโs like Electron but with a Go backendโway lighter and surprisingly powerful.
I used my own create-wails-app to get started, and then I went to battle with the Windows API.
1. Monitor Detection (The โWhere am I?โ problem)
To make a ring light for every monitor, I first had to find out how many monitors the user actually has.
Wails handles the UI beautifully, but for the deep OS-level stuff, I had to talk directly to user32.dll using Goโs syscall package. We use EnumDisplayMonitors to catch every screen and GetMonitorInfoW to get the exact coordinates of the โWork Areaโ (so we donโt cover the taskbar).
๐จ โThe Magic Ringโ: How it works

The goal was to draw a ring on top of everything else, but it shouldnโt block your clicks. Imagine having a ring light that prevents you from clicking the โMuteโ button. Pure chaos. ๐คก
The Secret Recipe:
- WS_EX_LAYERED: This lets us use transparency and alpha blending.
- WS_EX_TRANSPARENT: This is the magic flag. It makes the window โclick-through.โ The mouse events just pass right through to the apps behind it.
- Colorkeying: I fill the window background with Magenta (
0xFF00FF) and then tell Windows: โHey, make this specific color 100% invisible.โ
๐งฉ Interactive: Visualize the Ring Geometry
The ring isnโt just a border; itโs a subtraction. We take a โLarge Rectโ (the screen) and subtract a โSmaller Rectโ ( the inside) to create a perfect โDonutโ or โFrame.โ
Try adjusting the slider below to see how the subtraction creates the ring.
๐ง Brain-Breakers and Lessons Learned
Building desktop apps isnโt all sunshine and rainbows. Here are three things that almost made me throw my keyboard:
1. BGR vs RGB ๐
Windows GDI (the drawing engine) is old school. It doesnโt use the standard RGB format we use in CSS. It uses BGR (Blue-Green-Red). My first attempt at a yellow ring came outโฆ blue. I had to do some bit-shifting in Go to swap the channels.
2. The Thread Lock ๐
Win32 windows are โneedy.โ They are tied to the specific thread that created them. If you create a window in a goroutine and that goroutine finishes, your window disappears. I had to use runtime.LockOSThread() to keep the window message loop alive and stable.
3. Debouncing is Life โฑ๏ธ
When you move the color slider in the UI, it sends events fast. If I saved the settings to config.json every time the mouse moved a pixel, the app would lag like crazy.
Pro Move: I implemented a 500ms debounce. Visual updates happen instantly (GDI is fast!), but the disk save only happens when you stop fidgeting.
๐ The โPro Moveโ for Debugging
If youโre ever building something like this and want to see whatโs happening without the UI, check your home folder for the hidden config files. In FakeRing, itโs ~/.fakeRing/config.json. Seeing the raw data change while you poke at the app is the best way to understand the bridge between React and Go.
Wrap Up
FakeRing started as a โdesperation toolโ for a dark meeting, but it turned into a fun deep dive into the guts of Windows. Itโs open source, itโs light, and it saves me from buying a $10 lamp.
What weird problem are you going to solve today with code? Let me know! ๐


