npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@nofinite/media

v1.0.0

Published

Universal, framework-agnostic audio and video streaming media player suite powered by Vidstack and styled with NUICSS design tokens.

Readme

Universal, enterprise-grade audio and video streaming media player suite powered by Vidstack and styled with NUICSS design tokens.


Highlights

  • Framework-Agnostic Core: Native W3C Custom Element engine (createMediaPlayer) with zero React dependencies or bundle penalty.
  • Next.js App Router & RSC Ready: React entrypoint preserves byte-0 'use client'; directives across both ESM and CJS bundles.
  • Adaptive Streaming Built-In: Native support for HLS (.m3u8), DASH (.mpd), MP4, WebM, MP3, WAV, AAC, and YouTube with lazy-loaded streaming decoders.
  • Glassmorphic OKLCH Theming: Fully harmonized with NUICSS design tokens (--color-primary, --bg-surface, --bg-subtle, --fg-default) supporting seamless light and dark mode cascading.
  • CDN CORS Resilience: Default crossOrigin="anonymous" handling prevents browser CORS rejections on external WebVTT subtitles, storyboard thumbnails, and audio streams.
  • Zero Memory Leaks: Automatic listener registry detachment and element teardown on player.destroy(), engineered for single-page applications.

Installation

# pnpm
pnpm add @nofinite/media @nofinite/nuicss

# npm
npm install @nofinite/media @nofinite/nuicss

# yarn
yarn add @nofinite/media @nofinite/nuicss

Styles Setup

Nofinite Media player layout chrome, scrubber timelines, responsive aspect ratios, and glassmorphic OKLCH design tokens are styled natively via NUICSS. Import the stylesheet once at your application root (e.g., layout.tsx, main.tsx, or _app.tsx):

import '@nofinite/nuicss/styles.css';

Note: For modular or bundle-isolated setups, NUICSS also exports a dedicated subpath stylesheet: @nofinite/nuicss/media.css.


Usage

1. React Video Player

import '@nofinite/nuicss/styles.css';
import { VideoPlayer } from '@nofinite/media/react';

export function MoviePlayer() {
  return (
    <VideoPlayer
      title="Sprite Fight Keynote"
      src="https://files.vidstack.io/sprite-fight/hls/stream.m3u8"
      poster="https://files.vidstack.io/sprite-fight/poster.webp"
      thumbnails="https://files.vidstack.io/sprite-fight/thumbnails.vtt"
      playbackRates={[0.5, 0.75, 1, 1.25, 1.5, 2]}
      seekStep={10}
      crossOrigin="anonymous"
      tracks={[
        {
          src: 'https://files.vidstack.io/sprite-fight/subs/english.vtt',
          label: 'English',
          language: 'en-US',
          kind: 'subtitles',
          default: true,
        },
        {
          src: 'https://files.vidstack.io/sprite-fight/subs/spanish.vtt',
          label: 'Spanish',
          language: 'es-ES',
          kind: 'subtitles',
        },
      ]}
      onPlay={() => console.log('Playback started')}
      onTimeUpdate={({ currentTime, duration }) => {
        console.log(`Progress: ${currentTime}/${duration}`);
      }}
    />
  );
}

2. React Audio Player

import { AudioPlayer } from '@nofinite/media/react';

export function PodcastPlayer() {
  return (
    <AudioPlayer
      title="Episode 42: Modern Web Architecture"
      artist="Nofinite Studio"
      artwork="https://images.unsplash.com/photo-1511671782779-c97d3d27a1d4?w=200"
      src="https://files.vidstack.io/audio/audio.mp3"
      playbackRates={[0.75, 1, 1.25, 1.5]}
      seekStep={15}
      theme="auto"
    />
  );
}

3. Vanilla JavaScript / Framework-Agnostic Core

import { createMediaPlayer } from '@nofinite/media';

const player = createMediaPlayer({
  src: 'https://files.vidstack.io/sprite-fight/720p.mp4',
  poster: 'https://files.vidstack.io/sprite-fight/poster.webp',
  title: 'Sprite Fight',
  autoplay: false,
  muted: false,
  controls: true,
  aspectRatio: '16/9',
  playbackRates: [0.5, 1, 1.5, 2],
  tracks: [
    {
      src: 'https://files.vidstack.io/sprite-fight/subs/english.vtt',
      label: 'English',
      language: 'en-US',
      kind: 'subtitles',
      default: true,
    },
  ],
});

// Append to DOM
document.getElementById('app')?.appendChild(player.element);

// Reactive event listeners
const unsubscribe = player.on('time-update', (detail) => {
  console.log('Current time:', detail.currentTime);
});

// Imperative controls
player.seek(45);
player.setVolume(0.8);
player.setPlaybackRate(1.25);

// Cleanup on unmount (SPA safe, detaches all listeners)
// player.destroy();

4. Zero-Build CDN (ESM)

For rapid prototyping or server-rendered HTML/HTMX environments without a build step:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <!-- NUICSS Design Tokens & Media Player Styles -->
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/@nofinite/nuicss/dist/styles.css"
    />
  </head>
  <body class="bg-surface p-6">
    <div id="player-container"></div>

    <script type="module">
      import { createMediaPlayer } from 'https://esm.sh/@nofinite/media';

      const player = createMediaPlayer({
        src: 'https://files.vidstack.io/sprite-fight/720p.mp4',
        poster: 'https://files.vidstack.io/sprite-fight/poster.webp',
        title: 'Sprite Fight',
      });

      document.getElementById('player-container').appendChild(player.element);
    </script>
  </body>
</html>

API Reference

VideoPlayerProps

| Prop | Type | Default | Description | | :-------------- | :-------------------------------------------- | :------------------------------- | :------------------------------------------------------------------- | | src / url | string | — | Media stream or file URL (HLS, DASH, MP4, WebM, YouTube). | | poster | string | — | Preview poster image URL displayed before playback starts. | | title | string | — | Title of the media asset. | | aspectRatio | string | '16/9' | Aspect ratio of the player container. | | autoPlay | boolean | false | Automatically begin playback when loaded. | | muted | boolean | false | Whether audio is muted. | | loop | boolean | false | Loop media once it reaches the end. | | controls | boolean | true | Display the default Vidstack video controls overlay. | | theme | 'auto' \| 'light' \| 'dark' | 'auto' | Force light or dark mode styling, or adapt automatically. | | thumbnails | string | — | WebVTT storyboard thumbnails file URL for scrubbing previews. | | playbackRates | number[] | — | Available playback speed options in the settings menu. | | seekStep | number | 10 | Seconds to skip forward/backward on keyboard navigation. | | crossOrigin | 'anonymous' \| 'use-credentials' \| boolean | 'anonymous' | CORS policy for media, subtitles, and thumbnails. | | load | 'eager' \| 'idle' \| 'visible' \| 'play' | autoPlay ? 'eager' : 'visible' | Strategy used to load the media player engine. | | preload | 'none' \| 'metadata' \| 'auto' | — | Media buffering preload strategy. | | tracks | MediaTrack[] | — | Subtitle and caption tracks (src, label, language, default). | | slots | Record<string, ReactNode> | — | Custom slot overrides for video layout chrome. |

AudioPlayerProps

| Prop | Type | Default | Description | | :-------------- | :-------------------------------------------- | :------------ | :----------------------------------------------------- | | src / url | string | — | Audio stream or file URL (MP3, AAC, WAV, OGG, HLS). | | title | string | — | Track title displayed in the audio metadata card. | | artist | string | — | Artist or podcast author name. | | artwork | string | — | Album art or podcast thumbnail URL. | | theme | 'auto' \| 'light' \| 'dark' | 'auto' | Theme scheme override ('auto', 'light', 'dark'). | | playbackRates | number[] | — | Playback speed options in the audio settings menu. | | seekStep | number | 10 | Seek duration step in seconds. | | crossOrigin | 'anonymous' \| 'use-credentials' \| boolean | 'anonymous' | Cross-origin resource sharing attribute. |

MediaPlayerInstance (Core Engine Methods)

The imperative instance returned by createMediaPlayer (and forwarded by ref on React components):

| Method | Signature | Description | | :------------------------ | :-------------------------------- | :------------------------------------------------------------------------------- | | play() | () => Promise<void> | Starts media playback. | | pause() | () => void | Pauses media playback. | | seek(time) | (time: number) => void | Seeks playback to the specified time in seconds. | | setVolume(vol) | (volume: number) => void | Sets audio volume (between 0 and 1). | | setMuted(muted) | (muted: boolean) => void | Sets or removes mute state. | | setPlaybackRate(rate) | (rate: number) => void | Sets playback speed rate (e.g. 1.25). | | setSrc(url) | (newSrc: string) => void | Changes media source dynamically. | | enterFullscreen() | () => Promise<void> | Enters fullscreen mode with safe error rejection handling. | | exitFullscreen() | () => Promise<void> | Exits fullscreen mode. | | enterPictureInPicture() | () => Promise<void> | Enters Picture-in-Picture mode (supported video). | | exitPictureInPicture() | () => Promise<void> | Exits Picture-in-Picture mode. | | getState() | () => MediaPlayerState | Retrieves current player snapshot (currentTime, duration, paused, volume, etc.). | | on(event, cb) | (event, callback) => () => void | Subscribes to player event; returns an unsubscription function. | | destroy() | () => void | Detaches all registered listeners and unmounts DOM elements cleanly. |


Re-exported Vidstack Primitives

For developers building bespoke media interfaces, @nofinite/media/react re-exports the foundational Vidstack state hooks and compound components:

import {
  MediaPlayer,
  MediaProvider,
  Track,
  useMediaState,
  useMediaRemote,
  useActiveTextTrack,
  useVideoQualityOptions,
  useCaptionOptions,
  usePlaybackRateOptions,
  DefaultVideoLayout,
  DefaultAudioLayout,
} from '@nofinite/media/react';

Documentation

For full setup guides, component examples, and API references, read documentation.


License

This project is licensed under the Apache License, Version 2.0.

Feel free to use, modify, and share this project in your applications, products, and services. Attribution is welcome and appreciated, but never required.