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

@classytic/react-video

v0.1.0

Published

Production-ready video recording, upload, playback, and captions library for React. HLS streaming, multiple view modes, VTT/SRT subtitles.

Downloads

107

Readme

@classytic/react-video

Modern video player library for React with composable primitives and pre-built players.

Features

  • Composable Primitives - Build custom players with unstyled components
  • 4 Pre-built Players - StandardPlayer, ShortsPlayer, CinematicPlayer, ReelPlayer
  • HLS Adaptive Streaming - Automatic quality switching
  • Recording & Upload - Screen recording with S3/Cloudflare upload
  • Captions & Chapters - WebVTT support with thumbnail sprites
  • TypeScript - Full type safety
  • Modern React - React 18/19 with hooks

Installation

npm install @classytic/react-video

Quick Start

Option 1: Pre-built Players (Easiest)

import { StandardPlayer, ShortsPlayer, ReelPlayer } from '@classytic/react-video';

// 16:9 Landscape (YouTube-style)
<StandardPlayer src="video.mp4" />

// 9:16 Vertical (YouTube Shorts)
<ShortsPlayer
  src="short.mp4"
  creator={{ name: '@user', avatar: '/avatar.jpg' }}
  likes={1250}
/>

// 9:16 Stories (Instagram/TikTok)
<ReelPlayer
  items={[
    { id: '1', src: '/video1.mp4' },
    { id: '2', src: '/video2.mp4' },
  ]}
/>

// 21:9 Cinematic (Netflix-style)
<CinematicPlayer src="movie.mp4" title="Movie Title" />

Option 2: Build Custom with Primitives

import { VideoController, VideoRoot, Video, PlayButton, TimeSlider } from '@classytic/react-video';

<VideoController src="video.mp4">
  <VideoRoot className="w-full aspect-video bg-black relative">
    <Video className="w-full h-full object-contain" />
    <div className="absolute bottom-4 left-4 right-4 space-y-2">
      <TimeSlider className="h-1 bg-white/20 rounded cursor-pointer">
        {(progress) => (
          <div className="h-full bg-white rounded" style={{ width: `${progress}%` }} />
        )}
      </TimeSlider>
      <PlayButton className="px-4 py-2 bg-white/90 rounded text-black">
        {(state) => state.isPlaying ? 'Pause' : 'Play'}
      </PlayButton>
    </div>
  </VideoRoot>
</VideoController>

HLS Streaming

<StandardPlayer
  hlsSrc="video.m3u8"
  spriteVttUrl="sprites.vtt"
  chaptersVttUrl="chapters.vtt"
/>

Recording & Upload

Option 1: Tree-shakeable Provider Imports (Recommended)

Import only the provider you need for optimal bundle size:

import { useVideoRecorder } from '@classytic/react-video';
import { createS3Provider } from '@classytic/react-video/providers/s3';
// Or: import { createCloudflareProvider } from '@classytic/react-video/providers/cloudflare';

function Recorder() {
  const s3Provider = createS3Provider({ apiBase: '/api/upload' });

  const recorder = useVideoRecorder({
    provider: s3Provider,
    quality: 'medium',
  });

  return (
    <div>
      {recorder.status === 'idle' && (
        <button onClick={() => recorder.start({ id: 'session-1' })}>
          Start Recording
        </button>
      )}
      {recorder.status === 'recording' && (
        <button onClick={recorder.stop}>Stop & Upload</button>
      )}
      {recorder.status === 'uploading' && <p>Uploading: {recorder.progress}%</p>}
    </div>
  );
}

Option 2: String-based Provider (Simple)

import { useVideoRecorder } from '@classytic/react-video';

function Recorder() {
  const recorder = useVideoRecorder({
    provider: 's3',  // String: 's3' or 'cloudflare'
    providerConfig: { apiBase: '/api/upload' },
    quality: 'medium',
  });

  // ... rest of component
}

Note: String-based imports bundle all providers. Use tree-shakeable imports for smaller bundles.

Available Primitives

Core

  • VideoController - Context provider with state management
  • useVideo() - Hook to access video state and actions
  • VideoRoot - Container wrapper
  • Video - Video element

Controls

  • PlayButton - Play/pause toggle
  • MuteButton - Mute/unmute toggle
  • FullscreenButton - Fullscreen toggle
  • TimeSlider - Progress bar with seek
  • TimeDisplay - Current/total time
  • VolumeSlider - Volume control
  • QualitySelect - Quality switcher
  • PlaybackSpeed - Playback rate control

Advanced

  • ThumbnailPreview - Sprite-based scrubbing preview
  • ChaptersMenu - Chapter navigation
  • Captions - Subtitle display
  • DoubleTapSeek - Mobile-style seek gestures
  • PlayPauseAnimation - Visual feedback

Pre-built Players

StandardPlayer

16:9 landscape player with bottom controls, hover to show.

<StandardPlayer
  src="video.mp4"
  hlsSrc="video.m3u8"
  poster="poster.jpg"
  spriteVttUrl="sprites.vtt"
/>

ShortsPlayer

9:16 vertical player with YouTube Shorts UI (sidebar actions).

<ShortsPlayer
  src="short.mp4"
  creator={{ name: '@user', avatar: '/avatar.jpg' }}
  description="Check this out!"
  likes={1250}
  comments={45}
  onLike={() => {}}
  onComment={() => {}}
  onShare={() => {}}
/>

ReelPlayer

9:16 vertical player with Instagram/TikTok stories UI (progress bars, smooth transitions).

<ReelPlayer
  items={[
    { id: '1', src: '/video1.mp4', poster: '/poster1.jpg' },
    { id: '2', src: '/video2.mp4', poster: '/poster2.jpg' },
    { id: '3', src: '/video3.mp4', poster: '/poster3.jpg' },
  ]}
  autoPlay
  autoAdvance
  smoothTransitions
/>

Features:

  • Tap left/right edges to navigate
  • Tap center to play/pause
  • Story progress bars at top
  • Smooth crossfade transitions
  • Next video preloading

CinematicPlayer

21:9 ultra-wide player with Netflix-style UI.

<CinematicPlayer
  src="movie.mp4"
  title="Movie Title"
  autoPlay={false}
/>

Keyboard Shortcuts

| Key | Action | |-----|--------| | Space / K | Play/Pause | | ← / J | Seek backward 10s | | → / L | Seek forward 10s | | ↑ | Volume up | | ↓ | Volume down | | M | Toggle mute | | F | Toggle fullscreen | | 0-9 | Jump to % of video |

TypeScript

Full TypeScript support with exported types:

import type {
  VideoState,
  VideoActions,
  QualityLevel,
  TextTrack,
  Chapter
} from '@classytic/react-video';

Architecture

Why Primitives?

Primitives give you full control over styling and layout:

// ❌ Limited customization
<VideoPlayer theme="dark" controls={true} />

// ✅ Full control with Tailwind
<VideoController src="video.mp4">
  <VideoRoot className="rounded-xl overflow-hidden shadow-2xl">
    <Video className="object-cover" />
    <PlayButton className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-20 h-20 bg-gradient-to-r from-purple-500 to-pink-500 rounded-full">
      {(state) => state.isPlaying ? '⏸' : '▶'}
    </PlayButton>
  </VideoRoot>
</VideoController>

Pre-built Players

Pre-built players are reference implementations you can:

  1. Use directly for quick prototypes
  2. Copy and customize for your design system
  3. Study as examples of how to compose primitives

They're not meant to be "one size fits all" - they're starting points.

Upload Providers (Advanced)

Provider Pattern

This library uses a provider pattern for uploads - you choose where to upload:

import { createS3Provider, createCloudflareProvider } from '@classytic/react-video';

// S3 via presigned URLs (no AWS SDK required)
const s3 = createS3Provider({ apiBase: '/api/upload' });

// Cloudflare Stream
const cloudflare = createCloudflareProvider({ apiBase: '/api/upload' });

// Use any provider with VideoRecorder
const recorder = new VideoRecorder(s3, { id: 'recording-123' });

Benefits:

  • No vendor lock-in - Switch providers without changing code
  • Small bundle - No cloud SDKs bundled (uses fetch)
  • Testable - Mock providers easily
  • Extensible - Implement custom providers

Custom Upload Provider

Implement the UploadProvider interface for custom backends:

import type { UploadProvider } from '@classytic/react-video';

const customProvider: UploadProvider = {
  name: 'custom',

  async initUpload(params) {
    const res = await fetch('/my-api/init-upload', {
      method: 'POST',
      body: JSON.stringify(params),
    });
    return res.json();
  },

  async uploadChunk(session, chunk, partNumber) {
    // Upload chunk to your backend
    return { partNumber, size: chunk.size };
  },

  async completeUpload(session, parts, metadata) {
    // Finalize upload
    return { success: true, url: '...' };
  },

  async abortUpload(session) {
    // Cancel upload
  },
};

// Use custom provider
const recorder = new VideoRecorder(customProvider, { id: 'rec-123' });

Advanced Usage

Custom Progress Bar with Thumbnail Preview

<VideoController src="video.mp4">
  <VideoRoot className="relative w-full aspect-video">
    <Video />
    <div className="relative">
      <TimeSlider>{(progress) => (
        <div className="h-1 bg-white/20">
          <div className="h-full bg-red-600" style={{ width: `${progress}%` }} />
        </div>
      )}</TimeSlider>
      <ThumbnailPreview
        spriteVttUrl="sprites.vtt"
        className="absolute -top-32"
      />
    </div>
  </VideoRoot>
</VideoController>

Multiple Caption Tracks

<Captions
  tracks={[
    { id: 'en', src: '/en.vtt', label: 'English', default: true },
    { id: 'es', src: '/es.vtt', label: 'Español' },
  ]}
  style={{
    fontSize: 20,
    backgroundColor: 'rgba(0, 0, 0, 0.8)',
    color: '#ffffff',
  }}
/>

Custom Quality Selector

<QualitySelect>
  {({ qualities, currentQuality, setQuality }) => (
    <select
      value={currentQuality}
      onChange={(e) => setQuality(Number(e.target.value))}
      className="bg-black/80 text-white px-3 py-2 rounded"
    >
      {qualities.map((q, i) => (
        <option key={i} value={i}>{q.label}</option>
      ))}
    </select>
  )}
</QualitySelect>

Provider Setup

S3 Upload

import { createS3Provider } from '@classytic/react-video';

const provider = createS3Provider({
  apiBase: '/api/upload',
  // Your backend handles S3 presigned URLs
});

const recorder = useVideoRecorder({
  provider: 's3',
  providerConfig: { apiBase: '/api/upload' }
});

Cloudflare Stream

import { createCloudflareProvider } from '@classytic/react-video';

const provider = createCloudflareProvider({
  apiBase: '/api/upload',
  // Your backend handles Cloudflare Stream Direct Creator Upload
});

const recorder = useVideoRecorder({
  provider: 'cloudflare',
  providerConfig: { apiBase: '/api/upload' }
});

Examples

See the examples directory for complete examples:

  • complete-player.tsx - Full-featured player with all controls
  • custom-ui-with-callbacks.tsx - Custom UI with event callbacks

Requirements

  • React 18.0.0+
  • Node.js 18.0.0+
  • Modern browsers with ES2020 support

License

MIT

Related Packages