{"id":44095762,"url":"https://github.com/f/textream","last_synced_at":"2026-02-26T23:05:16.081Z","repository":{"id":337204033,"uuid":"1152691112","full_name":"f/textream","owner":"f","description":"Textream is a free macOS teleprompter app for streamers, interviewers, and presenters. It highlights your script in real-time as you speak, displayed in a beautiful Dynamic Island overlay.","archived":false,"fork":false,"pushed_at":"2026-02-12T10:36:16.000Z","size":6809,"stargazers_count":1225,"open_issues_count":2,"forks_count":76,"subscribers_count":5,"default_branch":"master","last_synced_at":"2026-02-14T20:38:58.427Z","etag":null,"topics":["macos","macos-app","streaming"],"latest_commit_sha":null,"homepage":"https://textream.fka.dev/","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/f.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-08T09:20:05.000Z","updated_at":"2026-02-14T17:48:42.000Z","dependencies_parsed_at":"2026-02-08T16:06:39.976Z","dependency_job_id":"857c7e89-d7a6-4549-9178-9a574fac2ca3","html_url":"https://github.com/f/textream","commit_stats":null,"previous_names":["f/textream"],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/f/textream","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f%2Ftextream","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f%2Ftextream/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f%2Ftextream/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f%2Ftextream/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/f","download_url":"https://codeload.github.com/f/textream/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f%2Ftextream/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29876378,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-26T22:37:10.609Z","status":"ssl_error","status_checked_at":"2026-02-26T22:37:09.019Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["macos","macos-app","streaming"],"created_at":"2026-02-08T12:19:18.730Z","updated_at":"2026-02-26T23:05:16.072Z","avatar_url":"https://github.com/f.png","language":"Swift","readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"Textream/Textream/Assets.xcassets/AppIcon.appiconset/icon_256x256.png\" width=\"128\" height=\"128\" alt=\"Textream icon\"\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eTextream\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eA free macOS teleprompter with real-time word tracking, classic auto-scroll, and voice-activated scrolling.\u003c/strong\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  Built for streamers, interviewers, presenters, and podcasters.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"#download\"\u003eDownload\u003c/a\u003e · \u003ca href=\"#features\"\u003eFeatures\u003c/a\u003e · \u003ca href=\"#how-it-works\"\u003eHow It Works\u003c/a\u003e · \u003ca href=\"#building-from-source\"\u003eBuild\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/video.gif\" width=\"600\" alt=\"Textream demo\"\u003e\n\u003c/p\u003e\n\n---\n\n## What is Textream?\n\nTextream 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.\n\nPaste your script, hit play, and start speaking. When you're done, the overlay closes automatically.\n\n## Download\n\n**[Download the latest .dmg from Releases](https://github.com/f/textream/releases/latest)**\n\nOr install with Homebrew:\n\n```bash\nbrew install f/textream/textream\n```\n\n\u003e Requires **macOS 15 Sequoia** or later. Works on Apple Silicon and Intel.\n\n### First launch\n\nSince Textream is distributed outside the Mac App Store, macOS may block it on first open. Run this once in Terminal:\n\n```bash\nxattr -cr /Applications/Textream.app\n```\n\nThen right-click the app → **Open**. After the first launch, macOS remembers your choice.\n\n## Features\n\n### Guidance Modes\n\n| Mode | Description | Microphone |\n|---|---|---|\n| **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 |\n| **Classic** | Auto-scrolls at a constant speed. No microphone needed. | Not needed |\n| **Voice-Activated** | Scrolls while you speak, pauses when you're silent or muted. Perfect for natural pacing. | Required |\n\n- **Scroll speed** — Adjustable 0.5–8 words/s for Classic and Voice-Activated modes.\n- **Speech language** — Choose your preferred speech recognition language for Word Tracking mode.\n- **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.\n\n### Overlay Modes\n\n| Mode | Description |\n|---|---|\n| **Pinned to Notch** | A Dynamic Island–shaped overlay anchored below the MacBook notch. Sits above all apps. |\n| **Floating Window** | A draggable window you can place anywhere on screen. Always on top. |\n| **Fullscreen** | Fullscreen teleprompter on any display. Press **Esc** to stop. |\n\n#### Pinned to Notch options\n\n- **Follow Mouse** — The notch moves to whichever display your cursor is on.\n- **Fixed Display** — Pin the notch to a specific screen.\n\n#### Floating Window options\n\n- **Follow Cursor** — The window follows your mouse cursor. A floating stop button lets you dismiss it.\n- **Glass Effect** — Translucent frosted glass background with adjustable opacity (0–60%).\n\n#### Fullscreen options\n\n- **Display selection** — Choose which screen to show the fullscreen teleprompter on.\n- **Esc to stop** — Press the Escape key to dismiss the fullscreen overlay.\n\n### Size\n\n- **Width** — Adjustable overlay width (280–500 px).\n- **Height** — Adjustable text area height (100–400 px).\n\n### Font \u0026 Color\n\n| Setting | Options |\n|---|---|\n| **Font Family** | Sans, Serif, Mono, OpenDyslexic (dyslexia-friendly) |\n| **Font Size** | XS (14 pt), SM (16 pt), LG (20 pt), XL (24 pt) |\n| **Highlight Color** | White, Yellow, Green, Blue, Pink, Orange |\n\n### External Display \u0026 Sidecar\n\n| Mode | Description |\n|---|---|\n| **Off** | No external display output. |\n| **Teleprompter** | Fullscreen teleprompter on the selected external display or Sidecar iPad. |\n| **Mirror** | Flipped output for prompter mirror rigs. |\n\n- **Mirror axis** — Horizontal (standard for mirrors), Vertical, or Both (180° rotation).\n- **Target display** — Pick from connected external displays and Sidecar iPads.\n- **Hide from screen share** — Hides the overlay from screen recordings and video calls.\n\n### Remote Connection\n\nView your teleprompter on **any device** — phone, tablet, or another computer — via a local network browser connection.\n\n- **Enable in Settings → Remote** — Starts a lightweight HTTP + WebSocket server on your Mac.\n- **QR code** — Scan the generated QR code from your phone or tablet to open the teleprompter instantly.\n- **Real-time sync** — Words highlight, waveform animates, and progress updates in real time over WebSocket.\n- **No app needed** — Works in any modern browser. No installation required on the remote device.\n- **Configurable port** — Default port 7373, adjustable in advanced settings.\n- **Fully local** — All traffic stays on your local network. Nothing leaves your Wi-Fi.\n\n### Director Mode\n\nLet someone else control your teleprompter remotely. A director can write, edit, and push scripts to your teleprompter in real time from any browser.\n\n- **Enable in Settings → Director** — Starts a dedicated HTTP + WebSocket server (default port 7575).\n- **Remote web UI** — The director opens a mobile-friendly web page with a full-featured script editor.\n- **Live text editing** — The director types or pastes a script, hits Go, and your teleprompter starts immediately with word tracking.\n- **Read-locked highlighting** — Already-read text is highlighted and locked in the web editor. Only unread text remains editable.\n- **Real-time sync** — Word progress, waveform, mic status, and audio levels stream to the director's browser at 10 Hz.\n- **Single-page mode** — Director mode works with a single page of text. Multi-page scripts are not used.\n- **Editor disabled** — When director mode is active, the macOS editor is replaced with a QR code overlay so the director has full control.\n- **QR code** — Scan or share the QR code from Settings or the editor overlay to connect the director instantly.\n\n### File Support\n\n- **PowerPoint notes import** — Drop a .pptx file to extract presenter notes as pages. For Keynote or Google Slides, export to PowerPoint first.\n- **Save as .textream files** — Save your scripts as .textream files to reuse anytime. Keep your notes organized across presentations.\n- **Multi-page support** — Navigate between pages with automatic advance. In follow-cursor mode, pages auto-advance with a 3-second countdown.\n\n### Other\n\n- **Live waveform** — Visual voice activity indicator so you always know the mic is picking you up.\n- **Tap to jump** — Tap any word in the overlay to jump the tracker to that position.\n- **Pause \u0026 resume** — Go off-script, take a break, come back. The tracker picks up where you left off.\n- **Mute / unmute** — Toggle the microphone on or off from the overlay in any mode.\n- **Completely private** — All processing happens on-device. No accounts, no tracking, no data leaves your Mac.\n- **Auto update checker** — Checks GitHub Releases for new versions on launch and from the Textream menu.\n- **Open source** — MIT licensed. Contributions welcome.\n\n## Who it's for\n\n| Use case | How Textream helps |\n|---|---|\n| **Streamers** | Read sponsor segments, announcements, and talking points without looking away from the camera. |\n| **Interviewers** | Keep your questions visible while maintaining natural eye contact with your guest. |\n| **Presenters** | Deliver keynotes, demos, and talks with confidence. Never lose your place. |\n| **Podcasters** | Follow show notes, ad reads, and topic outlines hands-free while recording. |\n\n## How It Works\n\n1. **Paste your script** — Drop your talking points, interview questions, or full script into the text editor.\n2. **Hit play** — The Dynamic Island overlay slides down from the top of your screen.\n3. **Start speaking** — Words highlight in real-time as you read. When you finish, the overlay closes automatically.\n\n## Building from Source\n\n### Requirements\n\n- macOS 15+\n- Xcode 16+\n- Swift 5.0+\n\n### Build\n\n```bash\ngit clone https://github.com/f/textream.git\ncd textream/Textream\nopen Textream.xcodeproj\n```\n\nBuild and run with ⌘R in Xcode.\n\n### Project structure\n\n```\nTextream/\n├── Textream.xcodeproj\n├── Info.plist\n└── Textream/\n    ├── TextreamApp.swift              # App entry point, deep link handling\n    ├── ContentView.swift              # Main text editor UI + About view\n    ├── TextreamService.swift          # Service layer, URL scheme handling\n    ├── SpeechRecognizer.swift         # On-device speech recognition engine\n    ├── NotchOverlayController.swift   # Dynamic Island + floating overlay\n    ├── ExternalDisplayController.swift # Sidecar / external display output\n    ├── NotchSettings.swift            # User preferences and presets\n    ├── SettingsView.swift             # Tabbed settings UI\n    ├── MarqueeTextView.swift          # Word flow layout and highlighting\n    ├── BrowserServer.swift            # Remote connection HTTP + WebSocket server\n    ├── DirectorServer.swift           # Director mode HTTP + WebSocket server\n    ├── PresentationNotesExtractor.swift # PPTX presenter notes extraction\n    ├── UpdateChecker.swift            # GitHub release update checker\n    └── Assets.xcassets/               # App icon and colors\n```\n\n## URL Scheme\n\nTextream supports the `textream://` URL scheme for launching directly into the overlay:\n\n```\ntextream://read?text=Hello%20world\n```\n\nIt also registers as a macOS Service, so you can select text in any app and send it to Textream via the Services menu.\n\n## Director Mode API\n\nThe 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.\n\n### Ports\n\n| Service | Default Port | Configurable in |\n|---|---|---|\n| **HTTP** (serves the built-in web UI) | `7575` | Settings → Director → Advanced |\n| **WebSocket** (bidirectional communication) | `7576` (HTTP port + 1) | Automatic |\n\n### Connecting\n\n1. Open a WebSocket connection to `ws://\u003cmac-ip\u003e:\u003cws-port\u003e` (e.g. `ws://192.168.1.42:7576`).\n2. The server immediately begins sending **state frames** as JSON at ~10 Hz once a script is active.\n3. Send **command frames** as JSON to control the teleprompter.\n\n### Commands (Client → App)\n\nSend JSON messages over the WebSocket:\n\n#### `setText` — Start reading a new script\n\n```json\n{\n  \"type\": \"setText\",\n  \"text\": \"Welcome everyone to today's live stream...\"\n}\n```\n\nReplaces the current text, starts word tracking, and opens the teleprompter overlay. This is equivalent to pressing **Go** in the built-in web UI.\n\n#### `updateText` — Edit unread text while active\n\n```json\n{\n  \"type\": \"updateText\",\n  \"text\": \"Welcome everyone to today's live stream We changed the rest of the script...\",\n  \"readCharCount\": 42\n}\n```\n\nUpdates 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.\n\n#### `stop` — Stop the teleprompter\n\n```json\n{\n  \"type\": \"stop\"\n}\n```\n\nStops word tracking and dismisses the overlay.\n\n### State (App → Client)\n\nThe server broadcasts a JSON object on every tick (~100 ms):\n\n```json\n{\n  \"words\": [\"Welcome\", \"everyone\", \"to\", \"today's\", \"live\", \"stream\"],\n  \"highlightedCharCount\": 24,\n  \"totalCharCount\": 120,\n  \"isActive\": true,\n  \"isDone\": false,\n  \"isListening\": true,\n  \"fontColor\": \"#F5F5F7\",\n  \"lastSpokenText\": \"Welcome everyone to today's\",\n  \"audioLevels\": [0.12, 0.34, 0.08, ...]\n}\n```\n\n| Field | Type | Description |\n|---|---|---|\n| `words` | `string[]` | The script split into words (same order as displayed in the overlay). |\n| `highlightedCharCount` | `int` | Number of characters recognized so far. Use this to determine the read boundary. |\n| `totalCharCount` | `int` | Total character count of the full script. |\n| `isActive` | `bool` | `true` when the teleprompter overlay is visible and a script is loaded. |\n| `isDone` | `bool` | `true` when `highlightedCharCount \u003e= totalCharCount` (finished reading). |\n| `isListening` | `bool` | `true` when the microphone is actively listening. |\n| `fontColor` | `string` | CSS color of the text in the overlay (user preference). |\n| `lastSpokenText` | `string` | Last recognized speech fragment. |\n| `audioLevels` | `double[]` | Array of audio level samples (0.0–1.0) for waveform visualization. |\n\nWhen the overlay is not active, the server sends a frame with `isActive: false` and empty arrays.\n\n### Example: Minimal Python Client\n\n```python\nimport asyncio, json, websockets\n\nasync def director():\n    async with websockets.connect(\"ws://192.168.1.42:7576\") as ws:\n        # Send a script\n        await ws.send(json.dumps({\n            \"type\": \"setText\",\n            \"text\": \"Hello everyone, welcome to the show.\"\n        }))\n\n        # Listen for state updates\n        async for msg in ws:\n            state = json.loads(msg)\n            pct = 0\n            if state[\"totalCharCount\"] \u003e 0:\n                pct = state[\"highlightedCharCount\"] / state[\"totalCharCount\"] * 100\n            print(f\"Progress: {pct:.0f}%  Done: {state['isDone']}\")\n            if state[\"isDone\"]:\n                break\n\n        # Stop\n        await ws.send(json.dumps({\"type\": \"stop\"}))\n\nasyncio.run(director())\n```\n\n## License\n\nMIT\n\n---\n\n\u003cp align=\"center\"\u003e\n  Original idea by \u003ca href=\"https://x.com/semihdev\"\u003eSemih Kışlar\u003c/a\u003e — thanks to him!\u003cbr\u003e\n  Made by \u003ca href=\"https://fka.dev\"\u003eFatih Kadir Akin\u003c/a\u003e\n\u003c/p\u003e\n","funding_links":[],"categories":["Swift","Utilities","macos"],"sub_categories":["Text"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ff%2Ftextream","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ff%2Ftextream","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ff%2Ftextream/lists"}