The format is based on “Keep a Changelog”, and this project adheres to the rules of Semantic Versioning.
[1.2.1] – 14 June 2026
Added
- VTT speech description (extended AD) added: If no descriptive video is configured, VidPly
kind="descriptions"WebVTT cues via the browser APIspeechSynthesis— in which case playback is paused at each cue and resumes once the audio description has finished (DescriptionSpeechManager). - Delivery modes for audio descriptions via
audioDescriptionMode:auto(default),swap,vtt_speech. In the case ofautoa described MP4/WebM source takes precedence over the VTT audio. - New options:
audioDescriptionSpeech(Enable/disable TTS),audioDescriptionExtended(Continue after the end of speech output rather than at the end of the cue time). - New events:
audiodescriptioncuestart,audiodescriptioncueend. - Demo:
demo/single-player-vtt-speech.html— VTT-AD with audio only, without replacing the video being described.
[1.2.0] – 4 June 2026
Maintenance release to implement the results of an internal code review. No public APIs have been removed; the changes include accessibility improvements, fixes for memory leaks, a reduction in bundle size and stricter typing.
Accessibility
- Menu semantics (1.1.1 / 4.1.2): Disabled and empty menu items are now excluded from focus navigation (arrow keys), so that screen reader and keyboard users no longer land on non-interactive elements.
- Single-selection menus (4.1.2): The ‘Speed’, ‘Quality’ and ‘Subtitles’ menus now offer
role="menuitemradio"witharia-checkedrather than just a visual tick. - Pinch-to-zoom restored (1.4.4 / 1.4.10): Pseudo-full-screen mode (iOS) no longer
maximum-scale=1.0, user-scalable=no, so that zooming is no longer blocked whilst the player fills the viewport. - Live voice announcements (4.1.3): Changes to play/pause, subtitles and volume triggered by mouse or touch inputs are now announced
(previously only via the keyboard), and the subtitle hint overlay includes a
aria-livearea. - Focus traps: The interactive transcript window and the settings dialogue now retain focus whilst open, and return it to the triggering element when closed.
- Reduced movement (2.3.3):
scrollIntoView({ behavior: 'smooth' })In menus, the control bar, the subtitle overlay and the transcript, movements are now restricted behindprefers-reduced-motion. - Target size (2.5.8): The resize handles for the floating player and the transcript, as well as the area markers, have been enlarged to meet the minimum requirement of 24×24 CSS pixels.
- Escape handling: The escape handlers for the floating player, as well as for dragging and resizing, are arranged and restricted in such a way that the drag-and-resize mode can be cancelled via the keyboard without immediately closing the player.
Performance
- Smaller core bundle: The subtitle-style panel builder has been moved to a deferred-import module
(
controls/CaptionStyleMenu), so that it is only fetched when the panel is first opened, rather than being included in the core, which is always loaded. - Shared SDK loader: A new
utils/ScriptLoader.loadScriptOnce(url, { integrity })simplifies the five separate SDK integration routines (hls.js, dash.js, YouTube, Vimeo, SoundCloud) and prevents duplicate<script>tags when multiple players are embedded on a single page. - CSS deduplication: The duplicate
.vidply-fullscreen/:fullscreenselector pairs have been consolidated and:is(.vidply-fullscreen, :fullscreen)the light design has been integrated into the existing--vidply-*variables, duplicate keyframes have been merged, and the blocks for resizing transcripts/sign language have been deduplicated. The minified CSS is ~102 KB in size.
Fixed
- memory leaks during renderer teardown:
HTML5Renderer.destroy()Previously,removeEventListenerwith new empty functions, meaning thatloadedmetadata/play/pause/timeupdateand associated listeners were never removed. All renderers and managers now register listeners via an instance-specificAbortControllerand detach them upondestroy(). - Untracked timers: HLS timers for subtitle retries and network error retries, the SoundCloud initialisation timeout, and the nested AudioDescription timeouts for subtitle changes are now tracked and reset during teardown.
- Listener leak in the PlaylistManager: All listeners in the
init()are nowdestroy()(previously there were only two of them). - SignLanguageManager: The listener for the ‘Close’ button click is now removed during clean-up.
- Embedding initialisation: YouTube and Vimeo renderers now reject the operation if their SDK cannot be loaded, rather than behaving as if initialisation had been successful.
Code quality
- HLS native path: The vulnerable prototype grafting in
HLSRenderer.initNativehas been replaced by an explicit composition delegated to an internalHTML5Renderer. Rendererinterface: Internal flags (_hlsSourceLoaded,_dashSourceLoaded,_didDeferredLoad) have been removed from the public interface.- Stricter TypeScript: Enables
noUnusedLocalsandnoUncheckedIndexedAccessand corrected all resulting issues (access to array/object indices is now protected throughout). The type checking is error-free and all unit tests have passed.
[1 January 19] – 29 May 2026
Changed
- Default CDN addresses for hls.js / dash.js set: default fallback URLs now load
hls.js1.6.16 anddash.js5.2.0 (modern UMD build). Override ashlsScriptUrl/dashScriptUrlas before.
[1.1.10] – 3 May 2026
Security
- XSS protection for subtitles (AUDIT-001): Cue text is now displayed exclusively
textContentdisplayed exclusively. The obsolete regular expression-basedDOMUtils.sanitizeHTML+innerHTMLpath has been removed; VTT-specific markup (<c>,<b>,<i>,<u>,<v>) is instead parsed into a structured DOM whitelist. - Strict URL whitelist for SoundCloud (AUDIT-005):
SoundCloudRenderer.isValidSoundCloudUrlis now parsed using the URL constructor and thehostname+https:schema. - Pinned hls.js / dash.js with optional SRI (AUDIT-006): Renderers now load the exact versions of
hls.js(1.5.18) anddash.js(5.1.1). The CDN URL and theintegrityattribute can be configured via the newhlsScriptUrl/hlsScriptIntegrity/dashScriptUrl/dashScriptIntegrityoptions. SRI is optional to prevent hash drift from affecting installations during dependency upgrades; SECURITY.md documents how the hash is calculated. - Automatic initialisation of the JSON.parse safeguard (AUDIT-004):
data-vidply-optionsis now parsed within `try/catch` with a structured warning, rather than throwing an error. - ‘mediaType’ whitelist (AUDIT-014): The constructor now rejects anything that is not
video/audio. - Metadata directives can now be enabled (AUDIT-013):
FOCUS:/#hashtagCue directives requiremetadataDirectives: trueand are restricted to the player container by default. - Protection against path traversal on development servers (AUDIT-002):
server.jsandserver.cjspath resolution under a fixed root directory and disallowing escapes; both files are also passed to the.gitignore. - AbortController for user-initiated requests (AUDIT-017): transcript downloads, loading of language files, downloading
of metadata via HEAD, and
validateTrackExistsare now protected by a per-playerAbortControllerwithAbortSignal.timeout. - secure localStorage payload (AUDIT-023):
StorageManagervalidates the structure of the parsed JSON and limits numerical ranges for positions/volume. - Protection against prototype pollution (AUDIT-022): i18n translations now use
Object.create(null)and reject__proto__/constructorkeys.
Accessibility
- Localised SR announcements (AUDIT-007):
KeyboardManager.announceActionnow run via i18n; new keysplayer.playing,player.paused,player.muted,player.unmuted,player.captionsOn,player.captionsOff,player.exitFullscreen,player.volumePercent,player.speedRatefor en/de/es/fr/ja. - The labelling design no longer misuses ‘
role="menu"’ (AUDIT-008): The control panel is now a labelledrole="dialog"with a focus trap and an ‘Escape’ close function. - Instance-specific live area (AUDIT-032): The announcer ID now contains the player
instanceId. - transcript lines are genuine ‘
<button>’ elements with localised labels (AUDIT-033). aria-valuetexton the volume control (AUDIT-038) andPage{Up,Down},Home,Endbuttons on the progress bar ( AUDIT-039).- Restoring focus in the settings dialogue (AUDIT-031): Focus now returns to the trigger element when the dialogue is closed.
- Correction to the demo
lang="ja"(AUDIT-030):demo/demo-jp.htmlnow declares the correct BCP-47 tag.
Code quality
- Listener/instance registry leaks in the
destroy()fixed (AUDIT-003):PlayerandControlBareachwindow/documentlistener via an instance-specificAbortController, splicing fromPlayer.instancesand cascading deletionplaylistManager/audioDescriptionManager. Playertyping has been tightened (AUDIT-019, AUDIT-036): instance fields now usePlayerOptions/PlayerState/Renderer;seek/setVolume/setPlaybackSpeed/load‘accept’number/ typed configurations and are restricted viaNumber.isFinite.(Player as any).observeLazy→ static methods (AUDIT-020).- Typing of dynamic feature loaders (AUDIT-018).
- i18n placeholder regex now includes escape characters (AUDIT-021).
- Empty “catch” statements are now logged under “
options.debug” (AUDIT-037).
Documentation
- README/CHANGELOG with version details (AUDIT-027), browser matrix adapted to esbuild target (AUDIT-028), default values
aligned (AUDIT-029),
playlisttrackchange/floatingchangeevents documented (AUDIT-010, AUDIT-011), incorrect API name corrected (AUDIT-009). - New ‘
SECURITY.md’, ‘CONTRIBUTING.md’ and ‘CODE_OF_CONDUCT.md’ (AUDIT-048),engines.nodedeclared (AUDIT-034),prepublishOnlyadded to the script (AUDIT-045), banner reproducibility issue resolved (AUDIT-046). - Volume step in KEYBOARD.md corrected to 10% (AUDIT-043). Reference to “searchable” transcription in the README file removed pending implementation (AUDIT-042). Language of touch targets in the README file updated to match CSS (AUDIT-040).
[1.1.8] – 2 May 2026
Note
Internal version used during the audit-driven hardening sprint; replaced by 1.1.10. No public API changes between 1.1.7 and 1.1.8.
[1.1.7] – 20 April 2026
Added
- Custom floating player (‘Own PiP’ / mini-player): An optional, page-internal, floating player that replaces the browser’s native
picture-in-picture function.
- Automatically appears as a floating player when the original player is scrolled out of view (via
IntersectionObserver) and automatically docks when it is scrolled back into view. - Manual docking/undocking via the existing PiP button. Manual docking/undocking overrides the scroll-based behaviour until the next
user-initiated
play. - close button pauses playback, returns the video to its original container and suppresses automatic pinning for the remainder of the playback session.
- Fully movable and resizable (
DraggableResizableutility); the geometry is controlled per player viaStorageManager. - Reduced control bar within the floating shell: only Play/Pause, Rewind, Fast-forward, Volume, Subtitles, PiP and
Full Screen are visible. Tooltips open above the buttons; subtitles are displayed on
font-size: 90%andwidth: 95%. - The browser’s native PiP is automatically suppressed (
disablePictureInPicture+disableRemotePlayback) whilst floating mode is enabled, providing users with a consistent user experience across all browsers. - By default, only available on desktop: The feature is
floatingMinViewportWidth(default768px) and the button for the floating PiP window is excluded from the overflow menu, so it is never displayed on mobile devices. - Audio (
<audio>) are automatically skipped. - The sign language overlay is forced to close whilst the floating shell is active, and is reactivated upon exit.
- Accessibility: The floating shell uses
role="dialog"with translatedaria-label; the PiP toggle usesaria-pressed; focus is reset to the original button upon closing.
- Automatically appears as a floating player when the original player is scrolled out of view (via
- New options:
floating: boolean(Defaultfalse) /data-vidply-floating="true"floatingPosition: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'(Default'bottom-right') /data-vidply-floating-position="..."floatingMinViewportWidth: number(Default768) /data-vidply-floating-min-viewport-width="..."
- New translation keys:
player.floatingPlayer,player.floatingPlayerClose,player.floatingPlayerEnter,player.floatingPlayerExit,player.floatingPlayerDialogfor all built-in languages (en, de, es, fr, ja). - Unit tests: 20 new Vitest tests covering
tests/unit/FloatingPlayerManager.test.jscover the following areas: Enter/Exit, manual pinning/unpinning, automatic float on scrolling out, suppression of manual unpinning, viewport protection and clean-up.
Changed
- The full-screen button is now permanently located outside the overflow menu in every viewport (
overflowPriorityMobile = 1) and is inserted in the DOM order behind the overflow menu button, so that on mobile devices the control on the far right is always ‘Full Screen’ and the overflow menu is directly to its left. .vidply-controls-rightnow usesjustify-content: flex-end, so that buttons on the right-hand side are reliably right-aligned even when the container expands to full width on mobile devices..vidply-overflow-menuno longer enforcesmargin-left: auto/order: 999; the new DOM order, in conjunction with the ‘flex-end’ alignment, ensures natural positioning.
[1.1.3] – 19 April 2026
Fixed
- HLS subtitle synchronisation: The
hls.jssubtitle track when the language is changed and in response to thistextcuesupdate, so that the active subtitle track always matches the user’s selection. - HLS subtitle fragments:
Hls.Events.SUBTITLE_FRAG_PROCESSEDand sendtextcuesupdate, so that transcripts and live subtitles are updated as soon as new subtitle fragments are downloaded (no more truncated transcripts for long streams).
[1.1.1] – 18 April 2026
Added
- Buffer loading indicator: A centred, accessible loading indicator that appears whenever media is being buffered (
waiting,seeking, initiallyloadstart) and disappears whencanplay/playing. Implemented for HTML5, HLS and DASH renderers.- Controlled via the
vidply-bufferingclass on the player container; uses the.vidply-loadingelement, which is positionedPlayer.createBufferingLoadingOverlay(). - ‘z-index’ lies beneath the playback overlay (
--vidply-z-buffering: 1), ensuring that the spinner never obstructs interaction with the mouse pointer. - Please note
prefers-reduced-motion(no rotation animation when ‘Reduced Motion’ is preferred).
- Controlled via the
[1.1.0] – 17 April 2026
Changed
- TypeScript migration: The entire
src/ES Module tree (.js) to strict TypeScript (.ts).- All renderers, managers, controls, i18n components, utilities and
core/Playerare now.ts. tsconfig.jsonhas beenstrict: trueupdatednoImplicitAny,strictNullChecks,noImplicitReturns.- build pipeline: esbuild bundles TypeScript directly into ESM and IIFE;
tsc --emitDeclarationOnlywrites type declarations indist/types/. package.jsonensurestypes: "dist/types/index.d.ts", so that users have full IntelliSense access without needing an additional@typespackage.- New scripts:
npm run build:types,npm run typecheck.
- All renderers, managers, controls, i18n components, utilities and
- All internal imports use paths without extensions (e.g.
import { Player } from './core/Player') and rely ontsconfigmoduleResolution.
Added
- Buffer spinner (initial implementation): A centred loading spinner is displayed until the media is ready to play, replacing the previous static text ‘Loading…’.
Migration notes
- No changes to the public API for end users. If you have
src/directly (e.g.src/renderers/HTML5Renderer.js), update the path to.ts(or omit the extension altogether) and ensure that your bundler can process TypeScript. -
TypeScript users can now import types directly:
import type { PlayerOptions, RendererType } from 'vidply';
[1.0.51] – 15 April 2026
Added
- Download button: New optional control in the control bar for downloading the current media file.
- Enabled via
downloadButton: true(defaultfalse) ordata-vidply-download-button="true". - a custom URL via
downloadUrl: '...'/data-vidply-download-url="...". Accesses the current media filesrcif not specified. - Fully internationalised (
player.downloadtranslation keys) and keyboard-accessible.
- Enabled via
[1.0.50] – 14 April 2026
Added
- SoundCloud renderer added: Top-quality SoundCloud playback via the SoundCloud Widget API.
- Automatically detected for any URL that
soundcloud.com(nodata-rendererrequired). - Uniform controls for play/pause, skip, volume, mute and progress bar; can be integrated into the VidPly user interface in exactly the same way as for YouTube/Vimeo.
- The privacy layer (in
mpc-vidply) natively supports SoundCloud (GDPR consent required before the iframe loads).
- Automatically detected for any URL that
- Apple HLS Native TextTrack Bridge: On iOS/iPadOS, where
hls.jscannot be executed, subtitles, transcripts and quality control now work via the native HLSTextTrackAPI.- Waits for
addtrack/removetrack/loadedmetadata(debouncing), so that subtitle variants are displayed in the subtitle menu and in the transcript area. - Uses the same user interface for subtitles and transcripts as
hls.jsfor a consistent user experience. canPlayNatively()now restricts the native path exclusively to iOS / iPadOS; Desktop Safari on macOS useshls.jsfor full functional parity (quality menu, advanced subtitle styling).
- Waits for
- Full-screen menu button on iOS: The ‘Settings/Menu’ button remains visible in iOS full-screen mode.
Fixed
- Subtitles and transcripts no longer disappear on iOS HLS streams.
- The quality menu is displayed for iOS HLS streams when multiple renditions are available.
[1.0.45] – 12 April 2026
Added
- MPEG-DASH streaming: Full DASH support via dash.js (loaded from the CDN as required)
- Adaptive bitrate selection via a quality menu
- Rendering of TTML/STPP subtitles natively delegated to dash.js
- Support for WebVTT subtitles with full subtitle formatting and interactive transcript
- Automatic renderer selection for
.mpdURLs - Support for deferred loading (
deferLoad: true) - Robust error handling and controlled stream termination (
dash.reset()beforedash.destroy()) - Appended to the TTML rendering div before
dash.initialize()to avoid race conditions - Quality labels include the bitrate for clarity (e.g. “720p (1427 kbps)”)
supportsAutoQuality()as well asisAutoQuality()for automatic quality switchinghandlesOwnCaptions()to delegate the display of TTML subtitles to dash.js
- Consistent updates to text cues: A new
textcuesupdateevent used by both HLS and DASH renderers for dynamic transcript updates - HLS cue update request: The HLS renderer now sends
textcuesupdatefor incrementally loaded WebVTT subtitle segments (resolves the issue of transcripts being truncated) - New
hideSpeedForDashOption to hide the playback speed controls for DASH streams - Demo pages:
single-player-dash.htmlanddash-test.htmlfeaturing multiple DASH test streams - Unit tests for DASHRenderer (initialisation, quality management, subtitle processing, error handling, clean-up)
Changes
CaptionManager.updateCaptions()now leaves processing to renderers that handle their own subtitles (TTML)TranscriptManagerwaits for a generictextcuesupdateevent (replacesdashtextcuesupdate)preventDragOnElementnow also stops thepointerdownredirect (resolves the issue with the ‘Autoscroll’ tick box in the transcript)- Obsolete
TextTrackfiltering (_vidplyStaleflag) prevents ghost tracks after a stream change
Fixed
- The ‘Autoscroll’ tick box in the transcript window could not be ticked due to a
DraggableResizableerrorspointerdown SourceBuffer append failed "InvalidStateError"error during DASH stream switching- Race condition during TTML rendering, which led to warnings such as ‘Subtitles cannot be displayed’
- HLS transcript ended prematurely (e.g. ‘bipbop’ at 01:11) due to the incremental loading of subtitles
- The quality menu does not display distinct levels for streams with the same resolution but different bitrates
- Control bar buttons are not updated correctly when switching between DASH streams
[1.0.44] – 3 April 2026
Amended
- WCAG 2.2 AA compliance: The accessibility target has been raised from WCAG 2.1 AA to WCAG 2.2 AA
Resolved
- Target size (WCAG 2.2 SC 2.5.8): It has been ensured that all interactive targets meet the minimum size of 24 × 24 CSS pixels
- Progress bar: A transparent
::beforehit area added (9 px visual → 24 px target) - Progress bar access point: Increased from 15 px to 24 px
- Volume control: Horizontal spacing for the 24-px touch target area has been increased
- Volume slider: Increased from 10 px to 24 px
- Resize handles (corners): Increased from 16 px to 24 px
- Resize drag points (edges): Increased from 8 px to 24 px on the narrow axis
- Progress bar: A transparent
- Dragging actions (WCAG 2.2 SC 2.5.7): It has been verified that all dragging operations have alternatives for operation using a single pointer without dragging
- Transcript/sign language window: Toggle via the D/R/Home/Esc keyboard keys and via the settings menu
- Progress bar: ‘Click to skip’ + keyboard arrow keys
- Volume control: Click to adjust + ‘Up’/‘Down’ arrow keys
- Playlist carousel: Native CSS scrolling + ‘Back’/‘Next’ buttons
Documentation
- Updated references to WCAG compliance, from 2.1 to 2.2, in the README file, the user manual and the ‘Getting Started’ guide
[1.0.40] – 21 February 2026
Added
- Dynamic HLS subtitle processing: Automatic detection and loading of subtitle tracks from HLS manifests
- Fixes and improvements to the light theme
- The copyright year has been updated to 2026
Fixed
- Removed a blocked Akamai video from the HLS stream demo page
[1.0.39] – 20 February 2026
Fixed
- Transcript dialogue box overflow (WCAG 1.4.10): Issues with the transcript dialogue box overflowing in full-width video players have been resolved, ensuring proper compliance with reflow guidelines
[1.0.38] – 19 February 2026
Fixed
- Browser fallback message removed
- HTML5 validation errors relating to accessibility and media elements
Changed
- esbuild updated to version 0.27.3
[1.0.37] – 18 February 2026
Added
- Testing infrastructure: Vitest added for unit tests and Playwright added for end-to-end tests
- Sign language display mode: New option for the sign language overlay display mode
- New picture-in-picture (PiP) icon for the sign language window
- Demo pages for single players and playlists for testing
Fixed
- Exits full-screen mode when clicking on external media in the playlist preview list
[1.0.36] – 17 February 2026
Fixed
- Comprehensive improvements to full-screen mode: several fixes to full-screen behaviour on various devices
[1.0.35] – 16 February 2026
Fixed
- Height of the mobile overflow menu when positioned below the trigger button
- Added aspect ratio handling for Vimeo or YouTube layers only
- Improvements to keyboard drag mode
- Various bug fixes for iOS playlists
- Support for sign language via touch: dragging and resizing via touch for sign language overlays enabled via pointer events
[1.0.34] – 15 February 2026
Fixed
- Display of audio cover art in mixed playlists when a poster image is available
[1.0.33] – 14 February 2026
Added
- Delayed loading: When selecting a playlist, metadata is now loaded without automatic playback
- Display of the initial duration before the media metadata is loaded
- Lazy loading for audio, video and HLS files (loading only upon playback)
Changed
- Updated documentation and demo files
[1.0.32] – 13 February 2026
Fixed
- Hiding the speed control for HLS streams (identified by the .m3u8 source URL)
- Obsolete JavaScript code removed
[1.0.31] – 12 February 2026
Added
- Preview thumbnails: Video preview thumbnails when hovering over the progress bar
- Automatic poster creation: Automatic creation of poster images from videos for playlists
[1.0.30] – 11 February 2026
Added
- Thumbnails: Video thumbnails and automatic poster generation for individual videos
Changed
- esbuild dependency updated
[1.0.29] – 10 February 2026
Fixed
- Swapped audio description subtitle tracks in playlists
Added
- Transcript descriptions: Always show descriptions in the transcript and swap tracks for videos with audio description
[1.0.27] – 8 February 2026
Added
- Support for mixed playlists: support for playlists containing both audio and video items
[1.0.25] – 6 February 2026
Added
- Added
dist/Directory added to the GitHub repository
Changed
- ESM optimisation: Improved ES module builds with legacy code as an option
[1.0.24] – 5 February 2026
Added
- Menu keyboard navigation: ‘scrollIntoView’ added for keyboard navigation in all menu pop-ups
[1.0.23] – 4 February 2026
Changed
- Support for light mode removed (simplified design)
- All size specifications have been converted to rem units for better scaling in terms of accessibility
[1.0.22] – 3 February 2026
Added
- WCAG-compliant light mode: Added light mode with proper support for colour schemes (later removed in 1.0.23)
[1.0.21] – 1 December 2025
Added
- Display of cover art for individual audio files: Cover art is now also displayed for individual audio files (not just for playlists).
If an
posteroption is specified for an individual audio file, VidPly automatically creates a cover art element that displays the album cover above the player, in the same way as for playlists. The cover art uses an aspect ratio of 16:3 with a responsive design. - Responsive overflow menu for the control bar when there are many buttons
- Transcript-style subtitle display for audio players (cumulative subtitles with highlighting)
- Drag and resize modes for the transcript window with keyboard and mouse support
- Drag and resize modes for the sign language video window
- Settings menus for the transcript and sign language windows
- Dynamic button texts and ARIA labels that change depending on the active state
Changed
- Touch support for dragging and resizing transcript and sign language windows: Touch support for dragging and resizing the transcript window and the sign language video on touch devices has been enabled. On mobile devices (< 768px), dragging and resizing are only available in full-screen mode. On tablets and desktops (>= 768px), dragging and resizing work in all modes. Users can drag windows by tapping the header and resize them by tapping the resize handles, providing the same functionality as mouse-based interactions.
- Automatically hide controls in full-screen landscape mode: The controls are now automatically hidden in full-screen landscape mode (as on a desktop), enabling an immersive viewing experience. Tapping or swiping on the screen reveals the controls; when inactive, they are automatically hidden. In full-screen portrait mode (mobile layout), the controls remain visible at all times.
- Simplified volume control on touch devices: On touch devices (iOS, Android, tablets), the volume control now displays a simple mute/unmute button instead of a volume slider. Mobile devices control the volume of HTML5 videos via hardware buttons, so a mute button is all that is needed to mute the audio quickly. Desktop devices retain full volume control via a slider. This ensures a better user experience, as it provides a quick mute function whilst avoiding faulty sliders on mobile devices.
- The mobile breakpoint has been uniformly updated from 640px to 768px in all CSS and JavaScript files
- The logic for the mobile breakpoint now uses
< 768pxfor mobile devices and>= 768pxfor desktop - Minimum width of the transcript window: 370px on desktop, 300px on mobile devices
- The transcript window for videos also has minimum widths (as with audio)
- Improved responsive design for mobile devices
Fixed
- Menu positioning in landscape mode: An issue has been resolved whereby menus in landscape mode on desktop computers, tablets and smartphones were not positioned correctly above the buttons. The CSS overrides specific to landscape mode for menu positioning, which interfered with the default logic for centring the menu, have been removed. Menus are now correctly centred above their buttons in all landscape scenarios using the default positioning (right: 50%; transform: translateX(50%)).
- Desktop overflow menu in landscape full-screen mode: An issue has been resolved whereby, on desktop devices in landscape full-screen mode, an empty button for the overflow menu was incorrectly displayed. The logic for detecting the overflow was forcing an overflow for all scenarios in landscape full-screen mode , but should only apply to mobile devices (< 768px). Desktop devices in full-screen mode now display all buttons directly, without the overflow menu.
- Issue with dual full-screen modes on iOS/iPadOS: An issue has been resolved where the native video full-screen mode was displayed on top of the
pseudo-full-screen mode on iOS/iPadOS devices. iOS/iPadOS detection has been added to always use pseudo-full-screen mode instead of
the native full-screen API, thereby preventing the video element from switching to its own native full-screen mode. Furthermore, the
webkit-playsinlinefor improved iOS compatibility. Now, only one full-screen layer is displayed on iOS devices. - Touch dragging and resizing in full-screen mode: An issue has been resolved where dragging and resizing in full-screen mode on mobile
devices was not working. Full-screen change listeners have been added to reinitialise ‘DraggableResizable’ instances when entering and exiting
full-screen mode on mobile devices. These have been
touch-action: noneto the transcript and sign language headers to prevent interference from browser touch inputs. CSS rule for mobile devicescursor: default !importantincursor: move !importantin full-screen mode. Touch-based dragging and resizing now works correctly in full-screen mode for both the transcript window and the sign language video on touch devices . - Positioning of subtitles in mobile full-screen mode in landscape orientation: An issue has been resolved where subtitles were not moved to the bottom edge when the controls were hidden in full-screen landscape mode. Subtitles are now dynamically positioned at the bottom edge: 16px when the controls are hidden, and move upwards to bottom: 96px when the controls are visible or the video is paused, ensuring an optimal viewing experience without obstructions.
- Correction to menu positioning in mobile full-screen landscape mode: An issue has been resolved where menus in
full-screen landscape mode were not correctly positioned above their buttons.
position: relativeto all buttons so that menus (whichposition: absolute) can be positioned relative to their parent button. It has been ensured that menus are correctly centred (right: 50%; transform: translateX(50%)) so that they appear directly centred above their respective buttons, rather than offset to the side. - Automatic hiding in mobile full-screen landscape mode on touch devices: An issue has been resolved where controls were not automatically hidden following a touch interaction in
full-screen landscape mode. The problem was that the CSS
:hoverpseudo-class persisted on touch devices, keeping the controls visible indefinitely. Now:hoverthis behaviour is restricted exclusively to desktop devices, which@media (hover: hover) and (pointer: fine), whilst touch devices rely exclusively on JavaScript-controlled visibility classes . Controls are now automatically hidden as intended on mobile devices after 4.5 seconds of inactivity. - Positioning of menus in mobile full-screen landscape mode: An issue has been resolved whereby menus in full-screen landscape mode were not positioned correctly above their buttons. The positioning has been changed from centred (left: 50%; transform: translateX(-50%)) to right-aligned (right: 0), so that menus appear directly above their respective buttons.
- Correction to video centring in mobile full-screen landscape mode: An issue has been resolved where the video was not centred within the viewport in full-screen landscape mode. The video wrapper has been positioned absolutely to fill the entire player (top: 0; left: 0; right: 0; bottom: 0), and Flexbox has been used to centre the video correctly both horizontally and vertically.
- Menu layout in mobile full-screen landscape mode: An issue has been resolved where menus (overflow, speed, labels, etc.) in full-screen landscape mode were displayed horizontally rather than vertically. ‘flex-direction: column’ has been explicitly added to ensure that the menu items stack vertically as in portrait mode, whilst maintaining the horizontal layout for icons and text within each menu item.
- Automatic hiding in mobile full-screen mode in landscape orientation: The issue where the controls were not automatically hidden in full-screen mode in landscape orientation has been resolved. CSS specificity has been increased using ‘!important’ rules to override the default values for mobile devices, thereby ensuring correct behaviour when automatically hiding the controls. The controls are now hidden when inactive and can be revealed again by tapping or swiping.
- Centring of videos in mobile full-screen landscape mode: An issue where videos were not centred in full-screen landscape mode has been resolved. Flex centring (align-items: centre, justify-content: centre) has been added for the video wrapper, along with the correct ‘object-fit: contain’ for the video element.
- Visibility of controls in mobile full-screen mode in landscape orientation: The issue where the controls on the right-hand side (overflow menu, full-screen button, etc.) were not displayed in full-screen mode in landscape orientation has been resolved. It has been ensured that all control containers and child buttons are displayed correctly using the ‘display: flex’ and ‘display: inline-flex’ rules.
- Overflow menu in mobile full-screen mode in landscape orientation: The detection of the overflow menu in full-screen mode in landscape orientation has been corrected. The overflow detection now correctly recognises full-screen mode in landscape orientation and ensures that buttons and the overflow menu function correctly, even when the viewport width exceeds 768 px.
- iOS full-screen mode: Full-screen functionality on iPhone/iPad devices has been corrected. As iOS does not support the full-screen API for container elements, VidPly now automatically switches to a ‘pseudo-full-screen’ mode, which uses CSS to position the player so that it fills the viewport. This ensures a correct full-screen experience on iOS, whilst all player functions remain intact.
- Orientation-dependent controls in mobile full-screen mode : The positioning of the controls depending on the device’s orientation in full-screen mode has been corrected. In landscape mode, the controls are now superimposed over the video at the bottom. In portrait mode, the controls remain below the video (mobile layout). This ensures an optimal viewing experience in any orientation.
- Correction to the z-index for the mobile menu: The issue where the overflow menu and volume menu were displayed behind the video wrapper in full-screen mode has been resolved. The z-index has been increased to 100 for all menus to ensure they appear above all video content. ‘pointer-events: auto’ has been added, to ensure the menus can be operated by touch.
- Support for volume buttons on iOS: The issue where the volume buttons did not respond to touch on iOS and mobile devices has been resolved. A ‘touchend’ event handler has been added for the mute/volume button to ensure the volume control menu opens correctly on touch devices.
- Touch support for the iOS volume control: The issue where the volume control on iOS and mobile devices did not respond to touch has been resolved. The ‘touchstart’, ‘touchmove’, ‘touchend’ and ‘touchcancel’ event handlers have been added to the volume control to enable correct touch interaction on all mobile devices. A larger touch target (padding) and “touch-action: none” have been added to prevent scrolling. Touch event prevention has been added to the volume menu to stop “event bubbling”.
- The issue where ‘overflow:hidden’ hid controls and menus in full-screen mode in landscape orientation has been resolved by allowing the video wrapper to use ‘overflow: visible’ only in landscape orientation.
- A ‘touchmove’ event listener and an ‘enterfullscreen’ handler have been added to ensure that controls are displayed when the screen is touched in full-screen mode.
- The delay for automatic hiding in full-screen mode has been increased (1.5 times the normal delay) to improve the user experience on mobile devices.
- Support has been added for the ESC key to exit pseudo-full-screen mode on iOS and other devices without native full-screen API support .
- Error handling for the full-screen API has been improved and now includes an automatic fallback to pseudo-full-screen mode if the native API fails.
- The function for resizing the transcript window now correctly displays the drag handles and works with the mouse
- The resizing function for sign language videos has been improved
- Consistent breakpoint logic throughout the code
Documentation
- All documentation files have been updated to include features for dragging and resizing
- References to mobile breakpoints have been corrected (640px → 768px)
- Comprehensive documentation on keyboard shortcuts for the ‘D’ and ‘R’ keys has been added
- The documentation on transcription and sign language has been expanded to include details on the settings menu
[1.0.11] – 15 November 2025
Added
- Settings menu for sign language videos with options to drag, resize and close using the keyboard
- Support for multiple sign language video sources with automatic language selection
- Automatic switching between sign language videos when subtitles change (provided the language codes match)
- Accessible labels for all selection fields (visually hidden but available to screen readers)
- FormUtils.js utility module for creating accessible form elements
createLabeledSelect()Utility function for creating labelled selection elementstoggleLabeledSelect()Helper function for showing and hiding labelled selection elementspreventDragOnElement()Helper function to centrally prevent dragging- Translation key
closeSignLanguageas well assignLanguageSettingsfor all integrated languages
Changed
- Drop-down menus now use
aria-expandedinstead ofaria-pressedoraria-haspopupfor better accessibility - Improved focus handling for drop-down menus – the Escape key returns focus to the trigger button
- Improved Tab key navigation – open drop-down menus close when the Tab key is used to move to another button, without losing focus
- The positioning of the sign language settings menu now utilises the parent container to ensure correct alignment
- The implementation of the language selection has been revised to utilise the new FormUtils helper functions
Fixed
- The resize icon was not displayed in the ‘Transcript’ and ‘Sign Language Settings’ menus
- The sign language settings button was not working correctly
- Drop-down menus close both old and new menus when clicking between buttons
- Pressing the Escape key causes the focus to jump back to the previous button
- The positioning of the menus jumps when opening drop-down menus
- Incorrect translation text on the button to close the sign language feature (‘Close Transcript’ → ‘Close Sign Language Video’)
- The sign language settings menu does not support navigation using the arrow keys
Improved
Accessibility
- All selection fields now have correctly assigned labels for screen readers
- Improved use of ARIA attributes in the drop-down menus
- Improved keyboard navigation in line with Bootstrap 5.3 guidelines
- Consistent focus management for all interactive elements
Code quality
- Reduction in code duplication by moving common patterns into helper functions
- Improved maintainability through centralised creation of form elements
- Consistent patterns for all language selection fields
Documentation
- Updated documentation on sign language, featuring multiple video sources and language switching
- Expanded documentation on the sign language settings menu and keyboard shortcuts
- Expanded README file with an updated description of sign language features
[1.0.5] – 16 October 2025
Added
- Full internationalisation of the time display and the formatting of time durations
- Translation strings for all units of time (hours, minutes, seconds) in all 5 supported languages
- Correct pluralisation of time units in all languages
- i18n support for the ‘aria-label’ of the ‘time display’ and the prefix ‘Duration:’
Changed
TimeUtils.formatDuration()The i18n system is now used instead of hard-coded English strings- The aria labels for the time display are now translated according to the user’s language settings
- Screen reader announcements regarding time and duration are now correctly localised
Improved
- Internationalisation
- All UI elements, including time displays, are now fully translated
- Time formatting now takes language-specific conventions into account
- Correct singular and plural forms for all supported languages (en, de, es, fr, ja)
- Improved accessibility through translated ARIA labels for screen readers
Documentation
- The README.md file has been updated with comprehensive feature descriptions
- Live demo links added for GitHub Pages
- Expanded API documentation with playlist examples
- Improved guidelines for contributions
- The copyright year has been updated to 2025
[1.0.4] – 16 October 2025
Added
- Navigation buttons for the previous/next track in playlist mode
- Dynamic visibility of control buttons depending on available features (subtitles, chapters, transcript)
- Focus management – returns to the player after selecting a playlist item
- Semantic HTML structure with correct
<ul>and<li>elements for playlists - Comprehensive ARIA attributes for playlist elements (
aria-posinset,aria-setsize,aria-current) - ARIA live regions to announce track changes to screen readers
- ARIA landmarks (
role="region") for the playlist panel - Visually hidden keyboard instructions for screen reader users
- Context regarding track position (“Track X of Y”) in the labels of playlist elements
- Human-readable time formats for screen readers (e.g. “3 minutes, 23 seconds” instead of “03:23”)
- Status indicators exclusively for screen readers for the track currently playing
Changed
- Playlist items now use semantic
<li>elements instead of<div>- elements - The control bar is updated dynamically when the media tracks change
- The transcript content is now automatically updated when switching between playlist items
- The time displays now use
aria-hiddenin visual format andaria-labelfor natural language - Improved heading structure with correct
<h2>elements in the playlist
Improved
- keyboard navigation
- Dynamic ‘tabindex’ pattern for efficient navigation within the playlist (only one element in the tab order)
- Navigation using the arrow keys (↑/↓) through the playlist items
- Home/End keys to jump to the first/last track
- Press Enter or the space bar to play the selected track
- Accessibility
- WCAG 2.2 Level AA-compliant navigation within the playlist
- Improved focus states with visible borders (2px throughout)
- Improved screen reader context with position, status and action instructions
- Intelligent time format announcements (adapts to duration)
- Seamless keyboard workflow from the playlist to the playback controls
- Smart button display (only show if functions are available for a particular track)
- The playlist remains open when tracks change, with the transcript content updated
Fixed
- Screen readers no longer read time formats character by character (colons, individual digits)
- The transcript is now updated correctly when switching between tracks with different subtitles
- Control buttons (subtitles, chapters, transcript) now appear and disappear correctly depending on the track
- Focus status is now correctly maintained whilst interacting with the playlist
[1.0.1] – 12 October 2025
Added
- Menu for selecting the subtitle track – Click the ‘CC’ button to switch between the available subtitle languages
- Visual indicator (tick) for the active subtitle track
- Keyboard shortcut (C) now opens the subtitle menu when multiple tracks are available
- Icon now updates automatically when subtitles are enabled or disabled
1.0.0 – 11 October 2025
Initial release
VidPly v1.0.0 is here! A complete, production-ready video player built using pure ES6 JavaScript.
Added
Core features
- Support for playing HTML5 video and audio files
- Support for multiple formats (MP3, OGG, WAV, MP4, WebM)
- YouTube integration with custom controls
- Vimeo integration with a unified API
- Support for HLS streaming with adaptive bitrate
- Responsive player design
Controls & user interface
- Play/Pause button with status indicator
- Progress bar with search function
- Time display (current/total duration)
- Volume control with vertical slider
- Mute/Unmute button
- Playback speed control (0.25x – 2x)
- Full-screen toggle
- Picture-in-picture support
- Settings dialogue with options
- Automatically hide controls within the video
- Tooltips when the mouse pointer hovers over the progress bar
Accessibility
- Full keyboard navigation (compliant with WCAG 2.2 AA)
- Support for screen readers with ARIA labels
- Customisable keyboard shortcuts
- Support for high-contrast mode
- Focus indicators for all interactive elements
- Voice announcements for active areas
- Support for reduced animations
- Touch targets at least 44px in size on mobile devices
Captions and subtitles
- Support for WebVTT subtitles
- Support for multiple audio tracks
- Customisable subtitle design (font, size, colour)
- Settings for background colour and opacity
- Options for positioning subtitles
- Support for VTT formatting (bold, italics, language labels)
Internationalisation
- English (en) translation
- Spanish (es) translation
- French (fr) translation
- German (de) translation
- Japanese (ja) translation
- Easily extensible translation system
- Runtime language switching
Features for developers
- Vanilla ES6 modules (no build required)
- Clear, well-documented API
- Event system for state changes
- Programmatic player control
- Multiple players on the same page
- Automatic initialisation via data attributes
- Support for manual initialisation
- Methods for deletion/clean-up
- Debug mode for development
Performance
- Support for lazy loading
- Configurable pre-loading strategies
- Efficient event handling
- Minimal dependencies
- Low memory usage (~50 KB uncompressed)
Technical details
Architecture
- Modular design based on ES6 classes
- Renderer patterns for various media sources
- Plugin system for extending functionality
- Event-driven architecture
- Separation of concerns (MVC-like)
Browser support
- Chrome 90+
- Firefox 88+
- Safari 14+
- Edge 90+
- iOS Safari 14+
- Android Chrome 90+
Renderer
- HTML5 Renderer – Native video/audio playback
- YouTubeRenderer – YouTube IFrame API
- VimeoRenderer – Vimeo Player API
- HLSRenderer – HLS.js integration
Components
- Player – Core class of the player
- ControlBar – Manager for UI controls
- CaptionManager – Manager for captions/subtitles
- KeyboardManager – Keyboard navigation
- SettingsDialog – Settings interface
- EventEmitter – Event system
Utility Functions
- DOMUtils – Utility functions for DOM manipulation
- TimeUtils – Utility functions for time formatting
- i18n – Internationalisation system
Documentation
- Comprehensive README file with API reference
- Quick start guide
- Detailed documentation on usage
- Inline code documentation
- Live demo with examples
Build system
- esbuild – Fast JavaScript bundler
- clean-css – CSS minifier
- Build scripts for creating production bundles
- Watch mode for development
- Multiple output formats (ESM, IIFE)
- Source maps for debugging
- Automatic minification
Build scripts
build/build.js- Main JavaScript buildbuild/build-css.js- CSS build and minificationbuild/watch.js- Development watch modebuild/clean.js- Clean up the ‘dist’ directory
Output files
dist/dev/vidply.esm.js- ES module (development)dist/prod/vidply.esm.min.js- ES module (production environment)dist/legacy/vidply.js- IIFE bundle (development)dist/legacy/vidply.min.js- IIFE bundle (production)dist/vidply.css- Styles (unminified)dist/vidply.min.css- Styles (minified)
Source files
src/core/Player.js- Main player class (~500 lines)src/controls/ControlBar.js- Control bar component (~600 lines)src/controls/CaptionManager.js- Subtitle management (~200 lines)src/controls/KeyboardManager.js- Keyboard controls (~150 lines)src/controls/SettingsDialog.js- Settings user interface (~300 lines)src/renderers/HTML5Renderer.js- HTML5 playback (~200 lines)src/renderers/YouTubeRenderer.js- YouTube support (~250 lines)src/renderers/VimeoRenderer.js- Vimeo support (~220 lines)src/renderers/HLSRenderer.js- HLS streaming (~250 lines)src/utils/EventEmitter.js- Event systemsrc/utils/DOMUtils.js- DOM helper functionssrc/utils/TimeUtils.js- Time helper functionssrc/i18n/i18n.js- i18n systemsrc/i18n/translations.js- Translation strings (5 languages)src/icons/Icons.js- SVG icon library (over 30 icons)src/styles/vidply.css- Player styles (~800 lines)src/index.js- Entry point
Demo files
demo/demo.html- Full demo with local media filesdemo/index.html- Demo landing pagedemo/media/- Demo media files (videos, audio, subtitles)
Documentation
README.md- Full documentation (~500 lines)docs/GETTING_STARTED.md- Getting started guide (installation + quick start)docs/USAGE.md- Detailed usage examplesdocs/PLAYLIST.md- Documentation on the playlist functiondocs/BUILD.md- Documentation on the build systemdocs/CHANGELOG.md- This fileLICENSE- GPL v2.0 or later licencepackage.json- Package configuration using build scripts
Statistics
- Total number of lines of code: ~4,000+
- Minified size (JS): ~50 KB
- Minified size (CSS): ~12 KB
- Total size (gzipped): ~18 KB
- Source files: 22
- Build scripts: 4
- SVG icons: over 30
- Languages: 5 included
- Demo files: over 20 media files