tts-voice-creator-clone-and.../static/sections/s-caststudio.html
mARTin-B78 f7264a8c07 chore: release 1.21.0 - Consistent ComfyUI Character Renders and Audiobook Export
- Deterministic hash-based character portraits and reference sheets
- Implemented strict early Renaissance aesthetic controls and role-specific headwear rules
- Added audiobook batch export scripts and progress tooling
- Verified book profiles with a new 'confirmed' state tracking mechanism
- Updated Pillow dependency for robust image handling
- Configured .gitignore for audiobook and audio cache exports
2026-08-23 09:12:57 +02:00

120 lines
8.0 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 type="button" class="stu-book-context-btn" id="stu-change-book-btn" title="Choose a different uploaded book"><span class="mdi mdi-book-open-page-variant-outline"></span> Change book</button>
<button type="button" class="stu-book-context-btn" id="stu-book-context-btn" title="Edit genre, setting, era and language before identifying characters"><span class="mdi mdi-book-cog-outline"></span> Edit book context</button>
<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>