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

zenith-player

v1.1.2

Published

Enterprise React Video Player

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 (plus onAdvertisementStart/End/Click aliases).

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