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

@vioraio/player

v2.9.2

Published

Viora Player — HLS video player for education (VOD & live classrooms)

Readme

Viora Player

@vioraio/player — HLS video player for education platforms (schools, universities, online classrooms).

Part of the Viora family by vioraio:

| Product | Role | | --- | --- | | Viora Player | HLS playback (this package) | | Viora Stream | VOD / streaming (coming) | | Viora Live | Online classroom (coming) |

Install

pnpm add @vioraio/player

Peer deps: react, react-dom, hls.js, framer-motion, clsx.

Styles (Tailwind v4 hosts — recommended)

Do not import @vioraio/player/styles.css inside apps that already run Tailwind (HeroUI / Next.js). That file ships a second theme layer and breaks host styles.

Scan the package from your global CSS instead:

@import "tailwindcss";
@source "../node_modules/@vioraio/player/dist/**/*.{js,cjs,mjs}";

Styles (no Tailwind)

import "@vioraio/player/styles.css";

Usage

Single video

import { VioraPlayer } from "@vioraio/player";

<VioraPlayer
  userId={user?.id}
  sources={[{ id: 1, title: "...", poster: "...", data: { type: "hls", src: "https://.../master.m3u8" } }]}
/>

data is { type: "hls", src } or { type: "file", src } (a progressive mp4/webm — no quality menu, no offline download).

Playlist

<VioraPlayer
  userId={user?.id}
  playerName="شهریار پلیر"
  sources={teasers.map((t) => ({ id: t.id, title: t.title, poster: t.cover, data: { type: "hls", src: t.src } }))}
  activeSourceId={activeId}
  onSourceSelect={(item) => setActiveId(item.id)}
  playlistTitle="تیزرها"
  autoPlayNext
  loopPlaylist
/>

With watch-session persistence

import { VioraPlayer, type WatchSessionFlushPayload } from "@vioraio/player";

<VioraPlayer
  userId={studentId}
  sources={[{ id: videoId, progressKey: subjectId, watchedDuration: watched, data: { type: "hls", src } }]}
  onSaveWatchSession={async (payload: WatchSessionFlushPayload) => {
    await api.post(`/course/video/watch/session/${videoId}`, payload);
  }}
/>

Theme & controls

<VioraPlayer
  sources={sources}
  theme={{
    colors: {
      primary: "#006FEE",
      secondary: "#17C964",
      danger: "#F31260",
      surface: "rgba(0,0,0,0.82)",
      foreground: "#ffffff",
      overlay: "rgba(0,0,0,0.55)",
    },
  }}
  controls={{ download: false }}
/>

When the control row is narrow (phones), enabled speed + quality + download fold into one تنظیمات control.

Behavior

  • Quality. A quality picked by hand stays picked: the player retries that rendition through network trouble instead of stepping down, and the choice is remembered per user. Only خودکار adapts, starting from the last measured bandwidth.
  • Fullscreen. Where the browser supports element fullscreen (desktop, Android, iPad) the player fills the screen with its own controls, and phones turn to landscape. iPhone has no element fullscreen: there the video goes to the system's own fullscreen player — the only real fullscreen an iPhone page gets (the whole screen, no Safari bars, landscape) — with Apple's controls while it lasts. Where neither exists or a WebView never settles the request, the player covers the viewport itself, above the host's sticky headers and bars, and locks page scroll.
  • Lock screen / background. Playback pauses when the page is hidden and resumes when it returns — only if the player (or the system, e.g. iOS on lock) paused it. On return a fresh frame is decoded so the picture is never left black, and a stuck pipeline is recovered.
  • Offline. A downloaded quality is stored with everything playback needs — playlists, segments, init segments, AES-128 keys and alternate audio — in the Cache API, and plays with no network at all, even when the stream URL carries a new token.
  • Gestures. On touch screens: tap toggles the controls, double-tap on either side seeks ±15 s (repeated taps add up).
  • Keyboard. Space/K play/pause · ←/→ seek · M mute · F fullscreen · C/X faster/slower · I info · Esc close/exit.

Props

Source & session

| Prop | Type | Default | Description | | --- | --- | --- | --- | | sources | VioraSource[] | — | Playable entries: id, data, optional title, poster, posterFallback, watchedDuration, progressKey, durationLabel | | defaultPlay | number | first item | Initial source: matched by id, else a 0-based index | | activeSourceId | number | — | Controlled active source | | onSourceSelect | (item, index) => void | — | Selection / skip / auto-next | | autoPlayOnSourceChange | boolean | false | Start playing when the active source changes from outside | | prepareState | "loading" \| "error" \| "ready" | "ready" | Host-driven ready state | | userId | number \| null | anonymous | Scopes stored progress and settings | | onSaveWatchSession | (payload) => Promise<void> | — | Server flush; without it progress stays in localStorage |

Branding & chrome

| Prop | Type | Default | Description | | --- | --- | --- | --- | | playerName | string | ویورا پلیر | Info panel brand name | | showTitle | boolean | true | Show title in the playing top bar | | theme | VioraPlayerTheme | defaults | 6 color tokens | | controls | VioraPlayerControlsConfig | all true | Toggle play, seek, skip, mute, fullscreen, speed, quality, download, info, playlist |

Playback

| Prop | Type | Default | Description | | --- | --- | --- | --- | | playbackRate | number | from settings / 1 | Rate 0.5–3 (0.5 steps) | | defaultQuality | number \| "auto" | from settings / "auto" | Initial quality | | onEnded | () => void | — | Fired when the current video ends | | pauseWhenOutOfView | boolean | true | Pause when scrolled fully out of view; resume when visible again |

Playlist

| Prop | Type | Default | Description | | --- | --- | --- | --- | | playlistTitle | string | لیست پخش | Drawer header title | | showPlaylistButton | boolean | true with 2+ sources | Show playlist chrome button | | playlistOpen | boolean | — | Controlled drawer open | | defaultPlaylistOpen | boolean | false | Uncontrolled initial open | | onPlaylistOpenChange | (open) => void | — | Drawer open changes | | autoPlayNext | boolean | false | Auto-play next after countdown | | showAutoPlayNext | boolean | true with 2+ sources | Show the in-drawer toggle (hide = fixed by autoPlayNext) | | onAutoPlayNextChange | (enabled) => void | — | Viewer toggled auto-next | | loopPlaylist | boolean | false | Wrap last → first | | autoOpenPlaylistOnEnded | boolean | true with 2+ sources | Open drawer when a video ends |

Deprecated (still supported)

id, title, poster, posterFallback, data, watchedDuration, progressKey, videoSubjectId → use sources. studentId → userId. playlist → sources. activePlaylistId → activeSourceId. defaultActivePlaylistId → defaultPlay. onPlaylistItemSelect → onSourceSelect.

Develop

pnpm install
pnpm build
pnpm typecheck

Release

Push to main publishes @vioraio/player to npm automatically.

  • If the current package.json version is already on npm, CI bumps the patch version, commits it ([skip ci]), then publishes.
  • Requires repo secret NPM_TOKEN (Granular Access Token with publish for @vioraio, bypass 2FA).

License

MIT