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

alkove

v0.4.2

Published

On-device voice input for the web: keep the user's voice, detect speech and wake words. No server, no key.

Readme

alkove

On-device voice input for the web: keep the user's voice and drop the rest, detect speech, hear a wake word, recognize a voice. Everything runs in the browser, in WebAssembly. No server, no key, no telemetry.

Preview (0.x). A minor version (0.2, 0.3) may break the API until 1.0; a patch never does. See stability and the changelog.

Read this first. Alkove is made for a near microphone and one person: a phone, a headset, a laptop in front of you. It keeps the closest voice (or the voice of a print) and removes the others, so on a room microphone in the middle of a meeting table it removes the other participants. Audio is processed at 16 kHz: the output carries speech up to 8 kHz ("HD voice", not full band).

Install

npm install alkove

ESM only, no runtime dependency (the engine, Alkove's own, is bundled). Works without COOP/COEP headers: no SharedArrayBuffer, no threads.

A call (WebRTC)

import { createCallInput } from 'alkove'

const input = await createCallInput({ learn: true, farEnd: remoteTrack })
pc.addTrack(input.track)
input.bind(pc.getSenders()[0]) // the SDK swaps in the raw mic if the audio clock stalls
input.on('voiceprint', (p) => localStorage.setItem('print', JSON.stringify(p.toJSON())))

Out goes the user's voice only, gated between sentences, at a steady level. With learn: true, the user's print is learned while they talk (about 6 s of their voice), then only their voice goes out.

A voice agent (speech to text, LLM)

import { createAgentInput } from 'alkove'

const input = await createAgentInput({ farEnd: 'manual', output: { format: 's16', rate: 24000 } })
input.on('audio', (pcm) => ws.send(pcm)) // continuous, 32 ms packets
input.on('utterance', ({ pcm }) => transcribe(pcm)) // one segment per sentence, 300 ms of pre-roll included
input.farEndActive(true) // the agent starts speaking; false when it stops

Nothing is cut: audio is continuous, speechstart / speechend tell where the user speaks.

  • near: true: a voice 10 dB under the user's, a colleague across the room or a video on another device, opens no phrase. No voiceprint: it goes by loudness.
  • input.listen(false) mutes (the phrase under way comes as speechcancel), input.hold() / input.release() hold to talk.
  • await input.ready once the models run; a quiet microphone is brought up before Focus by itself.

A wake word

import { createWakeListener, Spot } from 'alkove'

const word = await Spot.compile('Camille', { lang: 'fr' }) // or enroll it: Spot.enroll('Camille', { lang: 'fr' })
const wake = await createWakeListener({ words: [word] })
wake.on('wake', ({ word, start, audio }) => …)

Any word, typed in one of 7 languages (fr, en, es, it, pt, ca, ro). By default it counts only after a pause (far fewer false alarms; "Bon, Camille, on y va ?" does not wake it, use context: 'both' for that). Enrolling the word (the user says it 3 times) sets its thresholds on their voice. onlyMyVoice: print ignores other voices.

React

import { useAgentInput } from 'alkove/react'

const { status, error } = useAgentInput({ enabled: on, on: { utterance: ({ pcm }) => transcribe(pcm) } })

useAgentInput, useCallInput and useWakeListener take the options of their function, plus enabled and on. The input opens with the component and closes with it, strict mode and Next.js included. The React guide; two apps in examples (Next.js, Vite).

Files, offline

import { Alkove } from 'alkove'

const r = await Alkove.process(file, { focus: true, cue: true })
r.audio // Float32Array, 16 kHz, processed
r.raw // the same audio, raw
r.speech // [{ start, end }]

The same output as in real time for the same 16 kHz audio. In Node, the same WebAssembly engine as the browser.

Primitives

Timbre (voice prints: embed, verify, identify), Lex (text to phonemes), Spot (compile, enroll), Voiceprint, VoiceprintLearner. Inputs expose mode (raw, focus, focus+print, with the reason when raw), status, latency and typed diag events to plug into your own logs.

Errors

Creating an input fails only when there is no sound at all: AlkoveError with code mic.denied, mic.not-found, mic.busy, page.insecure or browser.unsupported. Anything about models, network or a slow device never fails: the raw microphone goes out at the same delay, mode says why, and the SDK retries.

Models and self-hosting

Models are not in the npm package. By default they are downloaded from Hugging Face (alkove-ai) at a revision pinned by this version, checked by sha256 and cached in the browser (Cache Storage). Good for trying it out. In production, host them yourself: your users then talk to your servers only.

npx alkove models ./public/alkove
Alkove.configure({ modelBaseUrl: '/alkove/', assetBaseUrl: '/alkove/' })

assetBaseUrl also serves the worker and the worklet as files instead of blob URLs. Alkove.preload('call', { onProgress }) downloads and compiles everything ahead (a settings screen), Alkove.cached('call') tells whether it can start offline.

| Usage | Download (brotli) | |---|---| | call / agent | Focus 0.9 MB + Cue 0.9 MB, + Timbre 0.7 MB with a print | | wake word | Spot 2.5 MB, + Lex 1.5 MB for a typed word | | engine | Alkove's own, 141 KB |

Content Security Policy

  • script-src: 'wasm-unsafe-eval', and blob: (the worklet falls under script-src) unless assetBaseUrl is set
  • worker-src: blob:, or the origin of assetBaseUrl
  • connect-src: your modelBaseUrl, or Hugging Face and its download hosts

Privacy

No network call besides downloading the models, from the origin you choose. No telemetry. Neither audio nor voice prints leave the device. A voice print your app stores or sends is biometric data (GDPR art. 9): treat it as such.

Other platforms

The same models and core, the same outputs to the bit:

License

Code and model weights: Apache-2.0. See NOTICE. The Apache license grants no right to the Alkove name or logo: a fork may not call itself Alkove.