Skip to content

Repository files navigation

OpenWebTTS

A free, open-source text-to-speech web reader for Firefox (Android-first) and Chrome. It reads web pages aloud — generic HTML articles, reader-mode pages, and PDFs — with a page-integrated accordion overlay, prev/next chunk navigation with smart-back, a char-weighted skip-to-section slider with heading markers, saved voice/speed settings, and configurable as-you-read highlighting (off | paragraph | sentence).

Built from scratch in TypeScript. Logic is ported from Read Aloud (MIT) with attribution — this is not a fork.

Status

Greenfield, under active development.

Project structure

Svelte-equivalent of Bulletproof React, under src/lib/:

  • features/<feature>/ — feature slices, each with an index.ts public barrel (+page.svelte / +component.svelte for UI); internal files are private to the feature.
  • components/ui/ — shadcn-svelte primitives (added via the shadcn-svelte CLI).
  • server/ — background / offscreen logic.
  • shared/ — cross-feature types and utilities (src/lib/utils.ts holds the shadcn cn helper).

Dev commands

Command What it does
pnpm dev extension dev — load the extension in a fresh browser profile.
pnpm build extension build — production artifacts.
pnpm check vp check — format + lint + type-aware checks.
pnpm test vp test — Vitest.
pnpm test:coverage vp test --coverage — Vitest with the coverage gate.
pnpm test:e2e Playwright E2E — loads the built extension.
pnpm lint / pnpm lint:fix standalone Oxlint.

Testing

Vitest (bundled in Vite+) is the unit + integration runner; Playwright drives E2E against the built extension. Vitest is configured in the test block of vite.config.ts; Playwright in playwright.config.ts.

Unit vs. integration

  • Unit tests live next to the source as src/lib/**/*.test.ts. Each tests one module through its public surface; browser globals (chrome, speechSynthesis, SpeechSynthesisUtterance) are faked on globalThis so the test stays fast and deterministic in the jsdom environment without a real browser.
  • Integration tests live in tests/ and assert cross-module or build-output contracts — e.g. tests/manifest.test.ts guards the cross-browser manifest produced by Extension.js.

Commands

  • pnpm testvp test, runs the whole unit + integration suite once.
  • pnpm test watchvp test watch for red→green iteration.
  • pnpm test:coveragevp test --coverage, runs the suite with the coverage gate.
  • pnpm test:e2e — Playwright E2E; loads the built extension and drives the overlay (see playwright.config.ts and e2e/).

Coverage gate

Coverage is measured over src/lib (product code only; test files and public barrels are excluded) with the v8 provider. The gate, set in vite.config.ts test.coverage.thresholds, requires ≥80% of lines, branches, functions, and statements. The gate runs only when coverage is enabled (pnpm test:coverage); pnpm test alone stays green.

Cross-browser targets & Android

A single src/manifest.json drives every target. Browser-specific fields use Extension.js prefixed keys (chromium: for Chrome/Edge, firefox: for Firefox/Gecko) that are filtered per build into dist/chrome and dist/firefox.

Target Build Dev load
Chrome pnpm build:chrome pnpm exec extension dev --browser chrome
Firefox pnpm build:firefox pnpm exec extension dev --browser firefox

Manifest notes:

  • Chrome (MV3) declares offscreen + storage permissions and <all_urls> host permissions; the offscreen document hosts the WASM Piper audio pipeline. Firefox has no chrome.offscreen — its event-page background already has DOM access — so offscreen is Chromium-only.
  • Firefox (MV3) declares tabs, <all_urls>, storage permissions and a browser_specific_settings.gecko_android.strict_min_version (120.0) so AMO lists the add-on for Firefox for Android as well as desktop. gecko.id is @openwebtts.
  • The toolbar icon activates the in-page overlay (the sole UI surface) on both targets: action.onClickedtabs.sendMessage({ type: "openwebtts:activate" }) → the content script renders the overlay. There is no side panel or sidebar.

Firefox for Android dev loop

Firefox for Android is the primary target. Development on a connected Android device/emulator is via manual web-ext sideload (Playwright does not drive Android):

  1. Build the Firefox artifact: pnpm build:firefox.
  2. Install web-ext (pnpm add -g web-ext).
  3. Push and load it on a USB-debug-enabled device/emulator: web-ext run --target=firefox-android --source=dist/firefox --adb-device <device-id>.

Release install on Android is via AMO signing: submit dist/firefox to addons.mozilla.org, then install from the device's Firefox Add-ons listing.

Attribution

OpenWebTTS reuses the following free/open-source software:

  • Read Aloud — by Hai Phan, MIT License, Copyright (c) 2016 Hai Phan. Foundational reference; TTS/extraction logic ported with attribution.
  • Mozilla Readability (@mozilla/readability) — article text extraction. Apache-2.0.
  • pdf.js (pdfjs-dist) — PDF text extraction. Apache-2.0.
  • Piper / VITS — on-device neural TTS (WASM fallback engine). Piper voice models are CC-BY; each model is attributed individually.
  • shadcn-svelte — overlay UI primitives. MIT.
  • wikimedia sentencex — sentence segmentation (WASM build) for sentence-granularity highlighting. MIT.

Built with

  • Extension.js — cross-browser extension builder (extension dev / extension build).
  • Vite+ (vite-plus) — unified lint/format/test toolchain (vp check, vp test).
  • Oxlint — linter (replaces ESLint).
  • Oxfmt — formatter (replaces Prettier), with sortImports, sortTailwindcss, sortPackageJson.

License

MIT — see LICENSE. Reused components retain their original licenses (noted above); Piper voice models are CC-BY.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages