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>
Restructure the sidebar into Voices / Speak / Setup groups and fuse the
Read Aloud and Script Rehearser features into one workspace:
- New combined Library section (Books · Theater Plays · Characters/Cast)
with cross-links (Rehearse a book, Read Aloud a play).
- Character tags like voice tags: one record, many productions, reusable
across books/scripts; seeded with origin book, editable in the editor.
- Shared cast resolution: opening a production fills empty cast slots from
the character roster (matched by book OR tag); voice choices written back
on save. Productions joined by normalized title (prodKey).
- Tags nav group for voices (distinct tags + counts, Cloned/Designed/Fav).
- Fold standalone Characters into Library; Read Aloud now a single entry.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a persistent, book-scoped Character Library (new Characters section,
IndexedDB) that auto-fills from Character-sheet analysis with editable cards.
Enrich extraction with six narrative fields (backstory, relationships,
motivation, fears, mannerisms, voice/speech) plus the greyscale Good↔Evil
alignment bar, arc arrow, and 5-area Deep Analysis. Add ⋯ separators between
non-contiguous passages in Recast unknown, and harden dialogue attribution
against hallucination with same-language emotion tags.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a collapsible "🎲 Seed Finder" panel to the voice inspector pane.
Select a voice, expand the panel, set a seed range (default 1–15), and
click Run to generate audio samples with different seeds.
Each result row has Play and "Use this seed" buttons. "Use this seed"
saves the chosen seed to the faster-qwen3-tts voices.json via the new
/api/tts-voice-seed proxy endpoint (which calls /voice-seed on the TTS
server). The saved row gets a ✓ marker.
Test sentence auto-selects DE/EN mixed or EN-only based on voice name.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
splitTextIntoChunks only split on sentence terminators (.!?), so structured
text separated by newlines was never chunked — the full page went as one
request, causing a TCP timeout that the browser reported as "Failed to fetch".
Fix: process each line individually before applying the sentence regex so
newline-separated segments become their own split points. Also move
generation.js from deferred batch E into the main feature batch C so
generateChunkedTts is always defined before the user can click Generate.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
## Script Rehearser (new feature)
- New section s-rehearser.html + rehearser.js + nav/loader wiring
- Phase 1: paste/upload script (.txt), auto-detect characters from
'CHARACTER: dialog' or ALL-CAPS screenplay format
- Phase 2: assign a TTS voice per character, or mark 'I play this'
- Phase 3: step-through rehearsal — synthesizes other characters via TTS,
shows level-meter + oscilloscope for your own lines, records them from mic
- Phase 4: session summary with per-line audio playback + download
## Connect Apps
- Removed duplicate standalone MCP/speak/hotkey full-width cards
- Kept the integration-grid cards (they use the real server URL from JS)
- Added Global Hotkey Daemon as a proper integration card with snippet-hotkey
populated by integrations.js (uses proxyBase URL dynamically)
## About page
- GET /api/changelog endpoint reads CHANGELOG.md and returns it as text
- Collapsible 'Changelog' <details> card fetches and displays it lazily
## Try It Out
- Reorganised into three cards: Voice & backend / Text to synthesize / Generate
- Backend help panel moved below the voice row (not in the same flex row)
- Style instruction field gains a dynamic badge ('style-aware ✓' / 'weak style')
and a yellow warning when a non-style-aware backend is selected while the
field is filled — wired to both backend-select change and input events
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Loader:
- Post-init modules (engines, ai-backends, generation, conversation) now
load AFTER the skeleton is removed instead of before. The UI is visible
~500 ms sooner on average; those four modules load while the user is
already browsing Voices / Clone / Design.
- Removed the sttReady event approach that was triggering a duplicate
/api/stt-backends call; init.js already populates all STT selects once
on startup.
Skeleton:
- Replaced the card-grid placeholder with a two-column workbench skeleton
(voice list rows on the left + inspector placeholder on the right) that
matches the real My Voices layout.
Connect Apps:
- MCP Server, /speak REST endpoint, and Global hotkey daemon sections
moved from Settings → About to Connect Apps, where they belong.
- About page now has GitHub + Releases links instead.
Clone section:
- Added a hint note beneath the sample-text textarea reminding the user
to replace the placeholder name (Sam / Alex / Marco …) with their own.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root cause: VERSION was not volume-mounted, so the server always reported
1.2.0, causing browsers to serve 1-year-immutable cached JS even after
code changes.
Fixes:
- docker-compose.yml: add ./VERSION:/app/VERSION:ro volume mount.
After `docker compose up -d`, the server reads the current VERSION file
and JS is cache-busted by the correct version string.
- loader.js: append session timestamp to _appVersion so every page load
generates a unique JS URL. JS is always fresh regardless of whether
VERSION is current, at the cost of one network round-trip per file per
session (acceptable for a local tool).
- s-clone.html: embed EN default text directly in the textarea so the
field is never empty even before JS runs.
- voice-clone.js: remove the 'skip if already filled' guard in
initCloneSampleText so navigating back always resets to the language
text; call refreshSttBackends on load with sttReady event fallback.
- stt.js: dispatch 'sttReady' event after all STT listeners are wired.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously all 11 section HTMLs had to complete before JS loading began.
Now only the active section loads first (needed before JS runs so event
listeners find their DOM elements). The other 10 sections fetch in parallel
with utils + settings; an explicit await before the 9-module feature batch
guarantees all section HTML is injected before any feature module sets up
its DOM listeners. On a local server the HTML files finish well before
settings.js completes, so the await is typically instant.
Sequential steps cut from: sections(11∥) + utils + settings + features + ...
to: section(1) + max(utils+settings, sections(10∥)) + features + ...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Perceived startup speed:
- index.html: animated shimmer skeleton (header + toolbar + 8 voice cards)
visible immediately; fades out when loader.js finishes
- WaveSurfer (57KB) and MDI icon font (394KB woff2) now served from
static/vendor/ — removes 3 render-blocking external requests from <head>
- Flag-icons CSS loaded async (rel=preload onload trick) — non-blocking
loader.js:
- Fade out skeleton + remove from DOM (300ms transition)
- Reveal page-sections after JS finishes loading
Conversation playground:
- Qwen3 thinking mode fix: fall back to delta.reasoning_content when
delta.content is empty so think-only LLM turns produce visible output
- Better error message with /no-think hint when LLM returns empty
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Move mic-blocked warning into conv-chat-window (prepend) so it scrolls
with the chat instead of pushing the input bar off-screen
- Remove min-height:400px from conv-chat-window; give conv-chat-panel a
viewport-relative height so the input bar is always visible at the bottom
- loader.js: append ?v=<timestamp> to section fetches to bust browser cache
(was serving stale s-conversation.html after updates)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Conversation Playground (new section):
- WhatsApp-style chat UI with user/assistant speech bubbles
- Click-to-record mic button using MediaRecorder API
- STT → LLM streaming → TTS pipeline via SSE (POST /api/conversation/turn)
- LLM tokens stream into assistant bubble in real time
- Audio auto-plays when TTS synthesises the reply
- Right-side stats panel: STT / LLM TTFT / LLM total / TTS / Total with bar chart
- Turn history list with per-turn total time and pass/fail indicator
- Configurable: STT backend, LLM URL + model, TTS backend + voice, system prompt
- Conversation history maintained across turns (last 20 messages sent to LLM)
- GET /api/conversation/llm-models proxies model list from any OpenAI-compatible LLM
XTTS v2 backend:
- Registers xtts as a first-class TTS backend (xtts_url setting, display name,
capabilities, health/voice discovery, OpenAI-compatible generation)
- Added XTTS URL field to Settings → Connections
- Use-as-TTS button now saves to xtts_url (not tts_url)
- Batch benchmark backend select now refreshes alongside perf/preview selectors
VibeVoice fix:
- Added /voices to _TTS_VOICE_ENDPOINTS so VibeVoice voices are discovered
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New s-performance section: dedicated Benchmark nav entry with run form,
per-session results table, RTF trend badge (faster/slower/stable), SVG
sparkline chart, and a History card backed by localStorage (last 50 sessions)
- Performance tab removed from Try It Out; element IDs unchanged so JS works
- renderIntegrationSnippets: adds Python MCP server + Claude Code .mcp.json
config snippets to the Connect Apps page (integration-card-wide styling)
- Save handler: persists all Captures settings fields (stt_language,
stt_preferred_backend, auto_refine, refine_model, refine_* toggles,
captures_default_voice) alongside existing settings
- CSS: integration-card-wide accent border, benchmark history rows, trend
badges, sparkline wrapper, bench-history-toolbar
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Inspector:
- Skinny 2-row header: 72px avatar + name/ID row / subtitle row / note row
- Searchable flag picker (dblclick flag icon) — filtered by voice language, falls back to ALL_FLAGS
- Searchable language picker (dblclick lang code) — shows full language names
- Tag reuse: entered tags persist to localStorage as datalist suggestions
- Compact active toggle (32×18px), slim save button (12px/4px padding)
- Show/hide eye toggle and "✓ Key saved" badge on API key fields
AI Backends (s-llms.html + style.css):
- Full CSS design: pill tabs with active accent, animated section transitions
- Service cards: icon bubbles, tier badges (Free/Demo/Paid), stat chips, endpoint rows, model tags
- Highlighted recommended card with accent border
- Dark code blocks for local service snippets with copy feedback
- Show/hide password toggle and auto-appearing "✓ Key saved" badge per card
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New light UI: fixed 220px sidebar, single scrolling page, 8 named sections
- Static files split by concern: style.css, app.js, loader.js, nav.js
- Each page section is its own partial in static/sections/s-*.html
- loader.js fetches all section partials in parallel, then loads app.js and nav.js
- All original functionality, element IDs, and API endpoints preserved
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>