Zero-cost deployment¶
The live site is a static bundle (GitHub Pages) plus model weights on the Hugging Face Hub. Nothing runs server-side, so hosting is free, permanent, and scales with the number of visitors’ devices.
1. Upload converted checkpoints to Hugging Face Hub¶
pip install huggingface_hub
hf auth login
hf upload-large-folder <user>/lenslapse-onnx --repo-type model /path/to/lenslapse-models-multi
Notes:
A public model repo is used (free storage for public repos, CORS-enabled
resolve/URLs; the files are model weights, just converted to ONNX).Layout is one directory per model id:
<model-id>/manifest.json+<model-id>/step{N}/backbone.f16.onnx+<model-id>/step{N}/lens.f16.onnx, with model ids matchingweb/public/data/models.json(e.g.pythia-14m,pythia-70m,pythia-160m,gpt2,mapneo-250m,aquila-135m,bloom-560m).Add
docs/model-card.mdas the repo README — re-upload it (hf upload iamtatsuki05/lenslapse-onnx docs/model-card.md README.md) whenever it changes; the file living in the checkout does not sync itself.
2. Point the app at the repo¶
Edit HF_DEFAULT in web/src/live.ts:
const HF_DEFAULT = 'https://huggingface.co/<user>/lenslapse-onnx/resolve/main/'
The app resolves models in this order: ?models= URL parameter → same-origin models/ → HF_DEFAULT.
If none is reachable it degrades to precomputed-only mode with a status badge (no crash).
3. Publish the site on GitHub Pages¶
Push this repository to GitHub (public, e.g.
lenslapse).Repository Settings → Pages → Source: GitHub Actions.
The included workflow (
.github/workflows/deploy-pages.yml) buildsweb/and deploysweb/diston every push tomain.
The built site is ~160MB for the seven shipped models (two ONNX Runtime WASM binaries ~44MB + precomputed shards ~58MB + tokenizer files ~28MB + app assets ~46MB), well under the 1GB Pages limit. Model weights are not part of the site — only the small per-model tokenizer directories that the live-probe path and the free-text tokenizer feature need locally.
Verification checklist after deploy¶
[ ] Page loads and the lens grid renders for the default prompt (precomputed, no download).
[ ] Slider scrubbing updates the grid; ticks show live-capable diamonds.
[ ] The model picker switches between all eleven shipped models — Pythia 14M / 70M / 160M, GPT-2, the multilingual MAP-Neo-250M / Aquila-135M / BLOOM-560M suites, and the four architecture- coverage examples SmolLM2-135M / Qwen3-0.6B / OPT-125M / Gemma-3-270M (steps and grid depth change per model; every model shows live-capable diamonds for every one of its checkpoints).
[ ] Clicking a cell pins it and draws trajectories; the permalink button reproduces the exact view (including the selected model).
[ ] Live probe on a free-text prompt downloads one checkpoint (~29MB for 14M, ~142MB for 70M, ~326MB for 160M, ~327MB for GPT-2, once per checkpoint) and completes; badge shows WebGPU or WASM.
[ ] Without a probe server connected, free-text live probe works for nine of the eleven models; MAP-Neo and Aquila fall back to “precomputed mode only” (their tokenizers are custom Python code with no browser-compatible
tokenizer.json— seedocs/model-card.md’s Reproduce section) — connect a probe server to live-probe those two with free text.[ ]
?ep=wasmforces the WASM path (for browsers without WebGPU).[ ] DevTools Network tab shows requests only to the site origin and
huggingface.co/its CDN.