
A modern, feature-rich media player written entirely in TypeScript and provided as an ES module with no dependencies. It combines the best accessibility features of AblePlayer with the streaming capabilities of MediaElement.js. Fully internationalised with support for 5 languages and full WCAG 2.2 AA compliance.
Live demos
Try VidPly in action:
- Main demo – demonstration of the video player with full functionality
- Audio playlist – Audio player with support for playlists
- Video playlist – Video playlist with thumbnails
- Mixed playlist – Combined audio and video playlist
- HLS streaming – Demo of adaptive bitrate streaming
- DASH streaming – MPEG-DASH streaming demo
Why VidPly?
- No dependencies – Pure vanilla JavaScript / TypeScript, no frameworks required
- TypeScript-native – Written in strict TypeScript with built-in type declarations (
dist/types/index.d.ts) - Accessibility first – WCAG 2.2 AA compliant with full keyboard and screen reader support
- Multilingual – Built-in translations for 5 languages with easy extensibility
- Fully customisable – CSS variables and comprehensive API
- Modern build structure – ES modules with tree-shaking, code splitting and source maps
- Production-ready – Thoroughly tested with real media content
Features
Core media support
- Audio and video playback – Native HTML5 support for both media types
- Multiple formats – MP3, OGG, WAV (audio) / MP4, WebM (video)
- YouTube integration – Embedding YouTube videos with standardised controls
- Vimeo integration – Seamless integration of the Vimeo player
- SoundCloud integration – Playback of SoundCloud tracks and sets via the Widget API with standardised controls
- HLS streaming – Adaptive bitrate streaming with quality selection and dynamic subtitle detection
- Usage
hls.jsin Chrome / Firefox / Edge / Desktop Safari for full feature parity (quality menu, subtitles, transcript) - Falls back to native HLS on iOS / iPadOS if MSE is unavailable; native text tracks are still displayed via the VidPly interface for subtitles and transcripts
- Usage
- DASH streaming – MPEG-DASH support via dash.js with adaptive quality, TTML and WebVTT subtitles
- Buffer loading indicator – Centred loading indicator that appears automatically whilst media is buffering (HTML5, HLS, DASH)
- Download button – Optional download control with support for custom URLs (
downloadButton+downloadUrl) - Preview thumbnails – Video preview thumbnails when hovering over the progress bar
- Playlists – Full support for playlists with automatic playback and navigation
- Audio playlists with track information
- Video playlists with thumbnails
- Mixed playlists – Combine audio and video in a single playlist
- ‘Back’ and ‘Forward’ controls
- Visual playlist window
- Full-screen mode: YouTube-style horizontal carousel
- Automatic fade-in and fade-out depending on playback status
- Swipe-enabled touch interface
- Responsive card layout
Accessibility features (WCAG 2.2 AA compliant)
- Full keyboard navigation – All functions are accessible via the keyboard, custom keyboard shortcuts and menu navigation using the arrow keys
- Support for screen readers – Full ARIA labels (
aria-controls,aria-expanded,aria-haspopup), live regions - Interactive transcripts – Click to search and automatic scrolling with correct semantic HTML
- Sign language overlay – Picture-in-picture with drag-and-resize, accessible via the keyboard
- Audio description – Alternative audio track with descriptions of visual content
- Caption styling – Fully customisable (font, size, colour, opacity, border style)
- High-contrast mode – Windows HCM support, colour-independent design
- Focus management – Logical focus order, programmatic focus management, visible indicators
- Touch accessibility – Buttons with a size of at least 24×24 CSS pixels in accordance with WCAG 2.2 AA (SC 2.5.8); swipeable interfaces
Subtitles
- WebVTT support – Standard subtitle format
- Multiple languages – Support for multiple audio tracks
- Subtitle selection – Easy switching between tracks using the CC button
- Subtitle styling – Dedicated styling dialogue (font, size, colour, opacity)
- Chapter navigation – Jump to video chapters
- Interactive transcripts – Transcript window with click-and-search function (the browser’s search function works for searching)
Playback functions
- Adjustable speed – Playback from 0.25x to 2x
- Navigation controls – Forward/backward navigation
- Volume control – 0–100% with mute
- Repeat – Single file or playlist
- Full-screen mode – Native full-screen API with smart playlist overlay
- Picture-in-picture – Native PiP support in the browser (activated via the standard PiP button)
- Custom floating player (mini-player) – Optional floating window on the page that
- automatically floats when the original player scrolls out of view, and docks again when it scrolls back into view
- can be manually pinned/unpinned via the PiP button (manual pinning overrides the scroll behaviour)
- is fully movable and resizable, with persistent geometry per player
- retains the VidPly subtitles, transport controls and full-screen mode within the floating shell
- automatically suppresses the browser’s native PiP whilst it is active
- is only available on desktop (disabled by default for viewport widths under 768 px)
Internationalisation
Built-in support for 5 languages:
- English (en)
- Spanish (es) – Español
- French (fr) – Français
- German (de) – Deutsch
- Japanese (ja) – 日本語
All UI elements are fully translated, including:
- Control buttons and menus
- Time display and duration formatting
- Keyboard shortcuts
- Error messages and notifications
- ARIA labels for screen readers
Custom translations: Easily add your own languages by loading JSON or YAML translation files via data attributes or
JavaScript options. The player automatically detects the HTML attribute lang and loads the appropriate translations.
Installation
Build from source code
First, build the player:
# Install dependencies
npm install
# Build production files
npm run build
This will place minimised files in the dist/ folder.
Option 1: Using the compiled files (recommended for production)
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="dist/vidply.min.css">
</head>
<body>
<video data-vidply src="video.mp4" width="800" height="450">
<track kind="subtitles" src="captions.vtt" srclang="en" label="English">
</video>
<script type="module">
import Player from './dist/prod/vidply.esm.min.js';
// Auto-initialized via data-vidply attribute
</script>
</body>
</html>
Option 2: Traditional script tag (IIFE)
<link rel="stylesheet" href="dist/vidply.min.css">
<script src="dist/legacy/vidply.min.js"></script>
<video id="my-video" src="video.mp4"></video>
<script>
const player = new VidPly.Player('#my-video', {
controls: true,
autoplay: false,
volume: 0.8,
language: 'en'
});
</script>
Option 3: Development (TypeScript source files)
import Player from './src/index';
const player = new Player('#my-video', {
controls: true,
autoplay: false,
volume: 0.8,
language: 'en'
});
The library is written in strict TypeScript. Type declarations are
dist/types/index.d.ts, so that users whotscorvitereceive full IntelliSense without an additional@typespackage.
Quick Start
1. Create the player
npm install
npm run build
2. Add it to your page
<link rel="stylesheet" href="dist/vidply.min.css">
<script type="module">
import Player from './dist/prod/vidply.esm.min.js';
</script>
3. Create a video player
<video data-vidply width="800" height="450">
<source src="video.mp4" type="video/mp4">
<track kind="subtitles" src="captions-en.vtt" srclang="en" label="English">
<track kind="subtitles" src="captions-es.vtt" srclang="es" label="Español">
</video>
That’s it! The player is initialised automatically.
YouTube player
<video data-vidply src="https://www.youtube.com/watch?v=VIDEO_ID"></video>
Vimeo player
<video data-vidply src="https://vimeo.com/VIDEO_ID"></video>
Audio player
<audio data-vidply>
<source src="audio.mp3" type="audio/mpeg">
</audio>
HLS streaming
<video data-vidply src="https://example.com/stream.m3u8"></video>
DASH streaming
<video data-vidply src="https://example.com/manifest.mpd"></video>
SoundCloud
<audio data-vidply src="https://soundcloud.com/artist/track"></audio>
Download button
Enable the download button and enter a custom URL (optional):
<video
data-vidply
data-vidply-download-button="true"
data-vidply-download-url="/files/lecture.mp4"
src="/streams/lecture/manifest.mpd">
</video>
const player = new Player('#my-video', {
downloadButton: true,
downloadUrl: '/files/lecture.mp4' // optional, falls back to current src
});
Custom floating player (mini-player)
Enable the in-page floating player (‘custom PiP’). When the original video scrolls out of view, VidPly opens a movable, resizable floating overlay in the selected corner; when the original scrolls back into view, it is docked again. Users can also manually pin or unpin the floating player using the PiP button in the control bar. The browser’s native Picture-in-Picture API is automatically suppressed whilst floating mode is enabled, ensuring a consistent experience for users.
Enable via the data-vidply-options JSON blob:
<video
data-vidply
data-vidply-options='{"floating": true, "floatingPosition": "bottom-right", "floatingMinViewportWidth": 768}'
src="video.mp4"
width="800" height="450">
<track kind="subtitles" src="captions.vtt" srclang="en" label="English">
</video>
Or programmatically:
const player = new Player('#my-video', {
floating: true,
floatingPosition: 'bottom-right', // or 'bottom-left' | 'top-right' | 'top-left'
floatingMinViewportWidth: 768 // disable feature below this viewport width
});
Notes:
- Audio-only players (
<audio>) ignore the “floating” option. - Closing the floating window pauses playback and prevents it from automatically reappearing until the next user-initiated
play. - The floating window retains its size and position per player via local storage.
- Below
floatingMinViewportWidth(default 768 px), the PiP button is hidden and the floating function is disabled.
DASH + HLS + MP4 fallback
To ensure maximum device compatibility, provide all three formats:
<video data-vidply width="800" height="450" poster="preview.jpg">
<source src="video/dash/manifest.mpd" type="application/dash+xml">
<source src="video/hls/master.m3u8" type="application/x-mpegURL">
<source src="video/fallback.mp4" type="video/mp4">
<track kind="subtitles" src="video/vtt/subtitles.de.vtt" srclang="de" label="Deutsch" default>
<track kind="subtitles" src="video/vtt/subtitles.en.vtt" srclang="en" label="English">
<track kind="chapters" src="video/vtt/chapters.de.vtt" srclang="de" label="Kapitel">
</video>
VidPly automatically detects the source type based on the file extension (.mpd / .m3u8 / .mp4) and selects the appropriate renderer.
Configuration options
const player = new Player('#video', {
// Display
width: 800,
height: 450,
poster: 'poster.jpg',
responsive: true,
// Playback
autoplay: false,
loop: false,
muted: false,
volume: 0.8,
playbackSpeed: 1.0,
startTime: 0,
// Controls
controls: true,
hideControlsDelay: 3000,
playPauseButton: true,
progressBar: true,
currentTime: true,
duration: true,
volumeControl: true,
muteButton: true,
chaptersButton: true,
qualityButton: true,
captionStyleButton: true,
speedButton: true,
captionsButton: true,
transcriptButton: true,
audioDescriptionButton: true,
signLanguageButton: true,
fullscreenButton: true,
pipButton: false,
downloadButton: false, // Show a download button in the control bar
downloadUrl: null, // Optional explicit download URL (falls back to current src)
downloadFormat: null, // Optional override for the displayed download format (e.g. "MP4")
downloadFileSize: null, // Optional override for the displayed file size (bytes)
downloadFetchSize: true, // Issue a HEAD request to detect file size when not provided
// Custom Floating Player (in-page miniplayer / "own PiP")
floating: false, // Enable the custom floating player; also disables native browser PiP
floatingPosition: 'bottom-right', // 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'
floatingMinViewportWidth: 768, // Floating feature is hidden below this viewport width (px)
// Seeking
seekInterval: 10,
seekIntervalLarge: 30,
// Captions
captions: true,
captionsDefault: false,
captionsFontSize: '100%',
captionsFontFamily: 'sans-serif',
captionsColor: '#FFFFFF',
captionsBackgroundColor: '#000000',
captionsOpacity: 0.8,
// Audio Description
audioDescription: true,
audioDescriptionSrc: null, // URL to audio-described version
// Sign Language
signLanguage: true,
signLanguageSrc: null, // URL to sign language video
signLanguagePosition: 'bottom-right', // 'bottom-right', 'bottom-left', 'top-right', 'top-left'
signLanguageDisplayMode: 'both', // 'pip' (overlay) | 'main' (source swap) | 'both'
signLanguageSources: undefined, // { en: '/sl/en.mp4', de: '/sl/de.mp4', ... }
// Transcripts
transcript: false,
transcriptPosition: 'external',
transcriptContainer: null,
// Keyboard (defaults; do not assign the same key to two actions)
keyboard: true,
keyboardShortcuts: {
'play-pause': [' ', 'p', 'k'],
'seek-forward': ['ArrowRight'],
'seek-backward': ['ArrowLeft'],
'volume-up': ['ArrowUp'],
'volume-down': ['ArrowDown'],
'mute': ['m'],
'fullscreen': ['f'],
'captions': ['c'],
'caption-style-menu': ['a'],
'speed-up': ['>'],
'speed-down': ['<'],
'speed-menu': ['s'],
'quality-menu': ['q'],
'chapters-menu': ['j'],
'transcript-toggle': ['t']
},
// Accessibility
screenReaderAnnouncements: true,
focusHighlight: true,
highContrast: false,
ariaLabels: {}, // Override individual ARIA labels by i18n key
metadataAlerts: {}, // Map of metadata-cue keys to alert handlers (opt-in)
metadataHashtags: {}, // Map of metadata-cue hashtags to handler config (opt-in)
// Internationalization
language: 'en',
languages: ['en'],
languageFiles: undefined, // { pt: '/i18n/pt.json', it: '/i18n/it.json' }
languageFile: undefined, // Single language code to load
languageFileUrl: undefined, // URL for the single language file
// Resume Playback
resumePlayback: true, // Save and offer to resume playback position
resumeThreshold: 10, // Seconds; do not offer resume if less than this was watched
resumePrompt: true, // false = silently auto-resume
// Thumbnail Preview
thumbnailPreview: true,
thumbnailCacheSize: 50,
thumbnailPregenerate: true,
thumbnailInterval: 10,
thumbnailWidth: 160,
thumbnailHeight: 90,
thumbnailQuality: 0.8,
// Lazy Loading
lazyInit: true,
lazyMargin: '200px',
// Theming
theme: 'dark', // 'dark' | 'light' | 'minimal' | 'high-contrast'
themeVariables: {}, // Custom --vidply-* CSS variable overrides
// Callbacks
onReady: () => console.log('Ready!'),
onPlay: () => console.log('Playing!'),
onPause: () => console.log('Paused!'),
onEnded: () => console.log('Ended!'),
onTimeUpdate: (t) => {},
onVolumeChange: (v) => {},
onError: (err) => console.error(err),
// Streaming
hideSpeedForHls: false, // Hide speed control for ALL HLS streams
hideSpeedForHlsVideo: false, // Hide speed control only for HLS video (e.g. live streams)
hideSpeedForDash: false, // Hide speed control for ALL DASH streams
hideSpeedForDashVideo: false, // Hide speed control only for DASH video
// Advanced
debug: false,
pauseOthersOnPlay: true,
classPrefix: 'vidply', // CSS class prefix and event/storage namespace
iconType: 'svg',
initialDuration: 0, // Optional duration shown before metadata is loaded
requirePlaybackForAccessibilityToggles: false, // If true, AD/SL toggles before play show a notice instead of starting playback
fillContainer: false,
playsInline: true, // Inline playback on iOS
// Performance
preload: 'metadata', // 'none', 'metadata', or 'auto'
deferLoad: false // Delay loading until user plays (good for many players)
});
Keyboard shortcut
| Key | Action |
|---|---|
| Space bar / P / K | Play/Pause |
| F | Toggle full screen |
| M | Mute/Unmute |
| ↑ / ↓ | Increase/decrease volume |
| ← / → | Skip -10s / +10s |
| C | Turn subtitles on/off (or open menu if multiple options are available) |
| A | Open subtitle style menu |
| < / > | Decrease/increase speed |
| S | Open speed menu |
| Q | Open the ‘Quality’ menu |
| J | Open chapter menu |
| T | Switch subtitles |
| D | Access drag mode (transcript/sign language) |
| R | Switch resizing mode (transcript/sign language) |
| Esc | Exit drag/resize mode or close menus |
| Home | Reset position of transcript/sign language |
API Reference
Playback Controls
player.play() // Start playback
player.pause() // Pause playback
player.stop() // Stop and reset
player.toggle() // Toggle play/pause
player.seek(30) // Seek to 30 seconds
player.seekForward(10) // Skip forward 10 seconds
player.seekBackward(10) // Skip backward 10 seconds
Volume control
player.setVolume(0.5) // Set volume (0.0-1.0)
player.getVolume() // Get current volume
player.mute() // Mute audio
player.unmute() // Unmute audio
player.toggleMute() // Toggle mute state
Note on mobile devices: On touch devices (iOS, Android, tablets), only a mute/unmute button is displayed instead of the volume slider. Mobile browsers control the volume of HTML5 videos via the device’s volume keys – this is standard behaviour that cannot be overridden by web apps for security reasons. The mute button provides a quick mute function, whilst the hardware buttons control the actual volume.
Playback speed
player.setPlaybackSpeed(1.5) // Set speed (0.25-2.0)
player.getPlaybackSpeed() // Get current speed
Full screen
player.enterFullscreen() // Enter fullscreen
player.exitFullscreen() // Exit fullscreen
player.toggleFullscreen() // Toggle fullscreen
Note on iOS/Mobile Safari: As iOS does not support the full-screen API for container elements, VidPly automatically switches to a ‘pseudo-full-screen’ mode, which uses CSS to position the player so that it fills the entire screen. This provides a full-screen-like experience on iOS devices, whilst retaining all player functions.
Subtitles
player.enableCaptions() // Enable captions
player.disableCaptions() // Disable captions
player.toggleCaptions() // Toggle captions
// Switch between caption tracks
player.captionManager.switchTrack(0) // Switch to first track
player.captionManager.getAvailableTracks() // Get all tracks
Transcript
// Show/Hide Transcript
player.transcriptManager.showTranscript() // Show transcript window
player.transcriptManager.hideTranscript() // Hide transcript window
player.transcriptManager.toggleTranscript() // Toggle transcript visibility
// Drag & Resize Modes (Desktop only, mobile breakpoint: 768px)
player.transcriptManager.toggleKeyboardDragMode() // Toggle drag mode (D key)
player.transcriptManager.toggleResizeMode() // Toggle resize mode (R key)
// Settings Menu
player.transcriptManager.showSettingsMenu() // Show settings dropdown
player.transcriptManager.hideSettingsMenu() // Hide settings dropdown
// Check State
if (player.transcriptManager.isVisible) {
console.log('Transcript is visible');
}
Audio description
player.enableAudioDescription() // Switch to described version
player.disableAudioDescription() // Switch back to original
player.toggleAudioDescription() // Toggle audio description
Sign language
// Show/Hide Sign Language Video
player.enableSignLanguage() // Show sign language overlay
player.disableSignLanguage() // Hide sign language overlay
player.toggleSignLanguage() // Toggle sign language
// Multi-Language Support
player.switchSignLanguage('de') // Switch to German sign language
// Drag & Resize (available via settings menu or keyboard)
// D key - Toggle drag mode with arrow keys
// R key - Toggle resize mode (shows resize handles)
// Home key - Reset position
// Escape - Exit drag/resize mode
Playlists
import { Player, PlaylistManager } from './dist/prod/vidply.esm.min.js';
// Create player
const player = new Player('#my-player');
// Create playlist manager
const playlist = new PlaylistManager(player, {
autoAdvance: true, // Auto-play next track
loop: false, // Loop back to start
showPanel: true // Show playlist UI
});
// Load tracks
playlist.loadPlaylist([
{
src: 'track1.mp3',
title: 'Track 1',
artist: 'Artist Name',
poster: 'thumb1.jpg'
},
{
src: 'track2.mp3',
title: 'Track 2',
artist: 'Artist Name',
tracks: [
{ src: 'captions.vtt', kind: 'captions', srclang: 'en' }
]
}
]);
// Control playlist
playlist.next() // Go to next track
playlist.previous() // Go to previous track
playlist.goToTrack(2) // Jump to specific track
playlist.hasNext() // Check if next track exists
playlist.hasPrevious() // Check if previous track exists
// Listen for track changes
player.on('playlisttrackchange', (e) => {
// e: { index: number, item: PlaylistTrack, total: number, previousIndex?: number }
console.log(`Now playing track ${e.index + 1} / ${e.total}:`, e.item.title);
});
Settings
player.showSettings() // Open settings dialog
player.hideSettings() // Close settings dialog
Status information
player.getCurrentTime() // Get current time
player.getDuration() // Get duration
player.isPlaying() // Check if playing
player.isPaused() // Check if paused
player.isEnded() // Check if ended
player.isMuted() // Check if muted
player.isFullscreen() // Check if fullscreen
Event listener
player.on('ready', () => {})
player.on('play', () => {})
player.on('pause', () => {})
player.on('ended', () => {})
player.on('timeupdate', (time) => {})
player.on('volumechange', (volume) => {})
player.on('playbackspeedchange', (speed) => {})
player.on('fullscreenchange', (isFullscreen) => {})
player.on('hlsmanifestparsed', (data) => {})
player.on('dashqualitychanged', (data) => {})
player.on('textcuesupdate', () => {})
player.on('captionsenabled', (track) => {})
player.on('captionsdisabled', () => {})
player.on('error', (error) => {})
Cleanup
player.destroy() // Remove player and cleanup
Customisation
Custom styling
VidPly offers extensive CSS variables for easy customisation:
/* Override default colors and sizing */
.vidply-player {
/* Colors */
--vidply-primary-color: #3b82f6;
--vidply-background: rgba(0, 0, 0, 0.8);
--vidply-text-color: #ffffff;
/* Sizing */
--vidply-button-size: 40px;
--vidply-icon-size: 20px;
/* Spacing */
--vidply-gap-sm: 4px;
--vidply-gap-md: 8px;
--vidply-gap-lg: 12px;
/* Border radius */
--vidply-radius-sm: 4px;
--vidply-radius-md: 8px;
--vidply-radius-lg: 12px;
/* Transitions */
--vidply-transition-fast: 150ms;
--vidply-transition-normal: 300ms;
}
/* Custom progress bar */
.vidply-progress-played {
background: linear-gradient(90deg, #667eea, #764ba2);
}
/* Custom buttons */
.vidply-button:hover {
background: rgba(59, 130, 246, 0.2);
}
Add a custom language
Option 1: Load from URL (recommended)
<video
data-vidply
data-vidply-language-files='{"pt": "languages/pt.json", "it": "languages/it.json"}'
src="video.mp4"
></video>
Option 2: JavaScript API
import { i18n } from './src/i18n/i18n';
// Load language file from URL
await i18n.loadLanguageFromUrl('pt', 'languages/pt.json');
// Or load multiple languages
await i18n.loadLanguagesFromUrls({
'pt': 'languages/pt.json',
'it': 'languages/it.json'
});
// Set the language
i18n.setLanguage('pt');
Option 3: Add translations programmatically
import { i18n } from './src/i18n/i18n';
i18n.addTranslation('pt', {
player: {
play: 'Reproduzir',
pause: 'Pausar',
mute: 'Silenciar',
unmute: 'Ativar som'
}
});
i18n.setLanguage('pt');
Language file format
Create languages/pt.json:
{
"player": {
"play": "Reproduzir",
"pause": "Pausar",
"mute": "Silenciar",
"unmute": "Ativar som",
"fullscreen": "Tela cheia",
"captions": "Legendas"
},
"time": {
"currentTime": "Tempo atual",
"duration": "Duração"
}
}
The player supports both the JSON and YAML formats for language files.
Build process
VidPly uses a modern build system with esbuild for TypeScript bundling, the TypeScript compiler for .d.ts
declarations, and clean-css for CSS.
Available scripts
npm run build # Build everything (JS + types + CSS)
npm run build:js # Bundle TypeScript with esbuild (ESM + IIFE)
npm run build:types # Emit type declarations to dist/types/
npm run build:css # Build CSS only
npm run typecheck # Run tsc --noEmit
npm run watch # Watch mode for development
npm run clean # Clean dist directory
npm run dev # Start dev server
npm run test # Run unit tests (Vitest)
npm run test:e2e # Run end-to-end tests (Playwright)
npm run test:all # Run all tests
Output files
dist/dev/vidply.esm.js- ES module (development)dist/prod/vidply.esm.min.js- ES module (production)dist/legacy/vidply.js- IIFE (development)dist/legacy/vidply.min.js- IIFE (production)dist/types/index.d.ts- TypeScript declarationsdist/vidply.css- Styles (unminified)dist/vidply.min.css- Styles (minified)
See BUILD.md for detailed documentation on the build process.
Browser support
The library contains two bundles. Choose the one that suits your target audience:
Modern ESM bundle (dist/prod/vidply.esm.min.js) – recommended.
- Chrome 100+
- Firefox 100+
- Safari 15+
- Edge 100+
- iOS Safari 15+
- Android Chrome 100+
Legacy IIFE package (dist/legacy/vidply.min.js) – for support of older browsers.
- Chrome 80+
- Firefox 78+
- Safari 14+
- Edge 88+
The TypeScript declarations target ES2022; both bundles are built using esbuild + Terser. The exact targets can be found in BUILD.md.
Licence
GNU General Public Licence v2.0 or later
Copyright (C) 2026 Matthias Peltzer
This programme is free software; you may redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) any later version.
The full text of the licence can be found in the LICENSE file.
Documentation
Guides
- User Guide – Complete Integration Guide for Web Developers
- Quick Start for Developers – Quick Guide for Contributors
Reference
- Getting Started Guide – Basic setup and usage
- Application Guide – Detailed application examples
- Playlist Guide – Audio/video playlists with full-screen support
- Transcript Guide – Interactive Transcripts
- Keyboard Shortcuts – Complete Keyboard Reference
- Build Guide – Build System and Development
- Change log – Version history and updates
Acknowledgements
Inspired by:
- AblePlayer – Accessibility features
- MediaElement.js – Streaming support
Built with Vanilla JavaScript by Matthias Peltzer