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.

~13 KB core, minified Zero runtime deps TypeScript HLS · DASH · DRM UMD & ESM

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

FileFormatUse case
vodlix-player.jsIIFE / UMDDrop-in <script> tag — global VodlixPlayer
vodlix-player.esm.jsESMimport in a bundler (Vite, webpack, Rollup)
vodlix-player-ads.jsIIFEAds-enabled build (IMA + VAST)
index.d.tsTypesTypeScript 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:

OptionTypeDefaultDescription
sourcesstring | VodlixSource[]Video URL, or array of sources (best quality auto-picked by res)
posterstringPoster image shown before playback
autoplaybooleanfalseAutoplay (respects browser policy — pair with muted)
mutedbooleanfalseStart muted
loopbooleanfalseLoop playback
fluidbooleantrueResponsive 16:9 layout
playsinlinebooleantrueInline playback on iOS
seekStepnumber10Seek step (s) for keyboard / buttons
hideControlsbooleanfalseHide all UI — trailer / ambient mode
contextMenubooleantrueVodlix right-click menu (set false for native)
backButtonboolean | objectTop-left back button (web bundle)
colorsVodlixPlayerColorsTheme colors applied as CSS variables
debugbooleanfalseConsole-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 },
  ],
});
FieldTypeDescription
srcstringMedia URL (MP4, HLS .m3u8, or DASH .mpd)
typestringMIME type, e.g. video/mp4, application/x-mpegURL
labelstringQuality label shown in the menu
resnumberVertical 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' });
OptionTypeDescription
hlsEngine'auto' | 'hls.js' | 'native'auto tries hls.js then native; native prefers <video> HLS
hlsConfigobjectRaw hls.js config override
qualitiesVodlixQuality[]Manual quality list (overrides auto-detection)
livebooleanMark as a live stream
dvrbooleanOverride 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',
  },
}
FieldTypeDescription
urlstringLicense server URL
headersobjectCustom HTTP headers (e.g. auth) on license requests
certificateUrlstringCertificate URL (FairPlay only)
transformLicenseRequestfnWrap the CDM challenge in a custom envelope (token DRM)
getLicensefnFully 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' },
  ],
});
FieldTypeDescription
srcstringWebVTT file URL
srclangstringBCP-47 language code
labelstringMenu label
defaultbooleanEnabled 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>
OptionTypeDefaultDescription
engine'ima'|'vodlix'|'auto''auto'Ad engine selection
adTagstringVAST URL (type 1) or video URL (type 2)
adType1 | 21 = VAST, 2 = custom linear
skipTimenumber5Seconds until skip is allowed
prerollbooleantruePlay ad before content
midrollsnumber[]Mid-roll break times (s)
postrollbooleanfalsePlay 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.

MethodReturnsDescription
play()Promise<void>Start playback
pause()voidPause
paused()booleanIs paused
currentTime(sec?)numberGet/set position (s)
duration()numberTotal duration (s)
volume(level?)numberGet/set volume 0–1
muted(mute?)booleanGet/set muted
playbackRate(rate?)numberGet/set speed
src(src?, type?)string | voidGet/set source
requestFullscreen()voidEnter fullscreen
exitFullscreen()voidExit fullscreen
isFullscreen()booleanIs fullscreen
readyState()numberHTML5 readyState
on(event, cb)thisSubscribe to an event (chainable)
destroy()voidTear 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'));
GroupEvents
Medialoadstart · loadedmetadata · canplay · play · pause · playing · seeking · seeked · waiting · timeupdate · ratechange · volumechange · ended · error
Tracksqualitychange · captionchange · subtitleTrackChanged · audioTrackChanged
PiPpip:enter · pip:exit
Adsad:start · ad:end · ad:skip · ad:quartile
DRMdrm:detected · drm:licenseRequested · drm:licenseReceived · drm:keyAdded · drm:error
Castcast:ready · cast:connected · cast:disconnected · cast:mediaLoaded · cast:error
AirPlayairplay:available · airplay:connected · airplay:disconnected
Statsstats:view_start · stats:view_complete · stats:view_end · stats:playback · stats:quartile · stats:error
Contentcontentchange · chapterchange · skipintro:show · upnext:show · sourcechange

Keyboard shortcuts

KeyActionKeyAction
Space / KPlay / Pause09Jump 0–90%
/ JRewind 10s> / <Speed up / down
/ LForward 10s. / ,Frame step
/ Volume ±10%CCycle captions
MMuteIPicture-in-Picture
FFullscreenTTheater 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
EntryOutput
src/umd.tsdist/vodlix-player.js (IIFE)
src/index.tsdist/vodlix-player.esm.js (ESM)
src/umd-ads.tsdist/vodlix-player-ads.js (Ads)