The Problem: You need transparent videos in your web app. You export from Blender/After Effects with alpha, drop it in your React project, and... it works in Chrome but breaks in Safari. Or the files are 10MB+ for a 5-second loop. You try VP9 with alpha, HEVC with alpha, AVIF sequences - nothing works reliably everywhere.
The Solution: This tool converts alpha videos using Jake Archibald's stacked alpha method - a brilliant technique that delivers 60-85% smaller files with perfect cross-browser compatibility, including Safari/iOS.
Why this exists: I built this while working on a React project that needed transparent video animations. After hitting WebKit limitations and finding Jake's work, I automated the conversion process so others don't have to fight with FFmpeg commands.
# macOS
brew install ffmpeg
# Ubuntu/Debian
sudo apt install ffmpeg
# Windows (Chocolatey)
choco install ffmpegExport from your video editor with an alpha channel:
- Recommended: QuickTime Animation codec (RGBA)
- Best quality: ProRes 4444
- Alternative: PNG sequence
See EXPORTING.md for After Effects, Blender, Premiere Pro, and other tools.
./scripts/convert-alpha-videos.sh input-video.movThis generates two files:
input-video_stacked_av1.mp4(modern browsers)input-video_stacked_hevc.mp4(Safari/iOS)
<script type="module">
import 'stacked-alpha-video';
</script>
<stacked-alpha-video>
<video autoplay muted playsinline loop>
<source src="video_stacked_av1.mp4" type='video/mp4; codecs=av01.0.08M.08.0.110.01.01.01.1' />
<source src="video_stacked_hevc.mp4" type='video/mp4; codecs=hvc1.1.6.H120.b0' />
</video>
</stacked-alpha-video>Install the web component: npm install stacked-alpha-video
./scripts/convert-alpha-videos.sh input.movOutput files are created in the same directory as the input.
./scripts/convert-alpha-videos.sh --output-dir ./output input.mov# Higher quality (larger files)
./scripts/convert-alpha-videos.sh --av1-crf 35 --hevc-crf 25 input.mov
# Lower quality (smaller files)
./scripts/convert-alpha-videos.sh --av1-crf 50 --hevc-crf 40 input.movCRF Guide: Lower = better quality, larger file
25-30- Excellent (hero animations)35-45- Very good (default: 45)50-55- Good (backgrounds)
# Fast preview (lower quality)
./scripts/convert-alpha-videos.sh --av1-cpu 6 --hevc-preset medium input.mov
# Production (best quality) - default
./scripts/convert-alpha-videos.sh input.mov# AV1 only (smallest, modern browsers)
./scripts/convert-alpha-videos.sh --av1-only input.mov
# HEVC only (Safari compatibility)
./scripts/convert-alpha-videos.sh --hevc-only input.mov# Convert multiple files
./scripts/convert-all-videos.sh video1.mov video2.mov video3.mov
# Convert all MOV files in directory
./scripts/convert-all-videos.sh videos/*.mov./scripts/convert-alpha-videos.sh [OPTIONS] INPUT_FILE| Option | Default | Description |
|---|---|---|
--av1-crf VALUE |
45 | AV1 quality (0-63, lower=better) |
--av1-cpu VALUE |
3 | AV1 speed (0-8, lower=slower/better) |
--hevc-crf VALUE |
30 | HEVC quality (0-63, lower=better) |
--hevc-preset VALUE |
veryslow | HEVC preset (medium/slow/slower/veryslow) |
--av1-only |
- | Only generate AV1 version |
--hevc-only |
- | Only generate HEVC version |
--output-dir DIR |
same as input | Output directory |
-h, --help |
- | Show help message |
Install Jake Archibald's web component:
npm install stacked-alpha-videoUse in your JavaScript/React/Vue:
import 'stacked-alpha-video';<stacked-alpha-video>
<video autoplay crossorigin="anonymous" muted playsinline loop>
<source src="video_stacked_av1.mp4" type='video/mp4; codecs=av01.0.08M.08.0.110.01.01.01.1' />
<source src="video_stacked_hevc.mp4" type='video/mp4; codecs=hvc1.1.6.H120.b0' />
</video>
</stacked-alpha-video>import { useEffect, useRef } from 'react';
import 'stacked-alpha-video';
export function TransparentVideo({ src }: { src: string }) {
return (
<stacked-alpha-video>
<video autoPlay muted playsInline loop>
<source src={`${src}_stacked_av1.mp4`} type='video/mp4; codecs=av01.0.08M.08.0.110.01.01.01.1' />
<source src={`${src}_stacked_hevc.mp4`} type='video/mp4; codecs=hvc1.1.6.H120.b0' />
</video>
</stacked-alpha-video>
);
}<script type="module">
import 'https://unpkg.com/stacked-alpha-video@1.0.10';
</script>
<stacked-alpha-video>
<video autoplay muted playsinline loop>
<source src="video_stacked_av1.mp4" type='video/mp4; codecs=av01.0.08M.08.0.110.01.01.01.1' />
<source src="video_stacked_hevc.mp4" type='video/mp4; codecs=hvc1.1.6.H120.b0' />
</video>
</stacked-alpha-video>See examples/basic-usage.html for a complete example.
# Serve via HTTP (required for WebGL/CORS)
python3 -m http.server 8000 --directory examples
# Then open http://localhost:8000/basic-usage.htmlNote: The example won't work when opened directly via file:// protocol due to browser CORS restrictions. You must serve it via HTTP.
| Browser | AV1 | HEVC | Recommended |
|---|---|---|---|
| Chrome 90+ | ✅ | ✅ | AV1 |
| Firefox 93+ | ✅ | ❌ | AV1 |
| Safari 17+ | ✅ | ✅ | Both |
| Safari 11-16 | ❌ | ✅ | HEVC only |
| Edge 90+ | ✅ | ✅ | AV1 |
| iOS 17+ | ✅ | ✅ | Both |
| iOS 11-16 | ❌ | ✅ | HEVC only |
Always generate both formats for maximum compatibility.
The converter accepts any video format with an alpha channel:
✅ Recommended:
- QuickTime Animation codec (
.mov) - ProRes 4444 (
.mov) - PNG sequence (converted to video first)
✅ Also works:
- WebM with VP9 alpha (
.webm) - Other QuickTime formats with alpha
- Any FFmpeg-supported format with alpha
See EXPORTING.md for export instructions from various tools.
When you try to use transparent videos on the web, you hit these issues:
- VP9 with alpha - Safari doesn't support it
- HEVC with alpha - Firefox doesn't support it, files are massive
- AVIF sequences - Terrible performance, buggy on Safari
- GIF/WebP - Limited colors, huge file sizes
No single format works everywhere. Until now.
Instead of native alpha channels, Jake Archibald's method splits each frame:
-
Split - Frames divided into two parts stacked vertically:
- Top half: RGB color data
- Bottom half: Alpha data (as brightness)
-
Encode - Both parts encoded as a standard video (no alpha channel needed)
-
Composite - A WebGL shader splits and recombines them in real-time in the browser
Result: Works everywhere, 60-85% smaller files, hardware-accelerated playback.
| Approach | Chrome | Firefox | Safari/iOS | File Size | Complexity |
|---|---|---|---|---|---|
| VP9 with alpha | ✅ | ✅ | ❌ | Large | Medium |
| HEVC with alpha | ✅ | ❌ | ✅ | Very large | High |
| Stacked alpha | ✅ | ✅ | ✅ | 60-85% smaller | Simple |
Credit: This method was pioneered by Jake Archibald. This tool just makes it easier to use.
Cause: Input video doesn't have an alpha channel
Solution:
- Re-export with alpha channel enabled (RGBA color mode)
- Try QuickTime Animation codec or ProRes 4444
- Verify your source has transparency before conversion
Solutions:
# Increase CRF (lower quality, smaller size)
./scripts/convert-alpha-videos.sh --av1-crf 50 --hevc-crf 40 input.mov
# Generate AV1 only (50-60% smaller than HEVC)
./scripts/convert-alpha-videos.sh --av1-only input.mov
# Reduce input resolution in your video editorNormal: AV1 encoding is CPU-intensive (10-30 min for a 10s video)
Speed up preview encoding:
./scripts/convert-alpha-videos.sh --av1-cpu 6 --hevc-preset medium input.movSolution: Install FFmpeg:
# macOS
brew install ffmpeg
# Ubuntu/Debian
sudo apt install ffmpeg
# Windows
choco install ffmpegCheck:
- Using the
stacked-alpha-videoweb component? - Browser supports WebGL?
- Check browser console for errors
- Verify source video has transparency
Real-world compression results:
| Video | Duration | Native VP9 | Stacked AV1 | Stacked HEVC | Savings |
|---|---|---|---|---|---|
| UI Animation | 5s | 2.1 MB | 287 KB | 412 KB | 86% |
| Logo Reveal | 3s | 1.8 MB | 201 KB | 356 KB | 89% |
| Product Demo | 10s | 3.7 MB | 428 KB | 661 KB | 88% |
Results vary based on content complexity and settings
- Jake Archibald's Article - Original stacked alpha method
- stacked-alpha-video Web Component - Jake's implementation
- FFmpeg Documentation - Video encoding reference
Contributions welcome! This tool is designed to be:
- Simple - Bash scripts, minimal dependencies
- Portable - macOS, Linux, Windows (with bash)
- Extensible - Easy to modify for your needs
MIT License - See LICENSE for details.
For issues or questions, please open an issue on GitHub.
Happy encoding! 🎥✨