- A4 paper page (white, serif font, shadow) renders the full script at once
so you can read ahead while rehearsing
- Each dialog block shows: character avatar (voice library photo or initial
letter), character name in their colour, TTS/Me badge, and dialog text
- Active line gets a blue left-border highlight and auto-scrolls into view
- Transport bar (sticky, above the script):
- Cast strip: all character avatars at a glance
- ⏮ Prev / ▶ Play all / ⏹ Stop / ⏭ Next / 🔁 Repeat
- Progress bar + line counter
- Auto-play: TTS lines synthesize, play, auto-advance; 'me' lines pause
and slide up a sticky recording overlay at the bottom of the page
- Recording overlay shows the line to speak, oscilloscope + meter,
Record / Stop / Keep & continue / Re-record / Skip
- voice-library.js now exports window._voices so the rehearser can resolve
voice IDs to has_picture flags and fetch /api/voice/picture/{id}
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
135 lines
8.3 KiB
HTML
135 lines
8.3 KiB
HTML
<div class="section-head">
|
|
<span class="section-icon"><span class="mdi mdi-theater"></span></span>
|
|
<div class="section-title">
|
|
<h2>Script Rehearser</h2>
|
|
<p>Upload a script, assign voices to characters, then rehearse with TTS synthesis and microphone recording.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="tab-content" id="tab-rehearser">
|
|
|
|
<!-- ── Phase 1: Script input ──────────────────────────────────── -->
|
|
<div class="reh-phase" id="reh-phase-1">
|
|
<div class="card">
|
|
<h2><span class="mdi mdi-script-text-outline"></span> Step 1 — Paste or upload your script</h2>
|
|
<p class="card-subtitle">Format: <code>CHARACTER: dialog</code> on one line, or screenplay style (ALL-CAPS character name on its own line, dialog below). Lines starting with <code>#</code> are stage directions.</p>
|
|
<div class="reh-input-row">
|
|
<textarea id="reh-script-text" placeholder="ALICE Hello, how are you today? BOB I'm doing great, thank you for asking! ALICE That's wonderful to hear." spellcheck="false"></textarea>
|
|
<div class="reh-input-side">
|
|
<label class="btn-secondary" style="cursor:pointer;display:inline-flex;align-items:center;gap:6px">
|
|
<span class="mdi mdi-upload"></span> Upload .txt
|
|
<input type="file" id="reh-file-input" accept=".txt,.md" style="display:none">
|
|
</label>
|
|
<div class="field" style="margin-top:10px">
|
|
<label style="font-size:12px">Script title (optional)</label>
|
|
<input type="text" id="reh-script-title" placeholder="My Script">
|
|
</div>
|
|
<p class="note" style="margin-top:8px;font-size:12px">Supported formats:<br>• <code>CHARACTER: text</code><br>• All-caps name + dialog below<br>• <code># stage direction</code></p>
|
|
</div>
|
|
</div>
|
|
<div class="btn-row" style="margin-top:12px">
|
|
<button class="btn-primary" id="reh-parse-btn"><span class="mdi mdi-auto-fix"></span> Parse characters</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ── Phase 2: Cast assignment ───────────────────────────────── -->
|
|
<div class="reh-phase" id="reh-phase-2" hidden>
|
|
<div class="card">
|
|
<h2><span class="mdi mdi-account-group-outline"></span> Step 2 — Cast your characters</h2>
|
|
<p class="card-subtitle">Assign a TTS voice to each character, or toggle <strong>I play this role</strong> — those lines will pause and wait for your microphone recording.</p>
|
|
<div class="field" style="margin-bottom:14px">
|
|
<label>TTS backend for synthesis</label>
|
|
<div style="display:flex;gap:8px;align-items:center">
|
|
<select id="reh-backend-select"><option value="">Checking…</option></select>
|
|
<button class="btn-secondary" id="reh-fetch-voices-btn"><span class="mdi mdi-refresh"></span> Fetch voices</button>
|
|
</div>
|
|
</div>
|
|
<div id="reh-cast-list" class="reh-cast-list"></div>
|
|
<div class="btn-row" style="margin-top:14px">
|
|
<button class="btn-secondary" id="reh-back-1-btn"><span class="mdi mdi-arrow-left"></span> Back</button>
|
|
<button class="btn-primary" id="reh-start-btn"><span class="mdi mdi-theater"></span> Open rehearsal</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ── Phase 3: Rehearsal — A4 script view ────────────────────── -->
|
|
<div class="reh-phase" id="reh-phase-3" hidden>
|
|
|
|
<!-- Transport controls -->
|
|
<div class="reh-transport-bar" id="reh-transport-bar">
|
|
<!-- Cast strip -->
|
|
<div class="reh-cast-strip" id="reh-cast-strip"></div>
|
|
<!-- Transport buttons -->
|
|
<div class="reh-transport-btns">
|
|
<button class="reh-tb-btn" id="reh-tb-prev" title="Previous line"><span class="mdi mdi-skip-previous"></span></button>
|
|
<button class="reh-tb-btn reh-tb-play" id="reh-tb-play" title="Play all"><span class="mdi mdi-play"></span></button>
|
|
<button class="reh-tb-btn" id="reh-tb-stop" title="Stop & reset"><span class="mdi mdi-stop"></span></button>
|
|
<button class="reh-tb-btn" id="reh-tb-next" title="Next line"><span class="mdi mdi-skip-next"></span></button>
|
|
<button class="reh-tb-btn" id="reh-tb-repeat" title="Loop script"><span class="mdi mdi-repeat"></span></button>
|
|
</div>
|
|
<!-- Progress -->
|
|
<div class="reh-transport-progress">
|
|
<div class="reh-tb-progress-wrap"><div class="reh-tb-progress" id="reh-tb-progress"></div></div>
|
|
<span class="reh-tb-label" id="reh-tb-label">0 / 0</span>
|
|
</div>
|
|
<button class="btn-secondary btn-sm" id="reh-exit-btn" style="margin-left:auto">Exit</button>
|
|
</div>
|
|
|
|
<!-- A4 script page -->
|
|
<div class="reh-page-wrap">
|
|
<div class="reh-a4-page" id="reh-a4-page">
|
|
<div class="reh-page-title" id="reh-page-title"></div>
|
|
<div class="reh-script-lines" id="reh-script-lines"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recording overlay (visible when my turn) -->
|
|
<div class="reh-rec-overlay" id="reh-rec-overlay" hidden>
|
|
<div class="reh-rec-overlay-inner">
|
|
<div class="reh-rec-cue" id="reh-rec-cue"></div>
|
|
<div class="mic-monitor-box" style="margin-bottom:10px">
|
|
<div class="mic-monitor-head">
|
|
<span>Input level</span>
|
|
<span class="meter-readout" id="reh-db-readout">-∞ dB</span>
|
|
</div>
|
|
<div class="mic-meter" id="reh-mic-meter" aria-hidden="true"></div>
|
|
<canvas id="reh-live-wave" class="mic-live-wave" width="300" height="48" aria-hidden="true"></canvas>
|
|
</div>
|
|
<div class="btn-row" style="gap:8px">
|
|
<button class="btn-red" id="reh-rec-start"><span class="mdi mdi-record-circle-outline"></span> Record</button>
|
|
<button class="btn-secondary" id="reh-rec-stop" disabled><span class="mdi mdi-stop-circle-outline"></span> Stop</button>
|
|
<span class="mic-timer" id="reh-rec-time">0:00</span>
|
|
<button class="btn-secondary" id="reh-skip-line"><span class="mdi mdi-skip-next"></span> Skip</button>
|
|
</div>
|
|
<audio id="reh-rec-preview" controls style="display:none;margin-top:8px;width:100%"></audio>
|
|
<div class="btn-row" style="margin-top:6px" id="reh-rec-confirm-row" hidden>
|
|
<button class="btn-green" id="reh-rec-keep"><span class="mdi mdi-check"></span> Keep & continue</button>
|
|
<button class="btn-secondary" id="reh-rec-redo"><span class="mdi mdi-refresh"></span> Re-record</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- TTS playback status (slim bar below transport) -->
|
|
<div class="reh-tts-status-bar" id="reh-tts-status-bar" hidden>
|
|
<span id="reh-tts-status-txt"></span>
|
|
<audio id="reh-tts-audio" controls style="flex:1;min-width:0;max-width:320px"></audio>
|
|
</div>
|
|
|
|
</div><!-- /phase-3 -->
|
|
|
|
<!-- ── Phase 4: Session summary ────────────────────────────────── -->
|
|
<div class="reh-phase" id="reh-phase-4" hidden>
|
|
<div class="card">
|
|
<h2><span class="mdi mdi-check-circle-outline"></span> Rehearsal complete</h2>
|
|
<p class="card-subtitle">All recorded and synthesized clips from this session.</p>
|
|
<div id="reh-summary-list" class="reh-summary-list"></div>
|
|
<div class="btn-row" style="margin-top:14px">
|
|
<button class="btn-secondary" id="reh-new-session-btn"><span class="mdi mdi-refresh"></span> New script</button>
|
|
<button class="btn-secondary" id="reh-resume-btn"><span class="mdi mdi-theater"></span> Resume rehearsal</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div><!-- /tab-rehearser -->
|