FlyCut Caption: The Secret Weapon for AI Video Subtitles
What if I told you that the most painful part of video creation—manually transcribing and syncing subtitles—could disappear entirely? That you could process hours of footage without uploading a single byte to the cloud, without paying API fees, without waiting in processing queues?
Every content creator, developer, and video editor knows the nightmare. You've finished shooting. The edit looks perfect. Then comes the subtitle slog: scrubbing through timelines, typing every word, adjusting timestamps, fixing sync issues. It's the creative equivalent of data entry. And the "solutions"? Expensive cloud APIs that charge per minute. Bloated desktop software that costs hundreds. Or worse—uploading your sensitive content to who-knows-where for processing.
Here's the truth that top developers have already discovered: local AI is no longer a compromise. It's the superior path. And FlyCut Caption just made it effortless.
This isn't another wrapper around OpenAI's API. This is a complete, production-ready React component that runs Whisper speech recognition directly in your browser—no backend required, no data leaves your machine, no subscription fees stack up. Built on React 19, TypeScript, and cutting-edge Web Workers architecture, FlyCut Caption transforms what used to be a multi-hour workflow into something that feels almost magical.
Ready to see how deep this rabbit hole goes? Let's dissect why this tool is quietly becoming the new standard for AI-powered video subtitle editing.
What Is FlyCut Caption?
FlyCut Caption is a complete video subtitle editing React component that combines AI-powered speech recognition with visual editing capabilities—all running locally in the browser. Created by the FlyCut Team and open-sourced under MIT license, it represents a fundamental shift in how developers approach video subtitle workflows.
The project emerged from a simple but powerful observation: cloud-based subtitle services create unnecessary friction. They require internet connectivity, introduce latency, raise privacy concerns, and accumulate costs at scale. Meanwhile, browser capabilities have exploded—WebAssembly, WebGPU, and modern JavaScript engines can now run sophisticated machine learning models that would have seemed impossible just years ago.
FlyCut Caption leverages Hugging Face Transformers.js to run OpenAI's Whisper model directly in the browser. This isn't a demo or proof-of-concept. It's a full-featured editing suite with drag-and-drop file upload, real-time video preview synchronized to subtitles, visual segment selection and deletion, style customization, and multi-format export—including burning subtitles directly into video files.
The timing couldn't be better. React 19's improved concurrent features, combined with Vite's lightning-fast builds and Tailwind CSS's utility-first approach, provide the perfect foundation for this kind of performance-sensitive UI. The project isn't just riding trends; it's architecturally positioned to exploit them.
What's particularly striking is the component's modular internationalization design. Rather than bolting on i18n as an afterthought, FlyCut Caption was built with global deployment in mind from day one—supporting Chinese, English, Japanese, and extensible to any language through its componentized locale system.
Key Features That Separate FlyCut Caption from the Pack
🎤 Intelligent Speech Recognition with Whisper
The core engine runs OpenAI's Whisper model through Transformers.js, delivering high-precision speech-to-text across multiple languages. But here's the technical kicker: ASR processing happens in Web Workers, completely decoupled from the main UI thread. Your interface stays buttery smooth even while crunching through hour-long videos. The model generates precise word-level timestamps, not just rough segment estimates.
✂️ Visual Subtitle Editing Interface
This isn't a JSON editor pretending to be user-friendly. FlyCut Caption provides genuine visual segment selection—click to select, shift-click for ranges, batch operations with undo/redo history. The subtitle list stays synchronized with video playback; click any segment and the player jumps instantly to that timestamp.
🎬 Real-time Video Preview with Interval Playback
The preview mode doesn't just play your video—it intelligently skips deleted segments, showing you exactly what your final export will look like. Keyboard shortcuts (space for play/pause, arrow keys for precise scrubbing, F for fullscreen) make navigation feel native and responsive.
📤 Multi-format Export Engine
Export clean SRT files for professional workflows. Export structured JSON for programmatic manipulation. Or export processed video with burned-in subtitles—complete with quality presets and format selection. The WebAV-powered processing happens entirely client-side.
🎨 Deep Style Customization
Override CSS custom properties for theming, or inject complete custom styles through the className and style props. Control font families, sizes, colors, positions, background transparency, and border treatments—all with real-time WYSIWYG preview.
🌐 Componentized Internationalization
The locale system deserves special mention. Unlike typical i18n approaches that require full re-renders or context switching, FlyCut Caption's design synchronizes external language controls with internal UI components automatically. Switch languages mid-edit without losing state or context.
Where FlyCut Caption Absolutely Dominates
1. Privacy-Critical Content Workflows
Legal depositions, medical recordings, internal corporate training, unreleased media—any situation where uploading to cloud services creates compliance risk or contractual problems. FlyCut Caption processes everything locally; your data never touches a remote server.
2. Offline-First Video Applications
Field journalists, documentary filmmakers in remote locations, educators in connectivity-limited environments. The entire pipeline works without internet once the initial application loads. No "sync when connected" compromises.
3. High-Volume Content Operations
Agencies processing hundreds of videos weekly. Cloud API costs scale linearly; local processing doesn't. The upfront cost is compute time on hardware you already own. For operations exceeding even modest volume, FlyCut Caption pays for itself in avoided API fees.
4. Embedded Editing in Existing Platforms
Because it's distributed as a React component with clean props interface, you can drop FlyCut Caption into existing CMS, learning management systems, or media management platforms. The event callbacks (onSubtitleGenerated, onVideoProcessed, onError) make integration straightforward.
5. Rapid Prototyping and MVPs
Need to demonstrate subtitle functionality without standing up backend infrastructure? npm install @flycut/caption-react and you're operational in minutes. The component includes all necessary UI, state management, and processing logic.
Step-by-Step Installation & Setup Guide
Prerequisites
- Node.js 18+ (required for modern ESM and worker support)
- pnpm (recommended) or npm
Clone and Run the Demo
# Clone the repository
git clone https://github.com/x007xyz/flycut-caption.git
cd flycut-caption
# Install dependencies
pnpm install
# Start development server
pnpm dev
# Open browser to http://localhost:5173
Production Build
# Build optimized bundle
pnpm build
# Preview production build locally
pnpm preview
Integrate as NPM Package
# Install in your project
npm install @flycut/caption-react
Critical: Import the required styles. The component won't render correctly without its CSS:
import '@flycut/caption-react/styles'
// Or the specific CSS file directly:
import '@flycut/caption-react/dist/caption-react.css'
TypeScript Configuration
Type definitions are included—no additional @types package needed. The component is built with TypeScript 5.8 in strict mode, so type safety propagates through your application automatically.
Development Commands Reference
pnpm dev # Start dev server with hot reload
pnpm run typecheck # Full TypeScript type checking
pnpm lint # ESLint with React-specific rules
pnpm build # Production build
pnpm preview # Preview production build
pnpm run build:lib # Build library distribution
pnpm run build:demo # Build demo application
REAL Code Examples from the Repository
Let's examine actual implementation patterns from FlyCut Caption's documentation, with detailed explanations of how each works.
Example 1: Basic Integration
The simplest possible implementation—just import, include styles, and render:
import { FlyCutCaption } from '@flycut/caption-react'
import '@flycut/caption-react/styles'
function VideoEditor() {
return (
<div className="video-editor-container">
<FlyCutCaption />
</div>
)
}
What's happening here: The component self-initializes with sensible defaults. Without any props, it uses zh-CN as default language, enables all features (drag-drop, export, video processing, theme toggle, language selector), and sets a 500MB file size limit. The className on the wrapper div lets you control layout positioning while the component handles its own internal styling.
Example 2: Event-Driven Integration with Backend
This pattern shows how to wire FlyCut Caption into a real application with persistence and error handling:
import { FlyCutCaption } from '@flycut/caption-react'
function VideoEditorWithEvents() {
const handleFileSelected = (file: File) => {
console.log('Selected file:', file.name, file.size)
// Could validate file, update UI state, or log analytics
}
const handleSubtitleGenerated = (subtitles: SubtitleChunk[]) => {
console.log('Generated subtitles:', subtitles.length)
// Persist to your backend immediately
saveSubtitles(subtitles)
}
const handleVideoProcessed = (blob: Blob, filename: string) => {
// Create object URL for download or preview
const url = URL.createObjectURL(blob)
// Trigger download or upload to storage
downloadFile(url, filename)
// CRITICAL: Clean up object URL to prevent memory leaks
// URL.revokeObjectURL(url) when done
}
const handleError = (error: Error) => {
console.error('FlyCut Caption error:', error)
showErrorNotification(error.message)
}
return (
<FlyCutCaption
onFileSelected={handleFileSelected}
onSubtitleGenerated={handleSubtitleGenerated}
onVideoProcessed={handleVideoProcessed}
onError={handleError}
/>
)
}
Key architectural insight: The component uses a push-based event model rather than requiring you to poll for state. Subtitles are delivered as structured SubtitleChunk[] arrays with precise timestamps. Processed video arrives as a Blob—the standard browser binary format—making it compatible with fetch uploads, FileReader processing, or direct download links.
Example 3: Configuration-Driven Feature Control
Fine-tune exactly which capabilities are exposed:
import { FlyCutCaption } from '@flycut/caption-react'
function ConfiguredEditor() {
const config = {
// Visual theme: 'light', 'dark', or 'auto' (system preference)
theme: 'dark' as const,
// UI language vs ASR recognition language can differ
language: 'zh-CN', // Interface language
asrLanguage: 'zh', // Speech recognition language
// Toggle specific features
enableDragDrop: true,
enableExport: true,
enableVideoProcessing: true,
enableThemeToggle: true, // Let users switch themes
enableLanguageSelector: true, // Let users switch languages
// File handling constraints
maxFileSize: 1000, // 1GB limit
supportedFormats: ['mp4', 'webm', 'mov'] // Restrict accepted formats
}
return (
<FlyCutCaption config={config} />
)
}
Why this matters: The separation of language (UI) and asrLanguage (recognition) enables powerful workflows—like an English-speaking editor processing Chinese footage, or vice versa. The supportedFormats array filters both the file picker dialog and drag-drop validation, preventing user confusion from unsupported files.
Example 4: Complete Internationalization with External Controls
This is where FlyCut Caption's architecture shines. Here's the full pattern for synchronized external/internal language switching:
import { useState } from 'react'
import { FlyCutCaption, zhCN, enUS, type FlyCutCaptionLocale } from '@flycut/caption-react'
function App() {
const [currentLanguage, setCurrentLanguage] = useState('zh')
const [currentLocale, setCurrentLocale] = useState<FlyCutCaptionLocale | undefined>(undefined)
const handleLanguageChange = (language: string) => {
setCurrentLanguage(language)
// Map language code to locale object
switch (language) {
case 'zh':
case 'zh-CN':
setCurrentLocale(zhCN)
break
case 'en':
case 'en-US':
setCurrentLocale(enUS)
break
default:
setCurrentLocale(undefined) // Falls back to default (zhCN)
}
}
return (
<div className="min-h-screen bg-background">
{/* External language controls */}
<div className="mb-8 text-center">
<button
className={currentLanguage === 'zh' ? 'active' : ''}
onClick={() => handleLanguageChange('zh')}
>
中文
</button>
<button
className={currentLanguage === 'en' ? 'active' : ''}
onClick={() => handleLanguageChange('en')}
>
English
</button>
</div>
{/* Component syncs both ways: external→internal and internal→external */}
<FlyCutCaption
config={{
theme: 'auto',
language: currentLanguage,
enableLanguageSelector: true // Internal selector stays synced
}}
locale={currentLocale}
onLanguageChange={handleLanguageChange} // Internal changes propagate out
onError={(error) => console.error('Component error:', error)}
onProgress={(stage, progress) => console.log(`${stage}: ${progress}%`)}
/>
</div>
)
}
The synchronization magic: When enableLanguageSelector: true, FlyCut Caption renders its own language dropdown. When a user selects a language there, onLanguageChange fires—updating your external React state, which flows back down as props. This bidirectional binding prevents the dreaded "two sources of truth" problem that plagues most i18n implementations.
Example 5: Custom Language Pack (Japanese)
For markets not covered by built-in packs, define complete custom locales:
import { FlyCutCaption, type FlyCutCaptionLocale } from '@flycut/caption-react'
// Complete Japanese locale definition
const customJaJP: FlyCutCaptionLocale = {
common: {
loading: '読み込み中...',
error: 'エラー',
success: '成功',
confirm: '確認',
cancel: 'キャンセル',
ok: 'OK',
},
components: {
fileUpload: {
dragDropText: 'ビデオファイルをここにドラッグするか、クリックして選択',
selectFile: 'ファイルを選択',
supportedFormats: 'サポート形式:',
},
subtitleEditor: {
title: '字幕エディター',
addSubtitle: '字幕を追加',
deleteSelected: '選択項目を削除',
},
},
messages: {
fileUpload: {
uploadSuccess: 'ファイルアップロード成功',
uploadFailed: 'ファイルアップロード失敗',
},
}
}
// Apply custom locale
<FlyCutCaption
config={{ language: 'ja' }}
locale={customJaJP}
/>
Extensibility note: The FlyCutCaptionLocale type is fully exported, so TypeScript validates your custom pack at compile time. Missing any required key? You'll know immediately, not at runtime in production.
Advanced Usage & Best Practices
Memory Management with Blob URLs
When handling onVideoProcessed or onExportComplete, always clean up object URLs:
const handleVideoProcessed = (blob: Blob, filename: string) => {
const url = URL.createObjectURL(blob)
// ... use url for download or preview
// Clean up when done to prevent memory leaks
return () => URL.revokeObjectURL(url)
}
SSR-Safe Dynamic Imports
For Next.js or similar frameworks, force client-side only rendering:
import dynamic from 'next/dynamic'
const FlyCutCaption = dynamic(
() => import('@flycut/caption-react').then(mod => mod.FlyCutCaption),
{ ssr: false } // Critical: prevents server-side rendering errors
)
Progressive Enhancement Pattern
Use onProgress to implement sophisticated loading states:
const [progress, setProgress] = useState({ stage: '', percent: 0 })
// In component:
onProgress={(stage, progress) => {
setProgress({ stage, percent: progress })
// Could update a global loading store, show stage-specific tips, etc.
}}
Theme Override Strategy
Rather than fighting specificity, use CSS custom properties:
.my-custom-editor {
--flycut-primary: #10b981; /* Your brand green */
--flycut-border-radius: 12px; /* Softer corners */
}
How FlyCut Caption Stacks Against Alternatives
| Feature | FlyCut Caption | Whisper API (OpenAI) | Descript | Otter.ai | FFmpeg + Whisper CLI |
|---|---|---|---|---|---|
| Cost | Free, open source | $0.006/minute | $12-24/month | $8-30/month | Free, but manual setup |
| Privacy | 100% local | Cloud processed | Cloud processed | Cloud processed | Local |
| Integration | React component drop-in | API calls required | Standalone app | Standalone app | Command-line scripts |
| Visual Editing | Built-in, sophisticated | None | Yes, proprietary | Limited | None |
| Video Export | Built-in with burn-in | Audio only | Yes | No | Manual FFmpeg |
| Offline Use | Full functionality | Requires internet | Requires internet | Requires internet | Full functionality |
| Customization | Deep (styles, i18n, events) | Limited | Limited | Limited | Unlimited but manual |
| Setup Complexity | npm install |
API key + integration | Account + download | Account + download | Model + dependencies |
| Real-time Preview | Synchronized player | N/A | Yes | No | N/A |
| Web Workers | Yes, non-blocking UI | N/A | Unknown | N/A | N/A |
The verdict: FlyCut Caption occupies a unique position—combining the privacy and cost benefits of local processing with the integration ease of a modern React component. It's the only solution that gives you visual editing, video export, and deep customization without cloud dependencies or subscription lock-in.
FAQ: What Developers Ask Most
Q: Does FlyCut Caption work with React 18, or only React 19?
A: The project is built and tested with React 19, leveraging its improved concurrent features. React 18 may work but isn't officially supported. The component uses modern hooks patterns that assume React 19's behavior.
Q: How accurate is the Whisper-based speech recognition?
A: Accuracy depends on audio quality, speaker clarity, and language. Whisper is state-of-the-art for open-source ASR, particularly strong with English and Chinese. The component generates word-level timestamps, enabling precise subtitle alignment that exceeds typical cloud API granularity.
Q: What's the maximum video file size?
A: Default is 500MB, configurable up to your system's capabilities via maxFileSize in config. The actual limit depends on available RAM for processing and browser storage quotas.
Q: Can I use this in a commercial project?
A: Yes, under MIT license terms. The only restriction: you cannot remove or modify FlyCut's logos, watermarks, or brand elements without explicit written permission. Contact the team if you need white-label rights.
Q: Does it support GPU acceleration?
A: Through Transformers.js and WebGPU (where available), yes. The component automatically uses the best available backend. Performance varies by hardware; dedicated GPU significantly speeds up ASR processing.
Q: How do I add support for my language?
A: Create a custom locale object following the FlyCutCaptionLocale type, then pass it via the locale prop. For ASR recognition, Whisper supports 99 languages—specify the appropriate language code in asrLanguage config.
Q: What browsers are supported?
A: Chrome 88+, Firefox 78+, Safari 14+, Edge 88+. Web Workers and modern ES2020 features are required. The component gracefully degrades where features are missing.
Conclusion: Why FlyCut Caption Deserves Your Attention
We've covered a lot of ground. The architecture decisions that make FlyCut Caption special—local AI through Transformers.js, Web Workers for non-blocking processing, componentized i18n that actually works, the complete visual editing suite with real-time preview. This isn't a toy project or a thin wrapper. It's a production-grade solution to a genuinely hard problem.
The video subtitle workflow has been broken for too long. Either you pay cloud APIs indefinitely, or you wrestle with command-line tools that don't integrate. FlyCut Caption threads this needle with surprising elegance: install as an npm package, drop in a React component, and you have a complete editing studio running in your user's browser.
For privacy-conscious applications, cost-sensitive operations, offline requirements, or simply developers who want control over their stack—this is the tool that makes local AI subtitle editing practical.
My take? The next wave of video applications won't upload content for processing. They'll process where the content already lives: in the browser, on the user's device. FlyCut Caption is early to this paradigm, but it's executing with the maturity of a much older project.
Ready to stop paying per-minute subtitle fees? Ready to stop explaining to clients why their sensitive footage needs cloud processing? Clone the repository, run pnpm dev, and experience what local AI subtitle editing actually feels like when it's done right.
Star the project, file issues, contribute improvements—this is open source at its best: solving real problems with modern technology, generously shared. The future of video subtitle editing is local, and it's already here.
Built with ❤️ by the FlyCut Team. Questions? Open an issue on GitHub or reach out at x007xyzabc@gmail.com.