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

webml-kit

v0.4.1

Published

Framework-agnostic utilities for loading and running ML models in the browser via WebGPU/WASM

Readme

webml-kit

Framework-agnostic utilities for loading and running ML models in the browser via WebGPU/WASM.

Live Playground & Interactive Demos →

If you've ever built a browser-ML demo, you know the drill: copy 150 lines of Web Worker boilerplate from the last project, wire up postMessage, add progress reporting, handle the GPU vanishing mid-inference, and pray the model is cached so your user doesn't wait 3 minutes. Every. Single. Time.

This library does that part for you. It wraps @huggingface/transformers with a sane API and handles the ugly bits: device detection, model caching, token streaming, KV-cache management, and GPU recovery.

Install

npm install webml-kit

Quick start

Zero-ceremony functional API

import webml from 'webml-kit';

// Speech recognition — auto-detects task, normalizes audio (Blob, File, URL, Float32Array)
const asr = await webml('onnx-community/whisper-tiny.en');
const { text } = await asr.transcribe(audioBlob);

// Live microphone listening
const mic = await asr.listen({
  onTranscript: (text) => console.log(text),
});

// Text generation with streaming
const llm = await webml('onnx-community/Llama-3.2-1B-Instruct-ONNX');
for await (const { token } of llm.stream('Tell me a joke')) {
  process.stdout.write(token);
}

// Image classification (callable object)
const classifier = await webml('Xenova/vit-base-patch16-224');
const labels = await classifier(imageFile);

Low-level ModelClient

For manual control over device detection, cache, and worker threads:

import { ModelClient } from 'webml-kit';

const client = new ModelClient();

// What can this machine do?
const device = await client.detect();
console.log(device.backend);         // 'webgpu' or 'wasm' or 'cpu'
console.log(device.gpu?.vendor);      // 'apple'
console.log(device.recommendedDtype); // 'q4'

// Load a model
await client.load({
  task: 'text-generation',
  modelId: 'onnx-community/Bonsai-1.7B-ONNX',
  dtype: 'q4',
  onProgress: ({ percent }) => console.log(`Loading: ${percent}%`),
});

// Stream tokens as they're generated
for await (const { token, tps } of client.stream('Tell me a joke')) {
  process.stdout.write(token);
}

What's in here

Device detection

Figures out what your user's machine can handle and picks a reasonable quantization level:

import { detectDevice, canRun } from 'webml-kit';

const info = await detectDevice();
// { backend: 'webgpu', gpu: { vendor: 'apple', vram: 8589934592, vramFormatted: '8.0 GB' }, recommendedDtype: 'fp16' }

const { ok, reason } = await canRun('4GB');    // human-readable
const same = await canRun(4_000_000_000);       // raw bytes — same result

Model discovery

Search the Hugging Face Hub for models that work with webml-kit. Only returns models tagged with transformers.js, so everything listed runs out of the box:

import { searchModels, listModelsForTask, trendingModels, listWebGPUModels } from 'webml-kit';

// Search by keyword
const results = await searchModels({ query: 'whisper', task: 'automatic-speech-recognition' });

// Top models for a task
const textModels = await listModelsForTask('text-generation', 5);

// What's trending right now
const hot = await trendingModels(5);

// Only from known WebGPU-friendly orgs (onnx-community, Xenova)
const webgpu = await listWebGPUModels({ task: 'text-generation' });

Cache visibility

The worst UX in browser ML is showing "downloading 2GB..." to someone who already has the model. Now you can check:

import { isCached, listCachedModels, getCacheSize, clearCache } from 'webml-kit';

if (await isCached('onnx-community/Bonsai-1.7B-ONNX')) {
  // Skip the progress bar entirely
}

const models = await listCachedModels();
// [{ modelId: 'onnx-community/Bonsai-1.7B-ONNX', size: '412.0 MB', sizeBytes: 432013312 }]

await clearCache('onnx-community/Bonsai-1.7B-ONNX'); // Free storage on mobile

Token streaming

A proper AsyncIterable instead of raw postMessage callbacks. Tracks tokens-per-second and time-to-first-token:

for await (const event of client.stream('Hello!')) {
  console.log(event);
  // { token: 'World', tps: 38.5, numTokens: 12, timeToFirstToken: 145 }
}

// Or grab everything at once:
const { text, tps, numTokens } = await client.generate('Hello!');

GPU recovery

GPUs disappear. It happens: TDR resets, VRAM pressure, mobile browsers reclaiming resources. Without handling this, the user has to reload the page. This recovers automatically with backoff:

import { GPURecovery } from 'webml-kit';

const recovery = new GPURecovery({ maxRetries: 3, baseDelayMs: 1000 });
recovery.on('lost', ({ reason }) => showBanner('GPU lost: ' + reason));
recovery.on('recovered', ({ adapter }) => console.log('Back online'));
recovery.on('failed', () => showFallbackMessage());

All pipeline tasks

Not just text generation. Every task @huggingface/transformers supports works through the same API:

// Classify an image
const labels = await client.run('image-classification', imageUrl);
// [{ label: 'tabby cat', score: 0.98 }]

// Transcribe audio
const { text } = await client.run('automatic-speech-recognition', audioBlob);

// Get embeddings
const vectors = await client.run('feature-extraction', 'Hello world');

// Detect objects
const objects = await client.run('object-detection', imageBlob);

// Translate, summarize, caption images, answer questions,
// classify text, extract entities, estimate depth, segment images

Standalone & Custom ONNX Models

Not every model uses standard @huggingface/transformers pipelines. webml-kit automatically detects and supports standalone ONNX models, companion audio preprocessors, and custom CTC decoders (such as NeMo Conformer-CTC models, standalone vision backbones, or raw ONNX graphs), with automatic WebGPU-to-WASM fallback when operators require WASM SIMD:

// Load standalone ONNX models from HF Hub, local files, or URLs
const asr = await webml('onnx-community/whisper-tiny.en'); // or any standalone ONNX model
const { text } = await asr.transcribe(audioFloat32Array);

Jev System One / OpenJev Decision Capabilities

Fast, calibrated, programmable decisions without autoregressive token generation. Turn natural language and application state into typed choices, binary verdicts (noul), or continuous level scores (score) with direct logit readouts:

import webml, { createDecisionEngine, directChoice } from 'webml-kit';

// One-shot direct choice
const result = await directChoice({
  state: 'Customer reports: "My subscription charged twice, please refund immediately."',
  question: 'Which department should handle this request?',
  options: ['billing', 'technical-support', 'sales'],
});
console.log(result.choice);        // 'billing'
console.log(result.confidence);    // 0.88
console.log(result.probabilities); // { billing: 0.88, 'technical-support': 0.08, sales: 0.04 }

// Binary evaluation (Noul)
const engine = webml.decision({ model: 'qwen3-0.6b' });
const { noul, passed } = await engine.noul({
  state: 'Production database cluster is reporting 500 errors',
  statement: 'Is there an urgent incident?',
});
console.log(noul);   // 0.94
console.log(passed); // true

// Continuous scoring along ordered criteria levels
const { score, confidence } = await engine.score({
  state: 'There is a minor typo in the footer disclaimer.',
  instructions: 'Rate issue severity',
  criteria: ['P3', 'P2', 'P1', 'P0'],
});
console.log(score); // 0.15 (continuous score on 0-3 scale)

Supports OpenJev GGUF models (minicpm5-2b, qwen3-0.6b, qwen3.5-4b) via @wllama/wllama with WebGPU/WASM in browser and worker environments, with automatic, zero-dependency heuristic fallback for Node.js, offline, or test environments.

API

ModelClient

| Method | What it does | |---|---| | detect() | Returns device capabilities and recommended dtype | | load(options) | Downloads and initializes a model pipeline | | stream(input, options?) | Returns an async iterator of tokens | | generate(input, options?) | Generates text, waits for completion | | run(task, input, options?) | Runs any pipeline task | | interrupt() | Stops an in-progress generation | | reset() | Clears the KV cache (new conversation) | | dispose(modelKey?) | Frees model memory | | isLoaded(task, modelId) | Checks if a specific model is ready | | terminate() | Kills the worker entirely | | on(event, listener) | Listens for progress, ready, error, device-lost, device-recovered |

Standalone functions

These work without a ModelClient — useful for pre-flight checks:

| Function | What it does | |---|---| | detectDevice() | Backend detection + GPU info + dtype recommendation | | checkWebGPU() | Boolean: is WebGPU available? | | canRun(bytes) | Can a model of this size fit in VRAM? | | isCached(modelId) | Is this model already downloaded? | | listCachedModels() | What's in the cache? | | clearCache(modelId?) | Delete cached model files | | getCacheSize() | Total bytes used by cached models | | parseSize(input) | Convert '4GB' / '512MB' to bytes | | formatSize(bytes) | Convert bytes to '4.0 GB' / '512.0 MB' | | searchModels(options?) | Search HF Hub for transformers.js-compatible models | | listModelsForTask(task) | Top models for a specific pipeline task | | trendingModels(limit?) | What's trending on HF Hub right now | | listWebGPUModels(options?) | Models from known WebGPU-friendly orgs | | getModelInfo(modelId) | Detailed info about a specific model |

Supported tasks

| Task | Streaming | Default model | |---|---|---| | text-generation | yes | onnx-community/Llama-3.2-1B-Instruct-ONNX | | text-classification | no | Xenova/distilbert-base-uncased-finetuned-sst-2-english | | image-classification | no | Xenova/vit-base-patch16-224 | | object-detection | no | Xenova/detr-resnet-50 | | automatic-speech-recognition | no | onnx-community/whisper-tiny.en | | text-to-speech | no | Xenova/speecht5_tts | | translation | no | Xenova/nllb-200-distilled-600M | | summarization | no | Xenova/distilbart-cnn-6-6 | | feature-extraction | no | Xenova/all-MiniLM-L6-v2 | | image-to-text | no | Xenova/vit-gpt2-image-captioning | | zero-shot-classification | no | Xenova/mobilebert-uncased-mnli | | fill-mask | no | Xenova/bert-base-uncased | | question-answering | no | Xenova/distilbert-base-uncased-distilled-squad | | token-classification | no | Xenova/bert-base-NER | | depth-estimation | no | Xenova/depth-anything-small-hf | | image-segmentation | no | Xenova/detr-resnet-50-panoptic |

How it works

Your App (main thread)          Web Worker
--------------------------      ---------------------------
ModelClient                     model-worker.ts
  .load()    --- postMessage -->  pipeline() from @hf/transformers
  .stream()  <-- tokens --------  TextStreamer + KV cache
  .run()     <-- result --------  One-shot inference
  .interrupt() -- signal ------>  InterruptableStoppingCriteria

TokenStream (AsyncIterable)     Singleton pipeline cache
GPURecovery (auto-reconnect)    WebGPU device management

Requirements

  • Chrome 113+, Edge 113+, or Safari 18+ (falls back to WASM on older browsers)
  • Node.js 18+ (WASM only, no WebGPU)
  • @huggingface/transformers >= 4.0.0 as a peer dependency

License

MIT — Hemanth HM