Repository

weightlift

In-browser model manager for local / on-device AI. Download progress, cache detection, concurrent-load deduping, React hooks, worker bridge — so you can ship Whisper, CLIP, etc. wi · License MIT · Install via npm · Maintenance unknown

License
MIT
Import
What
weightlift
ModelManager , Weightlift
weightlift/react
useModel , useModelManager , …

Specs

  • ImportWhat
  • weightliftModelManager , Weightlift
  • weightlift/reactuseModel , useModelManager , …
  • weightlift/workercreateWorkerReporter , attachWorker
  • weightlift/transformerstransformersModel , fallbackDevicePolicy , …
  • MethodPurpose
  • define(id, definition)Add or replace a model
  • remove(id)Drop definition and dispose instance
  • load(id)Load (or return in-flight promise)
  • get(id)Sync access to a ready instance
  • status(id)Progress + lifecycle for one model
  • isReady / isLoading / has / idsQueries
  • unload(id) / unloadAll()Dispose instances; keep definitions
  • clear()Unload and remove all definitions
  • preload([ids])Warm several models
  • subscribe / getSnapshotSubscribe to manager-wide state

README

weightlift

In-browser model manager for local / on-device AI. Download progress, cache
detection, concurrent-load deduping, React hooks, worker bridge — so you can
ship Whisper, CLIP, etc. without wiring all that yourself.

Works with Transformers.js out of the box; any custom loader is fine too.

Try the playground →

weightlift playground

These projects use weightlift to power their on-device AI experiences:

1. Rescript – Video Editor

rescript — a transcript-based
video editor that runs Whisper fully on-device in the browser.

rescript

Install

npm install weightlift

Load a model

import { pipeline } from "@huggingface/transformers";
import { ModelManager } from "weightlift";
import { transformersModel } from "weightlift/transformers";

const models = new ModelManager({
  models: {
    sentiment: transformersModel({
      pipeline,
      task: "sentiment-analysis",
      modelId: "Xenova/distilbert-base-uncased-finetuned-sst-2-english",
    }),
  },
});

const clf = await models.load("sentiment");
await clf("I love transformers!");
// [{ label: "POSITIVE", score: 0.999… }]

transformersModel picks WebGPU when available (falls back to WASM), wires progress, and detects cache hits.

Examples

Same patterns as the playground.

Zero-shot vision

vision: transformersModel({
  pipeline,
  task: "zero-shot-image-classification",
  modelId: "Xenova/clip-vit-base-patch32",
}),

const clip = await models.load("vision");
await clip(imageUrl, ["tiger", "lion", "house cat"]);

Sentiment

sentiment: transformersModel({
  pipeline,
  task: "sentiment-analysis",
  modelId: "Xenova/distilbert-base-uncased-finetuned-sst-2-english",
}),

Fill-mask

fillmask: transformersModel({
  pipeline,
  task: "fill-mask",
  modelId: "Xenova/bert-base-uncased",
}),

const unmask = await models.load("fillmask");
await unmask("The browser can run [MASK] models.");

Any other runtime

custom: {
  load: async ({ progress }) => {
    progress.dispatch({ type: "start" });
    // …fetch / init, dispatch progress events…
    progress.dispatch({ type: "ready" });
    return myModel;
  },
  dispose: (model) => model.destroy?.(),
},

Show progress

const { status, percent, fromCache } = models.status("sentiment");

const label =
  status === "loading"
    ? fromCache
      ? "Loading from cache…"
      : `Downloading… ${Math.round((percent ?? 0) * 100)}%`
    : "";

React

import { useModel } from "weightlift/react";

function LoadButton({ manager }: { manager: ModelManager }) {
  const { percent, fromCache, isLoading, load } = useModel(manager, "sentiment");

  return (
    <button => load()} disabled={isLoading}>
      {isLoading
        ? fromCache
          ? "Loading from cache…"
          : `Downloading… ${Math.round((percent ?? 0) * 100)}%`
        : "Load model"}
    </button>
  );
}

Packages

Import What
weightlift ModelManager, Weightlift
weightlift/react useModel, useModelManager, …
weightlift/worker createWorkerReporter, attachWorker
weightlift/transformers transformersModel, fallbackDevicePolicy, …

React is an optional peer. @huggingface/transformers is not a dependency — pass pipeline yourself.

API

const models = new ModelManager({ models: { /* … */ } });

await models.load("sentiment");   // dedupes concurrent callers
models.get("sentiment");          // sync access once ready
models.status("sentiment");       // { status, percent, fromCache, … }
await models.unload("sentiment");
await models.preload(["a", "b"]);
Method Purpose
define(id, definition) Add or replace a model
remove(id) Drop definition and dispose instance
load(id) Load (or return in-flight promise)
get(id) Sync access to a ready instance
status(id) Progress + lifecycle for one model
isReady / isLoading / has / ids Queries
unload(id) / unloadAll() Dispose instances; keep definitions
clear() Unload and remove all definitions
preload([ids]) Warm several models
subscribe / getSnapshot Subscribe to manager-wide state

GPU fallback

import { fallbackDevicePolicy } from "weightlift/transformers";

fallbackDevicePolicy.preferWasm();
await models.unloadAll();

Workers

// worker
import { Weightlift } from "weightlift";
import { createWorkerReporter } from "weightlift/worker";

const progress = new Weightlift();
createWorkerReporter(self, progress);

// main
import { attachWorker } from "weightlift/worker";
attachWorker(worker, progress);

Develop

npm install
npm test
npm run build
npm run demo:dev

License

MIT