This post was written with Claude Code (Anthropic's claude-opus-4-6 model) at định nguyễn's request. Claude Code helped build the entire project from spec to deployment — TypeScript components, Rollup build, VitePress docs, CI/CD, and this blog post.
TL;DR
I built a dependency-free Web Component media player with 7 layout presets, 7 themes, audio visualization, and i18n. Nobody asked for it. I’m not sure anyone needs it. But I built it anyway, with Claude Code doing most of the heavy lifting.
Docs & Playground: py.dinhnn.com
GitHub: github.com/dinhnguyen/py-player
npm: npm install py-player
An Idea That Sat Around for Years
I’ve wanted to build a custom media player for a long time. Not because the world needs another one — HTML5 <audio> and <video> have gotten really good. The native controls work fine for most people. The ecosystem of existing players is mature. There’s howler.js, plyr, vidstack, and dozens more.
But here’s the thing: every time I needed a player for a project, I’d spend hours looking for one that did exactly what I wanted. Most were close but not quite. Too many dependencies. Styling that fought against my design. Features I didn’t need bundled with missing ones I did. And the ones that were truly flexible required so much configuration that I might as well have built my own.
So the idea kept sitting there. “One day I’ll build my own player.” “One day” turned out to be a very long day.
Claude Code Changed the Math
What changed wasn’t motivation — it was feasibility. Building a full-featured media player from scratch is a lot of work. Web Audio API for visualization. Shadow DOM for encapsulation. CSS custom properties for theming. Playlist parsing. i18n. Responsive layouts. It’s the kind of project that a solo developer would start on a weekend and abandon by Tuesday.
Then Claude Code happened. And suddenly the math was different.
I wrote a spec. Claude Code turned it into a working project — TypeScript source, Rollup build, unit tests, E2E tests, VitePress documentation site, CI/CD pipeline, and npm publishing workflow. Not in weeks. In sessions.
I’m not going to pretend I wrote every line. I didn’t. Claude Code did most of the implementation. What I did was make decisions: what layouts to support, how theming should work, what the API surface should look like, when something felt wrong and needed to change. The architecture came from conversation. The code came from Claude.
What It Actually Does
Drop a <script> tag, write one HTML element, and you get a styled media player:
<script src="https://unpkg.com/py-player/dist/py-player.min.js"></script>
<py-audio
src="podcast.mp3"
layout="podcast"
theme="midnight"
title="Episode 42"
></py-audio>
That gives you a podcast-style player with a dark theme, progress bar, skip buttons, and a playlist panel. No build step. No framework. No dependencies.
There are 7 layouts (normal, minimal, album-art, compact, podcast, visualizer, playlist-first), 7 color themes, real-time audio visualization with Web Audio API, playlist and chapter support, full CSS variable theming, and i18n.
The video player handles fullscreen, Picture-in-Picture, volume, and playback speed. There’s also a smart wrapper <py-player> that auto-detects whether the source is audio or video.
Everything is a Web Component with Shadow DOM, so it won’t leak styles into or absorb styles from the host page.
Let’s Be Honest About the Audience
I don’t think this will go viral. I don’t think thousands of developers are out there searching for yet another media player. HTML5 has solved 90% of the use case, and the remaining 10% is split across established libraries with real communities behind them.
py-player is a small project by one person (with a lot of AI help). It has no community. No ecosystem. No Stack Overflow answers. No tutorial videos.
And that’s fine.
I built it because I was tired of looking for a player that did what I wanted. Now I have one. It does exactly what I need, styled exactly how I like, with an API that makes sense to me.
What I’m Actually Hoping For
If you’re reading this and thinking “I could use this” — great. Install it. Try it. And when something breaks (it will), or when you wish it did something it doesn’t (you will), open an issue. Or a PR.
I don’t need py-player to be popular. I need it to be used. Even by a handful of people. Because used software gets bug reports. Bug reports lead to fixes. Fixes lead to better software.
The worst fate for an open-source project isn’t being criticized. It’s being ignored.
So here’s my ask: if this solves even one small problem for you, let me know. If it almost solves your problem but falls short, let me know that too. I’ll maintain this. I’ll fix bugs. I’ll add features that make sense.
The playground lets you configure everything interactively and copy the code. The docs cover installation, layouts, theming, playlists, and the full API. The source is MIT licensed.
The Stack
For the curious:
- Runtime: Zero dependencies. Pure Web Components (Custom Elements v1 + Shadow DOM)
- Audio visualization: Web Audio API with AnalyserNode, 7 visualizer styles
- Build: Rollup → UMD + ESM + minified, with TypeScript declarations
- Docs: VitePress with custom dark/light theme and interactive playground
- Testing: Vitest (unit) + Playwright (E2E)
- CI/CD: GitHub Actions for lint/test/build, auto-publish to npm on release
- Hosting: Cloudflare Pages for docs, npm + unpkg/jsdelivr for the package
What’s Next
Things I want to add but haven’t yet:
- HLS/DASH streaming support
- Keyboard shortcuts and accessibility improvements
- More visualizer styles
- Waveform display (pre-rendered)
- Media session API integration (lock screen controls)
- Better mobile touch interactions
If any of these matter to you, open an issue and I’ll prioritize.
py-player is open source under MIT. Try it at py.dinhnn.com.