Too Fast

Too Fast SDK

A small JavaScript library that lets an HTML page follow, and control, the Too Fast desktop app, on Mac and on Windows. Use it to put the speaking pace into your own presentation: turn the slide red when you rush, show a live gauge, start listening when you reach a slide.

It is one file, toofast.js, with no build step and no dependencies. It talks to the desktop app over your local network.

Quick start

  1. Open the Too Fast app on your computer or Windows PC and go to the Phone page. Sharing must be on. Note the pairing code and the computer's address (for example 192.168.1.20).
  2. Add the SDK to your page. The computer serves it, so there is nothing to download:
<script src="http://192.168.1.20:4321/sdk/toofast.js"></script>
<script>
  const tf = new TooFast({ host: '192.168.1.20', code: '123456' });

  tf.on('state', (state) => {
    document.body.dataset.pace = state; // 'fast', 'warn', 'ok', 'listening' or 'idle'
  });
  tf.on('tick', (t) => {
    document.querySelector('#rate').textContent = t.smoothed?.toFixed(1) ?? '–';
  });

  tf.connect();
</script>
  1. Open the page in a browser on any device on the same Wi‑Fi as the computer, start listening in the desktop app (or call tf.start()), and talk.

example.html is a complete working page. Open it as http://COMPUTER-ADDRESS:4321/sdk/example.html?code=123456.

If you would rather keep the file next to your presentation, copy toofast.js there and use <script src="toofast.js">. It only needs to reach the computer over the network.

Pairing

Everything the SDK does needs the pairing code from the desktop app's Phone page. Anyone on the same Wi‑Fi without the code cannot read or control your computer.

Treat the code like a password for your computer's microphone controls. Do not commit it to a public repository or publish a presentation that contains it.

On the same computer

When your presentation runs on the same computer as the Too Fast app, skip the code:

const tf = new TooFast({ host: 'localhost' });
tf.connect();

This works from a page served by localhost or 127.0.0.1 (a local dev server for your slides, for example) and from scripts such as curl. It does not work for a website you have open in your browser: any page can reach localhost from your browser, so the computer only skips the code when the request cannot come from another website. A page loaded from https://example.com still needs the code, even when it talks to localhost, and so does a page opened straight from a file (file://).

Reference

new TooFast(options)

Option Default Meaning
code required, except for localhost Pairing code from the desktop app.
host the host serving the page Address or name of the computer, e.g. 192.168.1.20 or studio-pc.local.
port 4321 (4322 with secure) The port shown on the Phone page.
secure false Use https, see Presentations served over https.

It throws if code is missing and the host is not localhost.

Methods

Method Does
connect() Starts following the computer. Reconnects by itself if the network drops. Returns the client.
disconnect() Stops following.
start() Tells the computer to start listening. Returns a promise.
stop() Tells the computer to stop listening. Returns a promise.
toggle() Starts or stops, depending on what the computer is doing.
on(event, fn) Subscribes to an event. Returns a function that unsubscribes.

start, stop and toggle reject if the computer cannot be reached or refuses the code, so wrap them in try / catch if a failure should not stop your page.

Properties

Property Value
state Current pace state, see below.
rate Smoothed rate in syllables per second, or null.
monitoring true while the computer is listening.
connected true while the connection to the computer is open.
current The latest tick, or null.

Events

Event Fires when Value
tick Every 100 ms while the computer is listening. the reading, see below
state The pace state changes. the new state
fast, warn, ok, listening, idle The pace enters that state. the state
status The computer starts or stops listening, including when someone presses its Stop button. { monitoring, state, profile }
connection The connection opens or closes. true or false
error The computer refuses the code. { type: 'auth' } or { type: 'locked' }

Pace states

State Meaning
idle The computer is not listening, or it hears nothing.
listening Listening, still warming up.
ok At or below your baseline pace.
warn Picking up, between the baseline and the too-fast line.
fast Faster than your target for long enough to count.

How fast is fast depends on the profile set in the desktop app (conversation or presentation) and on your calibration. The SDK reports what the app decided; it does not recalculate it.

The tick reading

{
  smoothed: 3.4,     // the number the gauge shows, syllables per second
  rate: 3.6,         // instantaneous rate, may be null when there is no speech
  state: 'ok',
  speaking: true,    // someone is talking right now
  level: 0.42,       // microphone level, 0 to 1, handy for a VU meter
  syllables: 83,     // syllables counted this session
  speakingMs: 16080, // time spent speaking this session
  thresholds: { baseline: 3.3, warnAt: 3.6, fastAt: 4.0 }, // so you can draw your own gauge
  t: 35200           // milliseconds since listening started
}

thresholds are in syllables per second. They let you scale a gauge without hard-coding numbers.

Recipes

Slide goes red when you are too fast

tf.on('fast', () => document.body.classList.add('too-fast'));
tf.on('ok',   () => document.body.classList.remove('too-fast'));
tf.on('warn', () => document.body.classList.remove('too-fast'));

Start and stop with your slides (reveal.js)

Reveal.on('ready', () => tf.start().catch(console.warn));
Reveal.on('slidechanged', (e) => {
  if (e.currentSlide.dataset.pace === 'off') tf.stop();
  else if (!tf.monitoring) tf.start();
});

A progress bar for the pace

tf.on('tick', (t) => {
  const { baseline, fastAt } = t.thresholds;
  const share = Math.min(1, (t.smoothed ?? 0) / (fastAt * 1.5));
  bar.style.width = `${share * 100}%`;
  bar.style.background = t.state === 'fast' ? 'crimson' : t.state === 'warn' ? 'orange' : 'seagreen';
});

Say so when it is not working

tf.on('connection', (ok) => status.textContent = ok ? 'Connected' : 'Looking for the computer…');
tf.on('error', (e) => status.textContent =
  e.type === 'auth' ? 'Wrong pairing code' : 'Too many tries, wait a minute');

As a module or with a bundler

const { TooFast } = require('./toofast.js');

Presentations served over https

A page loaded over https (a hosted deck, for example) is not allowed to call plain http addresses. Use the computer's secure address instead. It is the port after the normal one, with a certificate made on the computer:

const tf = new TooFast({ host: '192.168.1.20', secure: true, code: '123456' });

Before the first use, open https://192.168.1.20:4322/ once in the same browser and accept the certificate warning. Pages opened from a local file or from http do not need any of this.

Troubleshooting