A keyboard-first conversation deck. Walk through a multi-step script while categorised response cards sit on the right rail, ready for the moment a prospect throws an objection. A call timer auto-starts on first interaction, per-step time is logged, and the analytics modal shows where the conversation actually got stuck. Built for sales, support, onboarding, training, or anyone who runs the same call twenty times a week — zero backend, full offline persistence via localStorage.
┌─────────────────────────────────────────────────────────────────────┐
│ TOOLBAR │
│ ▸ Step nav · Call timer · Edit mode · Undo / Redo │
│ ▸ Analytics · History · Import/Export · Theme · Reset │
│ ▸ Save indicator (you always know localStorage caught the last edit)│
├──────────────────────────────────────────────────────────────────────┤
│ MAIN PANELS │
│ ┌──────────────────────┬────────────────────────────────────────┐ │
│ │ SCRIPT (left) │ RESPONSE CARDS (right rail) │ │
│ │ ▸ Rich-text steps │ ▸ Categorised — trust, objection, │ │
│ │ ▸ Inline highlights │ value, pricing, competitor │ │
│ │ (key / value / │ ▸ Search + filter by category │ │
│ │ warn / cta) │ ▸ Click to expand · copy to clipboard │ │
│ │ ▸ Auto-saves per │ ▸ Edit / delete in edit mode │ │
│ │ keystroke │ │ │
│ │ │ CALL CHECKLIST │ │
│ │ │ ▸ Reset clears it (your deck stays) │ │
│ └──────────────────────┴────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────┘
Most "script" tools either chain you to a CRM (Salesforce, HubSpot, Outreach) or expect you to paste your script into a Google Doc and cmd-F for rebuttals mid-call. ScriptDeck fits the actual workflow: open a tab between dials, step through with →, copy a response card with one click when the prospect says "send me an email", hit 0 to start the timer, glance at the analytics modal at the end of the day to see where calls fell off.
Built for one operator running scripted conversations with no SaaS subscription — just localStorage, a PWA shell so it works offline, and a Markdown export so you can hand your deck to a colleague over Slack.
| 8-step script | Numbered tab nav, arrow-key navigation, per-step rich-text content. contenteditable body with bold / italic / highlights / lists — no external editor lib. |
| Categorised response cards | 11 starter cards across 5 categories (Trust · Objection · Value · Pricing · Competitor). Search across title + body, filter by category, click to expand, one-click copy. |
| Call timer | Auto-starts on first interaction. Per-step time logged. Reset saves the session to history before zeroing. |
| Session analytics | Call duration, steps reached, checklist completion, plus a horizontal bar chart of time-per-step so you can see where the conversation actually slows down. |
| Session history | Last 50 sessions stored in localStorage. Each entry records duration, step depth, and checklist completion. |
| Custom dialog system | Native <dialog> element with focus-trap + Esc-closes. Replaces every confirm() / alert() so the UX never breaks character. |
| Save indicator | Toolbar pill (Saved · 3s ago) tells you exactly when state last hit localStorage. |
| Undo / Redo | 50-step ring buffer in state.js. ⌘Z / ⌘⇧Z. Every meaningful change snapshots. |
| Markdown export | One-click export of the whole deck (steps + response cards + checklist) as a single .md file. Share with colleagues or print as a backup. |
| JSON import/export | Full workspace round-trip. Lock down your team's script as the canonical scriptdeck-export.json, distribute, import. |
| Offline-first PWA | manifest.webmanifest + service worker cache the shell. Add to home screen on iPad and run between calls with no wifi. |
| Dark mode | Light (clean blue) + dark (deep navy) themes. Preference persists across reloads. |
| Keyboard-first | 1–8 step jump · ← / → next/prev · 0 timer · E edit · ⌘Z / ⌘⇧Z undo/redo · ⌘S export · Esc close modal. |
ScriptDeck/
├── index.html single-page shell — toolbar + 2-panel grid
├── package.json vite only — zero runtime deps
├── vite.config.js relative-path build for sub-dir deploys
├── src/
│ ├── main.js app controller — render · events · timer
│ ├── state.js StateManager — localStorage · undo/redo
│ │ session history · JSON + Markdown export
│ ├── dialog.js custom <dialog> system (prompt / confirm / alert)
│ ├── data.js default 8-step script + 11 rebuttals + checklist
│ └── styles/
│ ├── variables.css tokens — colors, fonts, spacing, shadows
│ ├── layout.css page grid + modal layout
│ ├── toolbar.css action buttons, step nav, call timer
│ ├── script.css script card panels + highlights
│ ├── rebuttals.css right-rail cards + filter chips + analytics
│ ├── sidebar.css checklist
│ └── dialog.css custom <dialog> + save-indicator pill
├── public/
│ ├── manifest.webmanifest PWA install manifest
│ └── sw.js offline-first service worker
├── .github/workflows/ci.yml Vite build · Pages deploy
└── assets-readme/ brutalist banner SVGs (light + dark)
git clone https://github.com/hatimhtm/ScriptDeck.git
cd ScriptDeck
npm install
npm run dev # vite dev server → http://localhost:5173
npm run build # production bundle → dist/
npm run preview # serve dist/ → http://localhost:4173The build uses relative paths (base: './') so dist/ ships identically to GitHub Pages, S3, Vercel, Netlify, or any subdirectory deploy. Every push to main redeploys the live demo via the CI workflow.
- Replace the default deck: edit
src/data.js.defaultScript.steps[],defaultRebuttals[],defaultChecklist[],rebuttalCategories[]drive the first run; subsequent sessions load fromlocalStorage. - Add a category: append to
rebuttalCategoriesindata.js, then add matching CSS tokens (--c-{name}-bg/--c-{name}-text) insrc/styles/variables.css. - Brand it: edit
src/styles/variables.css. CSS custom properties drive every color, radius, shadow, and font stack. - Hand it to a teammate: hit Export to download
scriptdeck-export.json. They open the live demo and hit Import.
The 1.0 build shipped as a working app. v2 is a substantial polish + product pass:
- Live demo + GitHub Pages deploy — every push to
mainredeploys hatimhtm.github.io/ScriptDeck automatically. - PWA + service worker —
manifest.webmanifest+ an offline-first cache layer. Installable on iPad, works with no wifi. - Custom
<dialog>modal system — replaces every nativeconfirm()/alert()with a themed, focus-trapped dialog that matches the rest of the app. - Save-status indicator — toolbar pill (
Saved · 3s ago) with aonSavelistener + 15s refresh ticker, so you never wonder if the last edit hitlocalStorage. - Markdown export alongside JSON — one click produces a share-ready
.mdof the whole deck (steps + cards + checklist). - Brutalist house-style README + light/dark hero banners, OG + Twitter cards,
theme-colormeta, inline SVG favicon. - CI workflow — Vite build + dist sanity check + Pages deploy, all gated on
main.
MIT. Fork it, swap the script, re-skin it for any use case (call centres, demo flows, customer-onboarding tours, training pipelines). Just keep the copyright line.
/// OPEN FOR NEW WORK /// CONTRACT & FREELANCE /// REMOTE WORLDWIDE ///