Introduces the new Studio section (Source -> Characters -> Voices -> Perform & Export) that reuses the existing Read Aloud/Library/Script Rehearsal code via DOM reparenting instead of duplicating it, and rolls up a long tail of bugs found while producing a real audiobook through it: umlaut-eating name sanitizers, a voice picker that mispositioned itself and capped results at 60, PDF pagination silently breaking on trimmed \f markers, a race letting stale audio keep playing after a new line was clicked, an alias-overlap bug that could silently redirect a voice/image save onto the wrong character, voice design failing outright during brief TTS backend restarts instead of retrying, sparse cast entries defaulting to English/wrong gender, and a reassigned voice never reaching an already-open Stage session or invalidating its cached audio. Also adds a persistent per-line audio cache, audiobook export browsing/download, and an inline voice-design prompt editor. Full details in CHANGELOG.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
77 lines
4.9 KiB
HTML
77 lines
4.9 KiB
HTML
<div class="section-head">
|
|
<span class="section-icon"><span class="mdi mdi-movie-open-play"></span></span>
|
|
<div class="section-title">
|
|
<h2>Studio</h2>
|
|
<p>Source, cast, voice, and perform a whole audiobook or script in one place.</p>
|
|
</div>
|
|
<span style="flex:1"></span>
|
|
<!-- Studio's own Previous/Next — deliberately its OWN class, not a
|
|
reuse of .wf-header-nav: that cross-section widget is actively
|
|
hidden inside #s-caststudio (utils.js _wfUpdateHeaderNav) since
|
|
it only knows about the old s-reader/s-library/s-rehearser
|
|
sections, not these 4 phases — reusing its class here would have
|
|
gotten this hidden by that exact same suppression. Without this,
|
|
the only way to move between phases was clicking a tab directly
|
|
— no visible "what's next" affordance, confirmed as a real gap
|
|
live. -->
|
|
<div class="stu-phase-nav" id="stu-phase-nav">
|
|
<button type="button" class="stu-phase-nav-btn" id="stu-phase-prev"><span class="mdi mdi-chevron-left"></span><span>Previous</span></button>
|
|
<button type="button" class="stu-phase-nav-btn" id="stu-phase-next"><span>Next</span><span class="mdi mdi-chevron-right"></span></button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Phase tabs — a self-contained system deliberately separate from both
|
|
the cross-section .wf-stepper and Script Rehearser's own .reh-subtab
|
|
system; see the Studio build plan for why. Numbered so the tab bar
|
|
itself reads as an ordered flow, not just 4 unrelated sections. -->
|
|
<div class="stu-subtabs" id="stu-subtabs">
|
|
<button class="stu-subtab active" data-stu-phase="1"><span class="stu-subtab-num">1</span> <span class="mdi mdi-file-document-outline"></span> <span>Source</span></button>
|
|
<button class="stu-subtab" data-stu-phase="2"><span class="stu-subtab-num">2</span> <span class="mdi mdi-drama-masks"></span> <span>Characters</span></button>
|
|
<button class="stu-subtab" data-stu-phase="3"><span class="stu-subtab-num">3</span> <span class="mdi mdi-account-voice"></span> <span>Voices</span></button>
|
|
<button class="stu-subtab" data-stu-phase="4"><span class="stu-subtab-num">4</span> <span class="mdi mdi-theater"></span> <span>Perform & Export</span></button>
|
|
</div>
|
|
|
|
<div class="tab-content" id="tab-caststudio">
|
|
|
|
<!-- ── Phase 1: Source ─────────────────────────────────────────── -->
|
|
<div class="stu-phase" id="stu-phase-1">
|
|
<div id="stu-source-slot"></div>
|
|
<div class="card" style="margin-top:16px">
|
|
<h2><span class="mdi mdi-bookshelf"></span> Already uploaded</h2>
|
|
<p class="card-subtitle" style="margin:0 0 12px">Pick a book you've imported before instead of pasting/uploading it again.</p>
|
|
<div id="stu-books-slot"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ── Phase 2: Characters ─────────────────────────────────────── -->
|
|
<div class="stu-phase" id="stu-phase-2" hidden>
|
|
<div class="stu-inner-tabs" id="stu-cast-inner-tabs">
|
|
<button class="stu-inner-tab active" data-stu-cast-view="identify">Identify Characters</button>
|
|
<button class="stu-inner-tab" data-stu-cast-view="sheets">Cast Characters <small style="opacity:.6;font-weight:400">(optional)</small></button>
|
|
</div>
|
|
<div id="stu-cast-slot"></div>
|
|
<div id="stu-castchars-slot" hidden></div>
|
|
</div>
|
|
|
|
<!-- ── Phase 3: Voices ─────────────────────────────────────────── -->
|
|
<div class="stu-phase" id="stu-phase-3" hidden>
|
|
<div id="stu-voices-slot"></div>
|
|
</div>
|
|
|
|
<!-- ── Phase 4: Perform & Export ───────────────────────────────── -->
|
|
<div class="stu-phase" id="stu-phase-4" hidden>
|
|
<label class="stu-mode-toggle">
|
|
<input type="checkbox" id="stu-mode-audiobook">
|
|
<span><span class="mdi mdi-headphones"></span> Generate full audiobook (voice the Narrator too)</span>
|
|
</label>
|
|
<!-- "I play this" lives on the per-character cast cards, not the
|
|
Stage line view — only relevant in Rehearse mode. -->
|
|
<details class="card" id="stu-mecast-details" style="margin-bottom:14px">
|
|
<summary style="cursor:pointer;font-weight:700;padding:4px 0"><span class="mdi mdi-microphone"></span> Who's playing which character?</summary>
|
|
<div id="stu-mecast-slot"></div>
|
|
</details>
|
|
<div id="stu-stage-slot"></div>
|
|
</div>
|
|
|
|
</div>
|