{"id":20482065,"url":"https://github.com/leaonline/easy-speech","last_synced_at":"2025-04-12T23:34:32.229Z","repository":{"id":37387075,"uuid":"432159293","full_name":"leaonline/easy-speech","owner":"leaonline","description":"🔊 Cross browser Speech Synthesis also known as Text to speech or TTS; no dependencies; uses Web Speech API","archived":false,"fork":false,"pushed_at":"2025-02-01T11:33:20.000Z","size":1171,"stargazers_count":227,"open_issues_count":18,"forks_count":24,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-12T23:34:17.197Z","etag":null,"topics":["browser","cross-browser","hacktoberfest","hacktoberfest-accepted","javascript","js","speech-synthesis","standards","text-to-speech","tts","web","web-speech-api"],"latest_commit_sha":null,"homepage":"https://leaonline.github.io/easy-speech/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/leaonline.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["jankapunkt"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":["https://paypal.me/kuesterjan"]}},"created_at":"2021-11-26T11:46:09.000Z","updated_at":"2025-04-03T23:22:26.000Z","dependencies_parsed_at":"2022-08-03T04:46:22.032Z","dependency_job_id":"6e94a829-6b5b-4eec-add9-c7cdf712e6bd","html_url":"https://github.com/leaonline/easy-speech","commit_stats":{"total_commits":220,"total_committers":5,"mean_commits":44.0,"dds":0.4545454545454546,"last_synced_commit":"86ad9c66b579854835bf305661c88cfc3aa66c91"},"previous_names":["leaonline/easy-speech"],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leaonline%2Feasy-speech","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leaonline%2Feasy-speech/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leaonline%2Feasy-speech/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leaonline%2Feasy-speech/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/leaonline","download_url":"https://codeload.github.com/leaonline/easy-speech/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248647259,"owners_count":21139081,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["browser","cross-browser","hacktoberfest","hacktoberfest-accepted","javascript","js","speech-synthesis","standards","text-to-speech","tts","web","web-speech-api"],"created_at":"2024-11-15T16:11:19.445Z","updated_at":"2025-04-12T23:34:32.195Z","avatar_url":"https://github.com/leaonline.png","language":"JavaScript","funding_links":["https://github.com/sponsors/jankapunkt","https://paypal.me/kuesterjan"],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eEasy Speech\u003c/h1\u003e\n\n\u003cdiv align=\"center\"\u003e\nCross browser Speech Synthesis; no dependencies.\n\u003c/div\u003e\n\n  \u003cp align=\"center\"\u003e\n    \u003cbr /\u003e\n    \u003ca href=\"https://github.com/leaonline/easy-speech/blob/master/API.md\"\u003e\u003cstrong\u003eAPI docs »\u003c/strong\u003e\u003c/a\u003e\n    \u003cbr /\u003e\n  \u003c/p\u003e\n\n\n[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)\n[![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active)\n[![Test suite](https://github.com/leaonline/easy-speech/actions/workflows/tests.yml/badge.svg)](https://github.com/leaonline/easy-speech/actions/workflows/tests.yml)\n[![CodeQL Semantic Analysis](https://github.com/leaonline/easy-speech/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/leaonline/easy-speech/actions/workflows/codeql-analysis.yml)\n![npm](https://img.shields.io/npm/v/easy-speech)\n![npm bundle size](https://img.shields.io/bundlephobia/min/easy-speech)\n![npm bundle size](https://img.shields.io/bundlephobia/minzip/easy-speech)\n[![DOI](https://zenodo.org/badge/432159293.svg)](https://zenodo.org/doi/10.5281/zenodo.10816462)\n\n\n## ⭐️ Why EasySpeech?\n\nThis project was created, because it's always a struggle to get the synthesis\npart of `Web Speech API` running on most major browsers.\n\n## ✨ Features\n\n- 🪄 Single API for using `speechSynthesis` across multiple browsers\n- 🌈 Async API (Promises, async/await)\n- 🚀 Hooks for all events; global and/or voice-instance-specific\n- 🌱 Easy to set up and integrate: auto-detects and loads available voices\n- 🔧 Includes fixes or workarounds for many browser-specific quirks\n- 📝 Internal logging via `EasySpeech.debug` hook\n- 📦 Multiple build targets\n- 🎮 Live demo to test your browser\n \n\n**Note:** this is not a polyfill package, if your target browser does not  support speech synthesis or the Web Speech\nAPI, this package is not usable.\n\n\n## 🚀 Live Demo\n\nThe live demo is available at https://leaonline.github.io/easy-speech/\nYou can use it to test your browser for `speechSynthesis` support and functionality.\n\n[![live demo screenshot](./docs/demo_screenshot.png)](https://leaonline.github.io/easy-speech/)\n\n## Table of Contents\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n**Table of Contents**  *generated with [DocToc](https://github.com/thlorenz/doctoc)*\n\n- [📦 Installation](#-installation)\n- [👨‍💻 Usage](#-usage)\n  - [🚀 Initialize](#-initialize)\n  - [📢 Speak a voice](#-speak-a-voice)\n  - [😵‍💫 Troubleshooting / FAQ](#-troubleshooting--faq)\n- [🔬 API](#-api)\n- [⌨️ Contribution and development](#-contribution-and-development)\n- [📖 Resources](#-resources)\n- [⚖️ License](#-license)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## 📦 Installation\n\nInstall from npm via\n\n```bash\n$ npm install easy-speech\n``` \n\nYou can also use the various builds for different targets, see the `dist` folder:\n\n- `/dist/EasySpeech.js` - ESM\n- `/dist/EasySpeech.cjs.js` - CommonJs \n- `/dist/EasySpeech.es5.js` - Legacy node compatible\n- `/dist/EasySpeech.iife.js` - Legacy compatible build, works even with older \n  or exotic browsers, as long as they support Promises (PRs welcome to transform \n  to callbacks!)\n- `/dist/index.d.ts` - TypeScript type definitions\n\nYou can use them via CDN:\n\n```html\n\u003c!-- esm --\u003e\n\u003cscript type=\"module\"\u003e\n  import easySpeech from 'https://cdn.jsdelivr.net/npm/easy-speech/+esm'\n\u003c/script\u003e\n```\n\n```html\n\u003c!-- classic --\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/easy-speech/dist/EasySpeech.iife.js\"\u003e\u003c/script\u003e\n```\n\n## 👨‍💻 Usage\n\nImport `EasySpeech` and first, detect, if your browser is capable of tts (text\nto speech):\n\n```javascript\nimport EasySpeech from 'easy-speech'\n\nEasySpeech.detect()\n```\n\nit returns an Object with the following information:\n\n```javascript\n{\n  speechSynthesis: SpeechSynthesis|undefined,\n  speechSynthesisUtterance: SpeechSynthesisUtterance|undefined,\n  speechSynthesisVoice: SpeechSynthesisVoice|undefined,\n  speechSynthesisEvent: SpeechSynthesisEvent|undefined,\n  speechSynthesisErrorEvent: SpeechSynthesisErrorEvent|undefined,\n  onvoiceschanged: Boolean,\n  onboundary: Boolean,\n  onend: Boolean,\n  onerror: Boolean,\n  onmark: Boolean,\n  onpause: Boolean,\n  onresume: Boolean,\n  onstart: Boolean\n}\n```\n\nIf at least `SpeechSynthesis` and `SpeechSynthesisUtterance` are defined you\nare good to go.\n\n\n### 🚀 Initialize\n\nPreparing everything to work is not as clear as it should, especially when \ntargeting cross-browser functionality. The asynchronous init function will help\nyou with this situation:\n\n```javascript\nEasySpeech.init({ maxTimeout: 5000, interval: 250 })\n    .then(() =\u003e console.debug('load complete'))\n    .catch(e =\u003e console.error(e))\n``` \n\n#### 💽 Loading voices\n\nThe init-routine will go through several stages to setup the environment:\n\n- detect and that SpeechSynthesis is basically supported, if not -\u003e fail\n- load voices directly\n- if not loaded but `onvoiceschanged` is available: use `onvoiceschanged`\n- if `onvoiceschanged` is not available: fallback to timeout\n- if `onvoiceschanged` is fired but no voices available: fallback to timeout\n- timeout reloads voices in a given `interval` until a `maxTimeout` is reached\n- if voices are loaded until then -\u003e complete\n- if no voices found -\u003e fail \n\nIf your init routing has still not detected / loaded any voices, allthough\nspeechSynth is supported please leave an issue!\n\n#### Placing a fallback voice\n\nIf voices are found it will place a fallback voice by the following rules:\n\n- If there is a voice among all voices with the `default` property set to true\n  use this as fallback voice\n- Otherwise find the first matching voice by current `navigator.language`\n- Otherwise use the first voice in the Array\n\nNote: This fallback voice is not overridden by `EasySpeech.defaults()`, your\ndefault voice will be used in favor but the fallback voice will always be there\nin case no voice is found when calling `EasySpeech.speak()`\n\n### 📢 Speak a voice\n\nThis is as easy as it gets:\n\n```javascript\nawait EasySpeech.speak({\n  text: 'Hello, world!',\n  voice: myLangVoice, // optional, will use a default or fallback\n  pitch: 1,\n  rate: 1,\n  volume: 1,\n  // there are more events, see the API for supported events\n  boundary: e =\u003e console.debug('boundary reached')\n})\n```\n\nThe Promise will automatically resolve when the speaking ends or rejects when\nan error occurred. You can additionally attach these event listeners if you like\nor use `EasySpeech.on` to attach default listeners to every time you call \n`EasySpeech.speak`.\n\n### 😵‍💫 Troubleshooting / FAQ\n\nThere is an own [FAQ section](./FAQ.md) available that aims to help with common issues.\n\n## 🔬 API\n\nThere is a full API documentation available: [api docs](./API.md)\n\n## ⌨️ Contribution and development\n\nEvery contribution is welcomed, please open issues if anything is not working\nas expected.\n\nIf you intend to contribute code, please read the \n[guidelines on contributing](./CONTRIBUTING.md).\n\n## 📖 Resources\n\nThis project used several resources to gain insights about how to get the best cross-browser SpeechSynthesis running:\n\n- https://wicg.github.io/speech-api/#tts-section\n- https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis\n- https://gist.github.com/alrra/6741915\n- https://github.com/ubershmekel/audio-language-tests\n- https://stackoverflow.com/questions/33889107/speech-synthesis-in-chrome-for-android-not-loading-voices\n- https://stackoverflow.com/questions/49506716/speechsynthesis-getvoices-returns-empty-array-on-windows\n- https://stackoverflow.com/questions/21947730/chrome-speech-synthesis-with-longer-texts\n- https://stackoverflow.com/a/34130734\n- https://stackoverflow.com/a/68060634\n- https://stackoverflow.com/a/48056986\n- https://bugs.chromium.org/p/chromium/issues/detail?id=582455\n- https://stackoverflow.com/a/65883556\n\n## ⚖️ License\n\nMIT, see [license file](./LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleaonline%2Feasy-speech","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleaonline%2Feasy-speech","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleaonline%2Feasy-speech/lists"}