tts-voice-creator-clone-and.../static/sections/s-caststudio.html
mARTin-B78 5fecbf06d4 Fix Fish-Speech emotion tags, wire book context into portraits, add emotion controls app-wide (v1.20.5)
Fish-Speech emotion tags were silently ignored on non-English books: per-line
emotions are LLM-generated in the book's own language, but Fish-Speech only
recognizes English [tag] markers, and a double-tagging bug was stacking a
broken server-derived tag on top of the client's own. Added a DE->EN
translation table and removed the double-tagging. Also wires the existing
book-profile context and race_species field into character portrait prompts
(previously only used for voice design), adds a recast-until-threshold loop
for casting, and adds backend-aware emotion quick-picks to Read Aloud, Try a
Voice, and Conversation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 18:02:41 +02:00

118 lines
7.6 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 &amp; 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>
<div style="display:flex; align-items:flex-start; gap:14px; flex-wrap:wrap;">
<label class="stu-mode-toggle" style="flex-shrink:0">
<input type="checkbox" id="stu-mode-audiobook">
<span><span class="mdi mdi-headphones"></span> Generate full audiobook (voice the Narrator too)</span>
</label>
<!-- Borrowed here from the Stage toolbar (#reh-tone-warn) — it
used to render as its own full-width banner below the
toolbar, leaving this whole row's spare width unused right
above it. Same element, same id, just relocated. -->
<div id="stu-tone-warn-slot" style="flex:1; min-width:200px"></div>
</div>
<!-- Pause lengths applied when synthesising the full audiobook —
mergeWavBlobs otherwise butts every line together with zero
gap, which reads as scenes/paragraphs jump-cutting with no
beat between them. Settings persist per-browser (not per-book)
via localStorage since they're a pacing preference, not book
content. -->
<details class="card" id="stu-pause-details" style="margin-bottom:14px">
<summary style="cursor:pointer;font-weight:700;padding:4px 0"><span class="mdi mdi-timer-sand"></span> Pacing (pauses between paragraphs &amp; chapters)</summary>
<div class="settings-grid settings-behavior-grid" style="margin-top:10px">
<div class="s-field">
<label>Pause between paragraphs</label>
<div style="display:flex; align-items:center; gap:6px">
<input type="number" id="stu-pause-paragraph" min="0" max="20" step="0.5" style="width:80px">
<span>seconds</span>
</div>
</div>
<div class="s-field">
<label>Pause between chapters</label>
<div style="display:flex; align-items:center; gap:6px">
<input type="number" id="stu-pause-chapter" min="0" max="60" step="0.5" style="width:80px">
<span>seconds</span>
</div>
</div>
<div class="s-field">
<label>Chapter transition sound <small style="opacity:.6;font-weight:400">(optional)</small></label>
<div style="display:flex; align-items:center; gap:8px; flex-wrap:wrap">
<input type="file" id="stu-chapter-sfx-file" accept="audio/*" style="max-width:220px">
<button type="button" class="btn-secondary btn-sm" id="stu-chapter-sfx-clear"><span class="mdi mdi-close"></span> Clear</button>
<span id="stu-chapter-sfx-current" class="s-hint"></span>
</div>
<span class="s-hint">Plays once before each chapter's pause, e.g. a page-turn or chime. Any audio format your browser can play.</span>
</div>
</div>
</details>
<!-- "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>