Model Downloader
The headline local-first card a user sees while a model loads on-device — name, size, context, live progress, and cached-vs-downloading copy.
Model Downloader
The Model Downloader is the single most defining LocalMode surface: the card a user sees while their model loads on their device. It renders the model name, size, context length, and category alongside a live progress bar, and clearly distinguishes a first-time download ("Downloading…") from a cache load ("Loading from cache…") and a ready state. A lower-level Download Progress renders just the bar + percentage.
It is presentational and hook-driven — bind progress to useModelLoad's progressValue (its percent is a 0–1 fraction matching this component's DownloadProgressValue contract, with loaded / total bytes and a cached flag when known) and pass metadata from useModelRecommendations or your catalog. It does not initiate or own the download — useModelLoad().load() does.
Preview
Installation
pnpm dlx shadcn@latest add @localmode/ui/local-first/model-downloadernpx shadcn@latest add @localmode/ui/local-first/model-downloaderyarn dlx shadcn@latest add @localmode/ui/local-first/model-downloaderbunx --bun shadcn@latest add @localmode/ui/local-first/model-downloaderData source & dependencies
Data source: renders the progress + metadata you pass — works with any backend. Recommended producer: useModelLoad (provider-model loads; useModelStatus for a read-only view, useModelLoader for raw createModelLoader file downloads) from @localmode/react (on-device, optional).
lucide-react— iconsclsx+tailwind-merge— via the sharedcn()util
Files installed
model-downloader.tsx—ModelDownloader+DownloadProgresslib/utils.ts— thecn()helper (if not already present)
Props
ModelDownloader
Prop
Type
DownloadProgress
Prop
Type
Examples
Bound to useModelLoad
import { useModelLoad } from '@localmode/react';
import { wllama, isModelCached } from '@localmode/wllama';
import { ModelDownloader } from '@/components/model-downloader';
export function Loading() {
const { status, progressValue } = useModelLoad({
key: 'Llama-3.2-1B-Instruct-Q4_K_M',
create: (onProgress) =>
wllama.languageModel('Llama-3.2-1B-Instruct-Q4_K_M', { onProgress }),
isCached: () => isModelCached('Llama-3.2-1B-Instruct-Q4_K_M'),
autoLoad: true,
});
return (
<ModelDownloader
name="Llama 3.2 1B Instruct"
size="1.2 GB"
contextLength={8192}
category="Chat"
progress={progressValue}
ready={status === 'ready'}
/>
);
}useModelLoad normalizes every provider's onProgress shape (transformers per-file, webllm percent, wllama/litert bytes) into one progressValue — { loaded?, total?, percent, cached? } with percent as a 0–1 fraction — which drops straight into this component's progress prop. Its cached flag (from the isCached probe) switches the copy to "Loading from cache…" automatically.
Standalone progress bar
<DownloadProgress value={0.42} />Customization
Styled entirely with shadcn/ui CSS variables (bg-card, text-card-foreground, bg-primary), so it inherits your theme. The cached state uses Tailwind's emerald palette — swap those classes in the copied file to match your design system. The progress shape accepts either a 0–1 fraction or a { loaded, total, percent, cached } object, so it adapts to any provider's onProgress — useModelLoad's progressValue matches this object shape exactly.