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 🙏

© 2025 – Pkg Stats / Ryan Hefner

playstack

v2.0.11

Published

A React component for playing a variety of URLs, including file paths, YouTube, Facebook, Vimeo, Bunny Stream and etc..

Downloads

876

Readme

Playstack

A modern, customizable video player component for React that supports multiple video services including YouTube, Vimeo, Bunny Stream, Google Drive, Mux, and more. Built with TypeScript and featuring a beautiful, responsive UI with custom controls.

Features

  • 🎥 Multi-platform Support: YouTube, Vimeo, Bunny Stream, Google Drive, Mux, HLS, DASH, and direct video URLs
  • 🎨 Customizable UI: Modern, responsive design with theme customization (YouTube, Vimeo, and direct video platforms)
  • ⌨️ Keyboard Controls: Full keyboard navigation support
  • 📱 Mobile Optimized: Touch-friendly controls and iOS fullscreen support
  • 🎛️ Advanced Controls: Custom seekbar, volume control, playback speed, and fullscreen
  • 🔧 TypeScript: Fully typed with comprehensive interfaces
  • 🎯 Accessible: Built with accessibility in mind using Radix UI components

Installation

npm install playstack
# or
yarn add playstack

Import CSS Styles

To use the custom player controls, you need to import the CSS styles:

import 'playstack/dist/style.css';

Note: The CSS import is required for the custom controls to display properly. Without it, the player will still function but will use the default styling of the underlying video platforms.

Quick Start

YouTube

import { Player } from 'playstack';

function App() {
  return (
    <Player
      src="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
      onTimeUpdate={(time) => console.log('Current time:', time.current)}
    />
  );
}

Vimeo

import { Player } from 'playstack';

function App() {
  return (
    <Player
      src="https://vimeo.com/123456789"
      onTimeUpdate={(time) => console.log('Current time:', time.current)}
    />
  );
}

Bunny Stream Integration

Important: Bunny Stream requires both src (iframe URL) and config.bunny props to work properly. If src is not provided, the player will show a loading indicator indefinitely.

import { Player } from 'playstack';

function App() {
  return (
    <Player
      src="https://iframe.mediadelivery.net/embed/your-library/your-video-id"
      config={{
        bunny: {
          id: 'your-video-id',
          hostname: 'your-library.b-cdn.net'
        }
      }}
      onTimeUpdate={(time) => console.log('Current time:', time.current)}
    />
  );
}

API Reference

Player Props

| Prop | Type | Default | Description | | --------------------------- | ------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | src | string | - | Direct video URL (YouTube, Vimeo, Mux, HLS, DASH, direct video, etc.) or Bunny Stream iframe URL | | config | object | - | Configuration object (see below) | | config.bunny | { id: string; hostname: string } | - | Bunny Stream configuration (requires src to be provided) | | config.youtube | object | - | YouTube-specific configuration (see below) | | config.youtube.noCookie | boolean | true | Use YouTube's privacy-enhanced mode (youtube-nocookie.com). Set to false to use youtube.com. Note: YouTube Shorts always use youtube.com regardless of this setting. | | config.theme | string | '#00B2FF' | Theme color for player controls (YouTube, Vimeo, and direct video platforms only) | | config.defaultControls | boolean | false | Use default platform controls instead of custom controls | | config.hidePlayerControls | boolean | false | Hide all player controls (overlay and controls bar) | | onTimeUpdate | (time: { current: number; duration: number }) => void | - | Callback for time updates | | onDurationChange | (duration: number) => void | - | Callback when video duration is available | | onTitleChange | (title?: string) => void | - | Callback when video title is available (YouTube and Vimeo only) | | onReady | (player: any) => void | - | Callback when player is ready (receives player instance) | | onVolumeChange | (data: { volume: number; muted: boolean }) => void | - | Callback when volume or mute state changes (does not work on Bunny Stream and Google Drive) | | onPlaybackRateChange | (playbackRate: number) => void | - | Callback when playback rate changes (does not work on Bunny Stream and Google Drive) |

Player Ref

The Player component supports ref forwarding. You can use a callback function that receives the player object.

Note: The ref receives different player objects depending on the platform:

  • YouTube: YouTube Player instance with methods like playVideo(), pauseVideo(), seekTo(), etc.
  • Vimeo: Vimeo Player instance with methods like play(), pause(), setCurrentTime(), etc.
  • Direct video, HLS, DASH: HTMLVideoElement-compatible object with methods like play(), pause(), seekTo(), setVolume(), etc.
  • Bunny Stream: Bunny Player.js instance
  • Google Drive: iframe element only (no player functionality - just an iframe embed)

Supported Platforms

YouTube

  • Features: Full YouTube support including Shorts, automatic thumbnail generation

  • URL Formats: Standard YouTube URLs, YouTube Shorts, YouTube-nocookie

  • Usage: Simply pass the YouTube URL to the src prop

  • Theme Support: ✅ Full theme customization

  • iOS Fullscreen: ✅ Native fullscreen support on iOS (video automatically enters fullscreen when playback starts)

  • Privacy Mode: By default, uses YouTube's privacy-enhanced mode (youtube-nocookie.com). You can disable this by setting config.youtube.noCookie to false. Note: YouTube Shorts always use youtube.com regardless of this setting.

  • Example:

    <Player src="https://www.youtube.com/watch?v=dQw4w9WgXcQ" />
    <Player src="https://youtu.be/dQw4w9WgXcQ" />
    <Player src="https://www.youtube.com/shorts/dQw4w9WgXcQ" />
    
    // Use regular YouTube domain (not privacy-enhanced)
    <Player
      src="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
      config={{ youtube: { noCookie: false } }}
    />

Vimeo

  • Features: Full Vimeo support with automatic video detection
  • URL Formats: Standard Vimeo URLs, Vimeo player URLs
  • Usage: Simply pass the Vimeo URL to the src prop
  • Theme Support: ✅ Full theme customization
  • iOS Fullscreen: ✅ Native fullscreen support on iOS
  • Example:
    <Player src="https://vimeo.com/123456789" />
    <Player src="https://player.vimeo.com/video/123456789" />
    <Player src="https://vimeo.com/channels/staffpicks/123456789" />

Bunny Stream

  • Documentation: Bunny Stream Embedding Documentation
  • Features: Native integration with Bunny's Player.js library
  • Requirements: Both src (iframe URL) and config.bunny (configuration) props must be provided
  • Theme Support: ❌ Uses Bunny's native player (theme only affects loading indicator)
  • iOS Fullscreen: ✅ Full native iOS fullscreen support
  • Usage:
    <Player
      src="https://iframe.mediadelivery.net/embed/your-library/your-video-id"
      config={{
        bunny: {
          id: 'your-video-id',
          hostname: 'your-library.b-cdn.net'
        }
      }}
    />
  • Note: If src is missing, the player will display a loading indicator

Google Drive

  • Features: Simple iframe embedding only (no player functionality)
  • Limitation: Just an iframe wrapper - no controls, no callbacks, no player methods
  • Theme Support: ❌ Uses Google Drive's native iframe (no theme customization)
  • iOS Fullscreen: ✅ Full native iOS fullscreen support
  • Note: The component hides Google Drive's "Open" link button for cleaner UI. This is a basic iframe embed with no video player features.

Mux

  • Features: Native support for Mux video streams (HLS)
  • URL Formats: Mux stream URLs (automatically converts to .m3u8 if needed)
  • Theme Support: ✅ Full theme customization
  • iOS Fullscreen: ✅ Native fullscreen support on iOS
  • Example:
    <Player src="https://stream.mux.com/your-video-id" />
    <Player src="https://stream.mux.com/your-video-id.m3u8" />

Direct Video, HLS, DASH

  • Features: Native HTML5 video support, including HLS and DASH streams
  • Theme Support: ✅ Full theme customization
  • iOS Fullscreen: ✅ Native fullscreen support on iOS
  • Example:
    <Player src="https://example.com/video.mp4" />
    <Player src="https://example.com/stream.m3u8" />
    <Player src="https://example.com/stream.mpd" />

Keyboard Controls

| Key | Action | | ------- | ------------------ | | Space | Play/Pause | | | Rewind 10 seconds | | | Forward 10 seconds | | | Increase volume | | | Decrease volume | | M | Mute/Unmute |

Note: On iOS devices, the volume bar is hidden for custom controls because browsers do not allow programmatic volume control.

Customization

Theme Colors

Note: Theme customization only works with YouTube, Vimeo, and direct video platforms.

<Player src="https://www.youtube.com/watch?v=dQw4w9WgXcQ" config={{ theme: '#FF6B6B' }} />

YouTube Privacy Mode

By default, the player uses YouTube's privacy-enhanced mode (youtube-nocookie.com) which doesn't store cookies. You can disable this to use the regular YouTube domain:

<Player
  src="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  config={{ youtube: { noCookie: false } }}
/>

Note: YouTube Shorts always use youtube.com regardless of the noCookie setting.

Default Controls

You can use the platform's default controls instead of custom controls:

<Player src="https://www.youtube.com/watch?v=dQw4w9WgXcQ" config={{ defaultControls: true }} />

Hide Controls

You can hide all custom controls:

<Player src="https://www.youtube.com/watch?v=dQw4w9WgXcQ" config={{ hidePlayerControls: true }} />

Advanced Features

Time Tracking

<Player
  src="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  onTimeUpdate={(time) => {
    console.log(`Progress: ${time.current}/${time.duration}`);
    // Save progress to localStorage, analytics, etc.
  }}
/>

Duration Tracking

<Player
  src="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  onDurationChange={(duration) => {
    console.log(`Video duration: ${duration} seconds`);
  }}
/>

Title Extraction

Note: Title extraction only works with YouTube and Vimeo platforms.

<Player
  src="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  onTitleChange={(title) => {
    document.title = `Watching: ${title}`;
  }}
/>

Player Ready Callback

<Player
  src="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  onReady={(player) => {
    console.log('Player ready:', player);
    // Access player methods directly
    // player.play(), player.pause(), etc.
  }}
/>

Volume and Playback Rate Tracking

<Player
  src="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  onVolumeChange={({ volume, muted }) => {
    console.log(`Volume: ${volume}, Muted: ${muted}`);
  }}
  onPlaybackRateChange={(rate) => {
    console.log(`Playback rate: ${rate}x`);
  }}
/>

Note: onVolumeChange and onPlaybackRateChange do not work with Bunny Stream and Google Drive.

Browser Support

  • Chrome 60+
  • Firefox 55+
  • Safari 12+
  • Edge 79+

Mobile Support

  • iOS Safari:

    • YouTube: Native fullscreen support (video automatically enters fullscreen when playback starts)
    • Vimeo, direct video, HLS, DASH, Mux: Native fullscreen support on iOS
    • Bunny Stream and Google Drive: Full native iOS fullscreen support
    • Note: The volume bar will not be displayed on iOS devices for custom controls, as programmatic volume control is not supported by iOS browsers.
  • Android Chrome: Standard fullscreen APIs with touch-friendly controls

  • Touch Controls: Gesture support across all platforms

Dependencies

Credits

This project builds upon the excellent work of:

  • Bunny Stream - For their powerful video streaming platform and Player.js library
  • Radix UI - For accessible, unstyled UI primitives
  • Tabler Icons - For the beautiful icon set
  • HLS.js - For HLS video streaming support
  • Dash.js - For DASH video streaming support

License

MIT License - see LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Support

Need help? We're here to assist you!

  • 🐛 Bug Reports: Found a bug? Please open an issue with a detailed description, steps to reproduce, and your environment details.
  • 💡 Feature Requests: Have an idea for a new feature? We'd love to hear it! Open a feature request.
  • ❓ Questions: For general questions and discussions, check existing issues or start a new discussion.
  • 📖 Documentation: Make sure to check the API Reference and Examples sections above.

Before opening an issue, please:

  • Search existing issues to see if your question has already been answered
  • Include relevant code examples and error messages
  • Specify which platform(s) you're experiencing issues with (YouTube, Vimeo, Bunny Stream, etc.)