Creating an English Pronunciation mini-game with Svelte!
Tags: svelte, webdev, programming, javascript
Published: 2022-04-26 22:50:50

Link to Repo: [Here](https://github.com/LLxD/test-your-speech)
See it live: [Here](https://llxd.github.io/test-your-speech/)

Currently, the game is only with Portuguese (pt-BR) UI, but I hope that even with this, you can still use it to test and play a little!

The mini-game works by showing you a random English word and listening for the user pronunciation for a single word. If they match, the user gets a point and receives a new word, if they don't match, the user doesn't get the point.

This was my second project with Svelte and I'm going to show a little bit of the process of how I developed it.

I started with the basic Svelte template with Vite that you can look further how to setup [here](https://svelte.dev/).

The game only has one major component (and it's probably not the most organized way to do this, but it was a 3 hour project).

I divided this project into a few minor steps, to make it easier to get going. These minor steps are:

- Fetch a random english word
- Display the english word on the user's screen
- Listen for the user pronunciation of a single word
- Check if they match and increase the score counter if they do

So, for the first step (fetch a random english word), I found an API on the internet that could bring me the data I wanted (in this case, random english words). I used this API [here](https://random-word-api.herokuapp.com).

Then, I constructed my basic fetch mechanism:
```js
let word;
let loadWord = () => {
    return fetch(`https://random-word-api.herokuapp.com/word?number=1`)
      .then((r) => r.json())
      .then((data) => {
        word = data[0];
      });
  };
```
 

And that's it, we are all set for the first step. Going to the next, the native reactivity of Svelte would handle the process of re-render, so we are all set for that too.

Now comes a huge step: getting the user pronunciation for a single word. For that, I used the [Webkit Speech Recognition API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API/Using_the_Web_Speech_API).
It's really straight forward, you basically create a new instance of the webkitSpeechRecognition() and use it to gather the things you want! I also encapsulated all of this into a function, so the user can click a button to start the game later on.
```js

const start = () => {
    const recognition = new webkitSpeechRecognition();
    recognition.interimResults = false;
    recognition.lang = "en-US";
    recognition.continuous = false;
    recognition.start();
    // This event happens when you talk in the microphone
    recognition.onresult = function (event) {
      const content = event.results[0][0].transcript.trim();
      output = content;
    };
    recognition.onspeechend = () => {
      setTimeout(() => checkResult(word, output), 800);
      setTimeout(() => startGame(), 2000);
    };
  };

```

Besides that, we still need to clean the word the user said of all punctuation signs and other junk that can be gathered with this API, since it also detects intonation and more things like that.
For that, a simple cleaning function should work:
```js
const clean = (word) => {
const cleanedWord = word
      .toString()
      .toLowerCase()
      .replace(/\s+/g, "")
      .replace(/[.,\/#!$%\^&\*;:{}=\-_`~()?']/g, "");
    return cleanedWord;
  };
```

After our words are clean and we are gathering our speech from the user, the last step is just to compare these and increase the score.

```js
  const checkResult = (loadedWord, listenedWord) => {
    if (clean(listenedWord).includes(clean(loadedWord))) {
      correct = true;
      setTimeout(() => (correct = false), 2000);
      coinSound.play();
      count++;
    }
  };

```

Finally, to make our UI, I simply rendered a few phrases conditionally based on whether the word has already been loaded or not. Easy enough in Svelte:

```html

<div class="container">
  {#if word === undefined}
    <h1>Vamos jogar!</h1>
  {:else if gameStart}
    <h1>{clean(word)}</h1>
  {/if}
  {#if output === ""}
    <h1>Começar!</h1>
  {:else}
    <h1>{clean(output)}</h1>
  {/if}
  {#if correct}
    <h2>Você acertou!</h2>
  {/if}
  {#if count !== 0}
    <h2>Acertos: {count}</h2>
  {/if}
</div>
{#if !gameStart}
  <button on:click={startGame}> Vamos lá! </button>
{/if}
```

And that's it! Our English pronunciation mini-game it's done! You can actually improve this a lot by creating more languages for the UI, or simply a tracker of the highest score achieved for example!

I hope this was enlightening for you, and that's all folks.