Since I am on a roll with cleaning up my Hugo-based blog, adding alt text, and supporting math writing, I also had to experiment with adding support for musical scores.

For the Sensing Sound and Music book, I used music21 in Python after struggling to set up LilyPond. Both LilyPond (professional engraving) and music21 (symbolic analysis and MIDI generation) are powerful and could be integrated into a blog, but they usually require a server-side toolchain or extra installation. However, with the help of CoPilot, I discovered ABCjs, a lightweight client‑side library that provides rendering, playback, and MIDI export, which work well for static sites.

Setting it up

I added ABCJS to the Hugo site by including the ABCJS CSS/JS in the head partial (layouts/partials/head.html) and adding a small init script (assets/js/abcjs-init.js) that finds all div.abcjs elements and calls ABCJS.renderAbc(...) and, when available, the synth/MIDI APIs for playback and export.

I also added a simple shortcode (layouts/shortcodes/abcjs.html) that wraps its inner content in a <div class="abcjs">, so fenced ABC code in posts renders and becomes playable automatically.

Testing

Paste your ABC into a div with class abcjs, and the site will render it automatically.

Example:

<div class="abcjs">
X:1
T:Simple Example
M:4/4
L:1/4
K:C
C D E F | G A B c | c B A G | F E D C |
</div>

This will render as:

X:1 T:Simple Example M:4/4 L:1/4 K:C C D E F | G A B c | c B A G | F E D C |

I don’t write many music scores these days, but it is nice to have the option to include some notation here on the blog from time to time.


Thanks to CoPilot for getting this up and running.