A web-based subtitle editor for MP4 videos built with Vue 3, TypeScript, and FFmpeg WASM. Upload an MP4 video file, add customizable subtitles, preview them in real-time, and burn them directly into the video - all in your browser.
- Drag & Drop Upload: Easily upload MP4 files by dragging and dropping or clicking to browse
- Built-in Video Player: Play, pause, seek, and preview subtitles in real-time overlay
- Multiple Subtitles: Add unlimited subtitles with individual styling
- Customizable Styling:
- Position (X/Y coordinates with percentage-based positioning)
- Font size, family, and weight
- Text color and background color
- Background opacity
- Text shadow effects
- Real-time Preview: See subtitles appear over the video as you watch
- Time Controls: Set start/end times manually or use "Set Current" button while watching
- Subtitle List: View, edit, and delete all subtitles in a scrollable list
- Client-side Processing: All processing happens in your browser using FFmpeg WASM - no server required
- Burn-in Export: Subtitles are permanently burned into the video using ASS format
- Play & Download: Preview the generated video before downloading
- Vue 3 - Progressive JavaScript framework with Composition API
- TypeScript - Type-safe JavaScript
- Vite - Fast build tool and dev server
- FFmpeg WASM - WebAssembly version of FFmpeg for video processing
- @ffmpeg/ffmpeg - FFmpeg WASM core library
- @ffmpeg/util - Utility functions for FFmpeg WASM
- Upload: Upload an MP4 file (drag & drop or file picker)
- Add Subtitles: Click "Add Subtitle" to create a new subtitle entry
- Edit Content:
- Enter the subtitle text
- Set start and end times (manually or use "Set Current" while video plays)
- Customize position, font, colors, and effects
- Preview: Play the video to see subtitles appear in real-time
- Generate: Click "Generate Subtitled Video" to burn subtitles into the video
- Download: Download the subtitled MP4 file
The application uses the FFmpeg command:
ffmpeg -i input.mp4 -vf "ass=subtitles.ass" -c:a copy -c:v libx264 -preset fast output.mp4Where:
-i input.mp4: Input MP4 file-vf "ass=subtitles.ass": Apply ASS subtitle filter-c:a copy: Copy audio stream without re-encoding-c:v libx264: Re-encode video with H.264-preset fast: Use fast encoding presetoutput.mp4: Output MP4 file with burned-in subtitles
Each subtitle can be individually customized:
| Option | Values |
|---|---|
| Text | Any multi-line text |
| Start/End Time | Manual input or "Set Current" button |
| X Position | 0-100% (left to right) |
| Y Position | 0-100% (top to bottom) |
| Font Size | 12-72px |
| Font Family | Arial, Helvetica, Times New Roman, Georgia, Verdana, Courier New, Impact |
| Font Weight | Normal, Bold, Lighter |
| Text Color | Color picker |
| Background Color | Color picker |
| Background Opacity | 0.0-1.0 |
| Text Shadow | None, Small, Medium, Large |
src/
├── App.vue # Root component
├── main.ts # Application entry point
├── components/
│ └── SubtitleEditor.vue # Main subtitle editor component (~1500 lines)
└── assets/
├── base.css # Base CSS styles
└── main.css # Custom styles
FFmpeg WASM requires SharedArrayBuffer to work properly. This feature requires specific HTTP headers to be set on your server:
For Production Deployment:
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin
For Development (localhost): These headers are automatically handled by Vite, so the application should work without additional configuration.
If you encounter "SharedArrayBuffer is not defined" error:
- Ensure you're using a modern browser (Chrome 90+, Firefox 88+, Safari 14.1+)
- For production deployment, make sure your server sends the required headers
- Try using a different browser
- Check if your browser has disabled SharedArrayBuffer in security settings
pnpm installpnpm run devpnpm run buildLint with ESLint
pnpm run lint- Chrome/Edge 90+
- Firefox 88+
- Safari 14.1+
Note: This application requires SharedArrayBuffer support, which may require specific HTTP headers in production environments.
- FFmpeg WASM loads on demand (when you first generate a video)
- Large files (>500MB) may cause browser memory issues
- Processing time depends on file size and number of subtitles
- All processing happens locally in your browser
- The MP4 file is stored as a blob before processing
Creating Subtitles:
- Pause the video at the desired position, then click "Add Subtitle"
- Use "Set Current" buttons to quickly set start/end times while watching
- Preview subtitles in real-time by playing the video
Positioning:
- X=50%, Y=85% positions subtitles at bottom center (default)
- Use lower Y values for higher placement on screen
Styling:
- Use background opacity 0.3-0.5 for readable subtitles
- Add text shadow for better contrast on light scenes
- Larger font sizes (28-32px) work best for mobile viewing
Error: "SharedArrayBuffer is not defined"
- This is a browser security feature requirement
- For development (localhost), Vite handles this automatically
- For production, ensure your server sends the required headers
- Try using Chrome or Edge for best compatibility
Application not loading FFmpeg:
- Check browser console for error messages
- Ensure you're using a supported browser
- Try refreshing the page and uploading the file again
Video generation stops midway:
- Check if the file is too large (>500MB)
- Ensure you have enough browser memory available
- Try with a smaller MP4 file first
- Close other browser tabs to free up memory
Subtitles not visible in generated video:
- Ensure the Y position is within 0-100% range
- Check that text color contrasts with the video
- Verify start/end times are within video duration
VSCode + Volar (and disable Vetur) + TypeScript Vue Plugin (Volar).
TypeScript cannot handle type information for .vue imports by default, so we replace the tsc CLI with vue-tsc for type checking. In editors, we need TypeScript Vue Plugin (Volar) to make the TypeScript language service aware of .vue types.
If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a Take Over Mode that is more performant. You can enable it by following steps:
- Disable the built-in TypeScript Extension
- Run
Extensions: Show Built-in Extensionsfrom VSCode's command palette - Find
TypeScript and JavaScript Language Features, right click and selectDisable (Workspace)
- Run
- Reload the VSCode window by running
Developer: Reload Windowfrom the command palette.
MIT