Jump to content

Developer Quickstart

Quick reference for developers contributing to or extending VidPly.

VidPly Logo

πŸš€ Setup

 
# Clone repository
git clone github.com/MatthiasPeltzer/vidply.git
cd vidply

# Install dependencies
npm install

# Build production files
npm run build

# Start dev server
npm run dev
 

Dev server runs at localhost

πŸ“ Directory Structure

 
vidply/
β”œβ”€β”€ build/                       # Build scripts
β”‚   β”œβ”€β”€ build.js                 # TypeScript bundling (esbuild β†’ ESM + IIFE)
β”‚   β”œβ”€β”€ build-css.js             # CSS build (clean-css)
β”‚   β”œβ”€β”€ watch.js                 # Watch mode
β”‚   └── clean.js                 # Clean dist
β”œβ”€β”€ demo/                        # Demo pages
β”‚   β”œβ”€β”€ demo.html                # Main demo
β”‚   β”œβ”€β”€ playlist-audio.html      # Audio playlist demo
β”‚   β”œβ”€β”€ playlist-video.html      # Video playlist demo
β”‚   β”œβ”€β”€ hls-test.html            # HLS streaming demo
β”‚   β”œβ”€β”€ dash-test.html           # DASH streaming demo
β”‚   └── single-player-dash.html  # Single DASH player demo
β”œβ”€β”€ dist/                        # Built files (generated)
β”‚   β”œβ”€β”€ prod/vidply.esm.min.js   # ES Module (production)
β”‚   β”œβ”€β”€ legacy/vidply.min.js     # IIFE (production)
β”‚   β”œβ”€β”€ types/index.d.ts         # TypeScript declarations
β”‚   └── vidply.min.css           # Styles (production)
β”œβ”€β”€ docs/                        # Documentation
β”œβ”€β”€ src/                         # Source code (strict TypeScript)
β”‚   β”œβ”€β”€ core/
β”‚   β”‚   └── Player.ts            # Main Player class
β”‚   β”œβ”€β”€ controls/
β”‚   β”‚   β”œβ”€β”€ ControlBar.ts        # Control bar UI (incl. download button, buffering spinner)
β”‚   β”‚   β”œβ”€β”€ CaptionManager.ts    # Caption handling
β”‚   β”‚   β”œβ”€β”€ KeyboardManager.ts   # Keyboard shortcuts
β”‚   β”‚   β”œβ”€β”€ SettingsDialog.ts    # Settings menu
β”‚   β”‚   └── TranscriptManager.ts
β”‚   β”œβ”€β”€ features/
β”‚   β”‚   └── PlaylistManager.ts   # Playlist support
β”‚   β”œβ”€β”€ i18n/
β”‚   β”‚   β”œβ”€β”€ i18n.ts              # i18n system
β”‚   β”‚   β”œβ”€β”€ translations.ts      # Translation loader
β”‚   β”‚   └── languages/           # Built-in languages
β”‚   β”‚       β”œβ”€β”€ en.ts
β”‚   β”‚       β”œβ”€β”€ de.ts
β”‚   β”‚       β”œβ”€β”€ es.ts
β”‚   β”‚       β”œβ”€β”€ fr.ts
β”‚   β”‚       └── ja.ts
β”‚   β”œβ”€β”€ icons/
β”‚   β”‚   └── Icons.ts             # SVG icon definitions
β”‚   β”œβ”€β”€ renderers/
β”‚   β”‚   β”œβ”€β”€ HTML5Renderer.ts     # Native HTML5 video/audio
β”‚   β”‚   β”œβ”€β”€ YouTubeRenderer.ts   # YouTube iframe API
β”‚   β”‚   β”œβ”€β”€ VimeoRenderer.ts     # Vimeo Player API
β”‚   β”‚   β”œβ”€β”€ SoundCloudRenderer.ts# SoundCloud Widget API
β”‚   β”‚   β”œβ”€β”€ HLSRenderer.ts       # hls.js integration + native iOS bridge
β”‚   β”‚   └── DASHRenderer.ts      # dash.js integration
β”‚   β”œβ”€β”€ styles/
β”‚   β”‚   └── vidply.css           # Main stylesheet
β”‚   β”œβ”€β”€ types/                   # Shared TypeScript types
β”‚   β”‚   β”œβ”€β”€ options.ts           # PlayerOptions
β”‚   β”‚   └── globals.d.ts         # Ambient declarations (Hls, dashjs, …)
β”‚   β”œβ”€β”€ utils/
β”‚   β”‚   β”œβ”€β”€ DOMUtils.ts          # DOM helpers
β”‚   β”‚   β”œβ”€β”€ EventEmitter.ts      # Event system
β”‚   β”‚   β”œβ”€β”€ TimeUtils.ts         # Time formatting
β”‚   β”‚   β”œβ”€β”€ FocusUtils.ts        # Focus management
β”‚   β”‚   β”œβ”€β”€ MenuUtils.ts         # Menu helpers
β”‚   β”‚   β”œβ”€β”€ StorageManager.ts    # localStorage wrapper
β”‚   β”‚   └── ...
β”‚   └── index.ts                 # Main entry point
β”œβ”€β”€ index.html                   # Development page
β”œβ”€β”€ tsconfig.json                # Strict TypeScript config
β”œβ”€β”€ package.json
└── server.js                    # Dev server
 

⚑ NPM Scripts

ScriptDescription
npm run buildBuild everything (TypeScript bundles + types + CSS)
npm run build:jsBundle TypeScript with esbuild (ESM + IIFE)
npm run build:typesEmit .d.ts type declarations to dist/types/
npm run build:cssBuild CSS only
npm run typechecktsc --noEmit strict type-check across src/
npm run watchWatch mode (auto-rebuild)
npm run devStart dev server
npm run cleanClean dist directory
npm run startBuild + start dev server
npm run testVitest unit tests
npm run test:e2ePlaywright end-to-end tests

πŸ—οΈ Build System

TypeScript bundles (esbuild)

build/build.js consumes the TypeScript sources directly (esbuild handles transpilation) and produces:

FileFormatUse
dev/vidply.esm.jsES ModuleDevelopment
prod/vidply.esm.min.jsES ModuleProduction
legacy/vidply.jsIIFEDevelopment
legacy/vidply.min.jsIIFEProduction

Features:

  • Code splitting (renderers loaded on demand)
  • Tree shaking
  • Source maps (development)
  • Minification (production)

Type declarations (tsc)

npm run build:types runs tsc --emitDeclarationOnly against tsconfig.build.json and emits:

FileUse
dist/types/index.d.tsPublic type entry, referenced from package.json#types
dist/types/**/*.d.tsPer-module declarations for tree-shakable named imports

CSS (clean-css)

build/build-css.js produces:

FileUse
vidply.cssDevelopment
vidply.min.cssProduction

🎯 Architecture

Core Components

 
Player
β”œβ”€β”€ ControlBar           # UI controls
β”‚   β”œβ”€β”€ PlayButton
β”‚   β”œβ”€β”€ ProgressBar
β”‚   β”œβ”€β”€ VolumeControl
β”‚   β”œβ”€β”€ DownloadButton    # opt-in via downloadButton/downloadUrl
β”‚   β”œβ”€β”€ PipButton         # native PiP, or pin/unpin custom floating player when floating: true
β”‚   β”œβ”€β”€ SettingsButton
β”‚   └── FullscreenButton
β”œβ”€β”€ BufferingOverlay     # Centered loading spinner (.vidply-loading)
β”œβ”€β”€ CaptionManager       # Captions/subtitles
β”œβ”€β”€ KeyboardManager      # Keyboard shortcuts
β”œβ”€β”€ TranscriptManager    # Interactive transcript
β”œβ”€β”€ FloatingPlayerManager # Custom in-page miniplayer ("own PiP"), opt-in via floating: true
β”œβ”€β”€ Renderer             # Media playback
β”‚   β”œβ”€β”€ HTML5Renderer
β”‚   β”œβ”€β”€ YouTubeRenderer
β”‚   β”œβ”€β”€ VimeoRenderer
β”‚   β”œβ”€β”€ SoundCloudRenderer
β”‚   β”œβ”€β”€ HLSRenderer       # hls.js + native iOS TextTrack bridge
β”‚   └── DASHRenderer
└── PlaylistManager      # Playlist handling
 

Event Flow

 
User Action β†’ KeyboardManager/ControlBar β†’ Player β†’ Renderer β†’ DOM
                                              ↓
                                         EventEmitter β†’ External Listeners
 

Renderer Selection

 
// src/core/Player.ts
selectRenderer(src: string): RendererCtor {
  if (isYouTubeUrl(src)) return YouTubeRenderer;
  if (isVimeoUrl(src)) return VimeoRenderer;
  if (src.includes('soundcloud.com')) return SoundCloudRenderer;
  if (isHLSUrl(src)) return HLSRenderer;   // hls.js (or native HLS on iOS/iPadOS)
  if (isDASHUrl(src)) return DASHRenderer;
  return HTML5Renderer;
}
 

The HLS renderer self-decides whether to use hls.js (Chrome / Firefox / Edge / desktop Safari) or the native <video> HLS support (iOS / iPadOS where MSE is unavailable). On the native path it bridges the browser's TextTrack API into VidPly's caption / transcript / quality UI so feature parity is preserved.

 

πŸ“ Adding Features

New Control Button

  1. Add to ControlBar (src/controls/ControlBar.ts):
createMyButton(): HTMLButtonElement {
  const button = document.createElement('button');
  button.className = 'vidply-button vidply-my-button';
  button.setAttribute('aria-label', i18n.t('player.myButton'));
  button.innerHTML = Icons.myIcon;
  button.addEventListener('click', () => this.player.myAction());
  return button;
}
  1. Add icon (src/icons/Icons.ts):
export const Icons = {
  // ...existing icons
  myIcon: `<svg>...</svg>`,
} as const;
  1. Add translation (src/i18n/languages/en.ts):
export default {
  player: {
    // ...existing
    myButton: 'My Button',
  }
};
  1. Add to Player API (src/core/Player.ts):
myAction(): void {
  this.emit('myaction');
}
 

New Renderer

  1. Create renderer (src/renderers/MyRenderer.ts):
import type { Player } from '../core/Player';

export class MyRenderer {
  constructor(public player: Player) {}

  async init(): Promise<void> { /* ... */ }
  async load(src: string): Promise<void> { /* ... */ }
  play(): void { /* ... */ }
  pause(): void { /* ... */ }
  seek(time: number): void { /* ... */ }
  setVolume(vol: number): void { /* ... */ }
  getCurrentTime(): number { /* ... */ }
  getDuration(): number { /* ... */ }
  destroy(): void { /* ... */ }
}
  1. Register in Player:
import { MyRenderer } from '../renderers/MyRenderer';

// In selectRenderer()
if (isMyServiceUrl(src)) return MyRenderer;
 

New Language

  1. Create language file (src/i18n/languages/pt.ts):
export default {
  player: {
    play: 'Reproduzir',
    pause: 'Pausar',
    // ... all translations
  }
};
  1. Register (src/i18n/translations.ts):
import pt from './languages/pt';

export const translations = {
  en, de, es, fr, ja,
  pt,
};
 

🎨 CSS Architecture

Variables

 
:root {
  /* 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;
}
 

BEM Naming

 
.vidply-player { }           /* Block */
.vidply-player--fullscreen { } /* Modifier */
.vidply-controls { }         /* Block */
.vidply-controls__left { }   /* Element */
.vidply-button { }           /* Block */
.vidply-button--active { }   /* Modifier */
 

Accessibility

 
/* High contrast mode */
@media (forced-colors: active) {
  .vidply-button {
    border: 1px solid currentColor;
  }
}

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

/* Touch targets */
.vidply-button {
  min-width: 44px;
  min-height: 44px;
}
 

πŸ§ͺ Testing

Manual Testing

  1. Open localhost after npm run dev
  2. Test demos:
    • demo/demo.html - Full features
    • demo/playlist-audio.html - Audio playlists
    • demo/playlist-video.html - Video playlists
    • demo/hls-test.html - HLS streaming
    • demo/dash-test.html - DASH streaming

Accessibility Testing

  • Keyboard: Navigate using only keyboard
  • Screen reader: Test with NVDA/VoiceOver
  • High contrast: Enable Windows HCM
  • Mobile: Test touch interactions

Browser Testing

BrowserPriority
ChromeHigh
FirefoxHigh
SafariHigh
EdgeMedium
iOS SafariHigh
Android ChromeMedium

πŸ”Œ Plugin System

EventEmitter

 
// Player extends EventEmitter
player.on('play', () => console.log('Playing'));
player.on('pause', () => console.log('Paused'));
player.on('timeupdate', (time) => console.log(time));

// Custom events
player.emit('mycustomevent', { data: 'value' });
 

Available Events

EventDataDescription
ready-Player initialized
play-Playback started
pause-Playback paused
ended-Playback ended
timeupdatetimeCurrent time changed
volumechangevolumeVolume changed
playbackspeedchangespeedSpeed changed
fullscreenchangeisFullscreenFullscreen toggled
hlsmanifestparseddataHLS manifest parsed
dashqualitychangeddataDASH quality changed
textcuesupdate-New text cues available (HLS/DASH)
captionsenabledtrackCaptions enabled
captionsdisabled-Captions disabled
playlisttrackchangeitemPlaylist track changed
errorerrorError occurred

πŸ› Debugging

Enable Debug Mode

 
const player = new Player('#video', { debug: true });
 

Console Logging

 
if (this.options.debug) {
  console.log('[VidPly]', message, data);
}
 

Common Issues

IssueDebug Steps
Player not initializingCheck data-vidply attribute; check console errors
Renderer not loadingCheck source URL format; verify network requests
Captions not showingValidate VTT syntax; check CORS
Keyboard not workingCheck keyboard: true; verify focus

πŸ“š Documentation Files

FileContent
GETTING_STARTEDBasic setup
USAGEDetailed API usage
PLAYLISTPlaylist features
TRANSCRIPTTranscript system
KEYBOARDKeyboard shortcuts
BUILDBuild system details
CHANGELOGVersion history
Users-GuideIntegration guide

πŸ”— Quick Reference

Key Files

WhatWhere
Entry pointsrc/index.ts
Player classsrc/core/Player.ts
Player options typesrc/types/options.ts
Control barsrc/controls/ControlBar.ts
Captionssrc/controls/CaptionManager.ts
Keyboardsrc/controls/KeyboardManager.ts
i18nsrc/i18n/i18n.ts
Stylessrc/styles/vidply.css
Iconssrc/icons/Icons.ts
TypeScript configtsconfig.json

Build Output

FileFormatSize
vidply.esm.min.jsESM~45KB
vidply.min.jsIIFE~50KB
vidply.min.cssCSS~15KB

External Dependencies

DependencyPinned versionPurposeLoaded
hls.js1.7.3HLS streaming (Chrome / Firefox / Edge / desktop Safari)On demand (CDN fallback)
dash.js5.2.1 (modern UMD)DASH streamingOn demand (CDN fallback)
YouTube IFrame APIβ€”YouTube playbackOn demand
Vimeo Player APIβ€”Vimeo playbackOn demand
SoundCloud Widget APIβ€”SoundCloud playbackOn demand

Default CDN fallback URLs (override via hlsScriptUrl / dashScriptUrl):

🀝 Contributing

  1. Fork the repository
  2. Create feature branch: git checkout -b feature/my-feature
  3. Make changes
  4. Test thoroughly
  5. Build: npm run build
  6. Commit: git commit -m 'Add my feature'
  7. Push: git push origin feature/my-feature
  8. Open Pull Request

Code Style

  • Strict TypeScript (strict: true, noImplicitAny, strictNullChecks)
  • BEM CSS naming
  • Meaningful variable names
  • Comment non-obvious intent (not what the code does)
  • Include ARIA attributes on every interactive element
  • Run npm run typecheck and npm run test before committing

Version: 1.1.7 | License: GPL-2.0-or-later

Share page