Files
VoiceStudio/electron
Palash Debnath 8f06b4968f Merge branch 'fix/catalogue-install-capability' into fix/community-integration
# Conflicts:
#	CHANGELOG.md
#	docs/install/troubleshooting.md
2026-09-17 12:38:56 +05:30
..

VoiceStudio — Electron desktop app

Electron is the primary desktop app for voice cloning, stories, dubbing, transcription, voice design, and workflows. Tauri is retained only for its final sunset update; see migration notes.

The runtime supervisor manages the local FastAPI backend. Network integrations and remote workers require configuration; local generation stays on your machine.

Stack

Layer Choice
Shell Electron 44, electron-vite 6 (Vite 8 / Rolldown), electron-builder
Toolchain Vite+ (vp — vitest, oxlint, oxfmt), TypeScript 7 (tsgo), bun
UI React 19, Tailwind v4, shadcn v4 on Base UI (base-nova), lucide, sonner, wavesurfer.js
Data TanStack Query, Router (hash history), Form, Store, Virtual, Pacer
i18n i18next (src/renderer/src/i18n/locales/*.json) — no hardcoded UI text

Run it

# From the repository root
bun install
bun run dev        # electron-vite: main + preload + renderer with HMR

On launch the shell probes http://127.0.0.1:3900. If a backend is already running (for example bun run dev:api from the repo root) it attaches; otherwise it spawns one with uv run uvicorn … from the repo checkout and supervises it (restart on crash, exit code 78 = port already in use). The child's stdin is the liveness signal — closing it makes the backend exit.

Environment knobs: OMNIVOICE_PORT (backend port), VOICESTUDIO_UI_PORT (renderer dev server, default 3902), VOICESTUDIO_SKIP_BACKEND=1 (never spawn, only attach), OMNIVOICE_BACKEND_CMD (argv override, JSON array or whitespace-separated), OMNIVOICE_STARTUP_BUDGET_S (default 300).

Same-origin API

The renderer never fetches 127.0.0.1:3900 directly (no CORS games). It calls app-relative /api/...:

  • dev — the renderer dev server proxies /api to the backend;
  • prod — the renderer is served from the privileged app://voicestudio/ scheme and the main process proxies /api/* with net.fetch.

Quality gates

bun run typecheck   # tsgo, both projects
bun run check:electron # types, tests, build, packaging contract
bun run test        # vitest (jsdom)
bun run build       # electron-vite build → out/
bun run dist        # + electron-builder → release/

The app version is not stored here: electron.vite.config.ts and electron-builder.config.mjs read it from frontend/package.json, the single source of truth.

Layout

src/main/       backend supervisor, app:// protocol + /api proxy, IPC, window
src/preload/    contextBridge → window.voicestudio (typed in index.d.ts)
src/renderer/   React app: routes/, features/clone/, components/, lib/, hooks/
CONTRACT.md     module contracts shared by main, preload and renderer

Cloning workspace

The desktop workspace follows T3 Code's pane composition: a collapsible left sidebar for saved voices and recent takes, an independently scrolling central script canvas with a bottom composer, and an inline right inspector for reference audio and production settings. The inspector resizes by dragging its left divider or using the focused divider's arrow keys; width is remembered locally and clamped to preserve editor space. Opening a task pane leaves the editor usable. Confirmation dialogs remain only for destructive actions. Playback and export appear below the composer after generation.

Layout references: T3 Code's AppSidebarLayout, PreviewPanelShell, RightPanelTabs, and the repository's desktop product screenshot.

The sidebar extends through the native title-bar row. Pane headers provide window drag regions and reserve space for native caption controls; engine status and theme switching live at the foot of the sidebar. The Electron shell imports the canonical Tauri favicon and signal-field artwork directly, and uses the existing Tauri platform icons for its window and installer branding.

Typography uses locally bundled Inter Variable with system UI fallbacks with shared roles: 14px/20px interface text, 13px/20px labels, 12px/16px metadata, and 16px/28px script text. Controls use readable desktop sizing rather than Mira's smallest defaults. Sizes are rem-based and retain native display scaling; the app does not force a zoom factor.

Button and tab contents share centered icon/text alignment and symmetric padding. Standard icons are 16px, compact icons 14px; composer controls align on the same row, with the keyboard shortcut below the primary action. Lucide uses a shared 1.75 stroke weight. Font files ship with the app; typography requires no external font service.

The sidebar settings button opens /settings, a dedicated view with Appearance and General navigation. Theme, Inter/system font, UI scale, and automatic output playback persist locally. Settings remain accessible without a ready backend.

The sidebar footer places engine status and model above a separate Settings and Theme control row, with a labeled Settings link on the left and Theme on the right.

The composer groups language and generation options beside a single primary action. Its shortcut appears inline when the composer has space, and controls wrap in narrow panes.

Settings layout primitives are adapted from T3 Code settingsLayout.tsx, SettingsSidebarNav.tsx, and WorkspacePageContainer.tsx (MIT; see T3CODE-LICENSE.txt). Appearance and General have direct routes and share a breadcrumb header, searchable sidebar, max-w-4xl scroll frame, grouped sections, and consistent setting rows. Sidebar active/hover surfaces use the shared T3 theme tokens.

The local palette library includes VoiceStudio Original, Canopy, Current, Hearth, and Orchid, with upstream light/dark color definitions with VoiceStudio display names from T3 Code (MIT). Each appearance keeps its own selected palette. System mode follows live OS appearance changes; the sidebar toggle explicitly switches to light or dark. Choices persist under voicestudio.theme.v2, migrating the older light/dark setting. Studio restores the neutral palette. Semantic roles drive chrome, sidebar, overlays, controls, text, and waveform colors. No network request is needed to select a theme.

Glass mode is an opt-in, persisted appearance setting for translucent in-app surfaces with palette-tinted background depth. It does not make the native window transparent to the desktop. Reduced-transparency preferences or missing backdrop filter support retain opaque surfaces. voicestudio-classic maps the original Tauri Gruvbox dark palette, with a complementary light variant.

Glass materials use static palette lighting, fine edge highlights, and separate light/dark translucency. Major panes provide blur; nested pane headers reuse it instead of adding another backdrop filter. Classic keeps its original charcoal and rose anchors with refined ivory text, warmer raised surfaces, and softer borders.

Library tabs sit directly on the sidebar, with a highlight on the selected tab and no enclosing segmented-control background.

Classic uses plum-charcoal surfaces, lavender text, and violet glass reflections with the original rose action color.

Workspace interactions

Both library and inspector panes share the same resize behavior: pointer drag, arrow keys on the focused divider, and double-click to reset. Widths, library visibility, selected library tab, and inspector choice persist locally. Escape closes the inspector. Take selection opens details without changing the draft; Reuse explicitly restores the known script, voice, language, and generation parameters. New take parameters are saved locally for the latest 200 results; older history exposes only fields returned by the backend. Uploaded reference files must be attached again when reusing takes without a saved voice profile.

Generation has one provider above routing, so progress/cancellation remain shared and navigating to Settings does not abort a running request. Failures remain visible in the composer; synthesis can be retried. Library queries expose loading and retry states. Ctrl/Cmd+K opens quick search for views, voices, takes, and generation actions; Ctrl/Cmd+, opens Settings. The quick picker supports arrow keys, Enter, and Escape. Settings search jumps to specific controls; Reset restores the current settings section, and font choices preview their own typeface.

Clone readiness is shared by the composer, keyboard shortcut, and command picker. Synthesis stays disabled until the script is nonempty and either an accepted reference file or a loaded saved clone voice with reference audio is selected. Recording/cleanup and file preparation also block submission. Missing inputs show inline guidance with actions to open the reference pane or saved voices; they do not produce error toasts. Server-side validation remains authoritative for files that have been removed or cannot be decoded.

Cloning starts with an inline voice chooser when no usable reference is selected. Saved voices, upload, and recording are available directly in the main content area. A ready voice reveals and focuses the script editor; the composer appears only at that stage. Change voice preserves the draft and can be canceled. An in-flight generation retains its cancellation controls.

Batch dubbing can watch a selected local folder. Existing files are skipped; new videos are queued only after their size and modification time match across two five-second scans. The current language, voice and background settings apply to each arrival. Pause holds future arrivals; Stop or leaving the batch view releases access. Uploads stream through the shared native folder implementation, without loading whole videos into the renderer or sending filesystem paths to the backend. Folder replacement or loss of access stops watching with a message. This requires the native desktop helper; it is not exposed in the web preview.

Gallery > My Imports accepts local audio/video clips and portable voice bundles. URL downloads and video searches run only when submitted. Imported clips can be previewed, removed with confirmation, or saved as a voice and opened in cloning. The more-actions menu adds a voice to Stories or sets the Audiobook default, keeping the current draft. Trim opens an inline waveform editor with a movable selection, exact time fields, zoom and looping preview. Saving creates a separate clip of up to 15 seconds and keeps the original.

Gallery > Community loads the backend-managed community catalogue when opened. Presets can open in Designer; shared voices can be previewed and used in cloning, Stories or Audiobooks. Favorites retain their source identity. Submission buttons open a form in the browser; they do not publish a voice automatically.

Saved voice editor > Export persona downloads a portable .ovsvoice bundle. Include voice clip controls whether the original reference accompanies the watermarked preview. Gallery > My Imports accepts the exported bundle again.

Workspace navigation groups Clone, Design, Profiles, and Gallery under Voice; Stories and Audiobook under Stories; and single/batch dubbing under Dubbing. The current workflow opens automatically. Group buttons can expand or collapse without navigating; the compact rail opens the same destinations in a flyout. Transcribe, Projects, Tools, and Integrations remain directly accessible.