Limeplay React Media Player Components

repository·main·Indexed 42 days ago

https://github.com/winoffrg/limeplay

A library of copy-pasteable React media player components built on Shaka Player, following the shadcn/ui model. It provides production-ready VideoPlayer and AudioPlayer blocks supporting HLS, DASH, adaptive bitrate, and DRM-capable playback. Features include playlist management, accessible controls, and Browser Media Session integration. Components are installed via the shadcn CLI (e.g., @limeplay/video-player, @limeplay/audio-player, and @limeplay/captions).

Tokens
46.3K
Snippets
152
Records
199
Agent score
54%

What's inside Limeplay

  1. Overview of Limeplay

    main

    Limeplay provides copy-pasteable media player components for React. It is designed to give developers production-grade interaction patterns (similar to Netflix, YouTube, or Spotify) without having to rebuild complex playback logic.

    Key Features:

    • Engine: Built on Shaka Player, supporting HLS, DASH, adaptive bitrate, live streaming, and DRM-capable playback.
    • UI Model: Follows the shadcn/ui pattern. Components are added to your local codebase, allowing you to maintain full ownership and customize the UI code directly.
    • Focus Areas: Resilient error states, accessible controls, keyboard navigation, responsive layouts, and modern interaction states.
  2. Overview of Limeplay features and architecture

    main

    Limeplay is an open-source React component library designed for building custom media player interfaces. It is built on top of Shaka Player for advanced streaming capabilities like HLS, DASH, adaptive bitrate, and DRM, while also supporting native HTML5 playback.

    Key Technical Features

    • shadcn/ui Distribution Model: Unlike traditional npm packages, Limeplay components are copied directly into your src/ directory. This provides full ownership, allowing you to modify styles, logic, and behavior without being constrained by node_modules.
    • Feature-based Architecture: Capabilities such as playback controls, volume, and timeline are isolated features. You can opt into only the specific features your application requires to keep your bundle size minimal.
    • Typed Event System: Instead of scattered callbacks, Limeplay uses a centralized event emitter. You can subscribe to over 15 events (including volumechange, seek, and ended) with full TypeScript support.
    • Granular Reactivity: The library uses Zustand-powered stores with per-field selectors. This ensures that components only re-render when the specific data they are observing changes.
    • Accessibility: Every component includes built-in ARIA attributes, keyboard navigation, and focus management.
  3. Overview of Limeplay UI Components

    main

    Limeplay provides pre-built, accessible UI components designed to build media player interfaces. These components are composable and connect directly to Limeplay's feature stores.

    Key characteristics:

    • Copy-and-paste workflow: Components are copied into your project, allowing you to modify styles, behavior, and markup freely.
    • Feature-driven: Each component requires specific Limeplay features (e.g., mediaFeature, playbackFeature) to be registered in the media kit to function.
  4. AudioPlayer features and capabilities

    main

    The AudioPlayer component provides several built-in features:

    • Playlist Management: Supports a queue with track artwork, title, genre, and duration.
    • Timeline Controls: Fixed timeline with elapsed time, total duration, hover time previews, and scrubbing support.
    • Playback Controls: Previous, play/pause, next, volume, mute, repeat, and shuffle modes.
    • URL Resolution: Automatically resolves playback URLs from src or playbackUrls.primary.
    • Resilience: Automatic skip/reload behavior for recoverable load and playback failures.
    • Media Session Integration: Automatically populates Browser Media Session metadata (title, artist, album, poster) and handles media-key events.
  5. Understand the project layout

    main

    The project structure is organized as follows:

    PathPurpose
    apps/www/content/docsFumadocs documentation
    apps/www/registry/default/uiCopyable UI primitives
    apps/www/registry/default/hooksFeature hooks and utilities
    apps/www/registry/default/blocksComplete player blocks
    apps/www/registry/collectionshadcn registry metadata
    apps/www/public/rGenerated registry JSON
    promptsProject rules for local assistants and review tooling
  6. VideoPlayer features and capabilities

    main

    The VideoPlayer is a Shaka-backed player supporting HLS, DASH, and DRM-capable streams. Key features include:

    • Controls: Volume, mute, captions, playback rate, and picture-in-picture.
    • Playlist Management: Automatic playlist menu visibility when a multi-item queue is provided.
    • Timeline: Scrubbing with buffered progress feedback.
    • Media Session: Automatic integration with Browser Media Session metadata (derived from asset title, description, and poster).
    • Native Integration: Supports standard media-key handlers and playback state reporting.
  7. Register Feature Hooks in createMediaKit

    main

    Feature hooks are used for media player state management. Each feature hook provides a store slice, event listeners, and optionally a Setup component. To use these hooks, you must register them within the createMediaKit function call. Once registered, the hook will expose its corresponding state slice to your application.

    Available Feature Hooks:

    HookStore KeyDescription
    use-mediamediaBase media element reference and idle state
    use-playerplayerShaka Player initialization and asset loading
    use-playbackplaybackPlay/pause, status, loop, error state
    use-volumevolumeVolume level, mute, audio detection
    use-timelinetimelineCurrent time, duration, seeking, buffered ranges
    use-playlistplaylistQueue management, shuffle, repeat modes
    use-playback-rateplaybackRatePlayback speed control
    use-picture-in-picturepictureInPicturePiP mode toggle
    use-captionscaptionsText track management
    use-assetassetHigher-order hook combining player + playlist
  8. Understand the Limeplay component hierarchy

    main

    While custom players can be composed manually, most Limeplay players follow a standard hierarchical structure:

    1. MediaProvider: Provides the store, events, and feature setup.
    2. RootContainer: Manages root state attributes.
    3. PlayerContainer: Manages the media layout.
    4. Media: The actual video or audio element.
    5. ControlsContainer: Houses various control blocks:
      • Playback controls
      • Timeline controls
      • Volume controls
    6. FallbackPoster: Displayed when media is not active.
  9. Manage player state with the Store

    main

    Each MediaProvider instance creates an isolated Zustand store. State is namespaced by feature (e.g., playback.paused or volume.level). Multiple players on the same page do not share state unless explicitly wired together.

    Reading State

    Use selectors with the store hooks to ensure components only re-render when the specific fields they use change:

    const paused = usePlaybackStore((state) => state.paused)
    const volume = useVolumeStore((state) => state.level)

    Imperative State Updates

    For imperative logic, use the media API returned by your kit via useMediaApi():

    const api = useMediaApi()
    
    api.setState(({ volume }) => {
      volume.level = 0.5
    })
  10. State management rules with Zustand and Immer

    main

    Limeplay uses zustand/middleware/immer for state management. When updating stores, you must follow these strict rules to ensure stability:

    • Direct Mutation: Inside set((state) => { ... }), mutate draft fields directly. Never reassign the state object itself.
    • Explicit Returns: If you are replacing state, return the new value explicitly. Never return undefined.
    • Unidirectional Tree: Keep state as a strict unidirectional tree. Avoid circular references or shared object identities across different branches.
    • Array Mutation: For arrays, only mutate numeric indices or the length property.
    • External Payloads: Always clone or sanitize external payloads before storing them to prevent accidental mutations of the store state.
    // CORRECT: Mutating a draft field
    set((state) => {
      state.isPlaying = true;
    });
    
    // CORRECT: Replacing state explicitly
    set((state) => {
      return { ...state, volume: 1 };
    });
    
    // INCORRECT: Reassigning state
    set((state) => {
      state = { ...state, isPlaying: true }; // This will fail/break Immer
    });
  11. How use-controls-visibility manages state and events

    main

    The use-controls-visibility hook acts as a bridge between DOM events and the media store. It does not emit custom media events, but it handles the following DOM events to update the mediaFeature idle state:

    • blur / focus: Controls hide/show based on focus.
    • pointerenter / pointerleave: Controls show/hide based on pointer presence.
    • pointermove / pointerup: Shows controls and may schedule auto-hide.
    • pointerover: Keeps controls visible over forced areas.

    Underlying State Dependencies

    The hook reads from these fields in the existing features:

    FieldOwnerDescription
    debugmediaFeatureKeeps controls visible while debug mode is enabled.
    forceIdlemediaFeaturePrevents the hook from changing idle state when forced.
    idlemediaFeatureDrives whether controls and cursor can hide.
    statusplaybackFeatureKeeps controls visible while buffering, paused, or errored.

    Actions

    MethodOwnerDescription
    setIdle(value)mediaFeatureUpdates idle state after interaction timers.