Skip to content

jatinkrmalik/pmptr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

51 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

pmptr

npm version npm downloads GitHub release Build Release Pipeline

Status: beta License: MIT Platform Node Electron

pmptr is a minimal virtual teleprompter that lives as a transparent, always-on-top, click-through overlay over whatever you do on your screen.

Features

  • πŸŽ›οΈ 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.
  • ⌨️ Keyboard shortcuts - play/pause, reset, speed control, and click-through toggle.

Quick Start

The fastest way to try pmptr is via npm:

npm install -g pmptr
pmptr

Requires Node.js 20 or later.

Then click Open floating prompter in the control window.

Download

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.

Run from source

git clone https://github.com/jatinkrmalik/pmptr.git
cd pmptr
npm install
npm start

Shortcuts (in the floating window)

Key Action
Space Play / pause
R Reset scroll to the top
↑ / ↓ Speed Β± 5 px/s
L Toggle click-through (lock / unlock)
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).

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                              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.

How the click-through works

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.

Tweaking transparency

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.

Project layout

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 pipeline.
β”œβ”€β”€ nightly.yml               Daily scheduled builds.
└── pr-build.yml              Comment-triggered PR artifact builds.

Development

# 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

Known limitations

  • Wayland compositors vary in their support for setIgnoreMouseEvents and setAlwaysOnTop (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.

Contributing

Contributions are welcome! See CONTRIBUTING.md for details.

License

MIT - see LICENSE for details.

About

A minimal ad-free virtual teleprompter that lives as a transparent, always-on-top, click-through overlay over whatever you do on your screen.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors