# PACKAGE: @nofinite/media Accessible audio and video player primitives with custom NUICSS skins and streaming support. You are an expert React developer using @nofinite/media. Rules: 1. Import VideoPlayer and AudioPlayer from '@nofinite/media/react'. 2. Supports HLS, DASH, native MP4/WebM/MP3 streaming, playback speed controls, and picture-in-picture. --- ## TypeScript API Reference (Props) ### VideoPlayer - `src: string` (Default: none) - `url: string` (Default: none) - `poster: string` (Default: none) - `title: string` (Default: none) - `autoPlay: boolean` (Default: false) - `loop: boolean` (Default: false) - `muted: boolean` (Default: false) - `playsInline: boolean` (Default: true) - `controls: boolean` (Default: true) - `theme: any` (Default: auto) - `aspectRatio: string` (Default: 16/9) - `className: string` (Default: none) - `style: CSSProperties` (Default: none) - `tracks: MediaTrack[]` (Default: none) - `thumbnails: string` (Default: none) - `playbackRates: number[] | { min: number; max: number; step: number; }` (Default: none) - `seekStep: number` (Default: none) - `crossOrigin: boolean | "anonymous" | "use-credentials"` (Default: anonymous) - `load: enum` (Default: none) - `preload: enum` (Default: none) - `slots: any` (Default: none) - `onPlay: (() => void)` (Default: none) - `onPause: (() => void)` (Default: none) - `onEnded: (() => void)` (Default: none) - `onTimeUpdate: ((detail: { currentTime: number; duration: number; }) => void)` (Default: none) - `onVolumeChange: ((detail: { volume: number; muted: boolean; }) => void)` (Default: none) - `onError: ((error: any) => void)` (Default: none) - `onSeeked: ((time: number) => void)` (Default: none) - `onLoadedMetadata: ((detail: { duration: number; }) => void)` (Default: none) - `onFullscreenChange: ((fullscreen: boolean) => void)` (Default: none) ### AudioPlayer - `src: string` (Default: none) - `url: string` (Default: none) - `title: string` (Default: none) - `artist: string` (Default: none) - `artwork: string` (Default: none) - `autoPlay: boolean` (Default: false) - `loop: boolean` (Default: false) - `muted: boolean` (Default: false) - `controls: boolean` (Default: true) - `theme: any` (Default: auto) - `className: string` (Default: none) - `style: CSSProperties` (Default: none) - `tracks: MediaTrack[]` (Default: none) - `playbackRates: number[] | { min: number; max: number; step: number; }` (Default: none) - `seekStep: number` (Default: none) - `crossOrigin: boolean | "anonymous" | "use-credentials"` (Default: anonymous) - `load: enum` (Default: none) - `preload: enum` (Default: none) - `slots: any` (Default: none) - `onPlay: (() => void)` (Default: none) - `onPause: (() => void)` (Default: none) - `onEnded: (() => void)` (Default: none) - `onTimeUpdate: ((detail: { currentTime: number; duration: number; }) => void)` (Default: none) - `onVolumeChange: ((detail: { volume: number; muted: boolean; }) => void)` (Default: none) - `onError: ((error: any) => void)` (Default: none) - `onSeeked: ((time: number) => void)` (Default: none) - `onLoadedMetadata: ((detail: { duration: number; }) => void)` (Default: none) --- ### Document: media/audio-player/page.mdx # AudioPlayer **AudioPlayer** is a compact, accessible audio interface with high-resolution timeline scrubbing, volume controls, playback speed selector, and rich metadata display (artwork, title, and artist bylines). ```ts // Framework-Agnostic Core (Zero React Dependency) import { createMediaPlayer, formatMediaTime } from '@nofinite/media'; // React Adapter import { AudioPlayer } from '@nofinite/media/react'; ``` --- ## Interactive Preview --- ## 1. Usage in Vanilla TypeScript / DOM (Core First) In pure JavaScript or TypeScript, instantiate the audio player using `createMediaPlayer({ type: 'audio' })`: ```ts import { createMediaPlayer, formatMediaTime, type MediaPlayerInstance } from '@nofinite/media'; import '@nofinite/nuicss/styles.css'; const container = document.getElementById('audio-container')!; // 1. Initialize Framework-Agnostic Audio Player const audioPlayer: MediaPlayerInstance = createMediaPlayer({ src: 'https://interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3', type: 'audio', title: 'Episode 42: Modern Open-Source Frontend Architecture', artist: 'Dr. Elena Rostova & Marcus Brody', artwork: 'https://images.unsplash.com/photo-1511671782779-c97d3d27a1d4?w=200', controls: true, autoplay: false, }); // 2. Mount into DOM container.appendChild(audioPlayer.element); // 3. Listen to player events audioPlayer.on('timeupdate', () => { const { currentTime, duration } = audioPlayer.getState(); console.log(`Progress: ${formatMediaTime(currentTime)} / ${formatMediaTime(duration)}`); }); audioPlayer.on('play', () => console.log('Audio is playing')); audioPlayer.on('pause', () => console.log('Audio paused')); // 4. Imperative operations // await audioPlayer.play(); // audioPlayer.setPlaybackRate(1.5); // audioPlayer.setVolume(0.7); // audioPlayer.seek(120); // 5. Cleanup // audioPlayer.destroy(); ``` --- ## 2. Usage in React In React applications, import `AudioPlayer` from `@nofinite/media/react`: ```tsx 'use client'; import React from 'react'; import { AudioPlayer } from '@nofinite/media/react'; import '@nofinite/nuicss/styles.css'; export default function PodcastEpisode() { return ( ); } ``` --- ## Features - **High-Resolution Scrubber:** Smooth, drag-to-seek timeline scrubber displaying elapsed and remaining duration formatted via `formatMediaTime()`. - **Metadata Card:** Built-in thumbnail preview, bold title, and artist byline with graceful truncation. - **Volume & Mute Slider:** Responsive volume slider with keyboard arrow increments and mute toggle. - **Playback Rate Menu:** Instant 0.75×, 1×, 1.25×, 1.5×, and 2× playback speed adjustment. - **Strict NUICSS Token Integration:** Completely styled using active NUICSS tokens (`.nui-media-container`, `.nui-vidstack-audio-player`). --- ## API Reference ### `createMediaPlayer(options)` Audio Options | Option | Type | Default | Description | | :--- | :--- | :--- | :--- | | `src` | `string` | **Required** | Audio source URL (MP3, WAV, OGG, AAC, HLS audio stream) | | `type` | `'audio'` | `'audio'` | Sets player to audio layout mode | | `title` | `string` | `undefined` | Episode or track title | | `artist` | `string` | `undefined` | Artist, podcast host, or author byline | | `artwork` | `string` | `undefined` | Album or episode cover art image URL | | `controls` | `boolean` | `true` | Whether to render the audio control layout | | `autoplay` | `boolean` | `false` | Start audio playback automatically | | `loop` | `boolean` | `false` | Loop track upon completion | | `seekStep` | `number` | `5` | Arrow key seek interval in seconds | --- ### React `` Props --- ### Document: media/custom-layouts/page.mdx # Headless Custom Player Layouts While turnkey players provide complete interfaces out of the box, applications frequently require **custom, brand-specific media experiences** (e.g. minimalist floating video widgets, background ambient loopers, or bespoke podcast bars). **Nofinite Media** is designed as a headless engine first: you can disable default controls (`controls: false`) and compose custom interfaces with standard HTML/DOM elements or declarative React components using **NUICSS** superclasses. ```ts // Framework-Agnostic Core (Zero React Dependency) import { createMediaPlayer, formatMediaTime } from '@nofinite/media'; // React Adapter (Headless Primitives & Hooks) import { MediaPlayer, MediaProvider, useMediaState, useMediaRemote, } from '@nofinite/media/react'; ``` --- ## 1. Usage in Vanilla TypeScript / DOM (Core First) In pure JavaScript or TypeScript, pass `controls: false` to `createMediaPlayer()`. This initializes the video engine without default control bars, allowing you to attach your own bespoke control elements: ```ts import { createMediaPlayer, formatMediaTime } from '@nofinite/media'; import '@nofinite/nuicss/styles.css'; const container = document.getElementById('headless-mount')!; // 1. Initialize Headless Video Player (No Default Controls) const player = createMediaPlayer({ src: 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4', type: 'video', aspectRatio: '16/9', controls: false, // Disables default Vidstack video layout autoplay: false, }); // 2. Mount Player Container container.appendChild(player.element); // 3. Build Custom Control Overlay in Vanilla DOM const overlay = document.createElement('div'); overlay.className = 'absolute inset-x-0 bottom-0 p-4 bg-gradient-to-t from-black/80 to-transparent flex items-center justify-between text-white text-xs z-10'; const playBtn = document.createElement('button'); playBtn.className = 'w-9 h-9 rounded-full bg-white/20 hover:bg-white/30 flex items-center justify-center font-bold transition-colors'; playBtn.textContent = '▶'; const timeDisplay = document.createElement('span'); timeDisplay.className = 'font-mono text-xs opacity-90'; timeDisplay.textContent = '0:00 / 0:00'; overlay.appendChild(playBtn); overlay.appendChild(timeDisplay); player.element.appendChild(overlay); // 4. Bind Control Logic to Player Instance playBtn.addEventListener('click', () => { const state = player.getState(); if (state.paused) { player.play(); } else { player.pause(); } }); player.on('play', () => { playBtn.textContent = '❚❚'; }); player.on('pause', () => { playBtn.textContent = '▶'; }); player.on('timeupdate', () => { const { currentTime, duration } = player.getState(); timeDisplay.textContent = `${formatMediaTime(currentTime)} / ${formatMediaTime(duration)}`; }); ``` --- ## 2. Usage in React In React, compose low-level headless primitives re-exported from `@nofinite/media/react`: ```tsx 'use client'; import React, { useRef } from 'react'; import { MediaPlayer, MediaProvider, useMediaState, useMediaRemote, type MediaPlayerInstance, } from '@nofinite/media/react'; import '@nofinite/nuicss/styles.css'; function CustomVideoControls() { const remote = useMediaRemote(); const paused = useMediaState('paused'); const currentTime = useMediaState('currentTime'); const duration = useMediaState('duration'); return ( ); } export function HeadlessVideoPlayer() { const playerRef = useRef(null); return ( ); } ``` --- ## Recipe: Ambient Hero Background Video Looper Zero-UI background video with muted autoplay and loop: ### Vanilla TypeScript ```ts const backgroundLooper = createMediaPlayer({ src: '/assets/ambient-aurora.mp4', type: 'video', controls: false, autoplay: true, muted: true, loop: true, playsinline: true, aspectRatio: '16/9', className: 'w-full h-full object-cover pointer-events-none opacity-40', }); document.getElementById('hero-background')!.appendChild(backgroundLooper.element); ``` ### React ```tsx ``` --- ### Document: media/examples/page.mdx # Media Production Examples Below are production-ready, copy-paste implementations of **Nofinite Media** showcasing adaptive HLS streaming, multi-language WebVTT captions, podcast players, and picture-in-picture widgets across pure Vanilla TypeScript and React architectures. --- ## Example 1: Pure Vanilla TypeScript Enterprise VOD Player (Core First) A complete framework-agnostic video implementation featuring adaptive HLS streaming (`.m3u8`), WebVTT multi-language subtitles, interactive chapter markers, storyboard thumbnail scrubbing, and telemetry event logging: ```ts import { createMediaPlayer, type MediaTrack, type MediaPlayerInstance } from '@nofinite/media'; import '@nofinite/nuicss/styles.css'; // 1. Setup Tracks Configuration const vodTracks: MediaTrack[] = [ { src: 'https://media.example.com/vod/subs-en.vtt', label: 'English [CC]', language: 'en', kind: 'subtitles', default: true, }, { src: 'https://media.example.com/vod/subs-es.vtt', label: 'Español', language: 'es', kind: 'subtitles', }, { src: 'https://media.example.com/vod/chapters.vtt', label: 'Chapters', language: 'en', kind: 'chapters', default: true, }, ]; const container = document.getElementById('vod-player-container')!; // 2. Initialize Framework-Agnostic VOD Player const player: MediaPlayerInstance = createMediaPlayer({ src: 'https://stream.mux.com/v69R127x00KSKGrGQgahP800ugny00JvlA.m3u8', type: 'video', poster: 'https://image.mux.com/v69R127x00KSKGrGQgahP800ugny00JvlA/thumbnail.webp?time=12', thumbnails: 'https://image.mux.com/v69R127x00KSKGrGQgahP800ugny00JvlA/storyboard.vtt', tracks: vodTracks, aspectRatio: '16/9', controls: true, autoplay: false, seekStep: 5, }); // 3. Mount Player directly to DOM container.appendChild(player.element); // 4. Analytics & Telemetry Tracking player.on('play', () => { console.log('Analytics: Playback started at', new Date().toISOString()); }); player.on('pause', () => { const state = player.getState(); console.log('Analytics: Paused at second', state.currentTime); }); // 5. Cleanup on route teardown window.addEventListener('beforeunload', () => { player.destroy(); }); ``` --- ## Example 2: Pure Vanilla TypeScript Podcast Player with OS Lock-Screen Sync A high-fidelity audio player with album artwork, chapter navigation, 15-second skip intervals, and hardware media key bindings: ```ts import { createMediaPlayer, formatMediaTime } from '@nofinite/media'; import '@nofinite/nuicss/styles.css'; const mountEl = document.getElementById('podcast-player-mount')!; const podcastPlayer = createMediaPlayer({ src: 'https://media.example.com/podcasts/ep58.mp3', type: 'audio', title: 'Autonomous Systems & Edge Isolates', artist: 'Nofinite Deep Dive Podcast • Ep. 58', artwork: 'https://images.unsplash.com/photo-1590602847861-f357a9332bbc?w=300', playbackRates: [0.75, 1, 1.25, 1.5, 2], seekStep: 15, // 15-second skip buttons tracks: [ { src: 'https://media.example.com/podcasts/ep58-chapters.vtt', label: 'Chapters', language: 'en', kind: 'chapters', default: true, }, ], controls: true, }); mountEl.appendChild(podcastPlayer.element); ``` --- ## Example 3: Enterprise VOD Player in React Featuring adaptive HLS streaming (`.m3u8`), WebVTT multi-language subtitles, interactive chapter markers, and thumbnail frame scrubbing: ```tsx 'use client'; import React from 'react'; import { VideoPlayer, type MediaTrack } from '@nofinite/media/react'; import '@nofinite/nuicss/styles.css'; const vodTracks: MediaTrack[] = [ { src: 'https://media.example.com/vod/subs-en.vtt', label: 'English [CC]', language: 'en', kind: 'subtitles', default: true, }, { src: 'https://media.example.com/vod/chapters.vtt', label: 'Chapters', language: 'en', kind: 'chapters', default: true, }, ]; export function EnterpriseVodPlayer() { return ( ); } ``` --- ## Example 4: Technical Podcast Show in React A podcast player with album artwork, chapter navigation, 15-second skip buttons, speed selection, and OS lock-screen Media Session controls: ```tsx 'use client'; import React from 'react'; import { AudioPlayer } from '@nofinite/media/react'; import '@nofinite/nuicss/styles.css'; export function TechnicalPodcastPlayer() { return ( ); } ``` --- ### Document: media/installation/page.mdx # Installation & Setup Add `@nofinite/media` to your application. Built as a universal media player engine powered by W3C Custom Elements and styled strictly via **NUICSS** design tokens. --- ## 1. Install Package Install `@nofinite/media` using your preferred package manager: ```bash # pnpm pnpm add @nofinite/media # npm npm install @nofinite/media # yarn yarn add @nofinite/media # bun bun add @nofinite/media ``` > [!NOTE] > **Optional Peer Dependencies:** `react` and `react-dom` (`>= 18.0.0`) are **strictly optional** peer dependencies (`peerDependenciesMeta.react.optional: true`). If you are building with pure Vanilla TypeScript, Vue, Svelte, or Astro, you do **not** need to install React. --- ## 2. Import Styles Include `@nofinite/nuicss` in your application stylesheet or entry file: ```css /* In your global stylesheet (e.g. globals.css, main.css) */ @import "@nofinite/nuicss"; ``` Or in your JavaScript / TypeScript entry: ```ts import '@nofinite/nuicss/styles.css'; ``` > [!IMPORTANT] > **Zero Downstream CSS Invariant:** `@nofinite/nuicss` is the sole styling engine across the entire ecosystem. `@nofinite/media` does **not** compile or ship separate stylesheets. All player skins, control bars, scrubbers, volume sliders, and responsive aspect-ratio containers are defined in NUICSS superclasses (`.nui-media-container`, `.nui-vidstack-player`). --- ## 3. Verify Installation ### Option A: Framework-Agnostic / Core (Vanilla JS & TypeScript) Mount the player directly into any DOM element without React: ```ts import { createMediaPlayer } from '@nofinite/media'; import '@nofinite/nuicss/styles.css'; const mountTarget = document.getElementById('player')!; const player = createMediaPlayer({ src: 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4', type: 'video', controls: true, aspectRatio: '16/9', }); mountTarget.appendChild(player.element); player.on('play', () => console.log('Player is running!')); ``` --- ### Option B: React Application In React 18 or 19 (including Next.js App Router Client Components): ```tsx 'use client'; import React from 'react'; import { VideoPlayer } from '@nofinite/media/react'; import '@nofinite/nuicss/styles.css'; export function PlayerVerification() { return ( ); } ``` --- ## Direct HTML / CDN Usage (Zero-Build) You can also load the media player directly in plain HTML via ES module CDN: ```html Nofinite Media CDN Demo ``` --- ### Document: media/llms/page.mdx # LLMs.txt Documentation How to get tools like Cursor, Windsurf, GitHub Copilot, ChatGPT, and Claude to understand `@nofinite/media`. > [!TIP] > Looking for unified ecosystem presets or multi-package rules? Visit our central [AI Agents Hub](/ai). We support **LLMs.txt** files for making `@nofinite/media` video and audio player primitives directly available to large language models. --- ## Directory Overview The following machine-readable context files are available: - [`/media/llms.txt`](/media/llms.txt): The main LLMs index for `@nofinite/media`. - [`/media/llms-full.txt`](/media/llms-full.txt): Complete context bundle containing VideoPlayer and AudioPlayer APIs. - [`/llms.txt`](/llms.txt): Ecosystem index covering all 8 `@nofinite` libraries. - [`/llms-full.txt`](/llms-full.txt): The unified ecosystem bundle. --- ## Usage with Cursor & Windsurf ```markdown # Media Rules for AI Assistants 1. Framework-Agnostic Core First: Use `createMediaPlayer` from `@nofinite/media` for universal DOM mounting and zero-framework apps. For React, use `VideoPlayer` and `AudioPlayer` from `@nofinite/media/react`. 2. Custom Skins: Media controls strictly inherit `@nofinite/nuicss` tokens (`bg-surface`, `backdrop-blur-md`). Never create separate downstream CSS. 3. Streaming: Supports HLS (`.m3u8`), DASH (`.mpd`), and standard MP4/WebM/MP3 sources with automatic manifest detection. ``` --- ### Document: media/page.mdx --- ## Interactive Preview --- ## Architectural Invariants - **Framework-Agnostic Core First (`@nofinite/media`):** Universal DOM player engine powered by W3C Custom Elements (``, ``) and native browser APIs. Zero runtime dependencies on React. - **Optional React Adapter (`@nofinite/media/react`):** Declarative `` and `` wrappers and reactive hooks (`useMediaState`, `useMediaRemote`). In `package.json`, `peerDependenciesMeta.react.optional` is strictly `true`. - **Zero Downstream CSS Invariant:** All media controls, scrubber timelines, volume bars, and modal drawers are governed directly by **NUICSS** superclasses (`.nui-media-container`, `.nui-vidstack-player`). Never import secondary CSS files. - **Adaptive Bitrate Streaming (HLS/DASH):** Native hardware playback on Apple WebKit and automated MSE `hls.js` demuxing on Chrome, Firefox, and Edge. --- ## Key Capabilities - **Adaptive Bitrate Streaming:** Automatic `.m3u8` manifest detection, multi-resolution quality switching, and live stream DVR windows. - **WebVTT Tracks & Subtitles:** Multi-language subtitles, closed captions, and chapter navigation notches. - **Interactive Thumbnail Scrubbers:** Visual video frame previews on timeline hover via WebVTT sprite coordinates. - **Podcast Audio Player:** High-resolution album artwork, artist bylines, 15s skip buttons, and OS Lock-Screen Media Session synchronization. - **Headless Custom Layouts:** Low-level primitives (``, ``) for composing bespoke floating mini-players, background loopers, or sticky bars. - **Deep React Hooks:** Fine-grained reactive state hooks (`useMediaState`, `useMediaRemote`, `useVideoQualityOptions`, `useCaptionOptions`). --- ## Quickstart ### 1. Usage in Vanilla TypeScript / DOM (Core First) ```ts import { createMediaPlayer } from '@nofinite/media'; import '@nofinite/nuicss/styles.css'; const container = document.getElementById('media-container')!; // 1. Initialize universal media player const player = createMediaPlayer({ src: 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4', type: 'video', poster: 'https://images.unsplash.com/photo-1618005182384-a83a8bd57fbe?w=1200', aspectRatio: '16/9', controls: true, autoplay: false, }); // 2. Mount directly into the DOM container.appendChild(player.element); // 3. Listen to player lifecycle events player.on('play', () => console.log('Playback started')); player.on('timeupdate', () => { const state = player.getState(); console.log(`Current position: ${state.currentTime} / ${state.duration}`); }); // 4. Imperative controls // player.seek(30); // player.enterFullscreen(); // player.destroy(); ``` --- ### 2. Usage in React ```tsx 'use client'; import React from 'react'; import { VideoPlayer } from '@nofinite/media/react'; import '@nofinite/nuicss/styles.css'; export default function MediaDemo() { return ( ); } ``` --- ## Framework Integration Recipes ### Vue 3 (Composition API) ```vue