Documentation & Guides
Everything you need to embed, customize, and deploy YVPlayer across React, Next.js, Vue, and vanilla HTML.
Introduction to YVPlayer
YVPlayer is a high-performance, distraction-free HTML5 video player overlay designed specifically for YouTube videos. It strips away 100% of YouTube's native interface clutter, including video titles, channel avatars, "More videos" recommended drawers, and end-screen cards, while elevating playback with cinema-grade features inspired by modern production players like Video.js 10.
YVPlayer is handcrafted in pure vanilla ES6 JavaScript and clean modern CSS with zero heavy framework dependencies. Every animation uses GPU-accelerated cubic-bezier curves, every layout is mathematically locked to 16:9, and every theme dynamically recalculates CSS custom property tokens in real-time.
No complicated setups or bundler configurations required:
- Step 1: Include the CSS & JS links in your
<head>. - Step 2: Place
<div data-yv-video="YOUR_VIDEO_ID" style="aspect-ratio:16/9;"></div>anywhere on your page. - Step 3: That is it! The player automatically initializes with custom controls, themes, and scrubbing.
Zero YouTube Clutter
Masks top branding banners, avatars, share pills, and end-screen video grids for a pure theatrical playback experience.
Interactive Storyboard
Scrub across the timeline with high-resolution frame previews stitched on-the-fly from YouTube's storyboard sprites.
Triple-Engine PiP
Independent Document PiP (full custom player in OS window), Native Video PiP (720p HD stream with synced controls), and In-Page Dock mini-player.
Real-Time Color Theming
Pick from 7 polished presets or feed any custom hex color. Controls, glow effects, hover states, and ripples adapt instantly.
Feature Comparison Matrix
How YVPlayer compares against standard YouTube embeds and alternative web players:
| Capability | YVPlayer | Standard YouTube Embed | Video.js (YouTube Plugin) | Plyr |
|---|---|---|---|---|
| Zero Branding & Overlays | 100% Masked | YouTube UI | Partial | Partial |
| Storyboard Timeline Previews | Native Sprites | Built-in | Requires VTT | Requires VTT |
| True OS-Level Desktop PiP | 720p Native Stream | Context Menu Only | Blocked by iframe | In-tab only |
| In-Page Connected Mini-Player | 16:9 Corner Resizing | None | None | None |
| Custom Caption Styling | Box/Transparent + Alpha | Fixed | Limited | Limited |
| Built-in Sleep Auto-Pause Timer | 15m - End of Video | None | None | None |
| YouTube Live Stream & DVR Support | Auto 🔴 LIVE Pill + DVR Edge Sync | Cluttered UI | HLS plugin needed | HLS plugin needed |
| YouTube Shorts (9:16 Vertical Ratio) | 9:16 Vertical + Streamlined Controls | Feed overlay | Manual CSS override | Manual CSS override |
| Background Play (Ambient Video Behind Content) | Muted, Looping, Zero Controls | Native branding visible | Complex plugin config | Not supported |
| 1-Click HTML Drop-In (Zero JS) | <div data-yv-video> | <iframe> | Complex setup | Complex setup |
Core Architecture & Data Flow
YVPlayer bridges YouTube's underlying streaming infrastructure with a custom HTML5 canvas and controls tree:
Masked YouTube IFrame API with custom event dispatcher & audio sync
Native <video> element connected to 720p stream proxy with 16:9 aspect lock
Generate Production AI Prompts in 1 Click
Select your tech stack, PiP engine, theme palette, and open-source stream proxies. Copy and paste the generated prompt into ChatGPT, Claude, Cursor, Copilot, or Gemini to integrate YVPlayer flawlessly into your codebase.
1-Click Drop-In HTML (Zero JavaScript)
The simplest way to integrate YVPlayer into any HTML website, WordPress template, Webflow embed, or Shopify theme. You do not need to write a single line of JavaScript.
<!-- 1. YVPlayer Styles & Script via jsDelivr CDN -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@latest/tabler-icons.min.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/your-username/yvplayer@main/yvPlayer.css" />
<script src="https://cdn.jsdelivr.net/gh/your-username/yvplayer@main/yvPlayer.js"></script>
<!-- 2. Player Element: Set data-yv-video with your YouTube ID or URL -->
<div
data-yv-video="M7lc1UVf-VE"
data-yv-theme="red"
style="max-width: 960px; aspect-ratio: 16/9; margin: 0 auto; border-radius: 12px; overflow: hidden;"
></div>
When the browser parses yvPlayer.js, it automatically scans the DOM for elements with data-yv-video, loads the YouTube IFrame API in the background, parses full URLs or raw 11-char IDs, and mounts the player. No manual initialization scripts required!
CDN Providers & Local Assets
YVPlayer is distributed through leading global CDNs with automatic HTTP/3 caching and Brotli compression:
| CDN Provider | Stylesheet (CSS) URL | JavaScript (JS) URL | Status |
|---|---|---|---|
| jsDelivr (Recommended) | https://cdn.jsdelivr.net/gh/your-username/yvplayer@main/yvPlayer.css |
https://cdn.jsdelivr.net/gh/your-username/yvplayer@main/yvPlayer.js |
Production / Fast |
| Self-Hosted / Local | ./yvPlayer.css |
./yvPlayer.js |
Offline / Private |
Standard JavaScript API
When you need programmatic playback control, custom callbacks, or dynamic video switching, use the YVPlayer.init() Promise API:
<div id="player" style="max-width: 960px; aspect-ratio: 16/9; margin: 0 auto; border-radius: 12px; overflow: hidden;"></div>
<script src="https://www.youtube.com/iframe_api"></script>
<script src="yvPlayer.js"></script>
<script>
window.onYouTubeIframeAPIReady = function() {
YVPlayer.init("player", {
defaultId: "M7lc1UVf-VE",
theme: "red",
autoplay: true,
loop: false
}).then(function() {
console.log("YVPlayer initialized successfully!");
});
};
</script>
React & Next.js Component
Integrate YVPlayer into React 18, React 19, or Next.js (App Router / Pages Router) with proper mounting, unmounting, and memory leak cleanup:
import React, { useEffect, useRef } from "react";
export function VideoPlayer({ videoId, theme = "red", customColor, autoplay = true }) {
const containerRef = useRef(null);
const playerIdRef = useRef("yv-" + Math.random().toString(36).substring(2, 9));
useEffect(() => {
const id = playerIdRef.current;
if (typeof window === "undefined" || !window.YVPlayer) return;
window.YVPlayer.init(id, {
defaultId: videoId,
theme,
autoplay
}).then(() => {
if (customColor) window.YVPlayer.setTheme(id, customColor, "Custom");
});
return () => {
if (window.YVPlayer?.destroy) window.YVPlayer.destroy(id);
};
}, [videoId, theme, customColor, autoplay]);
return (
<div
id={playerIdRef.current}
ref={containerRef}
style={{ maxWidth: "960px", aspectRatio: "16/9", borderRadius: "14px", overflow: "hidden" }}
/>
);
}
Vue 3, Nuxt & Svelte Integration
Official production wrappers for Vue 3 Composition API, Nuxt 3 SSR applications, and Svelte 4/5 with reactive props, automatic player instance cleanup, and dynamic video switching.
Vue 3 (Composition API & <script setup>)
Drop the following reusable Single File Component (SFC) into your Vue 3 or Vite project. It automatically synchronizes video IDs, themes, and PiP modes with full reactive watchers:
<template>
<div
:id="playerId"
class="yvPlayer"
:style="{ width: '100%', aspectRatio: '16 / 9', borderRadius: radius, overflow: 'hidden' }"
></div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount, watch } from "vue";
const props = defineProps({
videoId: { type: String, required: true },
theme: { type: String, default: "red" },
customColor: { type: String, default: null },
autoplay: { type: Boolean, default: true },
pipMode: { type: String, default: "document" },
radius: { type: String, default: "14px" }
});
const playerId = "yv-" + Math.random().toString(36).substring(2, 9);
onMounted(() => {
if (typeof window === "undefined" || !window.YVPlayer) return;
window.YVPlayer.init(playerId, {
defaultId: props.videoId,
theme: props.theme,
customColor: props.customColor,
autoplay: props.autoplay,
pipMode: props.pipMode,
storyboard: true
});
});
watch(() => props.videoId, (newId) => {
if (window.YVPlayer && window.YVPlayer.changeVideo) {
window.YVPlayer.changeVideo(playerId, newId);
}
});
watch(() => props.theme, (newTheme) => {
if (window.YVPlayer && window.YVPlayer.setTheme) {
window.YVPlayer.setTheme(playerId, props.customColor || newTheme, newTheme);
}
});
onBeforeUnmount(() => {
if (window.YVPlayer && window.YVPlayer.destroy) {
window.YVPlayer.destroy(playerId);
}
});
</script>
<ClientOnly> to ensure client-side DOM evaluation since YVPlayer operates on browser window objects and the YouTube IFrame API.
Svelte 4 & Svelte 5 Component
In Svelte, bind the player target element with bind:this and control the lifecycle through onMount and onDestroy:
<script>
import { onMount, onDestroy } from "svelte";
export let videoId = "M7lc1UVf-VE";
export let theme = "red";
export let customColor = null;
export let pipMode = "document";
export let autoplay = true;
let playerEl;
let playerId = "yv-svelte-" + Math.random().toString(36).substring(2, 8);
let playerReady = false;
onMount(() => {
if (typeof window === "undefined" || !window.YVPlayer) return;
window.YVPlayer.init(playerId, {
defaultId: videoId,
theme,
customColor,
pipMode,
autoplay,
storyboard: true
}).then(() => {
playerReady = true;
});
});
$: if (playerReady && videoId && window.YVPlayer) {
window.YVPlayer.changeVideo(playerId, videoId);
}
onDestroy(() => {
if (window.YVPlayer && window.YVPlayer.destroy) {
window.YVPlayer.destroy(playerId);
}
});
</script>
<div
bind:this={playerEl}
id={playerId}
class="yvPlayer"
style="width: 100%; aspect-ratio: 16 / 9; border-radius: 14px; overflow: hidden;"
></div>
HTML Data Attributes Reference
All declarative properties supported by 1-Click Drop-in containers:
| Attribute | Type | Default | Description |
|---|---|---|---|
data-yv-video |
string |
required | YouTube Video ID (11 chars) or full URL (e.g. https://youtube.com/watch?v=...). |
data-yv-theme |
string |
"default" |
Preset theme name: red, cyan, purple, emerald, teal, gold, white. |
data-yv-color |
hex string |
null |
Custom accent color (e.g. #ff0055). Overrides preset theme dynamically. |
data-yv-autoplay |
boolean |
"true" |
Whether the player should start playback immediately on mount (subject to browser policy). |
data-yv-pip |
"document" | "os" | "inpage" |
"os" |
Default Picture-in-Picture engine preference (Document PiP, Native Video 720p PiP, or In-Page Dock). |
data-yv-storyboard |
boolean |
"true" |
Whether to prefetch and display storyboard thumbnails on seekbar hover. |
JavaScript Options Reference
Available parameters passed into YVPlayer.init(elementId, options):
| Option | Type | Default | Description |
|---|---|---|---|
defaultId |
string |
required | The 11-character YouTube video ID or full URL. |
theme |
string |
"default" |
Theme preset name ("red", "cyan", "purple", "emerald", etc.). |
autoplay |
boolean |
true |
Auto-start playback on ready. |
loop |
boolean |
false |
Whether to auto-replay video upon reaching the end. |
thumbnail |
boolean |
false |
Show YouTube thumbnail preview overlay prior to playback start. |
pipMode |
"os" | "inpage" |
"os" |
Picture-in-Picture mode preference (OS desktop window vs in-tab mini-player). |
Programmatic Methods
All player methods accept the target element ID as the first argument:
| Method Signature | Return Type | Description |
|---|---|---|
YVPlayer.play(targetId) |
void |
Starts or resumes video playback. |
YVPlayer.pause(targetId) |
void |
Pauses current video playback. |
YVPlayer.togglePlay(targetId) |
void |
Toggles between play and pause states. |
YVPlayer.seekTo(targetId, seconds) |
void |
Seeks timeline directly to specified seconds. |
YVPlayer.changeVideo(targetId, newVideoId) |
void |
Switches the video stream to another YouTube ID seamlessly. |
YVPlayer.setTheme(targetId, hexColor, name) |
void |
Dynamically updates all theme custom properties and glows in real time. |
YVPlayer.togglePiP(targetId) |
void |
Triggers Picture-in-Picture according to the active engine preference. |
YVPlayer.setPipMode(targetId, mode) |
void |
Sets active PiP engine: "document", "os", or "inpage". |
YVPlayer.setVolume(targetId, 0-100) |
void |
Sets player volume percentage. |
YVPlayer.mute(targetId) / unMute(targetId) |
void |
Mutes or unmutes audio. |
YVPlayer.setPlaybackRate(targetId, speed) |
void |
Adjusts playback speed rate (e.g. 0.5, 1.0, 1.5, 2.0). |
YVPlayer.setLoop(targetId, boolean) |
void |
Enables or disables seamless video loop repeat and syncs player settings drawer. |
YVPlayer.isLooping(targetId) |
boolean |
Returns whether the video is currently configured to loop continuously upon completion. |
YVPlayer.destroy(targetId) |
void |
Completely tears down DOM, removes listeners, intervals, and cleans memory. |
Events, State & Callbacks
Monitor player lifecycle transitions, real-time playback milestones, volume adjustments, and Picture-in-Picture handoffs using YVPlayer's unified event listener engine.
Playback State Constants
YVPlayer normalizes YouTube playback states into standard string identifiers and numeric constants accessible via YVPlayer.getState(videoTag):
| Code | State Constant | Lifecycle Description | Controls UI Appearance |
|---|---|---|---|
-1 |
unstarted |
Player initialized with video metadata; waiting for play trigger. | Large frosted center play button visible; poster thumbnail shown. |
1 |
playing |
Video actively decoding and playing audio/video frames. | Controls auto-fade after 3s; center pause icon on hover; seekbar glowing. |
2 |
paused |
Playback halted by user, sleep timer, or window blur. | Controls persistently visible; center play icon displayed. |
3 |
buffering |
Network fetching stream chunks or seeking to a new timestamp. | Smooth pulsating spinner displayed at the center of the video stage. |
5 |
cued |
New video queued via changeVideo() ready for instant start. |
Timeline slider resets to 0:00; title badge updates. |
0 |
ended |
Video completed playback without looping enabled. | Replay glyph appears; end-screen recommendations completely stripped. |
Subscribing to Events
Use YVPlayer.on(videoTag, eventName, handler) to listen for real-time player actions. Remove listeners via YVPlayer.off():
// 1. Listen for playback start
YVPlayer.on("my-player", "play", () => {
console.log("Playback started or resumed");
});
// 2. High-frequency timeline updates (every 250ms)
YVPlayer.on("my-player", "timeupdate", ({ currentTime, duration, progress }) => {
console.log(`Current: ${currentTime.toFixed(1)}s / ${duration.toFixed(1)}s (${progress.toFixed(1)}%)`);
});
// 3. Picture-in-Picture mode activation
YVPlayer.on("my-player", "pipenter", ({ mode }) => {
console.log(`Entered PiP mode: ${mode}`); // "document", "os", or "inpage"
});
// 4. Picture-in-Picture window closed
YVPlayer.on("my-player", "pipexit", () => {
console.log("Returned to on-page player stage");
});
// 5. Volume or mute toggle
YVPlayer.on("my-player", "volumechange", ({ volume, isMuted }) => {
console.log(`Volume: ${volume}%, Muted: ${isMuted}`);
});
// 6. Theme accent color change
YVPlayer.on("my-player", "themechange", ({ color, theme }) => {
console.log(`Switched to theme ${theme} (${color})`);
});
Dynamic Real-Time Theme Engine
YVPlayer features a GPU-accelerated CSS variable theming system. Switch branding accents, timeline gradients, glowing thumbs, and frosted overlays dynamically in real time without refreshing or reloading the video buffer.
CSS Custom Property Design Tokens
Every visual component inherits from standard scoped CSS custom properties applied directly to the .yvPlayer container:
| CSS Variable Token | Default Value | Target Component & Computed Effect |
|---|---|---|
--themeAccent |
#fe0001 |
Primary brand accent applied to active buttons, volume pills, and hover badges. |
--sliderSeekTrackColor |
var(--themeAccent) |
High-contrast fill color for the completed portion of the scrubbing timeline. |
--sliderThumbColor |
var(--themeAccent) |
Color of the glowing seek thumb handle. |
--themeGlow |
rgba(r, g, b, 0.45) |
Luminescent drop-shadow filter applied to the seekbar head and primary play button. |
--themeHoverBg |
rgba(r, g, b, 0.22) |
Translucent background tint applied to icon button hover rings. |
--startBtnBg |
var(--themeAccent) |
Backdrop tint for the initial center frosted play button. |
Built-In Preset Color Palettes
YVPlayer ships with 6 hand-tuned production presets engineered for perfect contrast across dark and light canvases:
| Preset Name | Key | Hex Code | RGB Glow Token | Best Used For |
|---|---|---|---|---|
| ● Classic Cinema Red | red |
#fe0001 |
rgba(254, 0, 1, 0.45) |
YouTube-native aesthetic, action cinema, bold branding. |
| ● City Cyan | cyan |
#00e5ff |
rgba(0, 229, 255, 0.45) |
Modern SaaS applications, dark mode dashboards, fintech. |
| ● Fantasy Purple | purple |
#a855f7 |
rgba(168, 85, 247, 0.45) |
AI platforms, creative portfolios, Web3 and gaming streams. |
| ● Forest Emerald | emerald |
#10b981 |
rgba(16, 185, 129, 0.45) |
Nature docs, educational courses, calm productivity tools. |
| ● Amber Gold | gold |
#f59e0b |
rgba(245, 158, 11, 0.45) |
Luxury brands, podcasts, retrospectives, warm cinematics. |
| ● Minimal Monochrome | white |
#ffffff |
rgba(255, 255, 255, 0.45) |
Clean architectural sites, typography-first portfolios, editorial. |
Applying Themes at Runtime
Switch themes via HTML data attributes or programmatically via the JavaScript API with zero latency:
<!-- 1. Declarative HTML preset theme -->
<div class="yvPlayer" id="player" data-yv-theme="purple"></div>
<!-- 2. Arbitrary Custom Brand Hex via HTML -->
<div class="yvPlayer" id="brand-player" data-yv-color="#8b5cf6"></div>
<!-- 3. Programmatic runtime theme switch (zero video interruption) -->
<script>
// Switch to preset theme
YVPlayer.setTheme("player", "emerald");
// Or apply any custom 6-digit hex color
YVPlayer.setTheme("player", "#ec4899", "Neon Pink");
</script>
Triple-Engine Picture-in-Picture (PiP) Architecture
Unlike ordinary video players that restrict users to basic OS video windows without controls, YVPlayer provides three distinct, independent Picture-in-Picture architectures engineered for every browser capability, operating system, and deployment workflow.
Document Picture-in-Picture (Full Desktop OS Window)
Pops out the entire rich YVPlayer DOM into an independent, always-on-top desktop operating system window using window.documentPictureInPicture.requestWindow(). All custom controls, storyboard scrubbing, audio sliders, and theme accents continue running smoothly outside the browser tab.
<!-- HTML: Set Document PiP as preferred mode -->
<div class="yvPlayer" id="my-player" data-yv-pip="document"></div>
<!-- JavaScript: Programmatically trigger Document PiP -->
<script>
YVPlayer.setPipMode("my-player", "document");
YVPlayer.enterPiP("my-player");
</script>
Native Hardware Video PiP (Hardware OS Streaming)
Leverages the W3C standard HTMLVideoElement.requestPictureInPicture() specification by streaming clean, direct 720p HD MP4 (YouTube Format 22) through the Cloudflare Worker or Python edge proxy. Delivers full OS-level hardware-accelerated playback with native operating system controls.
VTTCue objects into the native video element's TextTrack. Captions render crisp, clean subtitles directly inside the floating OS Picture-in-Picture window.
<!-- HTML: Configure Native Video PiP with proxy URL -->
<div class="yvPlayer" id="my-player" data-yv-pip="os" data-yv-proxy="https://my-worker.workers.dev"></div>
<!-- JavaScript: Toggle Native Hardware PiP -->
<script>
YVPlayer.setPipMode("my-player", "os");
YVPlayer.togglePiP("my-player");
</script>
In-Page Dock Mini-Player (Corner Resizable)
A fluid, corner-docked viewport overlay confined within the active browser tab with physical spring animations. Operates purely on client DOM with zero proxy or external network requirements.
<!-- HTML: Configure In-Page Dock mode -->
<div class="yvPlayer" id="my-player" data-yv-pip="inpage"></div>
<!-- JavaScript: Activate In-Page Dock Mini-Player -->
<script>
YVPlayer.setPipMode("my-player", "inpage");
YVPlayer.togglePiP("my-player");
</script>
Comprehensive PiP Engine Comparison
| Feature / Capability | Engine A — Document PiP | Engine B — Native Video PiP | Engine C — In-Page Dock |
|---|---|---|---|
| Operating System Floating Window | Yes (Independent OS Window) | Yes (Hardware OS Surface) | Tab Viewport Dock Only |
| Full Custom UI & Theming Preserved | Complete DOM Preserved | On-Page Stage Synced | Complete DOM Preserved |
| Live Subtitles in Floating Window | Styled HTML Subtitles | Native WebVTT Cues Injected | Styled HTML Subtitles |
| 16:9 Aspect Ratio Enforcement | Dynamic JS Guard | Native OS Surface Lock | 4-Corner Math Calculation |
| Scrubbing & Timeline Preview | Storyboard Tooltip Inside Window | Scrubber on Main Stage | Storyboard Tooltip on Hover |
| Backend Stream Proxy Required | No (Direct DOM) | Yes (Cloudflare or Python) | No (Direct DOM) |
| Browser & Device Compatibility | Chrome 116+, Edge 116+, Opera | Universal Desktop OS (Safari, Firefox, Chrome, Edge) | 100% All Modern Browsers, Tablets & Mobile |
Frame-Accurate Storyboard Scrubbing
YVPlayer extracts YouTube timeline mosaic sheets to deliver instant, zero-latency visual thumbnail previews on hover without downloading video frames or consuming heavy streaming bandwidth.
How YouTube Storyboards Work
YouTube encodes video previews into compressed JPEG mosaic sheets (e.g. 5x5 or 10x10 grids of frames captured at strict intervals like every 2 or 5 seconds). YVPlayer parses the video's storyboard_spec, computes the precise row and column coordinate for any cursor position along the timeline, and positions the preview via CSS background offsets:
| Mosaic Variable | Standard Value | Mathematical Role in Sprite Calculations |
|---|---|---|
cols ($N_{\text{cols}}$) |
5 (or 10) |
Number of horizontal frame tiles across a single JPEG sheet. |
rows ($N_{\text{rows}}$) |
5 (or 10) |
Number of vertical frame tiles down a single JPEG sheet. |
width ($W$) |
160px |
Exact pixel width of each individual 16:9 thumbnail frame tile. |
height ($H$) |
90px |
Exact pixel height of each individual 16:9 thumbnail frame tile. |
interval ($\Delta t$) |
2.0s (or 5.0s) |
Seconds of video playback represented between consecutive thumbnail frames. |
Sprite Coordinate Math & Offset Formula
Given total duration $D$, cursor hover ratio $R \in [0, 1]$, and hover timestamp $T = R \times D$:
// 1. Calculate overall tile index
const tileIndex = Math.floor(hoverTime / interval);
const tilesPerSheet = cols * rows;
// 2. Determine target mosaic sheet number
const sheetIndex = Math.floor(tileIndex / tilesPerSheet);
// 3. Determine exact column and row coordinates
const indexInSheet = tileIndex % tilesPerSheet;
const col = indexInSheet % cols;
const row = Math.floor(indexInSheet / cols);
// 4. Apply CSS background position offset
tooltipImg.style.backgroundImage = `url(${sheetUrl.replace("$M", sheetIndex)})`;
tooltipImg.style.backgroundPosition = `-${col * tileWidth}px -${row * tileHeight}px`;
Boundary Edge Clamping
To prevent the hover tooltip from clipping past the left or right edge of the video stage, YVPlayer implements sub-pixel boundary clamping:
// Keep tooltip center point strictly within [halfTooltip, stageWidth - halfTooltip]
const halfTooltip = tooltipWidth / 2;
const clampedX = Math.max(halfTooltip, Math.min(cursorX, stageWidth - halfTooltip));
Subtitle Styling & WebVTT Engine
Extract, style, and ship YouTube captions into both the HTML5 stage overlay and native OS Picture-in-Picture windows with full control over typography, backing modes, opacity, and languages.
Subtitle Display Modes
Configure caption rendering through the player's built-in Settings Drawer () or programmatically:
| Backing Mode | CSS Implementation | Visual Result |
|---|---|---|
| Frosted Box (Default) | background: rgba(0,0,0,0.75); backdrop-filter: blur(8px); border-radius: 6px; |
Modern cinema aesthetic with high contrast across busy backgrounds. |
| Solid Opaque Box | background: #000000; color: #ffffff; border-radius: 4px; padding: 4px 10px; |
Maximum legibility and strict accessibility compliance. |
| Drop-Shadow Outline (No Box) | text-shadow: 0 2px 4px rgba(0,0,0,0.9), 0 0 2px #000000; |
Clean broadcast styling without any obstructive background card. |
Shipping Subtitles into OS Picture-in-Picture
Standard browser Picture-in-Picture windows do not render HTML DOM elements. To display subtitles inside the floating OS window during Native Video PiP playback, YVPlayer bridges HTML captions to native VTTCue objects:
// 1. Create native text track on hidden video element
const textTrack = nativeVideo.addTextTrack("subtitles", "English", "en");
textTrack.mode = "showing";
// 2. Parse YouTube timed text and inject VTTCue objects
captionsArray.forEach(cap => {
const cue = new VTTCue(cap.start, cap.end, cap.text);
cue.line = -2; // Clean placement near the bottom
cue.size = 80;
textTrack.addCue(cue);
});
Tactile Gestures & Keyboard Hotkeys
YVPlayer provides a complete set of desktop keyboard shortcuts and mobile touch gestures engineered for muscle memory and rapid media scrubbing.
Complete Desktop Hotkey Reference
| Key / Shortcut | Action Description | HUD Feedback Pill |
|---|---|---|
| Space or K | Toggle Play / Pause playback. | Center circle morphs with micro-animation. |
| J / L | Instant 10-Second Rewind (J) or Fast-Forward (L). | Curved tactile ripple badge with ±10s indicator. |
| ← / → | Precise 5-Second Seek Backward / Forward. | Seekbar thumb glowing jump animation. |
| ↑ / ↓ | Volume Increase / Decrease by 5%. | Volume percentage HUD pill floats near top-right. |
| M | Toggle Mute / Unmute audio. | Volume icon toggles between muted and active. |
| F | Toggle Fullscreen Mode. | Canvas expands to fill 100% monitor resolution. |
| P | Toggle Picture-in-Picture (active engine). | Pops out into OS window or In-Page dock. |
| C | Toggle Captions / Subtitles. | Subtitle line fades in/out with smooth opacity. |
| 0 – 9 | Direct Jump to 0% through 90% of duration. | Instant timeline seek. |
| < / > | Decrease / Increase playback speed (0.25x – 2.0x). | Speed badge indicator (e.g. 1.25x, 1.5x, 2x). |
| Cmd+E / Ctrl+E | Open Quick Embed Code Customizer Modal. | Modal backdrop fades in smoothly. |
Mobile & Touch Ripple Gestures
On touch devices or laptops, double-tapping the left half of the player triggers a 10s rewind ripple; double-tapping the right half triggers a 10s fast-forward ripple. Both gestures feature GPU-accelerated spring animations.
YouTube Shorts Mode (9:16 Vertical Aspect Ratio)
Standard embedded YouTube videos force a 16:9 widescreen letterbox even when playing vertical shorts. YVPlayer provides native 9:16 mobile-first vertical aspect ratio support. It automatically crops YouTube's horizontal letterboxing, optimizes the layout for vertical viewing, and strips away UI clutter while preserving essential controls.
Streamlined Shorts Controls Architecture
In Shorts mode, the player hides redundant horizontal desktop chrome and keeps only the controls essential for short-form video:
- Timeline Scrubber: Ultra-responsive seekbar at the bottom for instant scrubbing across the short.
- Volume & Mute Pill: Quick toggle and volume slider without opening menus.
- Picture-in-Picture (PiP): Send the vertical Short into OS-level floating PiP or in-page mini player.
- Full Screen: Maximize to immersive full-device vertical display.
- Settings Button: Opens the full settings drawer with Playback Speed (0.25x - 2x), Subtitle Styles, Theme Accents, and Sleep Timer.
<!-- Drop-in vertical YouTube Short with 9:16 aspect ratio -->
<div
data-yv-video="https://www.youtube.com/shorts/YlyI2jmHEYc"
data-yv-shorts="true"
data-yv-theme="red"
style="width: 100%; max-width: 400px; aspect-ratio: 9 / 16; margin: 0 auto; border-radius: 20px; overflow: hidden;"
></div>
YVPlayer.init("shorts-player", {
defaultId: "YlyI2jmHEYc", // YouTube Short Video ID
shorts: true, // Enables 9:16 vertical ratio & streamlined controls
theme: "red",
autoplay: true
});
// Runtime toggle
YVPlayer.setShortsMode("shorts-player", true);
Ambient Background Play ("Muted, Looping Video Behind Your Content")
Similar to Video.js's ambient background video engine, YVPlayer allows you to transform any YouTube video into a muted, looping decorative background that plays seamlessly behind hero sections, banners, headers, or landing page content.
Zero-Interference Background Architecture
When background mode is enabled, YVPlayer automatically configures:
- Permanently Muted: Unconditionally mutes audio (
muted: true) to guarantee instant, unrestricted browser autoplay on mobile and desktop without user gestures. - Infinite Seamless Loop: Continuously restarts the video prior to reaching the final 0.2 seconds, preventing YouTube's native end-screen cards, channel suggestions, and replay overlays from ever displaying.
- 100% Zero Controls: Strips away the play button, progress bar, volume pill, HUD notices, keyboard shortcut listeners, and right-click menus.
- Full Pointer-Events Pass-Through: Sets
pointer-events: noneso user clicks, text selection, and touch gestures effortlessly pass straight through to your foreground buttons, forms, and cards.
<!-- Hero Section with Ambient Video Background -->
<div class="hero-container" style="position: relative; overflow: hidden; min-height: 480px;">
<!-- 1. Ambient Video Layer (Zero controls, automated loop) -->
<div
data-yv-video="aqz-KE-bpKQ"
data-yv-background="true"
style="position: absolute; inset: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none; opacity: 0.65;"
></div>
<!-- 2. Optional Tint / Scrim Layer -->
<div style="position: absolute; inset: 0; background: rgba(0,0,0,0.45); z-index: 2;"></div>
<!-- 3. Your Foreground Content (Interactive buttons, headings, text) -->
<div class="hero-content" style="position: relative; z-index: 3; padding: 60px 24px; text-align: center;">
<h1>Welcome to Next-Gen Web Video</h1>
<p>High-performance HTML5 video player built for modern developer workflows.</p>
<button class="btn-primary">Get Started Now</button>
</div>
</div>
YVPlayer.init("hero-bg-player", {
defaultId: "aqz-KE-bpKQ",
background: true, // Enables muted, looping, zero controls ambient mode
autoplay: true
});
// Runtime toggle
YVPlayer.setBackgroundMode("hero-bg-player", true); // Enable ambient background
YVPlayer.setBackgroundMode("hero-bg-player", false); // Restore interactive controls
Cloudflare Worker Proxy (Serverless)
Deploy your stream resolver on Cloudflare Workers for global edge delivery with $0 server maintenance costs and ultra-low latency. Below is the complete production script:
// ============================================================
// Cloudflare Worker: YouTube Stream & Storyboard Edge Proxy
// ============================================================
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
// Handle CORS preflight
if (request.method === "OPTIONS") {
return new Response(null, {
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, HEAD, OPTIONS",
"Access-Control-Allow-Headers": "Range, Content-Type",
"Access-Control-Max-Age": "86400"
}
});
}
const videoId = url.searchParams.get("id");
if (!videoId || !/^[a-zA-Z0-9_-]{11}$/.test(videoId)) {
return new Response(JSON.stringify({ success: false, error: "Invalid video ID" }), {
status: 400,
headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" }
});
}
// Proxy Range requests to raw YouTube streams
if (url.pathname === "/api/stream") {
const clientRange = request.headers.get("Range");
const headers = new Headers({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/147.0.0.0 Safari/537.36"
});
if (clientRange) headers.set("Range", clientRange);
const upstream = await fetch(streamUrl, { headers });
const respHeaders = new Headers(upstream.headers);
respHeaders.set("Access-Control-Allow-Origin", "*");
return new Response(upstream.body, { status: upstream.status, headers: respHeaders });
}
}
};
Open-Source Stream Proxies (Zero Backend Required)
When integrating YVPlayer into static Jamstack apps, client-only SPAs, or serverless projects where running a dedicated Python yt-dlp backend is undesirable, you can configure open-source community stream proxy networks.
googlevideo.com) without telemetry, tracking cookies, or user profile linkage.
1. Piped API Network (Recommended)
Piped is an open-source privacy frontend for YouTube. Its public API clusters decrypt YouTube video ciphers on the fly and return clean JSON payloads containing direct Google CDN streaming URLs.
- Endpoint Format:
GET https://<instance>/streams/{VIDEO_ID} - Live Instance Discovery: piped-instances.kavin.rocks (Real-time uptime tracker)
- Default Public Node:
https://pipedapi.kavin.rocks - Fallback Public Node:
https://api.piped.privacy.com.de
YVPlayer.init("video-stage", {
defaultId: "M7lc1UVf-VE",
proxyProvider: "piped",
pipedInstance: "https://pipedapi.kavin.rocks", // Optional custom instance
pipMode: "dual"
});
2. Invidious API Network
Invidious is a Crystal-based open-source YouTube alternative. Its API exposes pre-muxed combined MP4 video+audio streams via the formatStreams array.
- Endpoint Format:
GET https://<instance>/api/v1/videos/{VIDEO_ID} - Official Instances List: instances.invidious.io
- Default Public Node:
https://inv.tux.pizza - Fallback Public Node:
https://vid.puffyan.us
YVPlayer.init("video-stage", {
defaultId: "M7lc1UVf-VE",
proxyProvider: "invidious",
invidiousInstance: "https://inv.tux.pizza"
});
3. Cobalt API
Cobalt is a high-speed media processing engine built specifically to return single, direct streaming links without third-party adverts or tracking cookies.
- Endpoint Format:
POST https://api.cobalt.tools/(Body:{"url": "...", "videoQuality": "720"}) - Official Endpoint:
https://api.cobalt.tools
YVPlayer.init("video-stage", {
defaultId: "M7lc1UVf-VE",
proxyProvider: "cobalt",
cobaltInstance: "https://api.cobalt.tools"
});
Architecture Comparison Matrix
| Proxy Option | Backend Required | Resolution Speed | Direct Stream Format | Monthly Cost | Best Suited For |
|---|---|---|---|---|---|
| Piped API | Zero (Community CDN) | Fast (~180ms) | 720p / 1080p MP4 | $0 | Production SPAs, Next.js, and static websites. |
| Invidious API | Zero (Community CDN) | Moderate (~280ms) | 720p / 360p Pre-Muxed MP4 | $0 | Decentralized and privacy-strict web apps. |
| Cobalt API | Zero (Community CDN) | Ultra-Fast (~120ms) | 720p HD Direct MP4 | $0 | Clean single-link video playback and embeds. |
| Self-Hosted yt-dlp | Python 3.10+ (demo/server.py) | Near-Instant (Cached) | Adaptive 1080p / 720p | $0 (Local) / VPS | Enterprise intranets and full custom backend control. |
| Cloudflare Worker | Serverless Edge (worker.js) | Edge Cached (~40ms) | Direct 206 Byte Ranges | $0 (100k req/day free) | High-scale global edge architectures. |
Self-Hosted Python Stream Proxy
Deploy your own lightweight, zero-maintenance HTTP stream proxy on Linux, macOS, or Windows using Python and yt-dlp with built-in in-memory caching and HTTP 206 Partial Content range support.
Architecture & Features
The included demo/server.py is a hardened, multi-threaded HTTP server engineered specifically for direct 720p stream resolution and instant seeking:
ThreadingHTTPServer to serve concurrent video streams and static assets without request blocking.
bytes=start-end) directly to upstream CDNs, enabling smooth timeline scrub seeking in Native Video PiP.
yt-dlp extraction calls for frequently requested videos.
^[a-zA-Z0-9_-]{11}$ to prevent command injection and SSRF exploits.
Running Locally or in Production
Start the server with Python 3.10+ and yt-dlp installed:
# 1. Install yt-dlp dependency
pip install yt-dlp
# 2. Launch the multi-threaded proxy server
python demo/server.py
Production Systemd Service
For permanent 24/7 deployment on Ubuntu or Debian servers, create a systemd service file at /etc/systemd/system/yvplayer.service:
[Unit]
Description=YVPlayer Stream Proxy & Demo Server
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/var/www/yvplayer
ExecStart=/usr/bin/python3 demo/server.py
Restart=always
RestartSec=3
Environment=PORT=3000
[Install]
WantedBy=multi-user.target
Security, XSS Defense & CSP Guidelines
YVPlayer follows strict defensive design patterns to guarantee safety when embedding in multi-tenant or enterprise environments:
^[a-zA-Z0-9_-]{11}$ to prevent command flag injection, path traversal, or SSRF attacks.
.textContent rather than innerHTML, ensuring external WebVTT/SRT text cannot execute arbitrary script payloads.
"https://www.youtube.com" as the target origin rather than wildcard "*".