Skip to main content

Turn raw screen recordings + narration text into polished narrated screencasts

Project description

screencast-narrator

Turn raw screen recordings + narration text into polished narrated screencasts.

screencast-narrator is a Python library and CLI that takes a Playwright (or any) screen recording together with timestamped narration text and produces a final video with:

  • Text-to-speech narration synced to on-screen actions
  • QR-code-based frame-accurate synchronization
  • Automatic freeze-frame insertion when narration overflows action duration
  • Dead-air gap detection and cutting
  • Interactive HTML timeline visualizations

Installation

pip install screencast-narrator

For TTS support (Kokoro):

pip install screencast-narrator[tts]

System dependencies:

# macOS
brew install ffmpeg zbar

# Ubuntu/Debian
apt-get install ffmpeg libzbar0

Quick Start

As a library with Playwright

from pathlib import Path
from playwright.sync_api import sync_playwright
from screencast_narrator.timeline import ScreencastTimeline
from screencast_narrator.sync_frames import inject_sync_frame
from screencast_narrator.merge import process

output_dir = Path("my-screencast")
output_dir.mkdir(exist_ok=True)

timeline = ScreencastTimeline(output_dir, video_enabled=True)

with sync_playwright() as p:
    browser = p.chromium.launch()
    context = browser.new_context(
        record_video_dir=str(output_dir / "videos"),
        record_video_size={"width": 1920, "height": 1080},
    )
    page = context.new_page()
    timeline.video_recording_started()

    # Narration bracket with sync frames
    timeline.begin_narration_bracket()
    inject_sync_frame(page, timeline.active_narration_id(), "START")

    page.goto("https://example.com")
    timeline.add_action("Navigate to example.com")

    inject_sync_frame(page, timeline.active_narration_id(), "END")
    timeline.add_narration("We open the example website.", start_ms=0, end_ms=2000)
    timeline.end_narration_bracket()

    timeline.video_recording_ended()
    context.close()
    browser.close()

# Produce the final narrated video
process(output_dir)

As a CLI

screencast-narrator /path/to/recording-output/

The directory must contain:

  • A timeline.json file (produced by ScreencastTimeline)
  • A video file (.webm) in a videos/ subdirectory

Architecture

The pipeline has these stages:

  1. Timeline recording (timeline.py) — During your test/recording, track narrations, actions, highlights, and sync frames with timestamps.

  2. Sync frame injection (sync_frames.py) — Inject green QR-code overlay frames into the browser at narration bracket boundaries for frame-accurate sync.

  3. TTS generation (tts.py) — Convert narration text to speech audio files. Pluggable backend; ships with Kokoro TTS.

  4. Sync detection (sync_detect.py) — Extract frames from the recorded video, detect green sync frames, decode QR codes to map video frames to narration events.

  5. Freeze frame calculation (freeze_frames.py) — When narration audio is longer than the on-screen action, calculate where to insert freeze frames (paused video) so audio and video stay in sync. Avoids placing freezes during visual highlights.

  6. Video merge (merge.py) — Orchestrate FFmpeg to build the final video: insert freeze frames, overlay audio, cut dead air gaps, concatenate segments.

  7. Timeline visualization (timeline_html.py) — Generate interactive HTML timelines showing original events, adjusted (post-freeze) positions, and a combined three-column view.

Modules

Module Purpose
timeline.py Event recording during screen capture
sync_frames.py QR code overlay injection for frame-accurate sync
sync_detect.py Green frame detection and QR decoding from video
freeze_frames.py Freeze frame calculation algorithm
tts.py Pluggable TTS backend (Kokoro default)
ffmpeg.py FFmpeg subprocess helpers
merge.py Main merge pipeline and CLI entry point
timeline_html.py HTML timeline visualization generator

Custom TTS Backend

Implement the TTSBackend protocol:

from screencast_narrator.tts import TTSBackend
from pathlib import Path

class MyTTS(TTSBackend):
    def generate(self, text: str, output_path: Path) -> None:
        # Generate audio file at output_path
        ...

# Use it
from screencast_narrator.merge import process
process(target_dir, tts_backend=MyTTS())

Development

git clone https://github.com/mmarinschek/screencast-narrator.git
cd screencast-narrator
pip install -e ".[dev,tts]"

# Run tests
pytest tests/ -v

# On macOS, if pyzbar can't find libzbar:
DYLD_LIBRARY_PATH=/opt/homebrew/lib pytest tests/ -v

License

Apache License 2.0 — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

screencast_narrator-0.1.1.tar.gz (33.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

screencast_narrator-0.1.1-py3-none-any.whl (26.6 kB view details)

Uploaded Python 3

File details

Details for the file screencast_narrator-0.1.1.tar.gz.

File metadata

  • Download URL: screencast_narrator-0.1.1.tar.gz
  • Upload date:
  • Size: 33.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for screencast_narrator-0.1.1.tar.gz
Algorithm Hash digest
SHA256 08a085680a5052cf82ae2d70f4079b94bfd1c16305dbdff8413a5c3e7c5147a4
MD5 bf3aa9def9fa7a780bcaf4c865397f0d
BLAKE2b-256 fd2f20020eedde9dd6bfcd18d3107445789edd1be9ebb64aa0ac23afa12f0317

See more details on using hashes here.

Provenance

The following attestation bundles were made for screencast_narrator-0.1.1.tar.gz:

Publisher: publish.yml on mmarinschek/screencast-narrator

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file screencast_narrator-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for screencast_narrator-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 b1554c9b36f4219c53dd8015d763407b5cc85c5e99052404de602d004245ea42
MD5 54374cef2058da405589ccf1441b92b3
BLAKE2b-256 2c141b77a13e0d1f4ac9cac7d3e9c0c9f85543dcd152759f826cab1657a2d291

See more details on using hashes here.

Provenance

The following attestation bundles were made for screencast_narrator-0.1.1-py3-none-any.whl:

Publisher: publish.yml on mmarinschek/screencast-narrator

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page