zenith-player
v1.1.2
Published
Enterprise React Video Player
Maintainers
Keywords
Readme
Zenith Player
The next-generation React Video Player SDK — a developer-first, headless, and highly extensible media player for modern streaming and enterprise applications (OTT, LMS/e-learning, webinars, corporate training, product demos).
Highlights
- 🎛️ Headless + polished UI — composable hooks with a beautiful, themeable control bar.
- 📺 Streaming — HLS and MPEG-DASH via lazy-loaded adapters; MP4 and custom sources.
- 🎚️ Quality — YouTube-style selector with auto (ABR-aware) mode, badges, and session memory.
- 🧩 Interactive timeline — images, PDFs, Office docs, YouTube/Vimeo, quizzes, polls, forms, CTAs, and custom React viewers at any timestamp.
- 📢 Advertising — pre/mid/post-roll, overlay, companion; VAST/VMAP with quartile tracking (VPAID extension hook).
- 📡 Casting — Chromecast (with remote media + subtitle sync) and AirPlay.
- 🖼️ Thumbnails — sprite sheet or WebVTT hover/scrub previews.
- 🔐 DRM — Widevine, PlayReady, and FairPlay via EME.
- ♿ Accessible — keyboard shortcuts, ARIA roles, focus management.
- 🟦 TypeScript-first — full types for every prop, hook, and event.
Packages
| Package | Description |
| --- | --- |
| zenith-player | Core SDK (component, hooks, UI, ads, timeline, casting, thumbnails, DRM). |
| zenith-hls-adapter | HLS playback adapter (hls.js). |
| zenith-dash-adapter | MPEG-DASH playback adapter (dash.js). |
Installation
npm install zenith-player
# streaming adapters (optional, install what you need)
npm install zenith-hls-adapter # HLS (.m3u8)
npm install zenith-dash-adapter # DASH (.mpd)Peer dependencies: react >= 18 and react-dom >= 18. Node.js 18+ for tooling/CI.
Quick Start
import { ZenithPlayer } from "zenith-player";
// Styles auto-apply on import; this line is optional (override hook):
import "zenith-player/styles.css";
export function App() {
return (
<ZenithPlayer
src="https://cdn.example.com/video.mp4"
poster="https://cdn.example.com/poster.jpg"
controls
/>
);
}Styles are inlined into the JS bundle, so importing zenith-player applies them automatically. Import zenith-player/styles.css only if you want to control load order or override.
Plugin API
ZenithPlayer.use({
name: "custom-analytics",
setup(api) {
const unsubscribe = api.subscribe(() => {
const state = api.getState();
if (state.playbackState === "playing") {
api.emit({ name: "heartbeat", at: Date.now() });
}
});
return () => unsubscribe();
},
});HLS Adapter
import { ZenithPlayer } from "zenith-player";
const { createHlsAdapter } = await import("zenith-hls-adapter");
ZenithPlayer.use(createHlsAdapter({ emitHlsEvents: true, lowLatencyMode: true }));DASH Adapter
import { ZenithPlayer } from "zenith-player";
const { createDashAdapter } = await import("zenith-dash-adapter");
ZenithPlayer.use(createDashAdapter({ emitDashEvents: true }));Source-Aware Adapter Orchestration
ZenithPlayer.registerAdapter({
id: "hls",
matcher: (src) => /\.m3u8([?#].*)?$/i.test(src),
load: async () => {
const { createHlsAdapter } = await import("zenith-hls-adapter");
return createHlsAdapter();
},
});
ZenithPlayer.registerAdapter({
id: "dash",
matcher: (src) => /\.mpd([?#].*)?$/i.test(src),
load: async () => {
const { createDashAdapter } = await import("zenith-dash-adapter");
return createDashAdapter();
},
});Ads Plugin Contract
import { ZenithPlayer, createAdsPlugin } from "zenith-player";
ZenithPlayer.use(
createAdsPlugin({
async requestBreaks(context) {
return [
{
id: `preroll-${context.sourceIndex}`,
placement: "pre",
tagUrl: "https://example.com/vast.xml",
},
];
},
}),
);Quality Selection (YouTube-style)
Zenith Player ships a built-in, fully customizable quality selector with an intelligent Auto mode.
Multi-resolution sources (MP4 / custom)
<ZenithPlayer
sources={[
{ label: "360p", src: "/videos/video-360.mp4", type: "video/mp4" },
{ label: "720p", src: "/videos/video-720.mp4", type: "video/mp4" },
{ label: "1080p", src: "/videos/video-1080.mp4", type: "video/mp4" },
]}
defaultQuality="auto"
onQualityChange={(quality) => console.log("Quality changed:", quality)}
onAutoQualityEnabled={() => console.log("Auto enabled")}
onAutoQualityDisabled={() => console.log("Auto disabled")}
/>- HLS (.m3u8) and MPEG-DASH (.mpd) qualities are driven seamlessly through the streaming adapters (no restart, position preserved).
- MP4 / custom sources switch by swapping the media source while preserving the current time and play state.
API
const {
qualities,
currentQuality,
isAutoQuality,
setQuality,
setAutoQuality,
} = useZenithPlayer();
// or the focused hook:
const q = useQuality();Behavior
- Auto mode adapts to bandwidth, buffer health, and device/screen resolution.
- Active quality is highlighted with a checkmark; HD / Full HD / 2K / 4K badges are shown automatically.
- The selected quality is remembered for the session and falls back gracefully when unavailable.
- A subtle toast shows the newly selected quality (e.g.
Quality: 720p HD).
Customization (CSS variables)
.zenith-player {
--zenith-menu-bg: rgba(15, 18, 26, 0.96);
--zenith-menu-fg: #f3f7fa;
--zenith-accent: #4f9cff;
--zenith-badge-bg: #3563ff;
--zenith-menu-radius: 12px;
--zenith-menu-font: "Inter", sans-serif;
}The menu markup uses stable class names (zenith-menu, zenith-menu-option, zenith-badge, ...) so it can be themed with plain CSS, CSS Modules, Tailwind, styled-components, or Emotion. Set qualityMenu={false} to render your own UI with the hooks above.
Dynamic Configuration (JSON-driven)
Pass video, timeline events, advertisements, and DRM entirely as data.
import { ZenithPlayer, type ZenithVideoConfig, type TimelineEvent, type AdBreak } from "zenith-player";
const video: ZenithVideoConfig = {
id: "video-001",
title: "React Advanced Course",
poster: "https://cdn.example.com/poster.jpg",
sources: [
{ label: "1080p", src: "https://cdn.example.com/1080.mp4", type: "video/mp4" },
{ label: "720p", src: "https://cdn.example.com/720.mp4", type: "video/mp4" },
],
};
<ZenithPlayer
source={video}
timelineEvents={timelineEvents}
advertisements={advertisements}
drm={drm}
/>;Interactive Timeline Events (Stimuli)
Attach content to any timestamp. The correct viewer is chosen automatically from type.
const timelineEvents: TimelineEvent[] = [
{ id: "img-1", time: 45, type: "image", title: "Diagram", url: "/img/arch.png", trigger: "auto", display: "modal" },
{ id: "pdf-1", time: 120, type: "pdf", title: "Docs", url: "/docs/guide.pdf", trigger: "pause", display: "sidebar" },
{ id: "quiz-1", time: 300, type: "quiz", trigger: "pause", quiz: { question: "…", options: [{ id: "a", label: "A", correct: true }] } },
];- Types:
image,pdf,document,word,excel,ppt/powerpoint,chart,html,markdown,video,audio,youtube,vimeo,iframe/embed/webpage,quiz,poll,survey/form,product,cta,download,link,component, or any custom string. - Triggers:
auto(open on reach),pause(pause + open),click(marker only),notify(toast),overlay/sidebar(open while playing). - Display modes:
modal,side-panel,side-panel-left,bottom-drawer,floating-card,pip,fullscreen.
Custom viewers
ZenithPlayer.registerStimulusType("whiteboard", ({ event }) => <MyWhiteboard event={event} />);Runtime updates (no reload)
const timeline = useTimelineEvents();
timeline.addEvent(event);
timeline.updateEvent(id, { title: "New title" });
timeline.removeEvent(id);Callbacks
onTimelineEvent, onMarkerClick, onOverlayOpen, onOverlayClose, onTimelineMarkerReached, onTimelineMarkerSkipped, onStimulusStart, onStimulusEnd, onStimulusClick, onTimelineInteraction.
Advertising (VAST / VMAP / VPAID)
<ZenithPlayer
source={video}
advertising={{
vastUrl: "https://adserver.example.com/vast.xml",
vmapUrl: "https://adserver.example.com/vmap.xml",
vpaidMode: "disabled", // graceful fallback; set "enabled" to allow VPAID
}}
onAdStarted={(ad) => track("ad_start", ad)}
onAdFirstQuartile={(ad) => track("q1", ad)}
onAdCompleted={(ad) => track("complete", ad)}
/>;Or configure ad breaks directly as JSON:
const advertisements: AdBreak[] = [
{ id: "pre", type: "pre-roll", url: "/ads/pre.mp4", skipAfter: 5, clickUrl: "https://example.com" },
{ id: "mid", type: "mid-roll", time: 300, url: "/ads/mid.mp4", skipAfter: 5 },
{ id: "post", type: "post-roll", url: "/ads/post.mp4" },
{ id: "overlay", type: "overlay", time: 60, duration: 10, url: "/ads/banner.png", clickUrl: "https://example.com" },
];- Types: pre-roll, mid-roll, post-roll, overlay, companion, interactive/clickable.
- VAST: wrapper following, ad pods/sequencing, multiple media files, skip offset, click-through, impression/quartile/error tracking pixels.
- VMAP: automatic pre/mid/post scheduling from
timeOffset. - The main video pauses, the ad plays, and playback resumes from the exact position on complete or skip.
- Callbacks:
onAdRequest,onAdLoaded,onAdStarted,onAdFirstQuartile,onAdMidpoint,onAdThirdQuartile,onAdCompleted,onAdSkipped,onAdClicked,onAdError,onAdImpression(plusonAdvertisementStart/End/Clickaliases).
Adaptive Bitrate (ABR)
<ZenithPlayer
source={video}
adaptiveStreaming={{ enabled: true, mode: "auto", minBuffer: 10, maxBuffer: 30, startupQuality: "720p" }}
/>;Auto quality selection considers bandwidth, buffer health, and device/screen resolution. Switching never restarts playback and preserves the current time.
Casting (Chromecast + AirPlay)
<ZenithPlayer
source={video}
casting={{ chromecast: true, airplay: true }}
onCastConnected={() => {}}
onCastDisconnected={() => {}}
/>;The Cast SDK is lazy-loaded. On connect, media (with subtitle tracks) is loaded onto the receiver at the current position; on disconnect, local playback resumes from where the receiver left off. Cast and AirPlay buttons appear automatically when a device is available.
Thumbnail Previews
// Sprite sheet
<ZenithPlayer source={video} thumbnails={{ sprite: "/sprites/video.jpg", width: 160, height: 90, columns: 10, interval: 10 }} />
// WebVTT (supports #xywh sprite fragments)
<ZenithPlayer source={video} thumbnails={{ vtt: "/thumbnails/video.vtt" }} />Hovering or scrubbing the progress bar shows a centered thumbnail + timestamp.
DRM (Widevine / PlayReady / FairPlay)
<ZenithPlayer
source={video}
drm={{
widevine: { licenseUrl: "https://license.example.com/widevine" },
playready: { licenseUrl: "https://license.example.com/playready" },
fairplay: { licenseUrl: "https://license.example.com/fairplay", certificateUrl: "https://license.example.com/fairplay.cer" },
}}
/>;DRM is applied through hls.js/dash.js for MSE playback and via native EME for progressive/FairPlay. Requires a secure (HTTPS) origin and a license server. Advanced hooks: prepareLicenseRequest, prepareLicenseResponse, and per-request headers.
Hooks
import {
useZenithPlayer, // full player state + controls
usePlayback, // play/pause/seek/rate
usePlaylist, // playlist navigation
useFullscreen,
useQuality, // qualities, currentQuality, setQuality, setAutoQuality
useSubtitles,
useAnalytics, // event stream + emit
useTimelineEvents, // events, open/close, add/remove/update
useAds, // ads, addAd/removeAd, skip
useThumbnails,
useChromecast,
useAirPlay,
useAdaptiveStreaming,
} from "zenith-player";All hooks must be used inside a <ZenithPlayer> (or ZenithPlayerProvider) subtree — ideal for building custom controls with qualityMenu={false} / controls={false}.
Key Props (reference)
| Prop | Type | Description |
| --- | --- | --- |
| src / source | string / ZenithVideoConfig | Single URL or a full video config object. |
| sources | QualitySource[] | Multi-resolution MP4/custom sources. |
| poster, autoPlay, muted, controls | — | Standard playback options. |
| nativeControls | boolean | Use native browser controls instead of the Zenith bar. |
| fitMode / aspectRatio | "contain"\|"cover" / number\|"auto" | Video fit + aspect. |
| timelineEvents | TimelineEvent[] | Interactive stimuli. |
| ads / advertisements / advertising | AdBreak[] / AdvertisingConfig | Advertisement config. |
| thumbnails | ThumbnailConfig | Sprite/VTT previews. |
| casting | CastingConfig | Chromecast/AirPlay. |
| adaptiveStreaming | AdaptiveStreamingConfig | ABR settings. |
| drm | DrmConfig | Widevine/PlayReady/FairPlay. |
| qualityMenu | boolean | Toggle the built-in quality menu. |
Theming & Customization
Every UI surface is themeable via CSS variables on .zenith-player:
.zenith-player {
--zenith-seek-fill: #ff2f4e; /* progress bar */
--zenith-accent: #4f9cff; /* menus/checkmarks */
--zenith-menu-bg: rgba(15, 18, 26, 0.96);
--zenith-menu-fg: #f3f7fa;
--zenith-badge-bg: #3563ff; /* HD/4K badges */
--zenith-primary: #3563ff; /* buttons/CTAs */
--zenith-menu-font: "Inter", sans-serif;
}Stable class names (zenith-controlbar, zenith-menu, zenith-marker, zenith-tl-overlay, zenith-ad, …) work with plain CSS, CSS Modules, Tailwind, styled-components, or Emotion. Set controls={false} to build a fully custom UI from the hooks.
Browser Support
Chrome, Edge, Firefox, Safari, Brave, and Chromium-based browsers. Features degrade gracefully where unsupported (e.g. AirPlay is Safari-only; Chromecast requires the Cast-capable environment; DRM requires EME + HTTPS).
License
MIT — free to use in your products. No proprietary code or assets from commercial players.
Keywords
react · react-video-player · video-player · video · player · media-player · video-streaming · streaming · hls · hls.js · m3u8 · dash · dash.js · mpeg-dash · mpd · adaptive-bitrate · abr · drm · widevine · playready · fairplay · eme · chromecast · airplay · casting · vast · vmap · vpaid · video-ads · advertising · subtitles · captions · thumbnails · quality-selector · interactive-video · timeline · headless · typescript · ott
