Installation
Pleco-Xa ships as a single, zero-dependency ES module. There is nothing to compile and nothing to pull in behind it: the entire library — BPM and beat tracking, spectral features, structural analysis, and its signature loop detection — is plain JavaScript that runs the same in Node and in the browser.
npm install pleco-xaimport { beat_track, loop, feature } from 'pleco-xa'The package is pure ESM ("type": "module") and has no runtime
dependencies — installing it adds exactly one entry to your tree. It works with
any modern bundler (Vite, esbuild, Rollup, webpack) and with Node’s native ESM
loader; no plugin or loader configuration is required.
Because it is native ESM, you can import Pleco-Xa straight from a CDN with no
build step — a bare <script type="module"> is enough.
<script type="module"> import { beat_track, loop } from 'https://cdn.jsdelivr.net/npm/pleco-xa@2.0.3/dist/pleco-xa.js' // ...</script>The unpkg mirror works the same way, and a minified build is available beside the main bundle:
// unpkgimport * as pleco from 'https://unpkg.com/pleco-xa@2.0.3/dist/pleco-xa.js'
// minified build (either CDN)import * as pleco from 'https://cdn.jsdelivr.net/npm/pleco-xa@2.0.3/dist/pleco-xa.min.js'One import, two runtimes
Section titled “One import, two runtimes”The core analysis functions are deliberately runtime-blind. They take a mono
signal as a Float32Array (a plain number[] works too) plus a sample rate,
and return plain arrays or typed arrays — arrays in, arrays out. There is no
AudioContext, no DOM, and no window on that path:
import { beat_track, feature } from 'pleco-xa'
// y: Float32Array of mono samples, sr: sample rate in Hzconst { tempo, beats } = beat_track(y, sr)const mel = feature.melspectrogram(y, { sr }) // Array<Float32Array>, [freq][time]The exact same import line and the exact same call run in Node and in the
browser — that is the point. Where a function genuinely needs the host (playing
sound, reading a File, drawing to a <canvas>), it lives in a browser-facing
namespace and says so.
Loading audio in the browser
Section titled “Loading audio in the browser”beat_track and friends want samples, not files. To turn a URL or a File into
a signal, use one of the decoding entry points:
loadAudioFile(url)— fetches and decodes to a realAudioBuffervia the Web Audio API. Returns{ audioBuffer, audioContext, arrayBuffer }. This is the buffer theloopnamespace consumes directly.audioio.load(url, { sr, mono })— fetches and decodes to{ y, sr }(aFloat32Arrayand its sample rate), resampling tosrif you ask. This is the fast path to the(y, sr)core.decodeWav(arrayBuffer)— pure-JS WAV decoder (PCM 16/24/32-bit int and 32-bit float). Returns{ channels, sampleRate }and runs identically in Node, the browser, and workers — noAudioContextrequired.
import { loadAudioFile, beat_track, loop } from 'pleco-xa'
const { audioBuffer } = await loadAudioFile('/audio/break.wav')const y = audioBuffer.getChannelData(0)const sr = audioBuffer.sampleRate
const { tempo } = beat_track(y, sr) // (Float32Array, sr) coreconst result = await loop.detect(audioBuffer) // AudioBuffer-like inIn Node, decodeWav covers WAV out of the box; for other codecs, decode with a
library of your choice and hand the resulting samples to the (y, sr) core.
Requirements
Section titled “Requirements”Node. Version 18 or newer (declared in engines). Nothing else — no
native add-ons, no node-gyp, no system libraries.
Browsers. Any evergreen browser with ES module support and, for the audio I/O and playback layers, the Web Audio API:
| Browser | Notes |
|---|---|
| Chrome / Edge | Full support (desktop and Android) |
| Firefox | Full support |
| Safari | Full support (macOS and iOS) |
The pure (y, sr) analysis core needs only ES modules, so it runs anywhere
modern JavaScript does — including Web Workers and audio worklets. The
AudioContext-backed helpers (loadAudioFile, audioio.play, LoopPlayer,
the canvas display layer) require a browser.
Next steps
Section titled “Next steps”With the package installed, head to the Quickstart to load a clip, track its tempo, and find its loop in a dozen lines.