Making a Vim watch face glow
I wanted a Vim styled watch face for my Garmin Fenix 8. Line numbers, a filename at the top, and status information along the bottom. The time and other watch data could be the contents of the file.
I also wanted it to look like an old green CRT, with glowing letters and scanlines across the display. Getting the text onto the screen was straightforward. Getting it to glow took quite a few attempts. Here's where I ended up with Vim Glow:

Getting the clock to glow
My first approach was to build bitmap font atlases from Berkeley Mono using BMFont. An atlas puts the characters into one image; the watch draws the part of the image containing the character it needs.
The plan was to layer blurred copies behind the sharp green letters. I tried fonts at different sizes and overlapping passes to get a soft halo around the text. That meant loading several large atlases. The first version loaded nine and crashed when the simulator ran out of graphics memory.
Smaller atlases helped with memory, but I still couldn't get the glow to blend correctly. The blur was visible in the generated PNGs, yet the clock looked sharp in the simulator. Drawing the blurred atlas on its own produced a black rectangle around it. Other transparent glyph images disappeared entirely. I tried blend modes and a bitmap buffer with alpha blending enabled, but couldn't get transparency working reliably.
Eventually I moved the clock's glow into the images themselves. I generated a separate image for each digit and the colon, with the blur and sharp letter already combined against a black background. The watch only has to draw the finished image.
The build script crops each character out of the atlas, then uses ImageMagick to blur its mask:
execFileSync("magick", [ sharpPath, "-alpha", "extract", "-blur", `0x${blurRadius}`, "-evaluate", "multiply", glowAlpha, maskPath, ]);
It colours that blurred mask green and combines it with the sharp character on black. All the images use the same cell width, so the clock keeps its monospace spacing. Finally, the digits had the glow I'd been trying to get.
Putting the scanlines back
The scanlines had been troublesome for the same reason. I'd been drawing them behind the text, expecting them to show through the transparent parts of the letters. The opaque clock images now painted black rectangles over them. I had a glowing clock, but the scanlines stopped wherever a character was drawn.
The fix was to draw the scanlines last, over the letters and their glow. Multiply blending darkens the pixels already on screen:
function drawScanlines(dc, awake) { var color = awake ? SCANLINE_WAKE : SCANLINE; dc.setBlendMode(Graphics.BLEND_MODE_MULTIPLY); dc.setColor(color, BG); for (var y = 0; y < HEIGHT; y += 4) { dc.drawLine(12, y, WIDTH - 12, y); } dc.setBlendMode(Graphics.BLEND_MODE_DEFAULT); }
Now the lines run across the whole face, including the clock. I'd originally expected to build the effect from transparent layers, but the opaque character images with scanlines drawn over them still give it the look I wanted.
Running the simulator locally
I ran Garmin's Connect IQ simulator in Docker. It needs older libraries, including GTK and WebKitGTK, and I wanted to keep those dependencies off my main system. The container runs the simulator window on my desktop, so I can load the watch face and see how the glow and scanlines look as I change them.
Try Vim Glow
If you want to try it on your Fenix 8, I made a web installer. Plug in the watch and open the page in Chrome or Edge on a desktop computer.

