PromptHub
Developer Tools Video Processing

FlyCut Caption: The Secret Weapon for AI Video Subtitles

B

Bright Coding

Author

14 min read
29 views
FlyCut Caption: The Secret Weapon for AI Video Subtitles

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.

Comments (0)

Comments are moderated before appearing.

No comments yet. Be the first to share your thoughts!

Support us! ☕