Development · Data · AI

Voice-controlled local teleprompter

Teleprompter that scrolls at the pace of the voice using local Whisper, without sending data to the cloud.

1 star2026role: sole authorstatus: Active

01 Problem and context

A conventional teleprompter scrolls at a fixed speed, forcing the presenter to keep pace with it rather than the other way around. The common alternative (cloud-based speech recognition) requires sending audio of what is almost always unpublished script material to a third party.

A conventional teleprompter scrolls at a fixed speed and makes the presenter keep up with it. The usual alternative, cloud speech recognition, means handing a third party the audio of a script that is almost always unpublished material. This project handles voice-paced scrolling with the recogniser running on the presenter's own machine, on GPU, under the constraint that perceived latency stays low enough that the text never feels out of step.

02 Solution

The text scrolls at the pace of the speaker's voice, with the speech recognizer running locally on the presenter's GPU. It captures 500 ms chunks at 16 kHz with voice activity detection to prevent advancing during pauses, paired with sliding-window script alignment with monotonic progression. Neither the audio nor the script ever leaves the machine.

  1. Freezing the data contract before writing any backend: the scroll message was fixed as a schema carrying index, matched word, confidence and latency.
  2. Verifying the environment before building anything on top: isolated checks for CUDA, the microphone and the model load.
  3. Audio capture on a producer thread feeding a queue of 500 ms chunks at 16 kHz mono, with voice activity detection so the text does not advance during silences.
  4. Matching against the script with a sliding window, Unicode normalisation and forward-only movement; global edit distance was ruled out on cost, and forced alignment on lack of access to the model's logits.
  5. A reading interface and a WebSocket transport that drops stale scroll messages, plus a native window for a second display.

03 Results

Verifiable figures in the repository and its documentation:

100%of the speech recognition happens on the user's own machine
500 msaudio window per chunk, at 16 kHz mono
3operating modes

04 How it's built

Desktop teleprompter that synchronizes script scrolling with the speaker's voice in real time, featuring 100% offline processing. Captures microphone audio, transcribes it locally using faster-whisper on an NVIDIA GPU (CUDA), and aligns the transcript with the script via a deterministic matcher with fuzzy matching, sending the scroll position to the frontend over WebSocket from a FastAPI backend. Includes a classic auto-scroll mode, scene directives ignored by the speech recognizer, and a stealth mode running as a native app built with pywebview.

05 Ethical decisions

  • Recognition runs on a local GPU model instead of a cloud service precisely because what you read off a teleprompter is usually unpublished: neither the audio nor the script leaves the machine.
  • The borderless window mode exists so you can record your own content without the console showing up on screen. It is described for what it is, a presentation choice.

06 Highlights

  • Local speech recognition using CUDA-accelerated faster-whisper, configurable via environment variables (model, device, precision).
  • Deterministic script-to-transcript alignment algorithm with Unicode normalization and Levenshtein fuzzy matching ≤ 1.
  • FastAPI backend with a custom WebSocket protocol that orchestrates audio capture, STT, and matcher in real time.
  • Stealth mode as a native app via pywebview, featuring always-on-top behavior and interaction blocking.
  • Vanilla HTML/CSS/JS frontend with auto-scroll, bracketed scene directives, and keyboard shortcuts.

07 Limitations

No dataset and no training: faster-whisper is used as is, with the language pinned to Spanish because auto-detection costs both latency and accuracy. The latency targets are written down in the repository but remain unmeasured: until they are measured they are targets, not results. Matching works on the surface of the text rather than on forced alignment, so filler words and strong accents degrade it and drift can accumulate; a manual resync shortcut is identified and not implemented. Everything tested runs on a single configuration.