spleak2me
Reshape any input into a top-down guided-reading web page. The input can be anything; the value is the output format:
- Left: the macro theses (L1) — the big ideas someone should walk away with.
- Click a thesis → right panel: its cards (L2) with the actual, scannable content; optional inline
L3
detailfor code/JSON/tables. - 🎧 Audio (optional, on by default): one short, informal clip per card that explains the idea — an aid, never a reading of the text.
- Progress: a "got it?" toggle per card, a global bar, per-thesis mini-bars — all in
localStorage.
Responsive: two-pane on desktop, full-screen drill-down on mobile. Works opened straight from disk
(file://) — no server or network needed.
Files
A finished site is a folder:
site/
├── index.html # fixed shell (from template)
├── styles.css # fixed shell
├── app.js # fixed shell (renders window.DOC, uses window.AUDIO)
├── audio-manifest.js # window.AUDIO = {} (rewritten by gen-audio.js)
├── content.js # ← YOU author this: window.DOC = {...}
└── audio/ # ← generated clips (only if audio enabled)
content.js is the only creative artifact. The shell is generic and never edited per input.
Workflow
- Get the content. If the user pasted it, use it. If it's a link/file, fetch/read it first. Read enough to genuinely restructure it — don't skim.
- Scaffold the shell into an output dir (default: a sensible slug under the cwd, or where the user
says):
scripts/scaffold.sh <output-dir> - Author
content.js. This is the work. Reorganize top-down intowindow.DOC(theses → cards → optional detail), write rich scannablebody/overviewHTML, and — unless audio is off — a spoken-readynarrationper node. Read references/authoring.md for the schema, the allowed HTML, and the authoring principles (top-down, text-first, breathe, emojis with intent, faithful). Language defaults to the input's language; setmeta.langand, for non-English,meta.uilabels. - Generate audio (default on; skip only if the user opted out):
It auto-detects a TTS backend (node scripts/gen-audio.js <output-dir>edge-tts, else macOSsay), picks a voice frommeta.lang, runs clips in parallel, and rewritesaudio-manifest.js. If no backend exists it just skips audio and the site stays text-only (players don't render). Flags:--concurrency N,--backend edge|say,--voice <raw>,--save-voice. User prefs (default backend/voice) come from~/.spleak2me.json— see Audio notes. - Verify. Open
<output-dir>/index.html(or serve it) and sanity-check: theses render, a card drills in, a player plays, "got it?" ticks the progress bar. Fixcontent.jsand re-run step 4 if audio text needed changes. - Deliver the path. The deliverable is the HTML on disk. Do not publish anywhere unless the user
asks — if they do, that's a separate step (e.g. the
here-nowskill / their own hosting).
Audio notes
Backends are tried in order:
EDGE_TTS_BIN/edge-ttson PATH → macOSsay.sayoutput is converted to mp3 (ffmpeg) or m4a (afconvert) when available, else left as aiff.Keep each
narrationunder ~90s and spoken-ready (spell outV0,FAT,JSON,A/B…); the generator only strips markdown/URLs, it does not expand abbreviations.Audio is driven entirely by
audio-manifest.js: a card shows a player only if its clip was generated. To ship text-only, just don't run step 4.User prefs —
~/.spleak2me.json: an optional config in the home dir holding a preferred default backend and per-backend/per-language voices. Missing or malformed file = ignored (warns to stderr, never crashes), so the no-config path is unchanged. Schema:{ "backend": "say", "voices": { "say": { "en": "Zoe (Premium)" }, "edge": {} } }- Voice precedence (highest first):
--voiceflag →voices[backend][lang]from config → built-in default map. - Backend precedence (highest first):
--backendflag → configbackend(only if that backend is actually available) → auto-detect (edgeif present, elsesay). - The startup log line notes
config: loaded/config: noneand appends(from ~/.spleak2me.json)after the voice when it came from config.
- Voice precedence (highest first):
Voice preference is Claude-managed — the user never touches flags or the config file. The user just talks to you; you handle the file on their behalf.
- First time you generate audio for a user (no
~/.spleak2me.json, or it has no voice for this backend/lang): after delivering, tell them plainly which voice you picked and that they can change it just by asking — e.g. "I used the Zoe (Premium) voice — if you'd rather a different one, just tell me and I'll switch it in your config." Keep it to one line; don't lecture about the mechanism. - When the user asks for a different voice: resolve the exact backend voice name (for
say,say -v '?'lists them), then persist it and regenerate. Persist via the internal--save-voiceflag (node scripts/gen-audio.js <site> --voice "<name>" --save-voice) or by editing~/.spleak2me.jsondirectly — either is fine. Do not ask the user to run flags or hand-edit the file themselves. - Once a voice is saved, stay quiet about it on later runs — it's their default now; only mention it again if they ask or you couldn't honor it.
- First time you generate audio for a user (no
Scope reminders
- The format is the product. Don't tailor the shell to one kind of input.
- Faithful reorganization, not invention. Preserve exact code/data in
detail. - Output = files on disk. Publishing is opt-in, per user request, and out of this skill.