My daughter is three. She loves one specific playlist of Korean children’s songs, and she likes it best when it plays from a small JBL Bluetooth speaker tucked under her stroller.
We walk the neighborhood for about an hour most evenings. I put on her folder, the first song starts, and we go.
Thirty seconds later, my phone screen goes off.
One more song plays. Then it stops.
I have to unlock the phone, tap the next song, put the phone back in my pocket, and keep walking. A minute later, same thing.
I built this app myself — with Claude, because I can’t code on my own. I knew something in the app was doing this. I just could not figure out what.
So I spent about six hours trying to fix it.
I gave up.
What the App Is
Kids Player is the music and video player I built for my daughter. It runs on my Synology DS224+ NAS, served over Nginx, reachable from my phone via a Cloudflare Tunnel. No ads, no algorithm, no subscription. I put in only what I want her to hear.
One of its main features is folder-based continuous playback. Pick a folder, tap one song, and it plays through the whole folder automatically. That works fine when the phone screen is on.
The problem only appears when the screen goes off.
What I Tried
I described the symptom to Claude and we went through several approaches across the session:
Media Session API. Wiring up lock screen metadata, playback state, and previous/next button handlers. This had helped stabilize my hymnal app on Android, so we tried the same pattern here.
Prefetch. Loading the next song into a hidden audio element while the current one is still playing, so the transition needs no extra wait for a network request.
Source swapping. Replacing the audio source mid-play rather than creating a new element, with tighter timing on the handoff.
None of it worked. The symptom was always the same: one more song after the screen went off, then silence.
The Actual Cause
After the session, I asked Claude to re-read the source code with fresh eyes and explain what was happening. The answer was clear once the code was laid out.
The prefetch is the key. When a song starts, the app buffers exactly the next one song ahead. So when the screen goes off:
- The current song finishes.
- The already-buffered next song plays. That is the “one more song.”
- The song after that needs a new network request. The mobile browser — running in the background with the screen off — blocks that request. Silence.
Two things confirmed this reading:
Loop single works fine with the screen off. Same file, no new network request, just a seek back to zero.
A compilation file also works. Each of my folders contains both the individual song files and a single merged file of the whole folder. Playing the compilation as one track means no song transitions, no new requests.
In both cases the thing that stops — a mid-background network fetch for new media — is simply absent. The pattern is clean.
Why It Cannot Be Fixed in a Web App
This is not a bug in my code. It is a platform policy.
Mobile operating systems restrict what a browser tab can do when the screen is off. A native music app gets registered as a background audio service. The OS knows about it, keeps its network requests alive, and lets it buffer silently. A web app gets no such registration. It runs in a browser tab, and the tab gets throttled or suspended.
The Media Session API helps with lock screen controls. It does not give a web app background network access. That permission belongs to the native layer.
An experienced engineer hitting the same problem with a web app would get the same result. The fix exists — but it requires rewriting as a native Android or iOS app, with a foreground service for audio. That is a completely different project.
What I Do Now
For the stroller walks, I do one of two things.
Repeat one song. I pick the song my daughter wants most at the moment and set it to loop. Works perfectly with the screen off. Less variety, but she usually has a strong favorite anyway.
Use the compilation file. Each folder in the app holds both the individual song files and one merged compilation of the whole folder. The way I save audio files, the compilation is created alongside the individual tracks by default — so it is already there, not extra work. (How I build and organize these audio files is a topic for another post.) The player treats the compilation as a single track, so there are no transitions, no background buffering, no stops. The downside is that jumping to a specific song is gone. For walking music, that is fine.
What I Took From This
Vibe coding — building with AI when you could not build alone — can get you most of the way there fast. The app was running in a day. The main features work. My daughter uses it every day.
But “most of the way” is not “all the way,” and sometimes the remaining gap is not a coding problem at all. Some limits sit in the platform, not the code. No amount of prompting changes a policy the OS enforces.
That is not a failure of AI-assisted coding. It is just how software works. Tools have edges. I hit one.
The walks are fine now. She does not notice the difference.