player.style

A collection of drop-in visual themes for HTML5 media players, built on Media Chrome.

Library
npm
v0.3.4
250stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
50/100Fair
Development Activity16
Maintenance48
Community56
Maturity52
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
65/100Good
Architecture72
Code Quality55
Innovation62
Learning Curve70

player.style is a curated library of ready-to-use visual themes for web media players, built on top of Media Chrome’s headless custom elements. Each theme — Minimal, Sutro, Winamp, Notflix, Vimeonova, Reelplay, and more — ships as its own npm package containing a custom element and a matching React component, so teams can style a video or audio player’s controls, timeline, and captions without hand-building that UI from scratch.

Because every theme wraps Media Chrome rather than a specific video backend, the same theme works across Mux Player, YouTube, Vimeo, native HLS/DASH players, JW Player, Wistia, and Cloudflare Stream. The monorepo is built with Turborepo and a shared build-theme tool that compiles each theme’s template.html into a distributable custom element plus a React wrapper, keeping every theme’s packaging identical while letting only the CSS and markup vary per design.

What You Get

  • A library of ready-made themes - 14+ distinct visual themes (Minimal, Sutro, Sutro Audio, Winamp, Notflix, Vimeonova, Reelplay, Instaplay, Microvideo, YT, Halloween, X-Mas, Demuxed 2022, Tailwind Audio), each published individually under the @player.style npm scope.
  • Matching React components - every theme ships both a vanilla custom element (media-theme.js) and a React wrapper (react.js), generated from the same template by the shared build-theme tool.
  • Player-agnostic compatibility - themes sit on top of Media Chrome, so the same package works with Mux Player, YouTube, Vimeo, JW Player, Wistia, Cloudflare Stream, and native HLS/DASH players.
  • Framework usage guides - the player.style site documents integration patterns for plain HTML, React, Next.js, Vue, Svelte, and Lit.

Common Use Cases

  • Skinning a Mux Player or plain <video> element with a polished, branded control bar in minutes instead of building custom controls.
  • Swapping a video player’s look to match a seasonal or campaign theme (e.g. Halloween, X-Mas) without touching player logic.
  • Building a consistent player UI across multiple video backends (YouTube embed for one page, self-hosted HLS for another) by keeping the theme layer constant.
  • Prototyping a custom media player UI by starting from an existing theme’s template.html and adjusting CSS custom properties instead of writing controls from zero.

Under The Hood

Architecture The root package.json declares npm workspaces (site, examples/*, scripts/*, themes/*) orchestrated by Turborepo, whose build/lint/test/dev tasks chain through dependsOn: ["^build"] in turbo.json. Each theme under themes/* is a thin leaf — just a package.json, a template.html, and a changelog — with its build script delegating to the shared build-theme package (scripts/build-theme/build.js). That script reads the theme’s own package.json for its name, uses EJS to render template.html into dist/media-theme.html, emits dist/media-theme.js/.d.ts from shared templates, and bundles a React wrapper (dist/react.js) with esbuild around the same custom element. In effect, nearly all of a theme’s substance lives in one CSS/HTML template file, while all packaging and build logic is centralized in a single shared tool — a plugin-style layout where adding a new theme means adding a template, not new build code, and where changing build-theme reshapes every theme’s output at once since none of them roll their own build step.

Tech Stack A Node/ESM monorepo using npm workspaces and Turborepo 2.x for task orchestration, esbuild for bundling the React wrappers, EJS for templating, and TypeScript ^5 for hand-authored declaration templates. themes/* packages declare media-chrome as a peer dependency (>=1.0.0), while the root pins media-chrome ~4.19.0 for local development; chokidar-cli powers the root’s file-watching dev script and rimraf handles cleans. The site/ workspace is a separate Next.js app that renders theme/feature/framework documentation from markdown via content-collections. The package manager is pinned to npm@11.0.0.

Code Quality No test files, spec files, or test-runner configuration exist anywhere in the repo, and no workspace package defines a test script — despite turbo.json declaring a test task and CI (.github/workflows/ci.yml) invoking turbo test on every push, which makes that CI step effectively a no-op today. Linting is real and enforced: CI runs turbo lint against ESLint 8 with a Prettier 3 config embedded directly in the root package.json. Error handling in the build tooling is minimal (no explicit try/catch around file I/O in build.js), and naming is consistent throughout the small codebase. Overall: linted, but untested.

API Design Consumers import one path per theme — player.style/<theme> for the custom element or player.style/<theme>/react for the React component — so swapping a theme’s visual style requires changing only the import path and tag/component name, not any surrounding integration code. This is enabled by a wildcard exports map on the root package, letting one published npm name host many independently themed subpaths instead of requiring a separate top-level install per theme. In parallel, each theme is also published independently under the @player.style/* scope for teams that want to install just one theme directly — a dual-publishing approach (single root package with subpath exports, plus independently versioned scoped packages) that’s a deliberate, if somewhat unusual, choice for a theme library.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search