pmptr is a minimal virtual teleprompter that lives as a transparent, always-on-top, click-through overlay over whatever you do on your screen.
- 🎛️ Control window - paste your script, tune speed, size, colors, opacity, mirror, window dimensions, and more.
- 🪟 Floating prompter window - transparent, frameless, always on top, with a true OS-level click-through "lock" so you can keep working with your mouse on whatever is underneath.
- 💾 Settings persistence - settings are saved to disk in your Electron user-data folder.
- ⚡ Live updates - edits in the control window apply to the prompter instantly.
- 🎙️ Voice follow (opt-in) - the prompter scrolls while you speak and pauses when you stop, so the script follows your natural pace instead of forcing a monotonous rhythm. All audio processing happens locally; nothing is recorded or sent anywhere.
- ⌨️ Keyboard shortcuts - play/pause, reset, speed control, voice follow, and click-through toggle.
The fastest way to try pmptr is via npm:
npm install -g pmptr
pmptrRequires Node.js 20 or later.
Then click Open floating prompter in the control window.
Beta - pmptr is in active beta. Expect occasional bugs and breaking changes. Please report issues you encounter.
Prefer a native installer? Grab the latest build from the Releases page.
| Platform | Format |
|---|---|
| macOS | .dmg |
| Windows | .exe (NSIS installer) |
| Linux | .AppImage or .deb |
Not code-signed - your OS may warn on first launch. That's expected during beta.
git clone https://github.com/jatinkrmalik/pmptr.git
cd pmptr
npm install
npm start| Key | Action |
|---|---|
Space |
Play / pause |
R |
Reset scroll to the top |
↑ / ↓ |
Speed ± 5 px/s |
L |
Toggle click-through (lock / unlock) |
V |
Toggle voice follow |
Esc |
Close the prompter |
You can also use the small HUD in the bottom-right of the floating window (mouse over it to reveal it).
┌─────────────────────────────────────────────────────────────────────────────┐
│ pmptr Architecture │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────┐
│ Main process │
│ src/main/main.js │ Creates windows, owns
│ src/main/preload.js │ IPC, click-through,
│ │ always-on-top, settings
└──────────┬──────────┘
│
┌──────────────────────────┼──────────────────────────┐
│ spawns │ spawns │ read/write
▼ ▼ ▼
┌─────────────────────┐ ┌─────────────────────┐ ┌──────────────────┐
│ Control window │ │ Prompter window │ │ settings.json │
│ src/control/ │ │ src/prompter/ │ │ (Electron user │
│ control.html │ │ prompter.html │ │ data directory)│
│ control.js │ │ prompter.js │ └──────────────────┘
└─────────────────────┘ │ prompter-preload.js │
└─────────────────────┘
Data flow
─────────
Control window Main process Prompter window
│ │ │
│── IPC: setting changed ─►│ │
│ │── IPC: settings ─────────►│
│ │ │
│◄──────── IPC: state ─────│◄──────── IPC: state ──────│
│ │ │
- The **main process** spawns both windows and persists settings to `settings.json`.
- The **control window** sends new settings to the main process over IPC.
- The **prompter window** receives settings from the main process and reports its state back.
- Live edits in the control window are reflected in the prompter instantly.
The prompter is a separate BrowserWindow with transparent: true, frame: false,
and alwaysOnTop: true. When you toggle "click-through" (the lock), the main
process calls win.setIgnoreMouseEvents(true, { forward: true }) - clicks
and wheel events fall straight through to whatever app is behind, while the
window stays visible and keeps scrolling. The HUD itself is hidden while
locked, so nothing on the prompter intercepts your pointer.
Voice follow is off by default; enable it with the toggle in the control window's Reading tab, the mic button in the prompter HUD, or the V key. While enabled, the prompter listens to your microphone through the Web Audio API and runs a small voice-activity detector (signal level vs. an adaptive noise floor). While you speak, the text scrolls at your configured speed; when you pause, the scroll eases to a stop after a short grace period (so natural gaps between words don't stall it) and resumes as soon as you speak again.
- Mic sensitivity controls how loud you must be relative to background noise before scrolling starts. Raise it if the prompter misses quiet speech; lower it in noisy rooms.
- Everything runs locally in the prompter window - no audio is recorded, stored, or sent anywhere.
- If the microphone is unavailable, the prompter falls back to constant scrolling and the control window shows a mic error.
The window background is a CSS rgba() color set on .frame. Move the
Background opacity slider to 0 for fully see-through, or use
Background dim to keep it readable on bright content underneath. The text
itself stays opaque.
src/
├── main/
│ ├── main.js Electron main: creates both windows, handles IPC,
│ │ click-through, always-on-top, position presets.
│ └── preload.js contextBridge for the control window.
├── control/
│ ├── control.html The control panel UI.
│ ├── control.js Control panel logic.
│ └── control.css Control panel styles.
└── prompter/
├── prompter.html The floating teleprompter overlay.
├── prompter.js Prompter logic (scroll, shortcuts, HUD).
├── prompter.css Prompter styles.
└── prompter-preload.js contextBridge for the prompter window.
assets/
└── icon.svg Application icon.
.github/workflows/
── build.yml CI build for Linux, macOS, Windows.
├── release.yml Tag-triggered release: installers, GitHub Release, npm publish.
├── nightly.yml Daily scheduled builds.
└── pr-build.yml Comment-triggered PR artifact builds.
# Install dependencies
npm install
# Run the app
npm start
# Lint code
npm run lint
# Run tests (currently just lint)
npm test
# Build for distribution
npm run build- Wayland compositors vary in their support for
setIgnoreMouseEventsandsetAlwaysOnTop(the underlying APIs Electron uses). X11 (Xorg) and recent KDE / GNOME Wayland work fine; some lighter Wayland compositors may ignore these hints. If click-through or always-on-top does not work, the prompter is still useful - just drag it to a corner. - On macOS you may need to grant Accessibility / Screen Recording permissions to the app for click-through to behave predictably across all apps.
- The app is not code-signed. Your OS may warn on first launch.
Contributions are welcome! See CONTRIBUTING.md for details.
MIT - see LICENSE for details.