A modern, feature-rich HTML5 video player library built with TypeScript, Tailwind CSS, and the latest web technologies.
- 🎯 TypeScript - Full type safety and IntelliSense support
- � Tailwind CSS - Modern utility-first styling
- 🎨 Custom Controls - Beautiful, customizable player controls
- ⌨️ Keyboard Shortcuts - YouTube-style keyboard navigation
- 📱 Responsive - Works perfectly on all devices
- 🎭 Themes - Built-in light, dark, and auto themes
- 🖼️ Picture-in-Picture - Native PiP support
- ⛶ Fullscreen - Full native fullscreen support
- ⚡ Playback Speed - Adjustable playback rates
- 🎚️ Volume Control - Fine-grained volume control
- 📊 Progress Bar - Interactive seeking with buffer display
- 🎯 Multiple Qualities - Support for quality switching
- 🔄 Event System - Rich event system for all player actions
- 📦 Zero Runtime Dependencies - Pure TypeScript, minimal dependencies
- 🚀 Modern Build - Built with Vite for optimal performance
npm install @videoplayer/coreimport { VideoPlayer } from '@videoplayer/core';
import '@videoplayer/core/style.css';
const player = new VideoPlayer('#player', {
src: 'https://example.com/video.mp4',
poster: 'https://example.com/poster.jpg',
controls: true,
autoplay: false,
volume: 1,
theme: 'dark',
});
// Listen to events
player.on('play', (state) => {
console.log('Video playing!', state);
});
// Control playback
player.play();
player.pause();
player.seek(120);new VideoPlayer(container: HTMLElement | string, options: VideoPlayerOptions)interface VideoPlayerOptions {
src: string | VideoSource[]; // Video source(s)
controls?: boolean; // Show controls (default: true)
autoplay?: boolean; // Autoplay (default: false)
loop?: boolean; // Loop playback (default: false)
muted?: boolean; // Start muted (default: false)
volume?: number; // Initial volume 0-1 (default: 1)
poster?: string; // Poster image URL
playbackRate?: number; // Initial playback rate (default: 1)
enablePIP?: boolean; // Enable PiP (default: true)
enableFullscreen?: boolean; // Enable fullscreen (default: true)
theme?: 'light' | 'dark' | 'auto'; // Theme (default: 'dark')
showQualitySelector?: boolean; // Show quality selector (default: false)
keyboardShortcuts?: boolean; // Enable shortcuts (default: true)
subtitles?: SubtitleTrack[]; // Subtitle tracks
enableThumbnails?: boolean; // Enable thumbnails (default: false)
thumbnailInterval?: number; // Thumbnail interval in seconds (default: 5)
customStyles?: CustomStyleOptions; // Custom colors and styling
}play(): Promise<void>- Play the videopause(): void- Pause the videotogglePlay(): void- Toggle play/pauseseek(time: number): void- Seek to specific time in seconds
setVolume(volume: number): void- Set volume (0-1)toggleMute(): void- Toggle mute
setPlaybackRate(rate: number): void- Set playback ratecyclePlaybackRate(): void- Cycle through common rates
toggleFullscreen(): Promise<void>- Toggle fullscreen modetogglePIP(): Promise<void>- Toggle Picture-in-Picture
setQuality(quality: string): void- Change video quality
getState(): PlayerState- Get current player stateon(event: PlayerEventType, callback: EventCallback): void- Add event listeneroff(event: PlayerEventType, callback: EventCallback): void- Remove event listener
destroy(): void- Destroy the player instance
type PlayerEventType =
| 'play' // Video started playing
| 'pause' // Video paused
| 'ended' // Video ended
| 'timeupdate' // Playback time changed
| 'volumechange' // Volume changed
| 'ratechange' // Playback rate changed
| 'seeking' // Seeking started
| 'seeked' // Seeking completed
| 'waiting' // Waiting for data
| 'canplay' // Can start playing
| 'error' // Error occurred
| 'fullscreenchange' // Fullscreen toggled
| 'pipchange' // PiP toggled
| 'qualitychange'; // Quality changedSpace/K- Play/Pause←- Seek backward 5 seconds→- Seek forward 5 seconds↑- Increase volume↓- Decrease volumeM- Toggle muteF- Toggle fullscreenP- Toggle Picture-in-Picture
The player supports a fully customizable color system with automatic dark mode support using CSS custom properties:
The player uses a purple-based color palette with 11 shades (50-950):
--color-primary-50: #fbf4ff;
--color-primary-100: #f7e9fe;
--color-primary-200: #eed2fc;
--color-primary-300: #e3aef9;
--color-primary-400: #d47df5;
--color-primary-500: #be4ce9;
--color-primary-600: #a52ccd; /* Primary accent */
--color-primary-700: #8b21ab;
--color-primary-800: #731d8b;
--color-primary-900: #611d72;
--color-primary-950: #3e064c;Toggle between light and dark mode programmatically:
import { initTheme, setTheme, toggleTheme, getCurrentTheme } from '@videoplayer/core';
// Initialize theme from localStorage or system preference
initTheme();
// Set a specific theme
setTheme('dark'); // or 'light'
// Toggle between themes
toggleTheme();
// Get current theme
const theme = getCurrentTheme(); // returns 'light' or 'dark'
// Watch for system theme changes
const unwatch = watchSystemTheme((theme) => {
console.log('System theme changed to:', theme);
});
// Cleanup when done
unwatch();Override CSS variables in your own stylesheet:
:root {
/* Change primary color to blue */
--color-primary-600: #2563eb;
--color-primary-700: #1d4ed8;
/* Custom text colors */
--color-primary_txt: #1a1a1a;
--color-secondary_txt: #666666;
}
[data-theme="dark"] {
/* Dark mode overrides */
--color-primary_txt: #ffffff;
--color-card_bg: #1a1a1a;
}--color-primary-{50-950}- Primary color palette--color-link_txt- Link text color--color-primary_txt- Primary text color--color-secondary_txt- Secondary text color--color-tertiary_txt- Tertiary text color
--color-primary_bg- Primary background--color-card_bg- Card background--color-surface- Surface background--color-hover_bg- Hover state background--color-primary_active_bg- Active state background
--color-primary_border- Primary border--color-secondary_border- Secondary border--color-tertiary_border- Tertiary border--color-primary_active_border- Active state border
The color system is integrated with Tailwind CSS:
// tailwind.config.js
export default {
darkMode: ['class', '[data-theme="dark"]'],
theme: {
extend: {
colors: {
primary: {
50: 'var(--color-primary-50)',
600: 'var(--color-primary-600)',
// ... etc
},
},
backgroundColor: {
'surface': 'var(--color-surface)',
'card': 'var(--color-card_bg)',
},
},
},
}The video player supports extensive customization through the customStyles option, allowing you to change colors, button styles, and other visual elements without modifying CSS files.
const player = new VideoPlayer('#player', {
src: 'video.mp4',
controls: true,
customStyles: {
primaryColor: '#ff6b6b',
buttonBackground: 'rgba(255, 107, 107, 0.2)',
buttonBackgroundHover: 'rgba(255, 107, 107, 0.35)',
buttonBorderRadius: '12px',
progressColor: '#ff6b6b',
}
});interface CustomStyleOptions {
// Primary accent color (used throughout the player)
primaryColor?: string;
// Button styling
buttonBackground?: string; // Button background color
buttonBackgroundHover?: string; // Button background on hover
buttonColor?: string; // Button icon/text color
buttonBorder?: string; // Button border color
buttonBorderRadius?: string; // Button corner radius (e.g., '8px', '50%')
// Progress bar
progressColor?: string; // Progress bar fill color
progressBackground?: string; // Progress bar background
// Volume slider
volumeColor?: string; // Volume slider color
// Dropdown menus (quality, speed, subtitles)
menuBackground?: string; // Menu background color
menuColor?: string; // Menu text color
menuItemHoverBackground?: string; // Menu item hover background
activeMenuItemColor?: string; // Active menu item color
// Controls overlay
controlsBackground?: string; // Controls gradient background
}const player = new VideoPlayer('#player', {
src: 'your-video.mp4',
controls: true,
customStyles: {
// Brand color throughout
primaryColor: '#00d4ff',
// Glassmorphism buttons with cyan tint
buttonBackground: 'rgba(0, 212, 255, 0.15)',
buttonBackgroundHover: 'rgba(0, 212, 255, 0.25)',
buttonColor: '#ffffff',
buttonBorder: 'rgba(0, 212, 255, 0.3)',
buttonBorderRadius: '16px',
// Matching progress bar
progressColor: '#00d4ff',
progressBackground: 'rgba(255, 255, 255, 0.2)',
// Volume slider to match
volumeColor: '#00d4ff',
// Dark menus with cyan accents
menuBackground: 'rgba(10, 10, 15, 0.98)',
menuColor: '#ffffff',
menuItemHoverBackground: 'rgba(0, 212, 255, 0.2)',
activeMenuItemColor: '#00d4ff',
// Custom controls gradient
controlsBackground: 'linear-gradient(to top, rgba(0, 20, 30, 0.95) 0%, rgba(0, 20, 30, 0.3) 50%, transparent 100%)'
}
});customStyles: {
primaryColor: '#e50914',
buttonBackground: 'rgba(229, 9, 20, 0.1)',
buttonBackgroundHover: 'rgba(229, 9, 20, 0.2)',
buttonBorderRadius: '4px',
progressColor: '#e50914',
menuBackground: 'rgba(0, 0, 0, 0.95)',
activeMenuItemColor: '#e50914',
}customStyles: {
primaryColor: '#ff0000',
buttonBackground: 'transparent',
buttonBackgroundHover: 'rgba(255, 255, 255, 0.1)',
buttonBorder: 'transparent',
buttonBorderRadius: '50%',
progressColor: '#ff0000',
progressBackground: 'rgba(255, 255, 255, 0.4)',
volumeColor: '#ffffff',
}customStyles: {
primaryColor: '#6366f1',
buttonBackground: 'rgba(99, 102, 241, 0.08)',
buttonBackgroundHover: 'rgba(99, 102, 241, 0.15)',
buttonBorder: 'rgba(99, 102, 241, 0.2)',
buttonBorderRadius: '10px',
progressColor: '#6366f1',
menuBackground: 'rgba(255, 255, 255, 0.98)',
menuColor: '#1f2937',
activeMenuItemColor: '#6366f1',
}- Colors can be in any CSS format: hex (
#ff6b6b), rgb (rgb(255, 107, 107)), rgba (rgba(255, 107, 107, 0.5)), or named colors - Use CSS gradients for
controlsBackgroundto create custom overlay effects - Border radius accepts any CSS unit:
px,rem,% - All options are optional - only specify what you want to customize
- Custom styles work with both light and dark themes
# Install dependencies
npm install
# Start development server
npm run dev
# Build library
npm run build
# Run tests
npm run test
# Lint code
npm run lint
# Format code
npm run formatconst player = new VideoPlayer('#player', {
src: [
{ src: 'video-1080p.mp4', quality: '1080p', label: 'Full HD' },
{ src: 'video-720p.mp4', quality: '720p', label: 'HD' },
{ src: 'video-480p.mp4', quality: '480p', label: 'SD' },
],
showQualitySelector: true,
});player.on('play', (state) => {
console.log('Playing at', state.currentTime);
});
player.on('ended', (state) => {
console.log('Video ended');
// Auto-play next video
});
player.on('error', (state) => {
console.error('Playback error');
});// Play from specific time
player.seek(60);
await player.play();
// Set to 2x speed
player.setPlaybackRate(2);
// Enter fullscreen
await player.toggleFullscreen();
// Get current state
- [Tailwind CSS](https://tailwindcss.com/)
- [PostCSS](https://postcss.org/)
const state = player.getState();
console.log(`Playing: ${state.playing}`);
console.log(`Time: ${state.currentTime}/${state.duration}`);Contributions are welcome! Please feel free to submit a Pull Request.
MIT License - feel free to use this in your projects!
Built with modern web technologies:
Made with ❤️ by the community