npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

taktus

v0.1.0

Published

The tempo of music and where its beats fall, from the sound itself, for almost nothing. One small WebAssembly module, no dependency.

Readme

taktus

The tempo of music and where its beats fall, from the sound itself, for almost nothing.

One WebAssembly module of 70 KB (28 KB gzipped) inside the package: no dependency, nothing to fetch or to configure, the same in a browser, a worker, an audio worklet or Node. It is the Rust engine built for the web, and runs at about three quarters of its native speed: a second of sound takes about a third of a millisecond to hear.

npm install taktus

A recording

import { Ear, beatsOf, tempoOf } from "taktus";

// Mono samples between -1 and 1, at any rate from 8 kHz up.
const audio = await new AudioContext().decodeAudioData(await (await fetch("song.mp3")).arrayBuffer());
const ear = new Ear(audio.sampleRate);
const onsets = ear.hear(audio.getChannelData(0)); // "how much just started", a hundred values a second

const beat = tempoOf(onsets); // or null, when there is no beat to find
if (beat) {
  console.log(`${beat.bpm.toFixed(1)} beats a minute (sure ${beat.sure.toFixed(2)}, catch ${beat.catch.toFixed(2)})`);
  const beats = beatsOf(onsets, beat.period); // Float64Array: every beat, in seconds from the start
}

sure is how well the onsets keep the beat's period, from 0 to 1; catch is how much of what starts, starts on the beat, where 1 is no more than anywhere else. A reading with sure at 0.05 or more and catch at 1.0 or more was right 97 to 99 times in 100 on the recordings the engine was measured on, counting half and double tempo as right. A tempo and its half or double are the same beats counted at another level: pass beat.period * 2 or beat.period / 2 to beatsOf for the other.

For sound in two channels, hear their mean: left.map((v, i) => (v + right[i]) / 2).

A song as it plays

import { Ear, Follower } from "taktus";

const ear = new Ear(sampleRate);
const follower = new Follower(); // { attentive: true } never rests, and keeps closer to a tempo that wavers

// Every tenth of a second or so, with `now` in seconds on any clock:
function heard(samples, now) {
  if (!follower.listens(now)) {
    ear.reset(); // resting: the sound is not wanted, and its source can be closed
    return;
  }
  if (follower.hear(ear.hear(samples), now)) {
    const beat = follower.beat(); // { bpm, period, at } or null: the time of one beat, on the same clock
    // every other beat is a whole number of periods from `beat.at`
  }
}

The follower listens until two readings agree, says so (ten seconds in, typically), confirms on sixteen seconds, then rests and only looks again now and then. Following a song this way it listens to about a quarter of it. After a seek or a pause, call follower.moved(); for a new song, make a new follower.

Everything

| | | |---|---| | new Ear(sampleRate) | .hear(samples) gives a Float32Array of onsets; .reset() starts over; .free() | | beatOf(onsets) | the beat in 8 to 16 seconds of onsets: { bpm, period, sure, catch, ago } or null | | tempoOf(onsets) | the same for a long stretch: half a minute, a whole song | | beatsOf(onsets, period) | every beat, as a Float64Array of seconds from the start | | beatsAt(onsets, period) | for a tempo known from elsewhere: { catch, ago }, how much its beats catch and how long before the end the last one fell | | new Follower({ attentive }) | .listens(now), .hear(onsets, now), .beat(), .sleeps(now), .moved(), .listened, .free() | | RATE, LEAD | onsets a second (100), and how long after the sound begins the first one comes (0.08 s) |

Samples and onsets may be typed arrays or plain arrays. Types are included. It needs WebAssembly with SIMD: every browser since 2023, Node 18 or later.

How good it is, measured on the field's standard sets and against ten other libraries, is in the main README.

Licence, and credit

Apache License 2.0: free to use, to change and to ship, in anything. It asks for credit: a product that contains this engine keeps its NOTICE where its users can find it, which comes to one line:

This product includes taktus, a tempo and beat engine by Shakib Bin Kabir (https://github.com/shakibbinkabir/taktus).