# 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
```
---
## Documentation Directory
### Advanced Architecture & Deep Guides
- [Adaptive Bitrate Streaming & HLS](/media/streaming-and-hls) — Manifest detection, MSE buffer pipelines, quality selection, and live DVR streams.
- [Tracks, Captions & Scrubbers](/media/tracks-and-captions) — Multi-language WebVTT subtitles, chapter markers, and visual thumbnail scrubbing.
- [Headless Custom Layouts](/media/custom-layouts) — Composing bespoke player UIs with custom element layout or low-level primitives.
- [Podcast & Audio Players](/media/podcast-and-audio) — High-fidelity audio playback, artwork, chapters, and OS lock-screen Media Session API.
- [React Media Hooks](/media/react-hooks) — Fine-grained reactive state management with `useMediaState`, `useMediaRemote`, and track selectors.
- [Production Examples](/media/examples) — Enterprise VOD Player, Technical Podcast Player, and Floating Picture-in-Picture Widget.
### Components & Setup
- [VideoPlayer](/media/video-player) — Adaptive video player with HLS streaming, captions, and poster setup.
- [AudioPlayer](/media/audio-player) — Audio streaming with track scrubber, volume control, and metadata cards.
- [Installation & Setup](/media/installation) — Package installation, peer dependencies, and styling configuration.
---
### Document: media/podcast-and-audio/page.mdx
# Podcast and Audio Players
**Nofinite Media** provides a dedicated audio playback engine tailored for technical podcasts, audiobook narrations, music streaming, and interviews.
It incorporates high-resolution album artwork, artist bylines, chapter markers, speed presets, and automated **OS Lock-Screen Media Session** integration.
```ts
// Framework-Agnostic Core (Zero React Dependency)
import { createMediaPlayer, formatMediaTime } from '@nofinite/media';
// React Adapter
import { AudioPlayer } from '@nofinite/media/react';
```
---
## 1. Usage in Vanilla TypeScript / DOM (Core First)
In pure JavaScript or TypeScript, initialize the podcast player using `createMediaPlayer({ type: 'audio' })`:
```ts
import { createMediaPlayer, formatMediaTime, type MediaPlayerInstance } from '@nofinite/media';
import '@nofinite/nuicss/styles.css';
const container = document.getElementById('podcast-root')!;
// 1. Initialize Podcast Audio Player
const podcastPlayer: MediaPlayerInstance = createMediaPlayer({
src: 'https://media.example.com/podcasts/episode-42.mp3',
type: 'audio',
title: 'Episode 42: The Future of Single-Engine CSS Invariants',
artist: 'Nofinite Engineering Podcast • Hosted by Sarah Chen',
artwork: 'https://images.unsplash.com/photo-1590602847861-f357a9332bbc?w=300',
seekStep: 15, // 15-second skip intervals tailored for podcast dialogue
playbackRates: [0.75, 1, 1.25, 1.5, 2],
tracks: [
{
src: 'https://media.example.com/podcasts/episode-42-chapters.vtt',
label: 'Chapters',
language: 'en',
kind: 'chapters',
default: true,
},
],
controls: true,
autoplay: false,
});
// 2. Mount player element into DOM
container.appendChild(podcastPlayer.element);
// 3. Listen to playback telemetry
podcastPlayer.on('timeupdate', () => {
const { currentTime, duration } = podcastPlayer.getState();
console.log(`Episode progress: ${formatMediaTime(currentTime)} / ${formatMediaTime(duration)}`);
});
// 4. Imperative seek operations
// podcastPlayer.seek(180); // Jump directly to Chapter 2
```
---
## 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 function PodcastEpisodePlayer() {
return (
);
}
```
---
## OS Lock-Screen Media Session API Integration
When an audio track starts playing, the engine automatically registers with the browser's native `navigator.mediaSession` API:
- **Title & Artist:** Synced to `title` and `artist` metadata options.
- **Cover Artwork:** Provides responsive square artwork displayed on lock screens and system notification banners (iOS, Android, macOS Control Center, and Windows Media Overlay).
- **Hardware Multimedia Keys:** Automatically responds to system keyboard shortcuts:
- Play / Pause (⏯)
- Seek Backward 15s (⏮)
- Seek Forward 15s (⏭)
- **Background Audio:** Seamlessly continues playing audio when mobile screens lock or when switching browser tabs.
---
### Document: media/react-hooks/page.mdx
# React Media Hooks & Core Event Architecture
**Nofinite Media** provides a dual-model state architecture:
1. **Core Event & State API (`@nofinite/media`):** Universal, zero-framework DOM event listeners and synchronous `player.getState()` queries.
2. **React Hooks Suite (`@nofinite/media/react`):** Granular reactive hooks that subscribe to media states without triggering unnecessary component re-renders.
---
## 1. Core Event & State API in Vanilla TypeScript (Core First)
In pure JavaScript/TypeScript, reactive UI updates are implemented via `player.on()` and `player.getState()`:
```ts
import { createMediaPlayer, type MediaPlayerState } from '@nofinite/media';
import '@nofinite/nuicss/styles.css';
const player = createMediaPlayer({
src: 'https://media.example.com/stream.mp4',
type: 'video',
});
// 1. Synchronous State Inspection
const state: MediaPlayerState = player.getState();
console.log({
paused: state.paused,
currentTime: state.currentTime,
duration: state.duration,
volume: state.volume,
buffered: state.buffered,
});
// 2. Lifecycle Event Subscriptions
const unsubscribePlay = player.on('play', () => {
console.log('Playback commenced');
});
const unsubscribeTime = player.on('timeupdate', () => {
const current = player.getState().currentTime;
console.log(`Current time: ${current}s`);
});
// 3. Clean up listeners when done
// unsubscribePlay();
// unsubscribeTime();
```
---
## 2. React Hooks Suite (`@nofinite/media/react`)
When building inside React component hierarchies under ``, hooks re-exported from `@nofinite/media/react` provide declarative bindings:
| Hook | Returns | Primary Purpose |
| :--- | :--- | :--- |
| **`useMediaRemote`** | `MediaRemoteControl` | Dispatches transport commands (`play`, `pause`, `seek`, `changeVolume`, `fullscreen`) |
| **`useMediaState`** | Reactive value | Subscribes to fine-grained player state properties (`paused`, `currentTime`, `duration`, `buffered`) |
| **`useMediaPlayer`** | `MediaPlayerInstance \| null` | Accesses the underlying DOM player instance and low-level methods |
| **`useVideoQualityOptions`** | Array of quality options | Lists adaptive HLS video resolutions with a `.select(quality)` method |
| **`useCaptionOptions`** | Array of text tracks | Lists available subtitle languages with a `.select(lang)` method |
| **`usePlaybackRateOptions`** | Array of playback speeds | Lists playback rates (`0.75x`–`2x`) with a `.select(rate)` method |
---
### React Transport Controls Example
```tsx
'use client';
import React from 'react';
import { useMediaRemote, useMediaState } from '@nofinite/media/react';
export function CustomTransportControls() {
const remote = useMediaRemote();
const paused = useMediaState('paused');
const currentTime = useMediaState('currentTime');
const duration = useMediaState('duration');
return (
);
}
```
---
### React Adaptive Quality Selector Example
```tsx
'use client';
import React from 'react';
import { useVideoQualityOptions } from '@nofinite/media/react';
export function QualitySelector() {
const options = useVideoQualityOptions();
if (!options || options.length === 0) return null;
return (
);
}
```
---
### Document: media/streaming-and-hls/page.mdx
# Adaptive Bitrate Streaming and HLS
**Nofinite Media** provides built-in, zero-configuration support for **HTTP Live Streaming (HLS)** (`.m3u8`) and **Dynamic Adaptive Streaming over HTTP (DASH)** (`.mpd`) video distribution.
The engine automatically detects streaming manifests, dynamically loads the lightweight MSE demuxing engine on Chromium and Firefox, and seamlessly utilizes native Apple AVFoundation hardware decoding on Safari and iOS WebKit.
```ts
// Framework-Agnostic Core (Zero React Dependency)
import { createMediaPlayer, isHlsSource, isDashSource } from '@nofinite/media';
// React Adapter
import { VideoPlayer } from '@nofinite/media/react';
```
---
## Manifest Detection Architecture
The core player evaluates source URLs using internal pattern matchers before requesting the stream:
```ts
import { isHlsSource, isDashSource } from '@nofinite/media';
console.log(isHlsSource('https://stream.mux.com/v69R127x.m3u8')); // true
console.log(isDashSource('https://dash.example.com/stream.mpd')); // true
console.log(isHlsSource('https://cdn.example.com/asset.mp4')); // false
```
When an `.m3u8` source is detected:
1. **Apple WebKit (macOS / iOS Safari):** The browser's native hardware decoder executes the stream with maximum power efficiency and FairPlay DRM support.
2. **Chromium & Firefox:** The engine automatically initializes an MSE (Media Source Extensions) worker, downloads the master manifest, and negotiates video/audio elementary streams.
---
## 1. Usage in Vanilla TypeScript / DOM (Core First)
In pure JavaScript or TypeScript, pass the `.m3u8` or `.mpd` URL directly to `createMediaPlayer()`:
```ts
import { createMediaPlayer, isHlsSource } from '@nofinite/media';
import '@nofinite/nuicss/styles.css';
const container = document.getElementById('streaming-mount')!;
const hlsStreamUrl = 'https://stream.mux.com/v69R127x00KSKGrGQgahP800ugny00JvlA.m3u8';
// Verify manifest format
if (isHlsSource(hlsStreamUrl)) {
console.log('Detected valid HLS manifest stream');
}
// 1. Initialize Adaptive Stream Player
const player = createMediaPlayer({
src: hlsStreamUrl,
type: 'video',
poster: 'https://image.mux.com/v69R127x00KSKGrGQgahP800ugny00JvlA/thumbnail.webp?time=2',
title: 'Distributed Cloud Architecture Keynote',
aspectRatio: '16/9',
controls: true,
autoplay: false,
});
// 2. Mount player into DOM
container.appendChild(player.element);
// 3. Listen for streaming lifecycle events
player.on('canplay', () => console.log('HLS manifest loaded; ready to stream'));
player.on('waiting', () => console.log('Buffering next segment chunks...'));
player.on('error', (err) => console.error('Streaming error detected:', err));
```
---
## 2. Usage in React
In React applications, import `VideoPlayer` from `@nofinite/media/react`:
```tsx
'use client';
import React from 'react';
import { VideoPlayer } from '@nofinite/media/react';
import '@nofinite/nuicss/styles.css';
export function HlsStreamPlayer() {
return (
);
}
```
---
## Live Streaming with DVR Windows
For live broadcasts, the player supports real-time stream synchronization and live DVR timeline scrub navigation (jumping backward into live buffer cache and clicking "Live" to return to edge):
### Vanilla TypeScript Live Stream
```ts
const livePlayer = createMediaPlayer({
src: 'https://live.example.com/broadcast/event.m3u8',
type: 'video',
title: 'Keynote Address (Live Broadcast)',
controls: true,
autoplay: true,
muted: true, // Recommended for browser autoplay compliance
});
document.getElementById('live-mount')!.appendChild(livePlayer.element);
```
### React Live Stream
```tsx
```
---
## Network Resiliency & Auto Quality Adaptation
The adaptive bitrate (ABR) engine measures network bandwidth in real time during chunk downloads:
- **Bandwidth Throttling:** If network throughput drops, the player seamlessly steps down resolution (e.g., `1080p` → `720p` → `480p`) to eliminate buffering pauses.
- **Bandwidth Recovery:** When connection stabilizes, the player automatically steps back up to higher bitrates without interrupting audio.
- **Manual Quality Override:** Users can click the settings gear in the player toolbar to lock playback to specific target resolutions (`1080p`, `720p`, `480p`, or `Auto`).
---
### Document: media/tracks-and-captions/page.mdx
# Tracks, Captions, and Thumbnail Scrubbers
**Nofinite Media** provides comprehensive support for WebVTT text tracks, covering multi-language closed captions, subtitles, interactive chapter markers, and timeline thumbnail scrubbing.
```ts
// Framework-Agnostic Core (Zero React Dependency)
import { createMediaPlayer, type MediaTrack } from '@nofinite/media';
// React Adapter
import { VideoPlayer } from '@nofinite/media/react';
```
---
## 1. Usage in Vanilla TypeScript / DOM (Core First)
In pure JavaScript or TypeScript, pass an array of `MediaTrack` objects and a storyboard `.vtt` URL to `createMediaPlayer()`:
```ts
import { createMediaPlayer, type MediaTrack } from '@nofinite/media';
import '@nofinite/nuicss/styles.css';
const container = document.getElementById('player-root')!;
// 1. Define Subtitle, Caption & Chapter Tracks
const tracks: MediaTrack[] = [
{
src: 'https://media.example.com/subs/en.vtt',
label: 'English',
language: 'en',
kind: 'subtitles',
default: true,
},
{
src: 'https://media.example.com/subs/es.vtt',
label: 'Español',
language: 'es',
kind: 'subtitles',
},
{
src: 'https://media.example.com/chapters/architecture.vtt',
label: 'Chapters',
language: 'en',
kind: 'chapters',
default: true,
},
];
// 2. Initialize Media Player with WebVTT Tracks & Storyboard Thumbnails
const player = createMediaPlayer({
src: 'https://stream.mux.com/v69R127x00KSKGrGQgahP800ugny00JvlA.m3u8',
type: 'video',
tracks,
thumbnails: 'https://image.mux.com/v69R127x00KSKGrGQgahP800ugny00JvlA/storyboard.vtt',
aspectRatio: '16/9',
controls: true,
});
// 3. Mount into DOM
container.appendChild(player.element);
```
---
## 2. Usage in React
In React applications, pass `tracks` and `thumbnails` directly to ``:
```tsx
'use client';
import React from 'react';
import { VideoPlayer, type MediaTrack } from '@nofinite/media/react';
import '@nofinite/nuicss/styles.css';
const videoTracks: MediaTrack[] = [
{
src: 'https://media.example.com/subs/en.vtt',
label: 'English',
language: 'en',
kind: 'subtitles',
default: true,
},
{
src: 'https://media.example.com/subs/es.vtt',
label: 'Español',
language: 'es',
kind: 'subtitles',
},
{
src: 'https://media.example.com/chapters/architecture.vtt',
label: 'Chapters',
language: 'en',
kind: 'chapters',
default: true,
},
];
export function CaptionedVideoPlayer() {
return (
);
}
```
---
## WebVTT Track Formats
### 1. Subtitles & Closed Captions (`subtitles.vtt`)
Standard WebVTT time-coded cues for dialog translation and accessibility:
```vtt
WEBVTT
00:00:01.000 --> 00:00:04.500
Welcome to the Nofinite Media architecture deep dive.
00:00:05.000 --> 00:00:09.000
In this session, we examine framework-agnostic video pipelines.
```
### 2. Interactive Chapter Notches (`chapters.vtt`)
Chapters generate interactive visual segments along the timeline scrubber with title tooltip callouts:
```vtt
WEBVTT
00:00:00.000 --> 00:02:15.000
1. Executive Summary & Overview
00:02:15.000 --> 00:07:45.000
2. Custom Element Video Pipelines
00:07:45.000 --> 00:15:30.000
3. ABR Manifest Demuxing (HLS/DASH)
```
### 3. Storyboard Thumbnails (`thumbnails.vtt`)
Thumbnail scrubbers allow viewers to preview video frames by hovering over the timeline scrubber before seeking. Coordinates reference a mosaic sprite sheet:
```vtt
WEBVTT
00:00:00.000 --> 00:00:05.000
/sprites/storyboard.webp#xywh=0,0,160,90
00:00:05.000 --> 00:00:10.000
/sprites/storyboard.webp#xywh=160,0,160,90
00:00:10.000 --> 00:00:15.000
/sprites/storyboard.webp#xywh=320,0,160,90
```
---
## `MediaTrack` Interface Reference
```ts
export interface MediaTrack {
/** URL to the .vtt track file */
src: string;
/** Human-readable label displayed in the settings track picker */
label: string;
/** Two-letter BCP 47 language code (e.g. 'en', 'es', 'fr', 'ja') */
language: string;
/** Track role: 'subtitles' | 'captions' | 'chapters' | 'descriptions' | 'metadata' */
kind?: 'subtitles' | 'captions' | 'chapters' | 'descriptions' | 'metadata';
/** Set to true to activate track by default */
default?: boolean;
}
```
---
### Document: media/video-player/page.mdx
# VideoPlayer
**Nofinite Media** provides a universal, responsive video playback engine supporting MP4, WebM, HLS, and DASH streaming with keyboard shortcuts, picture-in-picture, multi-language WebVTT subtitles, and hardware-accelerated playback.
```ts
// Framework-Agnostic Core (Zero React Dependency)
import { createMediaPlayer, isHlsSource } from '@nofinite/media';
// React Adapter
import { VideoPlayer } from '@nofinite/media/react';
```
---
## Interactive Preview
---
## 1. Usage in Vanilla TypeScript / DOM (Core First)
In pure JavaScript or TypeScript, instantiate the video player using `createMediaPlayer()`. It returns a lifecycle-managed instance that mounts directly to any DOM element:
```ts
import { createMediaPlayer, type MediaPlayerInstance } from '@nofinite/media';
import '@nofinite/nuicss/styles.css';
const container = document.getElementById('player-root')!;
// 1. Initialize Video Player
const player: MediaPlayerInstance = createMediaPlayer({
src: 'https://stream.mux.com/VZtzUzGRv02OhRnZCxcNg49OilvolTqTtjhqNZNUxMm300.m3u8',
type: 'video',
poster: 'https://images.unsplash.com/photo-1618005182384-a83a8bd57fbe?w=1200',
aspectRatio: '16/9',
controls: true,
autoplay: false,
seekStep: 5,
tracks: [
{
src: '/captions/en.vtt',
kind: 'subtitles',
label: 'English',
language: 'en',
default: true,
},
{
src: '/captions/es.vtt',
kind: 'subtitles',
label: 'Español',
language: 'es',
},
],
});
// 2. Mount player into document DOM
container.appendChild(player.element);
// 3. Attach event listeners
player.on('play', () => console.log('Playback started'));
player.on('pause', () => console.log('Playback paused'));
player.on('timeupdate', () => {
const state = player.getState();
console.log(`Playback time: ${state.currentTime}s of ${state.duration}s`);
});
// 4. Imperative API operations
// await player.play();
// player.seek(45);
// player.setVolume(0.8);
// await player.enterPictureInPicture();
// await player.enterFullscreen();
// 5. Cleanup when disposing
// player.destroy();
```
---
## 2. Usage in React
In React applications, import `VideoPlayer` from `@nofinite/media/react`:
```tsx
'use client';
import React from 'react';
import { VideoPlayer } from '@nofinite/media/react';
import '@nofinite/nuicss/styles.css';
export function ReactVideoDemo() {
return (
);
}
```
---
## Features
### 1. MP4 and Adaptive Streaming (HLS & DASH)
Accepts local or remote video URLs. HLS streams (`.m3u8`) and DASH streams (`.mpd`) are automatically detected and decoded via MSE pipelines:
```ts
// 1. Standard MP4
const mp4Player = createMediaPlayer({
src: 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4',
type: 'video',
});
// 2. HLS Adaptive Stream (.m3u8)
const hlsPlayer = createMediaPlayer({
src: 'https://stream.mux.com/VZtzUzGRv02OhRnZCxcNg49OilvolTqTtjhqNZNUxMm300.m3u8',
type: 'video',
});
```
### 2. Captions & Subtitles
Pass subtitle tracks using standard HTML track definitions:
```ts
const player = createMediaPlayer({
src: '/videos/keynote.mp4',
tracks: [
{
src: '/captions/en.vtt',
kind: 'subtitles',
label: 'English',
language: 'en',
default: true,
},
{
src: '/captions/de.vtt',
kind: 'subtitles',
label: 'Deutsch',
language: 'de',
},
],
});
```
---
## Keyboard Shortcuts
Both vanilla and React players support standard accessible keyboard shortcuts out of the box:
| Shortcut | Action |
| :--- | :--- |
| Space / K | Toggle Play / Pause |
| → / ← | Seek forward / backward 5 seconds |
| ↑ / ↓ | Increase / decrease volume 5% |
| M | Toggle Mute |
| F | Toggle Fullscreen |
| P | Toggle Picture-in-Picture |
| C | Toggle Closed Captions |
---
## API Reference
### `createMediaPlayer(options)` Options
| Option | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `src` | `string` | **Required** | Video source URL (MP4, WebM, HLS `.m3u8`, DASH `.mpd`) |
| `type` | `'video' \| 'audio'` | `'video'` | Media view type |
| `poster` | `string` | `undefined` | Preview image URL displayed prior to playback |
| `aspectRatio` | `string` | `'16/9'` | Container aspect ratio (e.g. `'16/9'`, `'4/3'`, `'1/1'`) |
| `controls` | `boolean` | `true` | Whether to render the default UI control layout |
| `autoplay` | `boolean` | `false` | Whether to begin playback immediately |
| `loop` | `boolean` | `false` | Whether to loop the video upon reaching the end |
| `muted` | `boolean` | `false` | Start muted |
| `playsinline` | `boolean` | `true` | Prevent mobile browser from forcing native fullscreen |
| `tracks` | `MediaTrack[]` | `[]` | Array of subtitle, caption, or chapter track definitions |
| `thumbnails` | `string` | `undefined` | WebVTT sprite storyboard URL for timeline hover scrub previews |
| `seekStep` | `number` | `5` | Number of seconds to jump during arrow key seeks |
---
### React `` Props
---