Own product · Live · 2026
offScript
offScript is a rehearsal tool for actors. You paste or upload a script, it casts a voice for every character but yours, reads their lines with directed delivery, listens while you deliver yours, and tells you afterwards which lines you don't own yet. It has a directing room where you give notes in plain language, a dramaturg's breakdown of the scene, an improvised pitch-and-interview mode on a live speech model, and a cue engine that decides when to speak from what you said rather than from how long you were silent.
offscript.mytrya.com↗By Suraj Malla · Kathmandu

The problem
Rehearsing alone means reading both parts, so you learn your cue lines instead of your own.
A general voice assistant doesn't work either. It waits about 700 milliseconds of silence and then talks. In a scene, a pause is often the point. And generating a partner's line on demand takes 3 to 5 seconds, which is impossible inside a scene.
How it works
script in ──▶ parsed in the browser (PDF: server, glyphs → lines)
│
▼
segment() the script's own headings; else cut on a
│ returning speaker; ceiling 120 lines a scene
▼
scene opened ──▶ cast once per script ──▶ notes per line, in
│ gender held to the 45-line windows, as
│ model's own reading prose AND a ≤6-word cue
▼
render every partner line ──▶ disk cache cold ~5s · warm ~19ms
│ (Gemini TTS or ElevenLabs, 24kHz PCM)
▼
run ──▶ match live transcript against the expected line
│ coverage + progress → the wait ladder
▼
report ──▶ recordings re-transcribed with the line as context,
weak lines ranked, drill mode on the ones you fumble
/direct ──▶ "nobody is shouting, it's 3am" ──▶ proposal per line ──▶ take / drop
read the scene: units · characters · one action verb per line- Parsers for five formats, read in the browser. Only PDF goes to the server, where lines are rebuilt from glyph positions and page furniture is stripped. Speeches are parsed locally too, since a single speaker has no cues to split on.
- A segmenter with strict heading rules, a returning-speaker fallback, and a 120-line ceiling. Importing a 40-scene feature makes zero model requests; scenes the script named keep their names.
- Casting per script, deferred until a scene is opened, with the model's stated reading of each character's gender enforced against the voice it picked. Two engines with incompatible direction: Gemini reads a prose note, ElevenLabs takes a bracketed cue, so the directing pass writes both at once and each engine gets the one it can use.
- Pre-rendered partner lines in a shared cache keyed by line, voice and note, so a changed note re-renders only the lines it touched. A 30-second deadline per model attempt and 70 per line; rendering can be stopped and keeps what arrived; a line that won't render is left out with a retry that costs only the failures.
- The cue engine, per-line recording on one held-open microphone stream, an after-the-fact re-transcription that knows the expected line, deterministic scoring with a slow-pickup penalty, and a drill mode for the lines you keep fumbling, each preceded by its cue.
- A directing room: give a note in the words you'd use in the rehearsal room, get a proposal of only the lines it bears on, take or drop each, undo the last note. Read the scene into units, characters and one transitive action verb per line, then play the whole scene end to end with a seekable timeline whose ticks are the line breaks.
- Pitch and interview mode on Gemini Live: a persona brief and your talking points, an improvised partner that pushes back in character, and grading on whether each point landed rather than on words.
| Wait | What it heard |
|---|---|
| instant | clean delivery: enough coverage, and the final word |
| 500 ms | enough coverage, final word clipped by the recogniser |
| 900 ms | reached the end, middle mangled |
| 1400 ms | most of the line, and reached its end, then silence |
| 4000 ms | you said something, and stopped |
| 8000 ms | nothing heard at all |
Decisions that mattered
5
How it knows when to speak
The engine measures two things. Coverage is how much of the expected line was heard. Progress is how far into the line the furthest matched word sits. They answer different questions: 60% coverage can mean you're mid-line taking a beat, or that you finished and the recogniser dropped words.
The wait before the partner speaks is a ladder, not one timeout. It only interrupts instantly when it heard the actual final word, because stepping on the end of a line is the worst thing a scene partner can do. In improvised mode the ladder is switched off and plain silence detection takes over, because in a conversation a pause really does mean your turn.
Two speech engines that take direction differently, measured
Gemini TTS reads a delivery note as prose and performs better the longer and more situational the note is. ElevenLabs takes a short bracketed cue, and handing it Gemini's prose fails loudly: it reads the stage direction aloud. Measured against a 1.92-second baseline, a bracketed cue of 2, 6 or 10 words changes the delivery and nothing else; 14 words adds 6.16 seconds of the actor reading her own direction. The app's notes are 8 to 20 words, so about half would have been spoken.
So the directing pass writes both forms in one request, a prose note and a cue of at most six words, and each engine is handed the one it can use. Preparing a scene under one engine prepares it for both.
On one scene of six lines with the same notes: Gemini ranged 0.42 to 2.79 words per second and took about 12 seconds a line; ElevenLabs 1.85 to 3.20 and about 2.6 seconds a line. Gemini's wider spread was one five-word line dragged to 11.77 seconds, which in a rehearsal is a cue that never lands. Gemini stays the default for its richer control; the switch is one click.
Nothing generates during a scene
Every partner line is rendered when the scene is prepared and played from a local file. A four-line scene prepares cold in about 5 seconds and warm in about 19 milliseconds. The browser's own synthesiser is the fallback for lines that failed to render and for improvised modes.
For improvised partners the reply-then-synthesise pipeline measured 7.7 seconds a turn, of which 5.7 to 7.4 was speech generation. Gemini Live emits audio directly and starts speaking about 1.3 seconds in, so that mode runs on a Live session, speech in and speech out with no text step between.
The score is arithmetic; the coaching is optional
Everything in the report is arithmetic on what was measured during the run, no model in the loop, so today's numbers compare to last week's. Weak lines are ranked by accuracy with a penalty for slow cue pickup: a line you always get right after a two-second stall isn't one you know yet.
Chrome's recogniser has to run live because it's the only one that streams, but it doesn't know the script and returns don't for didn't pretend. Each recording is re-transcribed afterwards by a model told the expected line, which turns an open-vocabulary guess into a narrow judgement, and a forgiven artefact stops showing up as a memory failure. Subjective coaching notes are a separate step you ask for.
The sixty-input form nobody used
The first directing interface was a form: sixty text inputs, a palette of mood adjectives, two scene-wide sliders. It worked and nobody used it, because writing sixty delivery instructions by hand is not something anyone does. It was replaced by giving a note the way you would in the room, and letting the model decide which lines the note bears on and what it means for each of them. Nothing is applied until you take it, and each taken note stores what it overwrote, so it can be undone.
What is and isn’t shown
My own product, live at offscript.mytrya.com. Works in Chrome or Edge, and needs headphones so the microphone doesn't hear the partner's lines. All measurements above are from the project notes. From those notes: it stays on book so you can get off book.
Next step
Have a system like this in mind?
Describe it: what it is, who does it, how often, and what goes wrong when it's late. I reply within one working day with a scoping call or a reason it isn't worth automating.