This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle
What I Built
An indie author with fifteen novels has fifteen audiobooks they will probably never make. A human narrator costs roughly $200 to $400 per finished hour, so a ten-hour novel is a few thousand dollars, before anyone knows whether the audiobook will sell. Multiply by a backlist and the answer is "not this year", every year.
Text-to-speech solves the cost. It does not solve the other half of making an audiobook: proof-listening. Somebody has to hear every minute against the manuscript and catch the skipped words, the misread words and the lines that came out garbled. With a human narrator, that is a paid job of its own. With a voice model, it is ten hours of your life spent waiting for the six lines it got wrong.
Backlist does both halves on your own laptop:
- Kokoro, an open-weight voice model, narrates your chapter in the browser.
- Whisper, an open-weight speech recogniser, listens to every line it produced and checks it against your manuscript.
- You only listen to the lines it flags. If one sounds right, say so. If not, fix the text the narrator reads (or add a name to your pronunciation guide) and re-narrate just that line. Then download a chapter file mastered to audiobook spec.
That flag is real. Doyle's newspaper paragraph runs through "the Vehmgericht, aqua tofana, Carbonari, the Marchioness de Brinvilliers", and the listener heard "the Vame direct, Aquatophana, Carbonari, the Martianest of Brinvaliers". Fourteen other lines of the passage passed. Instead of 2 minutes 16 seconds of listening, the author has 19 seconds to check.
Who pays for this? Self-published authors with a backlist, which is a lot of people: the indie side hustle that already pays for covers, editing and ads. What they would pay for is not the voice (open voices are free) but the workflow that makes a voice usable: the proof-listening, the pronunciation guide, the mastering. Because everything runs on the author's machine, each extra book costs me nothing to serve, so it can be a one-off price per book, or a few dollars a month for a whole backlist, and still be a business.
An honest note on where the files can go: at the time of writing, Audible's ACX requires human narration, while Google Play Books has a "Synthesized voice" narrator type in its Partner Center, Kobo Writing Life accepts digitally narrated audiobooks if you say so, and selling direct (your own site, Bookfunnel, a Kickstarter reward tier) has no such rule. Backlist is for those.
Demo
π vanshajpoonia.github.io/backlist
No sign-up. Pick a sample and press Narrate this chapter:
- A Princess of Mars, chapter XI, which is full of names nobody has heard of: Dejah Thoris, Tars Tarkas, Sarkoja, Lorquas Ptomel. The pronunciation guide comes filled in, the way an author would hand one to a human narrator.
- A Study in Scarlet, chapter I: "Dr.", 1878, Netley, the Fifth Northumberland Fusiliers.
The first run downloads both models once (about 400 MB if your browser can use the graphics card, 170 MB if not). On my laptop, the Mars chapter (3 minutes 21 seconds of audio) is narrated, proof-listened and mastered in 44 seconds. Your manuscript never leaves the tab.
Code
VanshajPoonia
/
backlist
Audiobooks of your backlist, made on your own laptop: Kokoro narrates, Whisper proof-listens every line, both in the browser.
Backlist ποΈ
Audiobooks of the books you have already written, made on your own laptop.
Paste a chapter. Kokoro, an open-weight voice model, narrates it in your browser. Then Whisper, an open-weight speech recogniser, listens to every line and checks it against the manuscript. You re-check the handful of lines it flags instead of the whole chapter (accept them by ear, or fix the text and re-narrate just that line), and download a file mastered to audiobook spec.
Live: https://vanshajpoonia.github.io/backlist/
Why a second model
A human-narrated audiobook costs an indie author $200 to $400 per finished hour, so a ten-hour novel is $2,000 to $4,000. An author with fifteen books in their backlist does not have that, which is why most backlists are never narrated. Text-to-speech fixes the cost. It does not fix the other half of audiobook production: proof-listening, where someone hears every minute against theβ¦
Static files, no build step, no backend, no API keys. MIT.
How I Built It
Two open models, two workers, one runtime
Both models run on transformers.js, each in its own Web Worker. The narrator works ahead and the listener follows one line behind, so proof-listening costs almost no extra time and the page never freezes.
- Narrator: Kokoro-82M (Apache-2.0). On the GPU through WebGPU when there is one, 8-bit on the CPU otherwise. Kokoro's official JavaScript package is built on an older transformers.js, and loading both versions would mean two copies of the ONNX runtime in one tab. So I ported its text handling (about a hundred lines: normalisation, eSpeak NG phonemes, voice styles) onto the same runtime as the listener. That also means the browser and the test suite run identical code.
- Listener: Whisper base.en (MIT), 8-bit, on the CPU.
What the listener caught in the narrator
I built the listener to catch narration errors, and the first thing it did was catch Kokoro's:
- Roman numerals are read as "Roman". Chapter IV came back from the listener as "Chapter Roman 4". Henry VIII was "Henry Roman 8". A great many chapter headings look exactly like that. Backlist now reads book structure as cardinals ("Chapter Four") and monarchs as ordinals ("Henry the Eighth").
- Long sentences are cut off without a word. Kokoro reads at most 510 phoneme tokens at a time and silently drops the rest. I counted: across A Princess of Mars, A Study in Scarlet and A Christmas Carol, 21 sentences are over that limit. The longest, in A Princess of Mars, is 168 words, which is 1,317 tokens: more than half of it would simply never be said, and nothing would tell you. Backlist splits sentences over 50 words at their own semicolons and commas, and re-splits any line that still comes close.
I measured the narration rules too: of 31 test lines they change, the listener flagged 6 as written and 1 with the rules. Five of the six were chapter headings ("Chapter Romans 3, my Advent on Mark" is my favourite), all fixed. The one left is "bade adieu to their landlady upon Tuesday, the 4th inst.", which comes back as "bated due" either way: archaic and French words are exactly what the pronunciation guide is for. My other rules (Saint or Street, military titles) never changed a verdict in these books, so I am not claiming they fixed anything.
Teaching the listener what not to worry about
The obvious checker compares what Whisper heard with the book, word by word. On clean, correct narration of A Christmas Carol, that flagged 40% of the lines. Whisper is a model with habits of its own, and almost none of the differences were narration errors. A few I collected along the way:
- Dickens writes "door-nail"; Whisper writes "doornail". "Ironmongery" came back as "iron mongering".
- "In 1878" comes back as digits, "Mister" comes back as "Mr.", "colour" as "color".
- "There I was struck" came back as "Their eye was struck". Correct narration, creative spelling.
- And names. Whisper has never heard of Dejah Thoris, and writes "Digiothorus". "Tars Tarkas" was "Tar's Tar Cuss".
So the checker (src/compare.js) aligns the two word sequences, compares words by how they sound rather than how they are spelled, turns numbers into words on both sides, and forgives compounds, homophones and abbreviations. For names, it only checks that something name-shaped was said in the right place. Whether Tars Tarkas sounds right is a question for the author's pronunciation guide and the author's ears, and the app says so.
What it never forgives: words skipped, words added or said twice, a word swapped for a different one, a line cut short.
Measuring it with planted faults
A proof-listener has two jobs: catch real mistakes, and stay quiet on good audio. One that cries wolf sends you back to listening to everything. To measure both, npm test takes real lines from the books and renders each one five times through the real narrator: once as written, and four times with a fault planted in the text the narrator reads (three words skipped, three words said twice, one word swapped for an unrelated one, the last 40% never said). Every rendering is heard back by the real listener and checked against the book. Lines rotate through four voices, two American and two British.
I tuned the checker's rules on 30 lines of A Christmas Carol, then froze them and tested on lines from A Study in Scarlet and A Princess of Mars that it had never seen:
| Checker | False alarms on clean audio | Skipped | Repeated | Swapped | Cut off | All faults |
|---|---|---|---|---|---|---|
| Exact match after normalising | 25/80 (31%) | 74/74 | 68/74 | 74/74 | 74/74 | 98% |
| Word error rate β€ 15% | 1/80 (1%) | 27/74 | 24/74 | 5/74 | 74/74 | 44% |
| Backlist, rules frozen before the test | 1/80 (1%) | 74/74 | 67/74 | 72/74 | 74/74 | 97% |
| Backlist after fixing what the test exposed | 0/80 | 74/74 | 67/74 | 74/74 | 74/74 | 98% |
The exact-match checker catches nearly everything and cries wolf on almost a third of perfectly good lines. The usual word-error-rate threshold is quiet but misses more than half the faults, including 69 of 74 swapped words, because one wrong word in a long sentence is under 15%. Backlist's checker is as quiet as the threshold and nearly as thorough as exact match.
The test also found three gaps in my rules. A title-case table of contents had made "Through" count as a name (so a swap there was forgiven), "Decameron" came back as "de Cameron", and "corps" came back as its homophone "core". I fixed all three; the last row is after those fixes, so the frozen row above it is the honest held-out number.
Every fault it still misses is a repetition. Kokoro said "after he had after he had listened", and Whisper wrote it down once. Whisper was trained on tidied-up transcripts, and it tidies. That is a limit of the listener, not something a rule can fix, so the README says so plainly: a stutter can get through.
Mastering, and making it fast
The chapter file is built in the browser (src/audio.js): Kokoro's own silences trimmed, consistent pauses added (sentence, paragraph, scene break), resampled to 44.1 kHz with a windowed-sinc filter, the loudness set to -20 dB RMS and the peaks held under -3 dB with a limiter. That is the spec most audiobook distributors publish, and the app checks the file against it.
The listener was the bottleneck. It runs on the CPU, and single-threaded WebAssembly is slow. Cross-origin isolation lets ONNX Runtime use several threads, but it needs two HTTP headers, and GitHub Pages cannot send headers. So the service worker adds them to every file it serves, and the page reloads itself once on the first visit. On my laptop that took the Mars chapter (3 minutes 21 seconds of audio) from 1 minute 34 seconds to 44 seconds, 4.5x real time. A browser without WebGPU still gets there, with both models on the CPU, at 0.7x real time: a chapter is something to start before making a cup of tea.
Why Does Open Innovation Matter?
Because the business is the backlist. One audiobook is a few hundred thousand characters, rendered more than once while you fix things. A backlist is fifteen of those. With a voice model you rent by the character, every re-render is a line item, and the economics push you towards narrating only the books you are already sure will sell. With open weights on the author's own machine, the fifteenth book costs the same as the first: nothing. That is what makes a cheap tool for indie authors possible at all.
Because a manuscript is the most private thing an author has. Unpublished and backlist books are the author's income. Plenty of authors are, reasonably, unwilling to upload them to a service whose terms they cannot control. Here the chapter goes into a model in the tab, and audio comes out. Nothing is uploaded.
Because I could take the narrator apart. Every finding in this post (the 510-token cliff, the "Roman four", the stutters Whisper tidies away) came from running the same open weights in Node hundreds of times, reading the code that feeds them, and porting it. The test suite alone renders and listens to about 600 clips, and costs nothing to re-run. With a closed voice API I could not have found the truncation, only suffered it.
Because the safety net is open too. The proof-listener is itself an open model I can run locally and measure. That is why I can tell you how often it is wrong, on books it was not tuned on, instead of asking you to trust it.
My Agent Session
I built this with Claude Code as a pair programmer. I didn't save the session to DevRelay, so here is the next best thing: every number in this post can be re-run.
git clone https://github.com/VanshajPoonia/backlist
cd backlist && npm install && npm test
That downloads the three public-domain books from Project Gutenberg, renders every test line and its planted faults through Kokoro, listens to all of them with Whisper, and prints the table above along with every false alarm and every missed fault. SET=tuning npm test reproduces the tuning set; LISTENER=whisper-tiny.en npm test swaps in the smaller listener.
My First User
Not yet, and I would rather leave this empty than invent one. If you write, paste in a chapter of your own (it never leaves your browser) and tell me in the comments what it flagged, how your character names came out, and whether you would pay for it. I will add the first answers here.



Top comments (0)