Americo442 downloadsScroll notes as a teleprompter with mobile remote control, Stream Deck integration, countdown timer, and voice tracking.
Professional teleprompter for Obsidian — Stream Deck hardware control, mobile remote, neural text-to-speech, and full Markdown support.
Built for video recording, presentations, podcasts, speeches, and content creation.
Teleprompter Plus turns any Obsidian note into a professional teleprompter. Auto-scroll at adjustable speed, highlight your reading position, control playback from the keyboard, an Elgato Stream Deck, or a phone, and optionally read your script aloud with high-quality neural voices. Designed for creators who already live in Obsidian and want a teleprompter that speaks the same Markdown they write in.
say, Web Speech fallback, sentence-by-sentence highlighting[@ries2011] spoken as "(Ries, 2011)" using your .bib files
Clean reading display with hierarchical navigation panel, eyeline guide, and real-time position tracking.
Touch-friendly remote — phone, tablet, or second computer on the same network.
55+ hardware actions with live state synchronization across all controls.
Six-tab settings: Dashboard, Toolbar, Features, Profiles, Connection, About.
Obsidian → Settings → Community plugins → Browse → search Teleprompter Plus → Install → Enable.
main.js, styles.css, and manifest.json from the latest release.<your-vault>/.obsidian/plugins/teleprompter-plus/ (create the folder if needed).git clone https://github.com/JuracyAmerico/obsidian-teleprompter-plus.git
cd obsidian-teleprompter-plus
bun install
bun run build
# copy dist/main.js, dist/styles.css, and manifest.json into your vault's plugins folder
See CONTRIBUTING.md for the full development setup.
Cmd/Ctrl + P).+ / −, font size with Aa+ / Aa−.For 25+ keyboard commands, see Obsidian → Settings → Hotkeys → Teleprompter Plus.
| Tab | What's there |
|---|---|
| Dashboard | Live preview, quick profile picker, health status |
| Toolbar | Choose which controls appear in the teleprompter toolbar |
| Features | Collapsible cards by category — appearance, playback, navigation, voice, OBS, WebSocket |
| Profiles | 6 built-in profiles + your own saved configurations |
| Connection | Optional local WebSocket server for Stream Deck + mobile remote |
| About | Plugin info, shortcuts, credits |
55+ actions across 8 categories — Playback, Speed, Font, Navigation, Display, Utility, Countdown, Flip. Real-time bidirectional state sync: the Stream Deck button updates live when you change the teleprompter from any source.
{ "command": "toggle-play" }
{ "command": "set-speed", "value": 3 }
{ "command": "jump-to-header", "value": 1 }
Full action catalog, configuration steps, and Stream Deck plugin setup: docs/stream-deck-actions.md.
A local-only WebSocket server (default ws://127.0.0.1:8765) lets you build custom controls in any language.
const ws = new WebSocket('ws://127.0.0.1:8765')
ws.onopen = () => ws.send(JSON.stringify({ command: 'play' }))
ws.onmessage = (e) => {
const msg = JSON.parse(e.data as string)
if (msg.type === 'state') console.log('speed:', msg.data.speed)
}
Full command list, state shape, and integration examples: docs/websocket-api.md.
Privacy — the server binds to
127.0.0.1only. No LAN or internet exposure by default. The mobile remote piggy-backs on your existing Obsidian session over the same loopback bridge.
Three offline engines, selected automatically based on availability, plus one optional cloud engine:
say — built-in system voices (Samantha, Daniel, etc.). No setup.Pause/resume from the toolbar or keyboard. Citations are resolved from your bibliography (Quarto/Pandoc .bib files).
All default engines run fully offline — no audio or text leaves your machine. The ElevenLabs engine is the one exception and is strictly opt-in: when you explicitly select it and provide your own API key, the text of the script you are reading is sent to ElevenLabs' servers to synthesize audio, and playback consumes credits on your ElevenLabs account. No key is bundled with the plugin, and nothing is sent to ElevenLabs unless you turn the engine on. Prefer to keep everything local and free? Use Kokoro, macOS say, or Web Speech.
Most common issues:
| Issue | Fix |
|---|---|
| WebSocket port already in use | Settings → Connection → change port (default 8765). Click Restart server. |
| Stream Deck not connecting | Settings → Connection → Restart server. Confirm the Stream Deck plugin is installed and points at the same port. |
| Plugin doesn't appear after install | Verify <vault>/.obsidian/plugins/teleprompter-plus/ contains main.js, styles.css, manifest.json. Reload Obsidian (Cmd/Ctrl + R). |
| Content not updating when switching notes | Close and reopen the teleprompter view. |
| Fullscreen looks wrong | Plugin fullscreen is in-window. For true OS fullscreen, use Obsidian's View → Toggle Fullscreen first. |
| Pin window does nothing | macOS and Windows only. Some Linux window managers override this. |
Full troubleshooting guide: docs/troubleshooting.md.
%%{init: {'theme':'base', 'themeVariables': {
'background':'#0a0a0a',
'primaryColor':'#001a26',
'primaryTextColor':'#e0fbff',
'primaryBorderColor':'#00d4ff',
'secondaryColor':'#1a0a02',
'tertiaryColor':'#001824',
'lineColor':'#00d4ff',
'fontFamily':'Inter, sans-serif'
}}}%%
flowchart LR
subgraph Clients["🎮 EXTERNAL CLIENTS"]
direction TB
StreamDeck["Stream Deck<br/>55+ actions"]
Mobile["Mobile Remote<br/>touch web UI"]
Custom["Custom Scripts<br/>TS · Node · Python"]
end
subgraph Bridge["🔌 WEBSOCKET BRIDGE"]
direction TB
WS["ws://127.0.0.1:8765<br/><i>loopback only</i>"]
Commands["Command Router"]
Broadcast["State Broadcaster"]
WS --> Commands
WS --> Broadcast
end
subgraph Obsidian["📔 OBSIDIAN PLUGIN"]
direction TB
Plugin["Plugin Entry<br/>main.ts"]
View["Teleprompter View<br/>ItemView"]
Settings["Settings Manager"]
Plugin --> View
Plugin --> Settings
subgraph Core["Core Components"]
direction LR
Svelte["Svelte 5 UI"]
Markdown["Markdown<br/>marked + hljs"]
State["State<br/>$state · $effect"]
end
View --> Core
end
subgraph Branches["⚡ SIDE BRANCHES"]
direction TB
TTS["TTS Engines<br/>Kokoro · say · Web Speech"]
Cite["Citation Resolver<br/>[@key] → (Author, Year)"]
OBS["OBS Service<br/>recording sync"]
end
StreamDeck <-->|"commands ⇄ state"| WS
Mobile <--> WS
Custom <--> WS
Bridge <-->|"local IPC"| Plugin
View --> TTS
View --> Cite
Plugin --> OBS
classDef client fill:#1a0a02,stroke:#FF6B00,stroke-width:2px,color:#FF6B00
classDef bridge fill:#001824,stroke:#00d4ff,stroke-width:3px,color:#00d4ff
classDef obs fill:#001a26,stroke:#00d4ff,stroke-width:2px,color:#00d4ff
classDef branch fill:#001824,stroke:#00d4ff,stroke-width:2px,stroke-dasharray: 5 5,color:#e0fbff
class StreamDeck,Mobile,Custom client
class WS,Commands,Broadcast bridge
class Plugin,View,Settings,Svelte,Markdown,State obs
class TTS,Cite,OBS branch
Orange = command sent from a client. Cyan = state update broadcast back. All traffic stays on
127.0.0.1— never on LAN.
A richer Excalidraw version of this diagram is in docs/architecture.excalidraw — open it in Obsidian (with the Excalidraw plugin) to view, edit, or export to PNG/SVG for slides and presentations.
Design system, component reference, and icon catalog: docs/.
Pull requests welcome. See CONTRIBUTING.md for the tech stack, project structure, build workflow, code style, and contribution guidelines.
Full version history in CHANGELOG.md. Latest release: see the Releases page.
Have an idea? Open a discussion or submit an issue.
Created by Americo (@JuracyAmerico).
Built with Obsidian, Svelte 5, TypeScript, Vite, Tailwind CSS, marked.js, highlight.js, and ws.
The voice-tracking matcher (speech-to-script alignment) is ported from
jlecomte/voice-activated-teleprompter
(MIT) — its Levenshtein look-ahead algorithm and tokenizer are the basis for
src/voice/speech-matcher.ts, word-tokenizer.ts, and levenshtein.ts, with the
edit-distance core from js-levenshtein (MIT).
Thank you to those projects.
MIT License. Copyright © 2024–2026 Juracy Américo. See LICENSE.
If this plugin saves you time, you can support continued development: