Too Fast

Too Fast SDK

A small JavaScript library that lets an HTML page follow, and control, the Too Fast Mac app. 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 Mac app over your local network.

Quick start

  1. Open the Too Fast Mac app and go to the Phone page. Sharing must be on. Note the pairing code and the Mac's address (for example 192.168.1.20).
  2. Add the SDK to your page. The Mac 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 Mac, start listening in the Mac app (or call tf.start()), and talk.

example.html is a complete working page. Open it as http://MAC-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 Mac over the network.

Pairing

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

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

On the same Mac

When your presentation runs on the same Mac 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 Mac 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 Mac app.
host the host serving the page Address or name of the Mac, e.g. 192.168.1.20 or MecBook-Pro.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 Mac. Reconnects by itself if the network drops. Returns the client.
disconnect() Stops following.
start() Tells the Mac to start listening. Returns a promise.
stop() Tells the Mac to stop listening. Returns a promise.
toggle() Starts or stops, depending on what the Mac is doing.
on(event, fn) Subscribes to an event. Returns a function that unsubscribes.

start, stop and toggle reject if the Mac 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 Mac is listening.
connected true while the connection to the Mac is open.
current The latest tick, or null.

Events

Event Fires when Value
tick Every 100 ms while the Mac 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 Mac 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 Mac refuses the code. { type: 'auth' } or { type: 'locked' }

Pace states

State Meaning
idle The Mac 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 Mac 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 Mac…');
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 Mac's secure address instead. It is the port after the normal one, with a certificate made on the Mac:

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