After the script: Hinglish, voice and video

Turning the English script into Hinglish, building TTS prompts, word timing and the video plan.

TL;DR

Once the English script is finished, the next steps are derived from it and never the other way round. (1) Hinglish: a paragraph-for-paragraph Hinglish version, checked for facts and structure by hinglish-parity.js. (2) Voice: per-beat prompts for Google Gemini text-to-speech built by tts-gemini.js; the user generated 14 beat WAVs. (3) Timing: a Whisper-plus-alignment pipeline that gives word times; run so far on beats B1 and B2 only. (4) Video: a written plan (music, sound effects, four visual categories); nothing is rendered.

  • Proven: the parity check passes; the TTS prompts contain exactly the script's words plus tags; the alignment anchors 89% of words on B1 and B2.
  • Not proven: that the Hinglish sounds natural (no native read-aloud pass), that Gemini reads Roman-script Hinglish well, how the audio sounds (Claude cannot listen), and anything in the video plan.
  • Measured: the 14 Hinglish beats total 20.28 minutes, about 174 words per minute against the 150 the script's timecodes assume. The Hinglish hook is 108.5 seconds, inside the 110-second cap.

1. Hinglish from a finished English script

From references/hinglish-adaptation.md. Do this after the English script reaches BAR MET. The English is the source of truth for facts, structure and order. The lint and the chain are English-anchored (quotes are English substrings, voice rules read English words), so they cannot judge the Hinglish. What can be checked deterministically is that the Hinglish kept the facts and the structure.

Steps

  1. Write the Hinglish from the English, beat by beat, paragraph by paragraph: same beats and headings, same number of **VO:** paragraphs in the same order, same questions, same turns, same graphics lines (kept in English). Roman script, Hindi grammar, English words where Indian business speakers use them.
  2. Run the parity check:
    node .claude/skills/video-script-production/scripts/hinglish-parity.js --english SCRIPT-vN.md --hinglish SCRIPT-vN-hinglish.md
    It must say PARITY OK: same beats and titles, same paragraph count, the same digits in each paragraph, the same number of question marks, every direct quote of four words or more verbatim, every capitalised name present, identical graphics lines. It reports the length ratio per beat. Moser Baer v7: 3,029 English words to 3,519 Hinglish (16% longer; the hook 18% longer).
  3. Retime the headings with retime.js (150 wpm is an estimate).
  4. Build the TTS prompts (section 2).
  5. Record in the hand-off: the Hinglish has had no native read-aloud pass and no reader pass, its spoken length is unmeasured, and the lint does not apply to it.

Rules for the Hinglish itself (from the user's notes on the v6 Hinglish)

  1. Use the word people say. Prefer a common English word when it is shorter and clearer: feeling (not khinchaav), busy, pivot, strategy, scale, healthy, signs, capital-intensive. Keep Hindi where it is the everyday word (tapri, kaudiyon ke bhaav, hadap liya).
  2. Idiom, not translation. "ke just piche" for "just behind"; "haffti hui company" for a company panting on a treadmill; "dang reh jaate" for a double take. Replace any literal carry-over nobody would say.
  3. One idea per sentence, the verb near its subject.
  4. Do not gloss what the audience knows (crore, CBI).
  5. Tag every person where they arrive and where they return ("Ratul Puri, Deepak ke bete aur company ke director", then "Ratul, Deepak ke bete" at each return).
  6. Name a strategy once and call it back (scale; pivot, defined once in the hook, then counted first, second, third, fourth).
  7. Say the turn: lekin, par, fir bhi, lekin phir at every BUT, but not three lekin in a row (use par).
  8. Put the intensifier where someone pays: poore 17 saal, apni pay ka hissa tak.
  9. The narrator has no stated gender. Use mujhe, mere liye, main only with verbs that carry no gender (dekha, nahi mila); avoid karunga/karungi, sakta/sakti.
  10. Direct quotes stay in English; indirect speech stays indirect.
  11. Numbers. Digits stay as digits (parity needs them). Numbers spelled out in the English are spelled out in the Hinglish (forty-two becomes bayalis). The TTS builder spells out currency and acronyms by rule.
  12. Facts do not change in translation. If a note asks for a claim the sources do not support, write it in neither language and say so in the translation notes.

2. Gemini text-to-speech

Research and reasoning: research/the-fall-of-moser-baer/script/tts/TTS-NOTES-gemini.md. The user asked to try gemini-3.1-flash-tts.

The model situation

What is documented, what is third-party, what is unknown

QuestionAnswerGrade
Tag syntax (3.1)Square brackets; English tags can be combined with text in other languages.Documented (Google Cloud blog)
Where a tag goesExactly where the transition should occur; never two tags next to each other.Documented
Documented 3.1 tagsEmotion: determination, enthusiasm, adoration, interest, awe, admiration, nervousness, frustration, excitement, curiosity, hope, annoyance, amusement, aggression, tension, agitation, confusion, anger. Sentiment: positive, neutral, negative. Delivery: whispers, laughs. Pacing: slow, fast, short pause, long pause. Seen in Google's examples: seriousness, cautious, gasp, panic, anxiety, relief, alarm, happy.Documented. Only these were used.
Invented tagsInvented emotion adjectives gave flatter delivery than the documented set.Third-party (LiveKit), one team
PausesUse [short pause] and [long pause].Documented
Ellipses and dashes"Commas, dashes (--) and ellipses (...) for natural conversational hesitation"; about one or two ellipses per utterance.Documented for 3.8; third-party for 3.1
EmphasisCapitalise specific words.Documented (3.8 guide)
Line breaks and blank linesNot documented anywhere readable.Unknown
Direction block above the transcript (3.1)Profile, scene, performance notes, then a #### TRANSCRIPT header. Notes can be read aloud if vague; avoid apostrophes and flatness words ("quiet", "flat").Third-party (LiveKit)
3.8 directionDon't. Text is verbatim; long profiles are linked to voice drift.Documented
Digits, currency, acronymsGoogle's own example spells numbers out and spaces letters.Documented example; the generalisation is inferred
Roman against Devanagari for Hindi wordsNothing found.Unknown

The tool and its rules

node .claude/skills/video-script-production/scripts/tts-gemini.js --script SCRIPT-vN-hinglish.md --spec tts/spec-vN-hinglish.json --out tts --name vN-hinglish

It writes TTS-vN-hinglish-gemini-3.1.md (a direction block above the transcript, one fenced block per beat) and TTS-vN-hinglish-gemini-3.8.md (a style line separate from a verbatim transcript, only pause tags). The same works for the English script with spec-vN-english.json. The spec holds, per beat, a direction sentence, a style line, the tags ([snippet, tag]: the tag goes immediately before the first occurrence of the snippet after the previous tag) and the stress pairs (one word in capitals).

The tests that settle what the docs cannot

#QuestionAB
T1Roman or Devanagari for Hindi wordsthe Roman text as writtenHindi words in Devanagari, English words left in Roman
T2Do line breaks change anythingparagraphs separated by a blank linethe same text on one line
T3Ellipsis, tag or comma for a pause[short pause]... or , in the same spot
T4Numbers, rupaye, dates, acronymsB5 and B12 as writtenlisten for "79 crore rupaye", "21 June 2012", "C B I"
T5Do tags get spoken aloudany tagged beatlisten for "pause" or "slow"
T6Voice drift across beatsB0 against B7 against B13listen for changes in pitch or pace
T73.1 against 3.8TTS-...-gemini-3.1.mdTTS-...-gemini-3.8.md
What Claude can and cannot judge here

Claude can measure a WAV's length and the length of each silence in it. It cannot judge accent, naturalness or whether a pause feels right. That is the user's ear. The user generates the audio and saves it under script/audio/beats/ (English v6) or script/audio/gemini-v7-hinglish/beats/ (Hinglish v7), and the files can then be measured.

Files that exist

Pace

Durations read from the WAV headers on 2026-10-27:

TrackBeatsTotalScript wordsWords per minuteHook (B0)
English v6 (audio/beats)141,156.1 s (19.27 min)2,940about 153100.0 s
Hinglish v7 (audio/gemini-v7-hinglish/beats)141,217.0 s (20.28 min)3,519about 174108.5 s

The Hinglish hook, 108.5 seconds, sits just inside the 110-second cap (the English v6 hook was 110 s at 150 wpm; the v7 English hook is 107 s). The per-beat Hinglish lengths run from 50.1 s (B2) to 110.1 s (B12). The Hinglish audio is almost the same length as the English headings (20:12) although it has 16% more words, so it is spoken about 16% faster than the 150 words per minute the headings assume (173.5 against 150). The plan flags this as a decision: at this pace the viewer has less room per number, and the pace is set by the TTS prompt, not by the timing code. The plan's own pace figure is an unfilled placeholder (PACE_WPM); the value above is derived (words divided by minutes) and is not in the plan.

3. Word timing

Plan and reasoning: research/the-fall-of-moser-baer/video/PRODUCTION-PLAN.md. The user wants a deterministic alignment, not a language model. A reference tool used an LLM for alignment; it was not copied. Whisper's text is not trusted; only its times are.

StepFileWhat it does
Reference wordsvideo/tools/beat_text.py to video/timing/reference-words.jsonReads the TTS prompt that was sent to Gemini, strips the tags, and keeps each tag, paragraph end, stress capital, question and number as a flag on its word. 3,555 words, 61 tags, 12 stress words. It parses the 3.1 file; the 3.8 layout is not parsed.
Whispervideo/tools/whisper_words.py to video/timing/raw/B#.whisper.jsonopenai/whisper-base from the local Hugging Face cache, Hindi decoding, word times from the transformers pipeline, 30 s chunks.
Alignmentvideo/tools/align_words.py to B#.json, words.json, align-report.mdMatches each script word to a Whisper word by consonant skeleton (dynamic programming, longest-common-subsequence Dice at least 0.6), interpolates the rest, snaps word ends to the quietest 10 ms within 60 ms, and reports silences. Reads Urdu and Devanagari script.

Whisper settings that work, tested on B2

TrialResultDecision
language=enTranslates the meaning into English; words no longer match.Rejected
language=hi, a Roman prompt copied from the scriptRoman text, but the prompt is echoed and the first 43 of 135 words get zero-length times.Rejected
language=hi, generic Roman Hinglish promptNo echo, but 43 zero-length words in the opening chunk.Rejected for timing
language=hi, no promptMixed Devanagari and Urdu script, clean timings (0 zero-length).Used. The aligner reads both scripts.

Anchoring on B2 went 32% (first version) to 59% (LCS) to 86% (Urdu letters mapped). Final run: B1 285 of 315 words anchored (90.5%), B2 119 of 139 (85.6%); overall 404 of 454 (89.0%), 50 interpolated; 151.6 seconds of audio. One requested pause ("Agar", [short pause]) was checked: 0.23 seconds measured.

Limits

Environment

4. The video plan

Written 2026-10-25 for the Gemini Hinglish v7 beats. Stage 1 (timing) is built and measured; stages 2 to 5 are a plan, and nothing has been rendered or listened to by Claude. The plan's own assumptions, stated so you can correct them: "13 beats" is 14 WAV files (B0 plus B1 to B13); "Claude motion" is read as Remotion, the motion-graphics framework (its licence for this channel is unchecked); "being image search" is read as Bing image search, which Microsoft retired on 11 August 2025, so the plan does not use it.

Music and sound

Visuals: four categories and a rule for choosing

CategoryWhatSource and routeRights
A. Data and motion graphicsBars, lines, counters, calendars, maps, icon cards, the treadmill and price diagramsFigures from the ledger. Remotion components read a figure register; the render refuses a figure with no ledger row.Our own work; check map data licences.
B. Source documentsThe real article or statement, zoomed, with the cited phrase highlightedURLs already in the ledger; capture the page, find the quoted phrase, animate a zoom timed to its first word.Copyright in article text and images; the plan asks for a lawyer's read.
C. Photos and archive imagesPeople, places, objects the script namesWikimedia Commons first, Openverse second; CC0, public domain, CC BY, CC BY-SA only, with the credits file generated from the record.Per file; no photo of a private person without a licence.
D. AtmosphereGeneric gate, factory floor, city, coinPexels or Pixabay; chosen by a tag match; captioned "file footage".Free licences.

The rule for choosing, first match wins: a number, date, price, bar or line means A; a quotation, headline or source means B; a person, place or object with a licensed photo means C; a setting with no specific claim means D. The plan says not to re-typeset a newspaper headline as if it were a real clipping, not to use a news photograph without its own licence, not to show a photo of Mahesh Sharma or any private worker, and not to use the company logo without the user's decision.

Stitching (proposed, not built)

  1. Timeline from words.json; clips placed by their anchor words.
  2. Audio: the 14 beat WAVs as the voice; the act's music bed; ducking with ffmpeg sidechain compression; sound effects from the event rules.
  3. Render with Remotion at 1920 by 1080, 30 fps; test on a two-minute preview (B0 to B1) first. Render time on this machine is unknown.
  4. Loudness: two-pass ffmpeg loudnorm to about -14 LUFS.
  5. Pre-render checks that can fail the render: every number on screen traces to a ledger row; every on-screen quotation is a capture or scan with the source's name and date; every picture and sound has a licence row.

Decisions the plan hands to the user

  1. Pace: keep the delivered pace or regenerate slower?
  2. Music route (licensed library recommended) and who auditions three candidates per act.
  3. Source captures (category B): web page captures, scanned clippings, or only the ledger's own text on screen. Indian copyright law has a fair-dealing exception for criticism and review; this is not legal advice.
  4. Stock footage with a "file footage" caption?
  5. The Moser Baer logo or not (the default is no).
  6. Whisper model: base is enough for timing; small would anchor more words but needs a download.
  7. The real gap between beats (the timeline uses 0.5 s).
Unfilled placeholders

PRODUCTION-PLAN.md still contains two placeholders written for a later fill: RESULTS_TABLE_PLACEHOLDER in section 1.1 and PACE_WPM in section 1.3. The measured values for B1 and B2 are in video/timing/align-report.md.

Not proven

The emotion-to-sound mapping is a hypothesis about how sound should follow feeling; no viewer has been tested. Claude has not heard any of the audio. The timing is only as good as Whisper base's timestamps. No licence has been checked for a specific track or image. Render time and the Remotion licence are unknown.

Written 2026-10-27 from the repository files and the project memory notes. If a page and a file disagree, the file is right: fix the page.