ojo.zone

February 13, 2025

Aside from being a software engineer, I’m also a musician - specifically a DJ and producer. I’ve been working on a website to host my musical work for longer than I care to admit, and finally I’ve got something worth sharing… ojo.zone. In this post I’ll describe my goals and how they influenced the decisions made whilst building it.

Goals

Musicians these days are beholden to the platforms hosting or selling their music. In fairness, some of these platforms probably represent a net positive for the artist, but it’s nice to imagine a world where musicians have more control over the presentation of their work.

So my main target was to avoid using any embedded audio or links to other audio services, instead focussing on building a custom audio player at the core of the site.

The other priorities I had in mind were:

  • Cost: I don’t make a lot of money from music, so ongoing costs should be kept as low as possible
  • Content management UX: I had a fair bit of music to upload initially, so I needed a way to do it quickly and reliably, otherwise I was never going to get this finished
  • Accessibility & performance: The site should be accessible, fast, reliable, and generally in agreeance with web standards
  • Developer experience: It should be quick and enjoyable for me to build, iterate on, and maintain the site

Solving all these goals in conjunction taught me a lot about how I can offer similar websites for friends and other clients, many of whom are artists, musicians, or other creative folk. Get in touch if this sounds like you :~)

Tech Stack

  • Next.js for the frontend (static site mode)
  • Tailwind for styling
  • Jotai for state management (for the audio player)
  • Web Audio API for audio player & visualisations
  • Cloudflare for hosting the frontend and caching audio files
  • Directus for content management, self hosted on a Hetzner VM

Audio Player

Most of the time spent on this project was spent on the audio player UI, and the infrastructure required to support it. For example, I made the decision early on that I wanted to pre-compute the waveform for each track, to reduce the amount of browser processing required, and to give me full flexibility over the waveform presentation. This requires a separate service on my server which is triggered when a new track is uploaded, downloads the audio file, and outputs an array of numbers corresponding to the amplitude of the audio at a set number of points. Then, when the frontend is generated, the waveform is pulled from the CMS along with the rest of the metadata, and the frontend is able to render an SVG waveform based on the amplitude peaks.

I experimented with some frontend waveform libraries, but they were generally too heavy for my use case, as they were designed to provide the entire audio player functionality, which I wanted to implement myself. It was pretty fun to implement my own and learn some more SVG skills in the process.

Hosting Audio

A lot of my music is already hosted on Soundcloud, and I’m paying for the pro subscription which gives you unlimited uploads, in any file format. In the ideal world I would have used Soundcloud as the audio storage backend, and accesssed the audio files via their API, streaming them directly to my frontend. This would have cost me £0 (extra) per month and elimiated a certain amount of technical complexity, so it was a pretty appealing option at first. However Soundcloud’s API is closed for new signups with no plans to open it again, so I was somewhat forced to self-host the audio files and use a CDN to serve them. The upside of this is that I now have full control over the files which is much more ideologically aligned with what I wanted.

In order to things simple, I am currently hosting the audio files on my own server, and using Cloudflare as a CDN. I convert the audio to M4A before uploading, as it’s universally supported and offers a good balance between compression and quality, suiting it to audio streaming. The server comes with more than enough storage for all my music in this format, so I figured it’s not worth investing in extra storage. Using Cloudflare’s edge CDN provides caching for the audio files, which massively reduces latency for visitors, and load on my server.