A browser extension that creates a smart Picture-in-Picture video window that includes subtitles, even on websites where normal PiP drops them.
Most websites render subtitles as HTML overlays on top of videos. When Picture-in-Picture is activated, browsers only send the raw video stream to the PiP window, causing subtitles to disappear.
SubPIP fixes this by building a real-time synthetic video pipeline:
- Captures the video frames into a canvas
- Extracts subtitle text and timing
- Renders the subtitles directly onto the video frames
- Streams the combined result into a Picture-in-Picture window
The PiP window therefore shows exactly what the user sees on the page — video + subtitles — but floating.
- 📺 Works with any HTML5 video element
- 💬 Supports WebVTT & site-rendered subtitles (YouTube, Vimeo, Coursera, etc.)
- 🖼️ Burns subtitles into the PiP stream in real time
- 🎥 Uses canvas → MediaStream → Picture-in-Picture
- 🪟 Creates a fully subtitle-aware PiP window
- 🔌 Runs as a browser extension (Chrome / Firefox compatible)
HTML5 Video
↓
Frame Capture
↓
Canvas Renderer
↓
Subtitle Extractor
↓
Text Overlay
↓
Canvas Stream
↓
Synthetic MediaStream
↓
Picture-in-Picture
The extension does not rely on the browser's built-in PiP compositor. It creates its own video pipeline so subtitles become part of the pixels.
- Clone or download this repository
- Open your browser and navigate to
chrome://extensions/ - Enable "Developer mode" in the top right corner
- Click "Load unpacked"
- Select the
SubPipdirectory - The extension should now appear in your extensions list
- Clone or download this repository
- Open your browser and navigate to
about:debugging#/runtime/this-firefox - Click "Load Temporary Add-on"
- Select the
manifest.jsonfile in theSubPipdirectory - The extension should now be installed
- Navigate to a website with a video (e.g., YouTube, Vimeo, Coursera)
- Make sure subtitles are enabled on the video
- Click the SubPIP extension icon in your browser toolbar
- Click "Enable SubPIP"
- The Picture-in-Picture window will open with subtitles burned in
- To disable, click the extension icon again and click "Disable SubPIP"
When SubPIP is active, you can use these keyboard shortcuts:
- Spacebar / K - Play/Pause
- Left Arrow - Seek back 10 seconds
- Right Arrow - Seek forward 10 seconds
- C - Toggle subtitles
- S - Open Settings
- ? / / - Show help
Click the "Settings" button in the popup to customize:
- Subtitle font size (12-48px)
- Subtitle font color
- Subtitle background color
- Subtitle background opacity
Click the "About" link in the popup footer to learn more about SubPIP, its features, and how it works.
SubPIP works with any HTML5 video element. It has special support for:
- YouTube - Extracts captions from YouTube's custom caption system
- Vimeo - Extracts captions from Vimeo's caption display
- Coursera - Extracts subtitles from Coursera's video player
- Any site with WebVTT - Uses native text track API
DRM-protected platforms (Netflix, Disney+, Prime Video, etc.) block video capture and will not work with SubPIP. This is a browser security restriction that cannot be bypassed.
- Higher CPU/GPU usage compared to native PiP due to real-time canvas rendering
- Subtitle styling is simplified for performance
- Chrome/Edge/Brave: Full support
- Firefox: Full support
- Safari: Not supported (different extension model)
SubPip/
├── manifest.json # Extension manifest
├── popup.html # Extension popup UI
├── popup.css # Popup styles
├── popup.js # Popup logic
├── background.js # Service worker
├── content.js # Content script (main logic)
├── icons/ # Extension icons
│ ├── icon16.png
│ ├── icon48.png
│ └── icon128.png
└── README.md # This file
The main content script that:
- Finds video elements on the page
- Extracts subtitles from various sources
- Captures video frames to canvas
- Renders subtitles onto frames
- Creates MediaStream from canvas
- Launches Picture-in-Picture
Service worker that:
- Manages active SubPIP sessions
- Handles cross-tab communication
- Updates extension badge
Popup UI that:
- Shows current status
- Enables/disables SubPIP
- Communicates with content script
To add support for a new video platform, create a new subtitle extractor class in content.js:
class NewSiteSubtitleExtractor {
constructor() {
this.currentText = null;
this.observer = null;
}
initialize() {
this.startMonitoring();
}
startMonitoring() {
// Set up DOM monitoring
}
extract() {
// Extract subtitle text from DOM
}
getCurrent() {
if (this.currentText) {
return { text: this.currentText };
}
return null;
}
hasSubtitles() {
return this.currentText !== null;
}
cleanup() {
// Clean up observers
}
}Then add it to the setupSiteSpecificExtractor() method in the SubtitleExtractor class.
Contributions are welcome! Please feel free to submit issues or pull requests.
This project is open source and available under the MIT License.
SubPIP was created to solve a common problem faced by language learners, accessibility users, and multitaskers who want to watch subtitled content while working.
If you encounter any issues or have questions, please open an issue on the project repository.
If you find SubPIP helpful and want to support its continued development, consider buying me a coffee! Your support helps keep this project free and actively maintained.
Tagline: "Picture-in-Picture, but it actually shows what you're watching."