Four years ago, I pushed the first commit to my little Jamstack utility collection project called jam-my-stack. I’ve been relying on it ever since. The 2022 build pipeline post explained how the stack hooks into building my blogs, and today, I want to revisit the tools in that collection to see how these have evolved (or abandoned).
For the uninitiated, “Jamstack” is just a silly acronym for Javascript, APIs and Markup (JAM) thrown together onto a technology stack to create static websites that easily scale and improve flexibility. In short, for me, it’s a few scripts that generate stuff before or after my static site generator Hugo takes over. It basically makes up for the lack of dynamic features and still allows me to deploy just a bunch of CSS and HTML files. And yes, the Jamstack thing has been announced dead for years when front-end folks moved to even cooler things like… server-side JS block rendering streamed to the front-end? Or some other super-complicated unnecessary thing? I don’t know. My scripts still have a purpose and still do what they need to do, so I don’t care.
Here’s an overview of what my Jam-my-stack project still does for me in 2025:
YouTube embeds
Simple: I don’t have any. Embedding a YouTube frame is very invasive, enables Google to track my visitors and adds unnecessary junk/load to my sites. When I found out how Ruben Schade tackles that problem, I simply copied his approach: (1) fetch YouTube IDs from .md files, (2) if not done already, download the thumbnail and merge it with a transparent play button.
A few months ago, I threw out the youtube-dl dependency that Google completely blocked—at least from my usual IP ranges. I found a much simpler alternative: Just download the https://i1.ytimg.com/vi/${youtubeid}/hqdefault.jpg image, problem fixed! Interestingly, hqdefault.jpg returns a 1:33 image while maxresdefault.jpg returns a widescreen 1:77 one—if available. I first download the latter and fallback to the former in case of a 404. Be sure to correctly offset that overlay with ImageMagick’s -gravity center -geometry +0+0 -compose over -composite arguments.
So far I’ve only needed YT embeds but it could easily be expanded to other video repositories whilst for example adding a smile logo on the top right.
How Long To Beat data
On my gaming blog I rely on the trusty HLTB website to automatically fetch a game cover and play data. Since this one never exposed a public API, the unofficial one I cooked up myself is notorious for breaking regularly. They also seem to make things more and more difficult for scrapers every time I try it out, which is of course understandable.
I’ve been wanting to move to MobyGames but would lose the cool HLTB duration info. As long as I can get it to work without too much effort, I’ll keep on updating my evil hack. It’s only executed for a new game review entry once every week or so and the cover image rights are not owned by them.
See Reducing Workflow Load Facilitates Writing for details on how this integrates with my Hugo theme.
Board Game Geek data
A recent addition to the above: I started writing occasional thoughts on board games as well as video games. The problem is that both can be valid database entries: Slay The Spire is both a video and a board game. I ended up with a good-enough convention: if hltb_name is in the frontmatter, assume the HLTB API needs to be called; if bgg_name is in the frontmatter, assume this one needs to be triggered instead. After retrieving info, both will delete that key and replace it with game_name and add all the fetched info to be used in my Hugo themes.
I was surprised by the ease of integrating with BGG’s public XML API2. It contains a lot of interesting stuff including reliable designer name(s) that is not necessarily the case for HLTB.
A typical result might look like this in the sidebar of a game review:
A cover image and BGG info for Race for the Galaxy.
All of the above information from the sidebar/screenshot is automatically fetched, sparing me the time to hunt down critical game information and instead enabling me to focus on writing the actual review instead. I will not be hitting their rate limiter any time soon.
GoodReads (abandoned)
The GoodReads HTML widget of course comes with a lot of crap you don’t want to include in your website so I extracted the sanitation of it to the Jamstack utility. Since I stopped writing reviews on other sites and I don’t want to import them here after publishing something somewhere else, this module is abandoned.
Mastodon (abandoned)
I tried the microblog thing for a while at /notes, importing Mastodon toots by converting RSS feed items to Markdown pages for Hugo to process, but never really liked these loose blurbs. I even have an auto-delete enabled on Mastodon nowadays that deletes toots after a certain amount of weeks. In my view, it’s supposed to be ethereal anyway, and I mostly rely on social media for exchanging game-related silliness which should not be pulled into Brain Baking for no reason.
Webmentions (abandoned)
See Why I Retired My Webmention Server if you’re interested in the context as to why this is abandoned. The Jamstack tool used to automatically trigger the pushing and receiving of these mentions.
Generating indexed chunks for the search functionality on my static sites is not a custom script as part of Jam-my-stack but a simple call to Pagefind after building the site. Then, a simple rsync “deploy” includes everything that’s needed to get things up and running. I’m not very satisfied with the fuzzy search capabilities of Pagefind, it’s on my list to migrate to something else. But since Hugo can’t do this, it’ll still be some kind of Jamstack tool.