tl;dr — category actors in NodeBB now have better avatars/pictures! They’re generated from the icon, color, and bgColor settings for each category.

Did you know that categories in NodeBB can also be followed on the social web/fediverse? Categories, as they are known here, are also actors on the fediverse, so you can find them just like any other account.

e.g. @general-discussion @support @nodebb-development @activitypub

@[email protected] opened an issue back in April (!!) pointing out that the avatar/picture served by NodeBB for category actors was not as good as it could be.

It’s definitely possible to do something like this, although it is usually rather resource intensive. For example, when you paste a GitHub URL somewhere (e.g. Slack), it may try to unfurl the URL and display an image. GitHub blogged about how they did this using Puppeteer to generate the images.

I knew right away I didn’t want to bundle what was basically an entire browser runtime into NodeBB’s dependencies, so I needed a more lightweight solution.

I attempted to build my own SVG string and send that through as a data-uri, but not surprisingly, it was not handled by the implementations I tested.

Some more research this week led me to Vercel’s OG Image Generation, which allows you to create images on the fly using Vercel Edge Functions. Since NodeBB is neither a Vercel app, nor do any people running NodeBB use Vercel, that ruled out this product.

However, more research into Vercel’s implementation led me to Satori and resvg, a pair of programs that can generate an SVG from HTML, and a PNG from SVG.

From there, it was a fairly standard technical exercise to combine these with our font-awesome libraries in order to output our own implementation of this to generate colourful category avatars for its category actors.

For now, they are only generated on-demand when a category actor is requested, but if there are applications for the icons to be used elsewhere, then we could look into having them generated on direct file request.

Enjoy!

0ff837a6-8f76-4c81-a81f-d4ad6d24660e-image.png