Vodlix HTML5 Player
An ultra-light, framework-free HTML5 video player. Netflix-style dark glassmorphism UI, HLS & DASH adaptive streaming, multi-DRM, VAST/IMA ads, Chromecast, analytics, and a clean event-driven API.
The player wraps a native <video> element and layers a custom control bar, settings menu, and overlays on top. hls.js and dash.js are bundled as optional adapters — pass an .m3u8 or .mpd URL and the right engine is selected automatically.
Installation
1 · Script tag (UMD / IIFE)
The simplest path. Exposes a global VodlixPlayer factory. Serve the bundle yourself or load it from a CDN.
<!-- self-hosted -->
<script src="/vodlix-player.js"></script>
<!-- or via CDN -->
<script src="https://unpkg.com/vodlix-html5-player/dist/vodlix-player.js"></script>
2 · ES Module
import VodlixPlayer from 'vodlix-html5-player';
3 · NPM
npm install vodlix-html5-player
The package ships TypeScript declarations (index.d.ts), so VodlixPlayerOptions and every config interface are fully typed in editors.
Output bundles
Pick the bundle that matches your integration. All are produced by the build into dist/.
| File | Format | Use case |
|---|---|---|
vodlix-player.js | IIFE / UMD | Drop-in <script> tag — global VodlixPlayer |
vodlix-player.esm.js | ESM | import in a bundler (Vite, webpack, Rollup) |
vodlix-player-ads.js | IIFE | Ads-enabled build (IMA + VAST) |
index.d.ts | Types | TypeScript declarations |
Quick start
Add a <video> element, load the script, and instantiate. The factory takes a target (element id, HTMLVideoElement, or container element), an options object, and an optional ready callback.
<video id="player" playsinline></video>
<script src="/vodlix-player.js"></script>
<script>
const player = VodlixPlayer('player', {
sources: 'https://example.com/video.mp4',
poster: 'https://example.com/poster.jpg',
autoplay: false,
fluid: true,
});
player.on('play', () => console.log('playing'));
</script>
ES Module variant
import VodlixPlayer from 'vodlix-html5-player';
const player = VodlixPlayer(document.getElementById('player'), {
sources: [
{ src: 'video-720.mp4', type: 'video/mp4', label: 'HD', res: 720 },
{ src: 'video-1080.mp4', type: 'video/mp4', label: 'FHD', res: 1080 },
],
seekStep: 15,
});
Live demo
This player is running the exact bundle described above, embedded right on this page.
VodlixPlayer('docs-player', {
sources: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8',
poster: 'https://image.mux.com/VZtzUzGRv...thumbnail.jpg',
fluid: true,
});
Configuration — options overview
Everything is passed in a single VodlixPlayerOptions object. Only sources is required; pass only what you need. The most common top-level options:
| Option | Type | Default | Description |
|---|---|---|---|
sources | string | VodlixSource[] | — | Video URL, or array of sources (best quality auto-picked by res) |
poster | string | — | Poster image shown before playback |
autoplay | boolean | false | Autoplay (respects browser policy — pair with muted) |
muted | boolean | false | Start muted |
loop | boolean | false | Loop playback |
fluid | boolean | true | Responsive 16:9 layout |
playsinline | boolean | true | Inline playback on iOS |
seekStep | number | 10 | Seek step (s) for keyboard / buttons |
hideControls | boolean | false | Hide all UI — trailer / ambient mode |
contextMenu | boolean | true | Vodlix right-click menu (set false for native) |
backButton | boolean | object | — | Top-left back button (web bundle) |
colors | VodlixPlayerColors | — | Theme colors applied as CSS variables |
debug | boolean | false | Console-log lifecycle, gating and stats |
Feature configs — sprites, chapters, ads, stats, cast, captions, episodes, logo, upnext and more — are documented in their own sections below.
Sources & quality selection
Pass a single URL string, or an array of VodlixSource objects. With an array, the player picks the best by res and exposes the rest in the quality menu.
VodlixPlayer('player', {
sources: [
{ src: 'sd.mp4', type: 'video/mp4', label: 'SD', res: 360 },
{ src: 'hd.mp4', type: 'video/mp4', label: 'HD', res: 720 },
{ src: 'fhd.mp4', type: 'video/mp4', label: 'FHD', res: 1080 },
],
});
| Field | Type | Description |
|---|---|---|
src | string | Media URL (MP4, HLS .m3u8, or DASH .mpd) |
type | string | MIME type, e.g. video/mp4, application/x-mpegURL |
label | string | Quality label shown in the menu |
res | number | Vertical resolution — drives auto-selection & sorting |
HLS & DASH streaming
Hand the player a manifest URL — no extra setup. hls.js handles .m3u8 (with native HLS fallback on Safari), dash.js handles .mpd. Adaptive bitrate qualities populate the settings menu automatically.
// HLS
VodlixPlayer('player', { sources: 'https://cdn.example.com/master.m3u8' });
// DASH
VodlixPlayer('player', { sources: 'https://cdn.example.com/manifest.mpd' });
| Option | Type | Description |
|---|---|---|
hlsEngine | 'auto' | 'hls.js' | 'native' | auto tries hls.js then native; native prefers <video> HLS |
hlsConfig | object | Raw hls.js config override |
qualities | VodlixQuality[] | Manual quality list (overrides auto-detection) |
live | boolean | Mark as a live stream |
dvr | boolean | Override DVR detection (auto from seekable range) |
DRM (Widevine · PlayReady · FairPlay)
DRM is configured per source via keySystems. The browser selects the first supported system. Each entry needs at least a license server url.
VodlixPlayer('player', {
sources: [{
src: 'https://cdn.example.com/protected.mpd',
type: 'application/dash+xml',
keySystems: {
'com.widevine.alpha': {
url: 'https://license.example.com/widevine',
headers: { Authorization: 'Bearer ' },
},
'com.microsoft.playready': {
url: 'https://license.example.com/playready',
},
},
}],
});
FairPlay (Safari)
keySystems: {
'com.apple.fps.1_0': {
url: 'https://license.example.com/fairplay',
certificateUrl: 'https://license.example.com/fps-cert.der',
},
}
| Field | Type | Description |
|---|---|---|
url | string | License server URL |
headers | object | Custom HTTP headers (e.g. auth) on license requests |
certificateUrl | string | Certificate URL (FairPlay only) |
transformLicenseRequest | fn | Wrap the CDM challenge in a custom envelope (token DRM) |
getLicense | fn | Fully custom license exchange (native EME / FairPlay) |
See the live DRM test page for working Widevine and PlayReady manifests.
Captions & audio tracks
Provide subtitle tracks via captions. For HLS/DASH, in-manifest subtitle and audio tracks are detected automatically and added to the settings menu.
VodlixPlayer('player', {
sources: 'movie.mp4',
captions: [
{ src: 'en.vtt', srclang: 'en', label: 'English', default: true },
{ src: 'es.vtt', srclang: 'es', label: 'Español' },
],
});
| Field | Type | Description |
|---|---|---|
src | string | WebVTT file URL |
srclang | string | BCP-47 language code |
label | string | Menu label |
default | boolean | Enabled on load |
kind | 'subtitles'|'captions'|'descriptions' | Track kind |
Chapters & skip intro/outro
VodlixPlayer('player', {
sources: 'movie.mp4',
chapters: {
showMarkers: true,
chapters: [
{ title: 'Intro', start_time: 0, end_time: 90, type: 'intro' },
{ title: 'Act One', start_time: 90, end_time: 1200, type: 'chapter' },
{ title: 'Credits', start_time: 5400, end_time: 5600, type: 'credits' },
],
},
skipIntro: { start: 0, end: 90, label: 'Skip Intro' },
skipOutro: { start: 5400, end: 5600, label: 'Skip Credits' },
});
Chapter ticks appear on the seek bar and in a chapters panel. Skip ranges render a floating "Skip" button while the playhead is inside [start, end].
Thumbnail seek previews
Two modes — pre-generated sprite sheets, or on-demand Flussonic preview frames.
Sprite sheets
sprites: [
{ url: 'thumbs.jpg', start: 0, duration: 600, interval: 5,
width: 160, height: 90, cols: 10 },
]
Flussonic (on-demand)
sprites: {
stream_provider: 'flussonic',
mode: 'jpg', // or 'mp4'
width: 160, height: 90,
// baseUrl auto-derived from sources[0] by stripping /index.m3u8
}
Ads — VAST & Google IMA
Use the ads bundle (vodlix-player-ads.js). Supply a VAST tag URL (adType: 1) or a custom linear video (adType: 2). The player pre-flights the VAST tag and skips straight to content if the response is empty.
<script src="/vodlix-player-ads.js"></script>
<script>
VodlixPlayer('player', {
sources: 'movie.mp4',
ads: {
engine: 'auto', // 'ima' | 'vodlix' | 'auto'
adTag: 'https://ads.example.com/vast.xml',
adType: 1, // 1 = VAST URL, 2 = custom linear
skipTime: 5, // seconds until skippable
preroll: true,
midrolls: [300, 900], // seconds
postroll: false,
},
});
</script>
| Option | Type | Default | Description |
|---|---|---|---|
engine | 'ima'|'vodlix'|'auto' | 'auto' | Ad engine selection |
adTag | string | — | VAST URL (type 1) or video URL (type 2) |
adType | 1 | 2 | — | 1 = VAST, 2 = custom linear |
skipTime | number | 5 | Seconds until skip is allowed |
preroll | boolean | true | Play ad before content |
midrolls | number[] | — | Mid-roll break times (s) |
postroll | boolean | false | Play ad after content |
Analytics & stats
The stats config wires the player to the Vodlix Stats API (ClickHouse v3 payloads). Stats events are also re-emitted on the player so you can pipe them anywhere.
VodlixPlayer('player', {
sources: 'movie.mp4',
stats: {
apiBase: 'https://stats.vodlix.com',
endpoint: '/ingest',
version: 3,
data: {
object_id: 12345,
object_type: 1,
title: 'Movie Title',
},
},
});
player.on('stats:view_start', (e) => console.log('view_start', e));
Set stats.debug: true to console-log every resolved path and outgoing event while integrating.
Chromecast & AirPlay
Cast support is on by default (Cast button appears when a receiver is available). AirPlay shows automatically in Safari.
VodlixPlayer('player', {
sources: 'movie.m3u8',
cast: {
enabled: true,
receiverApplicationId: 'CC1AD845', // default styled receiver
},
airplay: { enabled: true },
// DRM casting needs a custom CAF receiver:
castDrm: {
receiverApplicationId: 'YOUR_APP_ID',
widevine: { licenseUrl: 'https://license.example.com/widevine' },
},
});
Episodes & seasons
Add next/previous navigation and a season → episode picker. Supply data directly, or let the player auto-fetch from the Vodlix API with seriesId + apiBaseUrl.
episodes: {
seriesId: 42,
seasonId: 3,
apiBaseUrl: 'https://app.vodlix.cloud/api',
autoPlayNext: true,
autoPlayTimeout: 10,
onEpisodeSelect: (ep) => loadEpisode(ep.videoid),
}
Logo, Up Next & metadata
VodlixPlayer('player', {
sources: 'movie.mp4',
logo: {
image: 'https://example.com/logo.png',
position: 'top-right',
opacity: 0.8,
link: 'https://example.com',
},
upnext: {
timeout: 10,
getTitle: () => 'Next Episode',
getThumbnail: () => 'next.jpg',
next: () => loadNext(),
},
metadata: { showTitle: true, showEpisodeInfo: true },
showMetaDataOnPause: true,
});
Theming
Two ways to theme: pass a colors object, or override CSS custom properties on the player root.
Via options
VodlixPlayer('player', {
sources: 'movie.mp4',
colors: {
primary: '#e63946',
primaryHover: '#ff5a67',
text: '#ffffff',
bgPanel: 'rgba(15,15,18,0.9)',
},
});
Via CSS
.vdx-player {
--vdx-primary: #e63946;
--vdx-bg: rgba(15, 15, 18, 0.85);
--vdx-text: #fff;
--vdx-font: 'Inter', sans-serif;
}
See the live theming demo to experiment.
API — methods
The factory returns a player instance. Getter/setter methods return the current value when called without arguments.
| Method | Returns | Description |
|---|---|---|
play() | Promise<void> | Start playback |
pause() | void | Pause |
paused() | boolean | Is paused |
currentTime(sec?) | number | Get/set position (s) |
duration() | number | Total duration (s) |
volume(level?) | number | Get/set volume 0–1 |
muted(mute?) | boolean | Get/set muted |
playbackRate(rate?) | number | Get/set speed |
src(src?, type?) | string | void | Get/set source |
requestFullscreen() | void | Enter fullscreen |
exitFullscreen() | void | Exit fullscreen |
isFullscreen() | boolean | Is fullscreen |
readyState() | number | HTML5 readyState |
on(event, cb) | this | Subscribe to an event (chainable) |
destroy() | void | Tear down UI, listeners & sources |
API — events
Subscribe with player.on(type, cb). Beyond the native media events, the player emits namespaced events for streaming, DRM, ads, cast and stats.
player.on('qualitychange', (e) => console.log('quality', e));
player.on('drm:keyAdded', () => console.log('DRM ready'));
player.on('ad:start', () => console.log('ad started'));
player.on('cast:connected', () => console.log('casting'));
| Group | Events |
|---|---|
| Media | loadstart · loadedmetadata · canplay · play · pause · playing · seeking · seeked · waiting · timeupdate · ratechange · volumechange · ended · error |
| Tracks | qualitychange · captionchange · subtitleTrackChanged · audioTrackChanged |
| PiP | pip:enter · pip:exit |
| Ads | ad:start · ad:end · ad:skip · ad:quartile |
| DRM | drm:detected · drm:licenseRequested · drm:licenseReceived · drm:keyAdded · drm:error |
| Cast | cast:ready · cast:connected · cast:disconnected · cast:mediaLoaded · cast:error |
| AirPlay | airplay:available · airplay:connected · airplay:disconnected |
| Stats | stats:view_start · stats:view_complete · stats:view_end · stats:playback · stats:quartile · stats:error |
| Content | contentchange · chapterchange · skipintro:show · upnext:show · sourcechange |
Keyboard shortcuts
| Key | Action | Key | Action |
|---|---|---|---|
| Space / K | Play / Pause | 0–9 | Jump 0–90% |
| ← / J | Rewind 10s | > / < | Speed up / down |
| → / L | Forward 10s | . / , | Frame step |
| ↑ / ↓ | Volume ±10% | C | Cycle captions |
| M | Mute | I | Picture-in-Picture |
| F | Fullscreen | T | Theater mode |
Example demos
Live, runnable examples covering each feature:
Building from source
TypeScript + esbuild. No core runtime dependencies.
npm install
./run.sh build # full production build → dist/
./run.sh dev # watch + HTTPS dev server (port 33334)
./run.sh demo # serve demo pages
| Entry | Output |
|---|---|
src/umd.ts | dist/vodlix-player.js (IIFE) |
src/index.ts | dist/vodlix-player.esm.js (ESM) |
src/umd-ads.ts | dist/vodlix-player-ads.js (Ads) |