A free macOS teleprompter with real-time word tracking, classic auto-scroll, and voice-activated scrolling.
Built for streamers, interviewers, presenters, and podcasters.
Download · Features · How It Works · Build
Textream is a free, open-source macOS app that guides you through your script with three modes: word tracking (highlights each word as you say it), classic (constant-speed auto-scroll), and voice-activated (scrolls while you speak, pauses when you're silent). It displays your text in a sleek Dynamic Island-style overlay at the top of your screen, a draggable floating window, or fullscreen on a Sidecar iPad — visible only to you, invisible to your audience.
Paste your script, hit play, and start speaking. When you're done, the overlay closes automatically.
Download the latest .dmg from Releases
Or install with Homebrew:
brew install f/textream/textreamRequires macOS 15 Sequoia or later. Works on Apple Silicon and Intel.
Since Textream is distributed outside the Mac App Store, macOS may block it on first open. Run this once in Terminal:
xattr -cr /Applications/Textream.appThen right-click the app → Open. After the first launch, macOS remembers your choice.
| Mode | Description | Microphone |
|---|---|---|
| Word Tracking (default) | On-device speech recognition highlights each word as you say it. No cloud, no latency, works offline. Supports dozens of languages. | Required |
| Classic | Auto-scrolls at a constant speed. No microphone needed. | Not needed |
| Voice-Activated | Scrolls while you speak, pauses when you're silent or muted. Perfect for natural pacing. | Required |
- Scroll speed — Adjustable 0.5–8 words/s for Classic and Voice-Activated modes.
- Speech language — Choose your preferred speech recognition language for Word Tracking mode.
- Mouse scroll to catch up — In Classic and Voice-Activated modes, scroll with your mouse to jump ahead or back. The timer pauses while you scroll and resumes from the new position.
| Mode | Description |
|---|---|
| Pinned to Notch | A Dynamic Island–shaped overlay anchored below the MacBook notch. Sits above all apps. |
| Floating Window | A draggable window you can place anywhere on screen. Always on top. |
| Fullscreen | Fullscreen teleprompter on any display. Press Esc to stop. |
- Follow Mouse — The notch moves to whichever display your cursor is on.
- Fixed Display — Pin the notch to a specific screen.
- Follow Cursor — The window follows your mouse cursor. A floating stop button lets you dismiss it.
- Glass Effect — Translucent frosted glass background with adjustable opacity (0–60%).
- Display selection — Choose which screen to show the fullscreen teleprompter on.
- Esc to stop — Press the Escape key to dismiss the fullscreen overlay.
- Width — Adjustable overlay width (280–500 px).
- Height — Adjustable text area height (100–400 px).
| Setting | Options |
|---|---|
| Font Family | Sans, Serif, Mono, OpenDyslexic (dyslexia-friendly) |
| Font Size | XS (14 pt), SM (16 pt), LG (20 pt), XL (24 pt) |
| Highlight Color | White, Yellow, Green, Blue, Pink, Orange |
| Mode | Description |
|---|---|
| Off | No external display output. |
| Teleprompter | Fullscreen teleprompter on the selected external display or Sidecar iPad. |
| Mirror | Flipped output for prompter mirror rigs. |
- Mirror axis — Horizontal (standard for mirrors), Vertical, or Both (180° rotation).
- Target display — Pick from connected external displays and Sidecar iPads.
- Hide from screen share — Hides the overlay from screen recordings and video calls.
View your teleprompter on any device — phone, tablet, or another computer — via a local network browser connection.
- Enable in Settings → Remote — Starts a lightweight HTTP + WebSocket server on your Mac.
- QR code — Scan the generated QR code from your phone or tablet to open the teleprompter instantly.
- Real-time sync — Words highlight, waveform animates, and progress updates in real time over WebSocket.
- No app needed — Works in any modern browser. No installation required on the remote device.
- Configurable port — Default port 7373, adjustable in advanced settings.
- Fully local — All traffic stays on your local network. Nothing leaves your Wi-Fi.
Let someone else control your teleprompter remotely. A director can write, edit, and push scripts to your teleprompter in real time from any browser.
- Enable in Settings → Director — Starts a dedicated HTTP + WebSocket server (default port 7575).
- Remote web UI — The director opens a mobile-friendly web page with a full-featured script editor.
- Live text editing — The director types or pastes a script, hits Go, and your teleprompter starts immediately with word tracking.
- Read-locked highlighting — Already-read text is highlighted and locked in the web editor. Only unread text remains editable.
- Real-time sync — Word progress, waveform, mic status, and audio levels stream to the director's browser at 10 Hz.
- Single-page mode — Director mode works with a single page of text. Multi-page scripts are not used.
- Editor disabled — When director mode is active, the macOS editor is replaced with a QR code overlay so the director has full control.
- QR code — Scan or share the QR code from Settings or the editor overlay to connect the director instantly.
- PowerPoint notes import — Drop a .pptx file to extract presenter notes as pages. For Keynote or Google Slides, export to PowerPoint first.
- Save as .textream files — Save your scripts as .textream files to reuse anytime. Keep your notes organized across presentations.
- Multi-page support — Navigate between pages with automatic advance. In follow-cursor mode, pages auto-advance with a 3-second countdown.
- Live waveform — Visual voice activity indicator so you always know the mic is picking you up.
- Tap to jump — Tap any word in the overlay to jump the tracker to that position.
- Pause & resume — Go off-script, take a break, come back. The tracker picks up where you left off.
- Mute / unmute — Toggle the microphone on or off from the overlay in any mode.
- Completely private — All processing happens on-device. No accounts, no tracking, no data leaves your Mac.
- Auto update checker — Checks GitHub Releases for new versions on launch and from the Textream menu.
- Open source — MIT licensed. Contributions welcome.
| Use case | How Textream helps |
|---|---|
| Streamers | Read sponsor segments, announcements, and talking points without looking away from the camera. |
| Interviewers | Keep your questions visible while maintaining natural eye contact with your guest. |
| Presenters | Deliver keynotes, demos, and talks with confidence. Never lose your place. |
| Podcasters | Follow show notes, ad reads, and topic outlines hands-free while recording. |
- Paste your script — Drop your talking points, interview questions, or full script into the text editor.
- Hit play — The Dynamic Island overlay slides down from the top of your screen.
- Start speaking — Words highlight in real-time as you read. When you finish, the overlay closes automatically.
- macOS 15+
- Xcode 16+
- Swift 5.0+
git clone https://github.com/f/textream.git
cd textream/Textream
open Textream.xcodeprojBuild and run with ⌘R in Xcode.
Textream/
├── Textream.xcodeproj
├── Info.plist
└── Textream/
├── TextreamApp.swift # App entry point, deep link handling
├── ContentView.swift # Main text editor UI + About view
├── TextreamService.swift # Service layer, URL scheme handling
├── SpeechRecognizer.swift # On-device speech recognition engine
├── NotchOverlayController.swift # Dynamic Island + floating overlay
├── ExternalDisplayController.swift # Sidecar / external display output
├── NotchSettings.swift # User preferences and presets
├── SettingsView.swift # Tabbed settings UI
├── MarqueeTextView.swift # Word flow layout and highlighting
├── BrowserServer.swift # Remote connection HTTP + WebSocket server
├── DirectorServer.swift # Director mode HTTP + WebSocket server
├── PresentationNotesExtractor.swift # PPTX presenter notes extraction
├── UpdateChecker.swift # GitHub release update checker
└── Assets.xcassets/ # App icon and colors
Textream supports the textream:// URL scheme for launching directly into the overlay:
textream://read?text=Hello%20world
It also registers as a macOS Service, so you can select text in any app and send it to Textream via the Services menu.
The Director Mode exposes an HTTP server and a WebSocket server on your local network. You can build your own director client using the protocol below.
| Service | Default Port | Configurable in |
|---|---|---|
| HTTP (serves the built-in web UI) | 7575 |
Settings → Director → Advanced |
| WebSocket (bidirectional communication) | 7576 (HTTP port + 1) |
Automatic |
- Open a WebSocket connection to
ws://<mac-ip>:<ws-port>(e.g.ws://192.168.1.42:7576). - The server immediately begins sending state frames as JSON at ~10 Hz once a script is active.
- Send command frames as JSON to control the teleprompter.
Send JSON messages over the WebSocket:
{
"type": "setText",
"text": "Welcome everyone to today's live stream..."
}Replaces the current text, starts word tracking, and opens the teleprompter overlay. This is equivalent to pressing Go in the built-in web UI.
{
"type": "updateText",
"text": "Welcome everyone to today's live stream We changed the rest of the script...",
"readCharCount": 42
}Updates the full script text while preserving the read position. readCharCount is the number of characters already read (locked). Only text after this offset is replaced. Use this for live editing during a read.
{
"type": "stop"
}Stops word tracking and dismisses the overlay.
The server broadcasts a JSON object on every tick (~100 ms):
{
"words": ["Welcome", "everyone", "to", "today's", "live", "stream"],
"highlightedCharCount": 24,
"totalCharCount": 120,
"isActive": true,
"isDone": false,
"isListening": true,
"fontColor": "#F5F5F7",
"lastSpokenText": "Welcome everyone to today's",
"audioLevels": [0.12, 0.34, 0.08, ...]
}| Field | Type | Description |
|---|---|---|
words |
string[] |
The script split into words (same order as displayed in the overlay). |
highlightedCharCount |
int |
Number of characters recognized so far. Use this to determine the read boundary. |
totalCharCount |
int |
Total character count of the full script. |
isActive |
bool |
true when the teleprompter overlay is visible and a script is loaded. |
isDone |
bool |
true when highlightedCharCount >= totalCharCount (finished reading). |
isListening |
bool |
true when the microphone is actively listening. |
fontColor |
string |
CSS color of the text in the overlay (user preference). |
lastSpokenText |
string |
Last recognized speech fragment. |
audioLevels |
double[] |
Array of audio level samples (0.0–1.0) for waveform visualization. |
When the overlay is not active, the server sends a frame with isActive: false and empty arrays.
import asyncio, json, websockets
async def director():
async with websockets.connect("ws://192.168.1.42:7576") as ws:
# Send a script
await ws.send(json.dumps({
"type": "setText",
"text": "Hello everyone, welcome to the show."
}))
# Listen for state updates
async for msg in ws:
state = json.loads(msg)
pct = 0
if state["totalCharCount"] > 0:
pct = state["highlightedCharCount"] / state["totalCharCount"] * 100
print(f"Progress: {pct:.0f}% Done: {state['isDone']}")
if state["isDone"]:
break
# Stop
await ws.send(json.dumps({"type": "stop"}))
asyncio.run(director())MIT
Original idea by Semih Kışlar — thanks to him!
Made by Fatih Kadir Akin
