Jump to content

User's Guide: VidPly Player

A practical guide for web developers on how to integrate VidPly into your websites.

VidPly Logo

Quick Overview

VidPly is a universal, accessible media player supporting:

FeatureSupport
VideoMP4, WebM, OGG
AudioMP3, OGG, WAV
YouTubeEmbedded with unified controls
VimeoEmbedded with unified controls
SoundCloudEmbedded via Widget API with unified controls
HLSAdaptive bitrate streaming (hls.js on most browsers, native on iOS / iPadOS)
DASHMPEG-DASH streaming via dash.js
Buffering SpinnerCentered loading spinner during waiting/seeking
Download ButtonOptional control with custom URL support
PlaylistsAudio, video & mixed media with thumbnails
AccessibilityWCAG 2.2 AA compliant
TypeScriptStrict TS sources + bundled .d.ts declarations
LanguagesEN, ES, FR, DE, JA + custom

Installation

1. Build the Player

 
npm install
npm run build
 

This creates files in dist/:

  • prod/vidply.esm.min.js - ES Module (recommended)
  • legacy/vidply.min.js - IIFE for script tag (global VidPly)
  • vidply.min.css - Styles

2. Include in Your Page

ES Module (Recommended):

 
<link rel="stylesheet" href="dist/vidply.min.css">
<script type="module">
  import Player from './dist/prod/vidply.esm.min.js';
</script>
 

Traditional Script Tag:

 
<link rel="stylesheet" href="dist/vidply.min.css">
<script src="dist/legacy/vidply.min.js"></script>
 

Basic Usage

Video Player

 
<video data-vidply width="800" height="450">
  <source src="video.mp4" type="video/mp4">
  <source src="video.webm" type="video/webm">
</video>
 

The data-vidply attribute auto-initializes the player.

Audio Player

 
<audio data-vidply>
  <source src="audio.mp3" type="audio/mpeg">
  <source src="audio.ogg" type="audio/ogg">
</audio>
 

With Poster Image

 
<video data-vidply poster="thumbnail.jpg" width="800" height="450">
  <source src="video.mp4" type="video/mp4">
</video>
 

External Services

YouTube

 
<video data-vidply src="https://www.youtube.com/watch?v=VIDEO_ID"></video>
 

Or with full URL:

 
<video data-vidply src="https://youtu.be/VIDEO_ID"></video>
 

Vimeo

 
<video data-vidply src="https://vimeo.com/VIDEO_ID"></video>
 

VidPly or Native Embed Controls

YouTube and Vimeo play in a chromeless iframe with the VidPly control bar by default (embedChrome: 'vidply'). To keep only the provider's own player UI, set embedChrome: 'provider':

 
<video data-vidply data-embed-chrome="provider" src="https://www.youtube.com/watch?v=VIDEO_ID"></video>
 

With 'provider' the VidPly control bar and play overlay are hidden and the iframe handles playback and keyboard input, so VidPly-only controls (captions menu, transcript, download, "Open on YouTube/Vimeo" link) are not available. YouTube captions are never shown in either mode; add sidecar WebVTT via playlist tracks with embedChrome: 'vidply' when captions are needed.

SoundCloud

 
<audio data-vidply src="https://soundcloud.com/artist/track-name"></audio>
 

SoundCloud keeps its widget UI by default (embedChromeSoundcloud: 'provider'); set data-embed-chrome-soundcloud="vidply" to show the VidPly bar below the widget.

The SoundCloud Widget API is auto-detected for any URL containing soundcloud.com. The widget is loaded on demand and integrates with the standard VidPly play / pause / seek / volume controls.

When using mpc-vidply in TYPO3, the Privacy Layer displays a GDPR consent overlay before the SoundCloud iframe is loaded — visitors must accept loading external content first.

HLS Streaming

 
<video data-vidply src="https://example.com/stream.m3u8"></video>
 

hls.js 1.7.3 is loaded on demand when .m3u8 URLs are detected (CDN fallback if not already on the page). Behavior per platform:

PlatformHLS engineCaptions / Transcript / Quality
Chrome / Firefox / Edgehls.jsFull VidPly UI
Desktop macOS Safarihls.js (for parity with other browsers)Full VidPly UI
iOS / iPadOS SafariNative <video> HLSFull VidPly UI via the native TextTrack API bridge
 

Even on iOS where hls.js cannot run (no MSE), VidPly still wires the captions menu, interactive transcript and quality menu into the browser's native HLS text tracks — you don't lose any UI controls.

 

DASH Streaming

 
<video data-vidply src="https://example.com/manifest.mpd"></video>
 

dash.js 5.2.1 (modern UMD) is loaded on demand when .mpd URLs are detected. DASH streams support:

  • Adaptive bitrate quality selection
  • TTML subtitles (rendered natively by dash.js)
  • WebVTT subtitles (handled by VidPly's caption system with transcript support)

DASH + HLS + MP4 Fallback

 
<video data-vidply width="800" height="450">
  <source src="dash/manifest.mpd" type="application/dash+xml">
  <source src="hls/master.m3u8" type="application/x-mpegURL">
  <source src="fallback.mp4" type="video/mp4">
  <track kind="subtitles" src="subtitles.en.vtt" srclang="en" label="English">
</video>
 

Adding Captions & Subtitles

Basic Captions

 
<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-de.vtt" srclang="de" label="Deutsch">
</video>
 

Track Types

KindPurpose
subtitlesTranslation of dialogue
captionsDialogue + sound effects (deaf/hard of hearing)
descriptionsText descriptions of visual content
chaptersChapter markers for navigation

Default Captions On

 
<track kind="subtitles" src="captions.vtt" srclang="en" label="English" default>
 

Chapters

Add chapter navigation with a chapters track:

 
<video data-vidply>
  <source src="video.mp4" type="video/mp4">
  <track kind="chapters" src="chapters.vtt" srclang="en">
</video>
 

chapters.vtt:

 
WEBVTT

00:00:00.000 --> 00:02:30.000
Introduction

00:02:30.000 --> 00:08:00.000
Main Topic

00:08:00.000 --> 00:12:00.000
Examples

00:12:00.000 --> 00:15:00.000
Conclusion
 

Configuration Options

Via Data Attributes

 
<video 
  data-vidply
  data-vidply-autoplay="false"
  data-vidply-loop="false"
  data-vidply-muted="false"
  data-vidply-volume="0.8"
  data-vidply-language="en"
  data-vidply-keyboard="true"
  data-vidply-responsive="true"
  src="video.mp4">
</video>
 

Via JavaScript

 
const player = new Player('#my-video', {
  // Display
  width: 800,
  height: 450,
  poster: 'poster.jpg',
  responsive: true,
  
  // Playback
  autoplay: false,
  loop: false,
  muted: false,
  volume: 0.8,
  playbackSpeed: 1.0,
  
  // Controls
  controls: true,
  hideControlsDelay: 3000,
  
  // Buttons (show/hide individual controls)
  playPauseButton: true,
  progressBar: true,
  volumeControl: true,
  speedButton: true,
  captionsButton: true,
  fullscreenButton: true,
  pipButton: true,
  downloadButton: false,        // Show a download button in the control bar
  downloadUrl: null,            // Optional explicit download URL (defaults to current src)

  // 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)

  // Language
  language: 'en',
  
  // Keyboard
  keyboard: true,
  
  // Accessibility
  screenReaderAnnouncements: true,
  focusHighlight: true
});
 

All Options Reference

OptionTypeDefaultDescription
widthnumber800Player width
heightnumber450Player height
posterstringnullPoster image URL
responsivebooltrueResponsive sizing
autoplayboolfalseAuto-start playback
loopboolfalseLoop playback
mutedboolfalseStart muted
volumenumber0.8Default volume (0-1)
playbackSpeednumber1.0Default speed
controlsbooltrueShow controls
hideControlsDelaynumber3000Auto-hide delay (ms)
keyboardbooltrueEnable keyboard shortcuts
languagestring'en'UI language
captionsbooltrueEnable captions support
captionsDefaultboolfalseShow captions by default
transcriptboolfalseShow transcript panel
debugboolfalseDebug logging
preloadstring'metadata''none', 'metadata', 'auto'
deferLoadboolfalseAvoid starting network loading during init; load on user play / explicit load
fillContainerboolfalseFill the player container
showTrackInfobooltrueRender .vidply-track-info for standalone players (playlists use their own header)
initialDurationnumber0Initial duration in seconds (UI only, before media metadata is loaded)
requirePlaybackForAccessibilityTogglesboolfalseIf true: AD/SL before playback shows a notice instead of implicitly loading/playing

Download Button

Show an opt-in download button in the control bar:

 
<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('#video', {
  downloadButton: true,
  downloadUrl: '/files/lecture.mp4' // optional; falls back to current src
});
 

The button is keyboard accessible, fully internationalized (player.download translation key) and uses aria-label so screen readers announce it correctly.

 

Hint for streaming sources: downloadUrl is normally the URL of an MP4/MP3 fallback because users typically can't download a .mpd or .m3u8 manifest as a single file.

 

In a playlist each track can bring its own file (downloadUrl, downloadFormat, downloadFileSize). The button then offers whatever is selected and hides on tracks that are not downloadable — see PLAYLIST.

Custom Floating Player (Miniplayer)

VidPly ships an optional in-page floating player ("own PiP") that pops up in a configurable corner of the viewport, can be dragged and resized, and keeps VidPly's own caption rendering, transport controls and fullscreen working inside the floating shell.

While floating is enabled, the native browser Picture-in-Picture API is suppressed automatically (disablepictureinpicture + disableremoteplayback) so the user gets a single, consistent experience across browsers.

Behavior

  • Auto-float on scroll-out - When the original player scrolls out of the viewport, the video pops into the floating shell. When it scrolls back in, the video docks back to its original container.
  • Manual pin/unpin - The PiP button in the control bar manually pins the floating shell. Manual pin/unpin overrides scroll-based auto-floating until the next user-initiated play.
  • Close button - The X button in the floating shell pauses the video, returns it to its original container and suppresses auto-float for the rest of the play session.
  • Drag & resize - The floating shell can be dragged by its header and resized via the corner/edge handles. Geometry is persisted per player via local storage.
  • Reduced control bar - Inside the floating shell only essential controls are shown: play/pause, rewind, forward, volume, captions, PiP and fullscreen. Tooltips open above the buttons; captions are sized at 90% and capped to 95% width.
  • Audio players are skipped - The floating feature only applies to <video> players.
  • Desktop only by default - Below floatingMinViewportWidth (default 768 px) the feature is disabled and the floating PiP button is hidden in the main control bar (it never falls into the overflow menu).

Enable via HTML (data-vidply-options JSON)

Floating options are passed via the data-vidply-options JSON blob (the same channel TYPO3 / mpc_vidply uses):

 
<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>
 

Enable via JavaScript

 
const player = new Player('#video', {
  floating: true,
  floatingPosition: 'bottom-right', // or 'bottom-left' | 'top-right' | 'top-left'
  floatingMinViewportWidth: 768
});
 

Accessibility

  • The floating shell is announced as a role="dialog" with a translated aria-label (player.floatingPlayerDialog).
  • The PiP toggle uses aria-pressed to expose the pinned state.
  • Focus is returned to the originating button when the floating shell is closed via keyboard.
  • All built-in languages (en, de, es, fr, ja) include translations for player.floatingPlayer, player.floatingPlayerClose, player.floatingPlayerEnter, player.floatingPlayerExit and player.floatingPlayerDialog.

Buffering Spinner

A centered loading spinner appears automatically while the media is buffering (waiting / seeking / initial loadstart) and disappears on canplay / playing. It works for HTML5, HLS and DASH renderers and respects prefers-reduced-motion.

You can theme it via CSS variables:

 
.vidply-player {
  --vidply-spinner-color: #ffffff;
  --vidply-spinner-size: 56px;
  --vidply-z-buffering: 1; /* sits below the play overlay */
}
 

The container exposes a .vidply-buffering class while loading, which you can use to style or hook into:

 
.vidply-player.vidply-buffering .my-skin-overlay {
  opacity: 0.3;
}
 

Playlists

Audio Playlist

 
<div id="audio-player"></div>

<script type="module">
  import { Player, PlaylistManager } from './dist/prod/vidply.esm.min.js';
  
  // When you pass a non-media element, VidPly will create the media element for you.
  const player = new Player('#audio-player', { mediaType: 'audio' });
  const playlist = new PlaylistManager(player, {
    autoAdvance: true,
    loop: false,
    showPanel: true
  });
  
  playlist.loadPlaylist([
    {
      src: 'track1.mp3',
      title: 'Track 1',
      artist: 'Artist Name',
      poster: 'cover1.jpg'
    },
    {
      src: 'track2.mp3',
      title: 'Track 2',
      artist: 'Artist Name',
      poster: 'cover2.jpg'
    }
  ]);
</script>
 

Video Playlist

 
<div id="video-player"></div>

<script type="module">
  import { Player, PlaylistManager } from './dist/prod/vidply.esm.min.js';
  
  const player = new Player('#video-player');
  const playlist = new PlaylistManager(player, {
    autoAdvance: true,
    showPanel: true
  });
  
  playlist.loadPlaylist([
    {
      src: 'video1.mp4',
      title: 'Video 1',
      poster: 'thumb1.jpg',
      tracks: [
        { src: 'captions1.vtt', kind: 'captions', srclang: 'en', label: 'English' }
      ]
    },
    {
      src: 'video2.mp4',
      title: 'Video 2',
      poster: 'thumb2.jpg'
    }
  ]);
</script>
 

Playlist Options

OptionDefaultDescription
autoAdvancetrueAuto-play next track
autoPlayFirsttrueAuto-play first track on loadPlaylist() (if false: first track is loaded/selected but not played)
loopfalseLoop playlist
showPaneltrueShow playlist panel

Playlist Controls

 
playlist.next()           // Next track
playlist.previous()       // Previous track
playlist.goToTrack(2)     // Jump to track index
playlist.hasNext()        // Check if next exists
playlist.hasPrevious()    // Check if previous exists
 

Accessibility Features

Audio Description

VidPly supports spoken audio description in two ways:

  1. Described video (recommended for production) — upload or link a pre-mixed MP4/WebM where narration is already embedded in the audio track. VidPly swaps the entire video source when the user toggles AD.

  2. VTT speech (extended AD fallback) — when no described video is available, a kind="descriptions" WebVTT track can drive browser text-to-speech: the player pauses at each cue, speaks the description, then resumes playback. Quality depends on the browser voice; use described video when broadcast-grade narration is required.

Text description cues are always available in the transcript panel for reading, regardless of which spoken path is active. Set audioDescriptionSpeech: false to use text-only descriptions (no TTS).

Mode (audioDescriptionMode, default auto):

ValueBehavior
autoDescribed video if configured, else VTT speech if descriptions VTT present
swapDescribed video swap only
vtt_speechVTT speech only
const player = new Player('#my-video', {
  audioDescription: true,
  audioDescriptionSrc: 'video-with-description.mp4', // optional
  audioDescriptionMode: 'auto',
  audioDescriptionSpeech: true,
  audioDescriptionExtended: true
});
 

Users toggle AD via the AD button. Demo: `demo/single-player-vtt-speech.html`.

Sign Language

Add sign language interpretation overlay:

 
const player = new Player('#my-video', {
  signLanguage: true,
  signLanguageSrc: 'sign-language.mp4',
  signLanguagePosition: 'bottom-right'
});
 

Position options: bottom-right, bottom-left, top-right, top-left

Interactive Transcripts

 
const player = new Player('#my-video', {
  transcript: true,
  transcriptPosition: 'external',
  transcriptContainer: '#transcript-panel'
});
 

Features:

  • Click any line to seek to that point
  • Auto-scrolls during playback
  • Searchable text
  • Draggable/resizable window

Keyboard Shortcuts

VidPly includes comprehensive keyboard controls:

KeyAction
Space / P / KPlay/Pause
FToggle fullscreen
MMute/Unmute
↑ / ↓Volume up/down
← / →Seek ±10 seconds
CToggle captions
ACaption style menu
<** / **>Decrease/increase speed
SSpeed menu
QQuality menu
JChapters menu
TToggle transcript
DDrag mode (transcript/sign)
RResize mode
HomeReset position
EscapeExit mode/close menu

Custom Keyboard Shortcuts

 
const player = new Player('#my-video', {
  keyboardShortcuts: {
    'play-pause': [' ', 'p', 'k'],
    'seek-forward': ['ArrowRight', 'l'],
    'seek-backward': ['ArrowLeft', 'j'],
    'volume-up': ['ArrowUp'],
    'volume-down': ['ArrowDown'],
    'mute': ['m'],
    'fullscreen': ['f'],
    'captions': ['c']
  }
});
 

Styling & Theming

CSS Variables

 
.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);
}

.vidply-button:focus {
  outline: 2px solid var(--vidply-primary-color);
  outline-offset: 2px;
}
 

Internationalization

Built-in Languages

  • English (en)
  • Spanish (es) - Español
  • French (fr) - Français
  • German (de) - Deutsch
  • Japanese (ja) - 日本語

Set Language

 
const player = new Player('#my-video', {
  language: 'de'  // German
});
 

Auto-detect from HTML

 
<html lang="de">
  <!-- Player auto-detects German -->
</html>
 

Load Custom Language

Via data attribute:

 
<video 
  data-vidply 
  data-vidply-language-files='{"pt": "languages/pt.json"}'
  src="video.mp4">
</video>
 

Via JavaScript (options):

 
import Player from './dist/prod/vidply.esm.min.js';

const player = new Player('#my-video', {
  language: 'pt',
  languageFiles: { pt: 'languages/pt.json' }
});
 

Language File Format

languages/pt.json:

 
{
  "player": {
    "play": "Reproduzir",
    "pause": "Pausar",
    "mute": "Silenciar",
    "unmute": "Ativar som",
    "fullscreen": "Tela cheia",
    "captions": "Legendas",
    "settings": "Configurações"
  },
  "time": {
    "currentTime": "Tempo atual",
    "duration": "Duração"
  }
}
 

API Reference

Playback

 
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 10s
player.seekBackward(10)    // Skip backward 10s
 

Volume

 
player.setVolume(0.5)      // Set volume (0-1)
player.getVolume()         // Get volume
player.mute()              // Mute
player.unmute()            // Unmute
player.toggleMute()        // Toggle mute
 

Speed

 
player.setPlaybackSpeed(1.5)   // Set speed (0.25-2.0)
player.getPlaybackSpeed()      // Get speed
 

Fullscreen

 
player.enterFullscreen()   // Enter fullscreen
player.exitFullscreen()    // Exit fullscreen
player.toggleFullscreen()  // Toggle fullscreen
 

Captions

 
player.enableCaptions()    // Enable captions
player.disableCaptions()   // Disable captions
player.toggleCaptions()    // Toggle captions
 

State

 
player.getCurrentTime()    // Current time in seconds
player.getDuration()       // Total duration
player.isPlaying()         // Is playing?
player.isPaused()          // Is paused?
player.isEnded()           // Has ended?
player.isMuted()           // Is muted?
player.isFullscreen()      // Is fullscreen?
 

Events

 
player.on('ready', () => {})
player.on('play', () => {})
player.on('pause', () => {})
player.on('ended', () => {})
player.on('timeupdate', (time) => {})
player.on('volumechange', (volume) => {})
player.on('fullscreenchange', (isFullscreen) => {})
player.on('captionsenabled', (track) => {})
player.on('error', (error) => {})
 

Cleanup

 
player.destroy()           // Remove player
 

Browser Support

BrowserVersion
Chrome90+
Firefox88+
Safari14+
Edge90+
iOS Safari14+
Android Chrome90+

Troubleshooting

Video Not Playing

IssueSolution
Black screenCheck video URL is accessible
CORS errorEnsure proper CORS headers on server
Format unsupportedProvide MP4 fallback
Autoplay blockedSet muted: true for autoplay

Captions Not Showing

IssueSolution
VTT not loadingCheck file URL; validate VTT syntax
CORS errorServe VTT from same domain or enable CORS
Wrong encodingSave VTT as UTF-8

YouTube/Vimeo Not Working

IssueSolution
Not loadingCheck video URL format
API errorsEnsure videos are embeddable
Controls missingVidPly uses native service players

HLS Not Playing

IssueSolution
Stream not loadingVerify .m3u8 URL is accessible
CORS issuesConfigure CORS on streaming server
Segments failingCheck segment URLs in manifest

DASH Not Playing

IssueSolution
Stream not loadingVerify .mpd URL is accessible
CORS issuesConfigure CORS on streaming server
No quality levelsCheck MPD has multiple representations
TTML captions missingdash.js renders TTML natively; ensure tracks are in the manifest
Transcript not availableTTML tracks don't support transcript; use WebVTT for transcript

Best Practices

Performance

  • ✅ Use responsive: true for fluid layouts
  • ✅ Provide poster images
  • ✅ Use appropriate video resolutions
  • ✅ Compress videos for web delivery

Accessibility

  • ✅ Always provide captions
  • ✅ Use meaningful track labels
  • ✅ Test with keyboard only
  • ✅ Test with screen readers

Cross-browser

  • ✅ Provide MP4 + WebM sources
  • ✅ Test on mobile devices
  • ✅ Handle fullscreen differences on iOS

Live Demos

Try VidPly in action:

Need help? Check the API documentation or open an issue on GitHub.

Share page