A minimal, mobile-first teleprompter app that runs entirely in the browser — no server, no account, no install required. Speeches are stored in JSONBin, a free cloud JSON storage service, so they sync across any device you connect.
Built as a personal tool and shared as an example of what you can build quickly with plain HTML, CSS, and vanilla JS.
- Store and manage speeches — create, edit, and delete named speeches from a clean list view
- Prompter view — displays one line at a time in large, readable text
- Section navigation — mark sections with
# Section Nameto jump between them using arrows - Scrubber — drag or click a vertical track to jump anywhere in the speech
- Timer — starts automatically when you advance past the first line
- Sync across devices — all data lives in your personal JSONBin, so any device with your credentials sees the same speeches
- Offline fallback — the last successful load is cached in localStorage so the app still works without a connection
- PIN lock — a simple numeric PIN prevents casual access if you leave the app open (default:
0000)
| Action | How |
|---|---|
| Next line | Tap Next →, swipe up, or scroll down |
| Previous line | Tap ← Prev, swipe down, or scroll up |
| Jump to section | Tap the ‹ › arrows in the section indicator |
| Seek anywhere | Drag or tap the scrubber (right edge of prompter) |
| Edit speech | Tap the pencil icon (top right) |
One line per entry. Rules:
- Blank lines are skipped (pauses in the flow)
- Lines starting with
#mark a new section — e.g.# Introduction - Everything else is displayed as a line to read
The app needs two things: a JSONBin Bin ID and a Master Key. This is all free and takes about 2 minutes.
Go to jsonbin.io and sign up for a free account.
- In the left sidebar, click + New Bin
- Paste this as the initial content:
{"speeches":[]} - Give it a name (e.g.
Teleprompter) and click Create - The URL will change to something like
/b/abc123...— copy the ID after/b/. That's your Bin ID.
- Click your profile icon (top right) → API Keys
- Under Master Key, click Show Key and copy it — it starts with
$2a$10$...
- Open the app in your browser (see Running locally below)
- Enter your PIN (default:
0000) - On the Setup screen, paste in your Bin ID and Master Key and tap Connect
Your credentials are saved to your browser's localStorage — you only need to do this once per device. To use the same speeches on another device, just enter the same Bin ID and Master Key on that device too.
The app is plain static files — no build step, no dependencies.
The only requirement is serving it over HTTP (not opening index.html directly as a file), because ES modules require a server.
Quickest way with Python:
cd teleprompter
python3 -m http.server 8080Then open http://localhost:8080.
Or with Node:
npx serve .Or deploy to any static host — GitHub Pages, Netlify, Vercel, Cloudflare Pages — just point it at the repo root.
The PIN defaults to 0000. To change it, open your browser's DevTools console and run:
localStorage.setItem('tp_pin', 'YOUR_NEW_PIN');Then reload the page. The new PIN will be required on your next visit.
teleprompter/
├── index.html # Single-page app shell, all views defined here
├── css/
│ └── styles.css # All styles
└── js/
├── app.js # Main controller — state, views, event handlers
├── speech.js # Pure navigation helpers (no DOM) — line/section traversal
├── storage.js # JSONBin API calls + localStorage helpers
└── timer.js # Session timer module
- No framework, no bundler — ES modules loaded directly by the browser
- Single HTML file — all views are
<div class="view">blocks; only one is.activeat a time - Cloud storage via JSONBin — all writes go to
PUT /v3/b/:binId, reads fromGET /v3/b/:binId/latest - LocalStorage — used for offline cache (
tp_cache), credentials (tp_creds), and PIN (tp_pin)
- Fork or clone this repo
- Go to Settings → Pages
- Set source to Deploy from a branch, select
main, folder/(root) - Your app will be live at
https://<your-username>.github.io/<repo-name>/
This is a personal tool, but if you have questions or want to extend it, the agent.md file contains a prompt you can paste into Claude (or any AI assistant) to get context-aware help with the codebase.