monotonous.org

speechSynthesis.getVoices()

Half of the DOM Web Speech API deals with speech synthesis. There is a method called speechSynthesis.getVoices that returns a list of all the supported voices in the given browser. Your website can use it to choose a nice voice to use, or present a menu to the user for them to choose.

The one tricky thing about the getVoices() method is that the underlying implementation will usually not have a list of voices ready when first called. Since speech synthesis is not a commonly used API, most browsers will initialize their speech synthesis lazily in the background when a speechSynthesis method is first called. If that method is getVoices() the first time it is called it will return an empty list. So what will conventional wisdom have you do? Something like this:

function getVoices() {
  let voices = speechSynthesis.getVoices();
  while (!voices.length) {
    voices = speechSynthesis.getVoices()
  }

  return voices;
}

If synthesis is indeed not initialized and first returns an empty list, the page will hang in an infinite CPU-bound loop. This is because the loop is monopolizing the main thread and not allowing synthesis to initialize. Also, an empty voice list is a valid value! For example, Chrome does not have speech synthesis enabled on Linux and will always return an empty list.

So, to get this working we need to not block the main thread by making asynchronous calls to getVoices, we should also have a limit on how many times we attempt to call getVoices() before giving up, in the case where there are indeed no voices:

async function getVoices() {
  let voices = speechSynthesis.getVoices();
  for (let attempts = 0; attempts < 100; attempts++) {
    if (voices.length) {
      break;
    }

    await new Promise(r => requestAnimationFrame(r));
    voices = speechSynthesis.getVoices();
  }

  return voices;
}

But that method still polls, which isn’t great and is needlessly wasteful. There is another way to do it. You could rely on the voiceschanged DOM event that will be fired once synthesis voices become available. We will also add a timeout to that so our async method returns even if the browser never fires that event.

  async function getVoices() {
    const GET_VOICES_TIMEOUT = 2000; // two second timeout

    let voices = window.speechSynthesis.getVoices();
    if (voices.length) {
      return voices;
    }

    let voiceschanged = new Promise(
      r => speechSynthesis.addEventListener(
        "voiceschanged", r, { once: true }));

    let timeout = new Promise(r => setTimeout(r, GET_VOICES_TIMEOUT));

    // whatever happens first, a voiceschanged event or a timeout.
    await Promise.race([voiceschanged, timeout]);

    return window.speechSynthesis.getVoices();
  }

You’re welcome, Internet!

HTML AQI Gauge

I needed a meter to tell me what the air quality is like outside. Now I know!

If you need one as well, or if you are looking for an accessible gauge for anything else, here you go.

You can also mess with it on Codepen.

This is how I surf the Internet

tab bar with a bunch of new tabs

Aside from a handful of pinned tabs, I open a new tab for anything I need to do: search the web, file a bug, look up documentation, check on the news, the weather, you get the idea. I am also addicted to Firefox’s new tab page, so I’ll often open a new tab out of boredom to let Pocket suggest an article for me. I hardly ever look at the same tab twice. If I need to get to something, it is never worth digging through all those tabs, I’ll just type what I am looking for in a new tab, and hope for a good suggestion from the awesomebar. After a couple of days I’ll have hundreds of tabs open. I declare “tab bankruptcy”, I purge them all, and start over.

A while ago I made an addon for myself. It was essentially a tab FIFO. It would only allow 10 tabs to be open at a time. If an 11th tab was created, the least recently activated tab would be closed.

Throttle Tabs popup

I came to think what if I am not the only person who abuses tabs in this way? What if there are other poor souls out there with hundreds or even thousands of open tabs. Are they waiting for Marie Kondo to hold their hand while they deliberate each tab before they discard it?

So I decided to polish my addon a bit, give it a UI, and put it up on AMO. Since users might not trust an addon that automatically closes tabs, I decided to add an “overflow” feature which is essentially tab purgatory. Instead of having the addon auto-close the tab, it hides it. The tab is still accessible via the addon’s popup, Firefox’s “Hidden Tabs” submenu, or through tab search in the awesomebar. The overflow can be capped too so it can permanently discard old tabs after a given limit.

Revamping Firefox’s Reader Mode this Summer

This is cross-posted from a Medium article by Akshitha Shetty, a Summer of Code student I have been mentoring. It’s been a pleasure and I wish her luck in her next endeavor!

For me, getting all set to read a book would mean spending hours hopping between stores to find the right lighting and mood to get started. But with Firefox’s Reader Mode it’s now much more convenient to get reading on the go. And this summer, I have been fortunate to shift roles from a user to a developer for the Reader Mode . As I write this blog, I have completed two months as a Google Summer of Code student developer with Mozilla. It has been a really enriching experience and thus I would like to share some glimpses of the project and my journey so far.

Motivation behind choosing this organization and project

I began as an open-source contributor to Mozilla early this year. What really impressed me was how open and welcoming Mozillians were. Open-source contribution can be really intimidating at first. But in my case, the kind of documentation and direction that Mozilla provided helped me steer in the right direction really swiftly. Above all, it’s the underlying principle of the organization — “people first” that truly resonated with me. On going through the project idea list, the “Firefox Reader Mode Revamp” was of great interest to me. It was one of the projects where I would be directly enhancing the user-experience for Firefox users and also learning a lot more about user-experience and accessibility in the process.

Redesign of the Reader mode in making

The new design of the reader mode has the following features -

  1. A vertical toolbar is to replaced by a horizontal toolbar so that it is the sync with the other toolbars present in Firefox.
  2. The toolbar is now being designed so that it complies with the Photon Design System (the latest design guidelines proposed by the organization).
  3. The accessibility of the Reader Mode is being improved by making it keyboard friendly.
Mock-up for Reader Mode Redesign

Thanks to Abraham Wallin for designing the new UI for the Reader mode.

Get Set Code

Once the design was ready, I began with the coding of the UI. I thoroughly enjoyed the process and learnt a lot from the challenges I faced during this process. One of the challenges I faced during this phase was to make the toolbar adjust it’s width as per the content width of the main page. This required me to refactor certain portions of the existing code base as well make sure the newly coded toolbar follows the same.

To Sum it all up

All in all, it has been a really exciting process. I would like to thank my mentor — Eitan Isaacson for putting in the time and effort to mentor this project. Also I would like to thank — Gijs Kruitbosch and Yura Zenevich for reviewing my code at various points of time.

I hope this gets you excited to see the Reader Mode in its all new look ! Stay tuned for my next blog where I will be revealing the Revamped Reader Mode into action.