The two-second look away
Here’s the workflow I was trying to kill.
Board’s drawing current it shouldn’t. You want to know which component is getting hot, so you pick up the thermal camera, point it at the board, look at its screen, find the bright spot, then look back at the microscope and try to work out which part that was. Two displays, two coordinate systems, and a mental transform between them that you redo every single time.
It’s not hard. It’s just constant, and it breaks concentration at exactly the moment you had some.
benchhud started as “I want to see which part is overheating without looking away from the scope.” It turned into the bench’s command center.
Fusion, not picture-in-picture
The headline feature is putting the thermal image on the scope image, registered — so the heat bloom sits over the actual component instead of in a separate window you have to mentally line up.
A short on a rail lights up the part that’s pulling the current, in place, at the magnification you’re already working at. You can blend it as a heatmap, tint everything over a threshold, or drop a marker with a live temperature label on the part you care about.
The bit that makes it real rather than decorative: it reads the raw Y16 stream from the thermal camera, not the pre-colormapped MJPEG. Most thermal cameras will happily hand you a pretty orange-and-purple picture. That picture has already thrown away the measurement — the colors are relative to whatever the camera decided the scene range was. Y16 is raw per-pixel data you can convert to actual degrees. That’s the difference between “this area looks hot” and “that pad is 78°C.” On a repair bench, only one of those is useful.
The rest of the bench, in one window
Once you have a window that owns the scope, everything else on the bench wants to be in it:
- Instrument telemetry — DMM and PSU readings over SCPI in a proper bench-style meter, with peak-hold and a V/A/W trend graph. On screen, and optionally burned into the stream.
- Repair jobs — a local-first log of what’s on the bench. One button attaches the current scope frame, thermal frame, and meter readings to the job timeline. An over-current trip logs itself, which is the sort of thing you never remember to write down at the time and always want later. Export a customer-facing report when the job’s done.
- Ticket import — optionally pull the open queue from the shop intake system and drop a ticket onto the bench as a job. Runs standalone without one.
- Tool launcher — opens the tools you already use, OpenBoardView and friends, straight from the HUD.
It’s all dockable panels, so you arrange the bench the way you actually work and the layout sticks.
One reader, and why OBS can’t have the camera
The composite goes out to a virtual camera, so OBS treats the whole bench as a normal camera source and I can stream a repair without a capture card or a second machine.
That drove an architecture decision that isn’t obvious until it bites you: a UVC camera allows exactly one reader at a time. So benchhud is the sole reader of both the scope and the thermal cam, builds the composite, and writes that to a loopback device. OBS pulls the loopback. If you ever find OBS insisting it can’t open a camera that’s plainly right there — that’s why. Something already has it.
Each camera runs on its own thread feeding a latest-frame buffer, so a slow feed never stalls the pipeline. Capture → register → analyze → composite → output, and the slowest device doesn’t get to set the pace for everything else.
Where it actually is
I want to be straight about this, because “I built a thermal fusion HUD” reads like a finished product and it isn’t one yet.
The application is built. It is not a daily driver. The shell, capture pipeline, thermal math, overlay compositing, instrument driver, live controls, and repair log are all written and tested. Scope capture is verified against a real camera. The rest of the device-facing work — thermal Y16 off the actual Sipeed unit, the virtual cam, the OWON on serial — sits behind interfaces that are tested off-hardware and gets wired up on the bench.
That’s a real gap and I’m not going to paper over it. Off-hardware tests tell you your code is right about the world you described; they don’t tell you that you described the world correctly. The interesting failures are all still ahead of me.
Linux-first, because that’s where the bench lives and where the virtual-camera output works. The app itself runs on macOS today; virtual cam there needs its own backend and doesn’t have one.
More soon, once it’s been through a few real repairs and I know which of my assumptions were wrong.