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

am-audio-player-widget

v1.1.9

Published

A standalone and embeddable audio player widget, built for **Audio Modeling** with **React + TypeScript + Vite**. The widget can be integrated into any website via UMD bundle and supports multiple audio sources including Audius platform.

Readme

🎵 AM Audio Player Widget

A standalone and embeddable audio player widget, built for Audio Modeling with React + TypeScript + Vite. The widget can be integrated into any website via UMD bundle and supports multiple audio sources including Audius platform.

🚀 Key Features

  • 🎯 Standalone Widget: Zero external dependencies, React bundled internally
  • 🌐 UMD Universal: Compatible with any website or CMS (WordPress, etc.)
  • 🎨 CSS Isolation: Shadow DOM + Tailwind CSS v4 with PostCSS transformations
  • 🔊 Multi-Source: Audius API support with extensible architecture
  • 📱 Responsive: Spotify-like design for desktop and mobile
  • Performance: Optimized bundle with Vite + Rollup
  • 🎮 Programmatic API: Control playback via JavaScript API
  • 🧩 Multiple Modes: Bar, compact, and full player layouts
  • 🎵 Enhanced UX: Volume persistence, smooth seeking, accessibility support
  • 🎛 Smart Progress Bars: Multiple styles including minimal always-visible indicator

🎨 Player Modes & Progress Bar Styles

Player Modes

| Mode | Description | Use Case | |----------|-------------|----------| | bar | Horizontal minimal bar with mobile/desktop layouts | Headers, navbars, sticky players | | compact | Reduced version | Sidebars, footers | | full | Complete player with all controls | Dedicated pages |

Progress Bar Styles

| Style | Description | Features | |-------|-------------|----------| | default | Standard progress slider with hover effects | Time display, click-to-seek, hover thumb | | waveform | Visual waveform representation | Audio visualization, interactive seeking | | minimal | Thin bottom bar indicator | Always-visible progress, space-efficient |

🛠 Tech Stack

  • Frontend: React 19 + TypeScript
  • Build Tool: Vite 7 + Rollup
  • Styling: Tailwind CSS v4 with CSS isolation via Shadow DOM
  • CSS Processing: Custom PostCSS plugin for @property transformation
  • Audio: react-use-audio-player with custom hooks
  • Data Fetching: TanStack Query v5
  • UI Components: Radix UI + shadcn/ui
  • Icons: Lucide React
  • Package Manager: pnpm

📦 Installation*

*CDN (Recommended for WordPress/CMS)

<!DOCTYPE html>
<html>
<head>
  <title>My Website</title>
  <style>
    /* Modern animations for player visibility */
    .am-player-sticky {
      position: fixed;
      bottom: 0;
      left: 0;
      right: 0;
      z-index: 1000;
      transform: translateY(100%);
      opacity: 0;
      transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
    }
    
    .am-player-sticky.show {
      transform: translateY(0);
      opacity: 1;
    }
    
    .am-mini-trigger {
      position: fixed;
      bottom: 20px;
      right: 20px;
      z-index: 1001;
      width: 56px;
      height: 56px;
      background: linear-gradient(135deg, #8b5cf6, #ec4899);
      border-radius: 50%;
      border: none;
      cursor: pointer;
      display: none;
      align-items: center;
      justify-content: center;
      box-shadow: 0 4px 20px rgba(139, 92, 246, 0.3);
      backdrop-filter: blur(10px);
      transition: all 0.3s ease;
    }
    
    .am-mini-trigger:hover {
      transform: scale(1.1);
      box-shadow: 0 6px 25px rgba(139, 92, 246, 0.4);
    }
  </style>
</head>
<body>
  <!-- Player container -->
  <div class="am-player-sticky" role="region" aria-label="Music Player">
    <div id="am-footer-audio-player"></div>
  </div>

  <!-- Mini trigger button -->
  <button class="am-mini-trigger" aria-label="Open music player" title="Open Player">
    <svg width="20" height="20" viewBox="0 0 24 24" fill="none">
      <path d="M8 5v14l11-7z" fill="white"/>
    </svg>
  </button>

  <!-- Load widget -->
  <script src="https://unpkg.com/[email protected]/dist/am-audio-player-widget.js"></script>
  <script>
    (function() {
      'use strict';
      
      let widget = null;
      let isPlayerVisible = false;
      
      const elements = {
        player: document.querySelector('.am-player-sticky'),
        trigger: document.querySelector('.am-mini-trigger'),
        container: document.querySelector('#am-footer-audio-player')
      };
      
      // Get configuration from data attributes, URL params, or globals
      function getConfig() {
        const container = elements.container;
        const urlParams = new URLSearchParams(window.location.search);
        
        const trackId = container?.dataset?.trackId || 
                       urlParams.get('trackId') || 
                       window.trackId;
                       
        const playlistId = container?.dataset?.playlistId || 
                          urlParams.get('playlistId') || 
                          window.playlistId;
        
        return {
          trackId,
          playlistId,
          mode: 'bar',
          progressBarStyle: 'minimal', // 🎯 NEW: minimal style by default
          showCloseButton: true,
          showVolume: true,
          showProgressBar: true,
          onClose: hidePlayer
        };
      }
      
      function showPlayer() {
        if (elements.player && !isPlayerVisible) {
          elements.player.style.display = 'block';
          requestAnimationFrame(() => {
            elements.player.classList.add('show');
          });
          if (elements.trigger) elements.trigger.style.display = 'none';
          isPlayerVisible = true;
        }
      }
      
      function hidePlayer() {
        if (elements.player && isPlayerVisible) {
          // Pause music when closing
          if (widget && widget.togglePlay && widget.isPlaying) {
            widget.togglePlay();
          }
          
          elements.player.classList.remove('show');
          setTimeout(() => {
            elements.player.style.display = 'none';
          }, 400);
          if (elements.trigger) elements.trigger.style.display = 'flex';
          isPlayerVisible = false;
        }
      }
      
      function initWidget() {
        const config = getConfig();
        
        // Only initialize if we have trackId or playlistId
        if (!config.trackId && !config.playlistId) {
          console.warn('[AM Widget] No trackId or playlistId provided. Widget not initialized.');
          return;
        }
        
        try {
          widget = AMAudioPlayerWidget.init('#am-footer-audio-player', config);
          showPlayer();
          
          // Setup mini trigger
          if (elements.trigger) {
            elements.trigger.addEventListener('click', showPlayer);
          }
        } catch (error) {
          console.error('[AM Widget] Initialization failed:', error);
        }
      }
      
      // Initialize when DOM is ready
      if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initWidget);
      } else {
        initWidget();
      }
    })();
  </script>
</body>
</html>

NPM/Package Manager

npm install @andreadf/am-audio-player-widget
# or
pnpm add @andreadf/am-audio-player-widget
import AMAudioPlayerWidget from '@andreadf/am-audio-player-widget';

const widget = AMAudioPlayerWidget.init('#player', {
  trackId: 'XB2lGlO',
  mode: 'bar',
  progressBarStyle: 'minimal',
  showVolume: true,
  showProgressBar: true
});

⚙️ Widget Configuration

interface WidgetConfig {
  // Source configuration
  trackId?: string           // Audius track ID
  playlistId?: string        // Audius playlist ID
  tracks?: AMTrack[]         // Custom tracks array
  
  // Player configuration
  mode?: "bar" | "compact" | "full"
  progressBarStyle?: "default" | "waveform" | "minimal"  // 🎯 NEW: minimal option
  
  // UI Configuration
  showVolume?: boolean       // Show/hide volume control (default: true)
  showProgressBar?: boolean  // Show/hide progress bar (default: true)
  showCloseButton?: boolean  // Show/hide close button (default: false)
  onClose?: () => void      // Close button callback
  
  // Asset URLs
  backgroundUrl?: string     // Custom background image
  noAlbumArtUrl?: string    // Placeholder cover image
  
  // Styling
  className?: string         // Additional CSS classes
}

🎛 API Methods

const player = AMAudioPlayerWidget.init('#player', config);

// Playback control
player.togglePlay();              // Toggle play/pause
console.log(player.isPlaying);   // Get playback state

// Configuration management
player.update({ 
  mode: 'compact',
  trackId: 'newTrackId',
  progressBarStyle: 'minimal',    // 🎯 NEW: Switch progress bar style
  showVolume: false
});

// Get current configuration
const currentConfig = player.getConfig();

// Cleanup
player.destroy();

// Version info
console.log(AMAudioPlayerWidget.version); // "1.0.0"

🎨 Features

Shadow DOM CSS Isolation

  • Complete CSS encapsulation using Shadow DOM
  • Custom PostCSS plugin converts Tailwind v4 @property declarations
  • No style conflicts with host website

Spotify-like Design

  • Mobile Layout: Single row with album art, track info, and compact controls
  • Desktop Layout: Three-column grid with centered controls and progress bar
  • Mini Progress Bar: Always visible thin progress indicator at bottom (NEW!)
  • Hover Effects: Scale transforms, color changes, and smooth transitions

Enhanced UX

  • Volume Persistence: Settings saved in localStorage across page refreshes
  • Smart Seeking: Progress bar updates smoothly during playback and when paused
  • Anti-Flash Logic: Prevents visual glitches when seeking while paused
  • Accessibility: Full ARIA labels and keyboard navigation support
  • Responsive: Adaptive layouts for mobile/desktop with media queries

Progress Bar Styles

  • Default: Interactive slider with time display and hover effects
  • Waveform: Visual audio representation with seeking capabilities
  • Minimal: Thin bottom indicator bar that's always visible (NEW!)

Modern Animations

  • CSS transforms with cubic-bezier easing
  • Backdrop blur effects and glassmorphism

🏗 Development

Available Commands

# Development with demo page
pnpm dev                 # Start dev server on http://localhost:5173

# Build for production
pnpm build              # Create UMD bundle in dist/
pnpm build:test         # Build test mode 
pnpm build:prod         # Build production mode
pnpm build:debug        # Build debug mode

# Quality checks
pnpm lint              # ESLint check
pnpm preview           # Preview local build

Project Structure

am-player/
├── src/
│   ├── components/
│   │   ├── controls/           # Playback controls (play/pause, volume)
│   │   ├── core/              # Main player logic
│   │   ├── layouts/           # Layout components (bar, compact, full)
│   │   ├── progress/          # Progress bars (default, waveform, minimal)
│   │   ├── ui/                # UI primitives (slider, button, etc.)
│   │   └── types/             # TypeScript definitions
│   ├── hooks/                 # Custom React hooks (useAudioTime, etc.)
│   ├── api/                   # Data fetching (Audius API)
│   ├── styles/                # Global CSS and Tailwind config
│   ├── Widget.tsx             # Main widget entry point
│   └── main.tsx              # Development demo page
├── postcss.config.ts          # PostCSS with Shadow DOM transformation
├── vite.config.ts            # Vite build configuration
└── README.md

🔧 Technical Details

CSS in Shadow DOM

The widget uses a custom PostCSS plugin to transform Tailwind CSS v4 for Shadow DOM compatibility:

// Converts @property declarations to :root, :host selectors
@property --tw-gradient-from { initial-value: transparent; }
// Becomes:
:root, :host { --tw-gradient-from: transparent; }

Performance Optimizations

  • Smart Audio Hooks: useAudioTime optimized for continuous playback monitoring
  • Conditional Updates: Progress bars only update when necessary
  • Memoized Components: React.memo for heavy UI components
  • localStorage Caching: Volume and settings persistence
  • Efficient Bundling: Tree-shaking and code splitting with Vite

Audio Position Management

// Consolidated useAudioTime hook with smart seeking
const useAudioTime = (getPosition: () => number, active: boolean) => {
  // Handles both playing and paused states
  // Detects significant position changes (seeks)
  // Optimizes requestAnimationFrame usage
};

Progress Bar Architecture

  • Default: Full-featured slider with time display
  • Waveform: Visual audio representation
  • Minimal: Thin Radix UI slider with subtle styling (NEW!)

📄 License

MIT License - see LICENSE file for details.

🤝 Contributing

Contributions are welcome! Please read our contributing guidelines and submit pull requests to our repository.


Built with ❤️ by Audio Modeling Team