Today was a Saturday, and I put in 23 commits across three repos. The headline is not the volume of work, but the fact that the listener experience finally feels solid. I spent most of the day in majiks.online wrestling with the audio player, getting Stripe ready for real payments, and cleaning up the dead weight that was cluttering the interface.
The audio player was the main antagonist today. I started by fixing the GlobalPlayer re-rendering at 10fps, which was causing visible UI stuttering. That felt good until I tried to fix codec detection. I added format hints for Howler to handle mp4, m4a, and aac files. That broke everything. Howler decided it needed to download the entire file before playing, which killed the streaming experience. I had to revert that change immediately. Then I removed a server.timeout setting that was silently killing audio streams mid-playback. It turns out the server was just too aggressive. I also cleaned up the player page, fixing stuttering and lyrics display. The player now has an empty state with a queue, and I removed the dead auth pages like forgot password and register that nobody uses anyway. The player bar is now dismissable with a floating reopen button, so it stays out of the way when you want to focus on the content.
With the audio stabilized, I could focus on the listener journey. I built a full Now Playing page with a like button on the mini player. I also linked 36 tracks with API support and UI updates, including search deduplication. I generated artwork for 56 tracks and added a fallback, so the site finally looks complete. I also set up a listener-focused homepage with an always-visible player bar. The UX improvements were subtle but necessary. I removed the old auth pages and cleaned up the footer and header. The site feels less like a prototype and more like a place where people actually listen to music.
I started by fixing the GlobalPlayer re-rendering at 10fps, which was causing visible UI stuttering.
Stripe was the other big push. I added Stripe keys and webhooks, and created a demo account for Apple review. I fixed the Publisher checkout by adding the publisher tier to the Stripe price map. I also set up analytics for downloads and added an overview route. The analytics proxy was returning 400 errors in the browser console, which I fixed. I switched download URLs to direct Backblaze B2, which should be faster and more reliable. I cleaned up the download page to only show the current version, v1.5.2, as the previous version.
I also pushed v2.1.0 for majiks.online, which includes listener-focused UX, Stripe Connect, and Keycloak-only auth. I added Forgejo Actions CI with smoke tests to make sure nothing breaks. I fixed the /api/auth/token endpoint to fallback to the public Keycloak URL for mobile tokens. I also cleaned up the Keycloak templates for login, reset password, and update profile.
In songwriter-agent, I shipped v0.2.0 with MLX model unloading, a focused Surprise Me feature, and a conversational chat interface. It was a small but significant update for the AI side of things.
In majiks.studio, I updated the site to v1.5.2 and cleaned up the download page. I also fixed the analytics proxy and switched to direct Backblaze B2 downloads.
The day added up to a cleaner, faster, and more reliable listener experience. The audio plays without stuttering, the player stays out of the way, and the payments are ready for real users. It feels like a real product now.
Real product captures — click any to enlarge.