DEV Community

Aakash
Aakash

Posted on

Someone Built a CRT Music Player for the Browser and I Respect the Hell Out of It

I opened this repo thinking, okay, nice retro UI toy. Then I looked properly.

This thing is called Phosphor. Rupam built it as a web-based music player with a CRT terminal / old oscilloscope aesthetic. You can tune into internet radio, drag in local audio files, import folders, queue tracks, switch visualizers, save favorites, keep playback history, like radio tracks, and run the whole thing without a build step.

No React.

No npm install.

No "please wait while 900 packages enter your house and rearrange your furniture."

Just static files. Browser APIs. Canvas. Web Audio. CSS. Done.

Repo: https://github.com/rupampoddar/phosphor

The vibe is not fake-retro. It actually commits.

A lot of "retro" web apps are basically:

black background
green text
monospace font
done bro ship it

Phosphor goes further than that.

It has scanlines, phosphor glow, CRT glare, a sweep line, screen vignette, flicker, terminal-style HUD, channel-switch static, and a “NO SIGNAL” idle state. It does not just wear the aesthetic as a sticker. The UI behaves like it belongs to that world.

And yeah, this is the part I liked most.

Because when a project picks an aesthetic and then half-commits, it feels cheap. But when the tiny details are consistent, the whole thing suddenly feels like an object. Not just a web page. An object.

Phosphor feels like someone found a cursed lab terminal from 196X and somehow taught it to play SomaFM.

It is also a real music player, not just a canvas demo

The obvious thing would have been to make a visualizer and stop there.

But Phosphor does more boring-product stuff too, which is usually where side projects start falling apart.

It supports local audio files. It supports drag and drop. It supports importing a folder. It builds a queue. It can auto-advance. It has repeat modes. It has keyboard shortcuts. It remembers settings. It has station favourites. It has playback history. It has liked tracks.

This is the difference between:

“I made a cool visual effect”

and

“I made a thing I can actually use while working.”

That second category is harder. Less glamorous. More annoying. More edge cases. More state. More UI panels. More “wait, what happens if the user switches from radio to local file while something is already playing?”

The repo has that smell of someone actually using the thing and then adding the missing buttons one by one.

The visualizers are the fun part

There are 13 modes:

  • scope
  • bars
  • VU
  • LEDs
  • lissajous
  • waterfall
  • sonar
  • ripples
  • warp
  • horizon
  • particles
  • radar
  • off

My personal weakness is anything oscilloscope-ish, so obviously scope / lissajous / radar hit the brain chemicals.

But the more interesting thing is that the visualizers are not random “music = particles go brrrr” stuff. A lot of them map to audio concepts in a readable way. Waveform, frequency bars, phase plot, spectrogram, VU meters, terrain from frequency snapshots. It is playful, but it is not nonsense.

Also, the app has four phosphor themes:

  • Amber
  • Green
  • Blue
  • White

Amber is the default and probably the correct answer. Green is the hacker answer. Blue feels like some Tektronix ghost machine. White is for people who enjoy haunted monochrome TV energy.

The zero-dependency bit matters

I know “no dependencies” can become a weird flex sometimes.

Like yeah bro, you hand-rolled your own broken date parser because npm scared you. Congrats.

But here, it makes sense.

This is a self-contained browser app. The platform already gives you the important pieces:

  • Web Audio API for audio analysis
  • Canvas 2D for rendering
  • CSS custom properties for themes
  • localStorage for persistence
  • normal HTML controls for interaction

So why add a framework?

For this kind of project, a framework could easily become the heaviest thing in the room. Phosphor being just static files is part of the charm. Clone it, serve the folder, open it in the browser.

git clone https://github.com/rupampoddar/phosphor.git
cd phosphor
python3 -m http.server 1960
Enter fullscreen mode Exit fullscreen mode

Then open:

http://localhost:1960
Enter fullscreen mode Exit fullscreen mode

That’s it.

No build step. No bundler. No config goblin hiding in the corner.

The potato mode is peak good taste

The README says it has four performance levels:

  • HI-FI
  • NORMAL
  • LO-FI
  • POTATO

This is exactly the kind of control I like seeing in visual projects.

Not everyone wants the browser to cosplay as a GPU benchmark. Sometimes you just want the thing to run, especially if it is sitting in another tab while music plays.

The code caps device pixel ratio, reduces frame rates, reuses analyser reads, caches the static graticule, and drops animation work when silent or hidden. That is good engineering. Not sexy engineering. Useful engineering.

A lot of web visual projects die because they assume the only acceptable machine is “developer laptop plugged into wall with Chrome eating 4GB RAM.”

Phosphor at least acknowledges weaker machines exist.

Respect.

The radio support has a real-world browser problem baked in

Internet radio in browsers sounds simple until CORS enters the room and ruins everyone’s day.

Phosphor handles this in a pragmatic way.

For CORS-enabled streams, the audio can pass through the Web Audio analyser, so the visualizer reacts properly. For non-CORS streams, it can still play audio directly, but the visualizer may not work because the analyser cannot safely read that stream.

That is a good compromise.

Not everything needs a backend proxy. Not everything needs auth, accounts, ingestion pipelines, and some cursed “cloud audio relay” architecture.

Sometimes the correct answer is:

play what the browser allows, explain when the browser blocks analysis, keep the app simple.

Boring? Maybe.

Correct? Mostly yes.

What I’d nitpick

Because obviously I have to nitpick. This is the internet.

I would probably want a few things over time:

A PWA mode would fit this perfectly. Installable little CRT radio thing? Yes.

Media Session API support would be nice too, so OS-level playback controls show proper station / track info.

An import/export option for favourites and liked tracks could help, because localStorage is convenient until the browser decides to do browser things.

Maybe a small “help” overlay for shortcuts, because there are many controls and I will absolutely forget half of them.

Also, local file metadata could become a rabbit hole. Album art, ID3 tags, better names, maybe waveform pre-analysis. But that can also turn a clean project into a swamp very fast, so maybe restraint is the better call.

This is the annoying thing with good side projects. The moment they work, your brain starts generating feature requests like a broken printer.

Why I like this project

Because it is not trying to be important.

It is not pitching itself as the future of music. It is not trying to disrupt Spotify. It is not pretending a browser visualizer is some revolutionary new computing layer.

It is just a lovingly built little thing.

But under that, there are a lot of good engineering instincts:

  • pick boring platform primitives
  • avoid unnecessary dependencies
  • make the UI coherent
  • add persistence where it matters
  • handle browser limitations honestly
  • expose performance controls
  • optimize the hot path
  • make the thing fun

That last one matters more than we admit.

A lot of software now feels like it was assembled by people who hate software. Every page is a funnel. Every button is a conversion event. Every app wants an account, a subscription, a notification permission, and probably your blood type.

Then you open a thing like Phosphor and it is just:

here, load music, tune into radio, stare at a fake CRT, enjoy.

Hell yeah.

More of this please.

Links

GitHub: https://github.com/rupampoddar/phosphor

Disclosure: I used AI assistance to help shape and edit this post, but the technical checks, opinions, and final wording are mine.

Top comments (0)