Real WASM · no server · no network
Semantic search, running entirely in this browser tab.
Everything below is the actual ferrovec Rust→WebAssembly core — the same 77 KB crate published to npm — doing live approximate-nearest-neighbour search over 24 sentence embeddings. The WASM binary and the vectors are baked into this single HTML file. Nothing is fetched for this tab; close your Wi-Fi and the search still works.
Search
pick a query →These queries are pre-embedded with all-MiniLM-L6-v2. Click one — the ranking is computed live by the WASM core, not looked up. Note how matches share almost no words with the query.
- Pick a query above to run the WASM core.
The index
24 notesHow this runs with zero backend
Rust → WASM, inlined
The published ferrovec crate compiled to a 77 KB .wasm, base64-embedded in this page and instantiated with WebAssembly.instantiate. The HNSW graph, SIMD distances and search all execute in your browser's WASM sandbox.
MiniLM embeddings
Each note was embedded once with all-MiniLM-L6-v2 (384-dim, mean-pooled, normalised) and stored as plain numbers in the page. In a real app, transformers.js does this in a Web Worker on the fly.
Live k-NN ranking
On each query the core walks the HNSW graph and returns the nearest neighbours by cosine similarity — in well under a millisecond here. The corpus is 24 vectors, so this shows the code path, not the scaling; the graph walk is what keeps it sub-linear on large indexes.
// In a real app the same core drives a three-line API (npm: ferrovec):
import { Ferrovec } from 'ferrovec';
const db = await Ferrovec.open('notes'); // worker + model + OPFS
await db.insert('the cat curled up in the sun'); // embed + index
const hits = await db.query('a sleepy kitten', 5); // → ranked, nearest-first
Real ferrovec · in this tab · no server
A notebook that remembers.
Write a few notes. Then kill the tab while it is still saving, or open it in a second tab. The notes are in the real ferrovec store: a Rust→WASM index written to this browser's private file system behind a checksummed write-ahead log. What this page acknowledges, it keeps.
Your notes
Each save is acknowledged only after its log record is flushed to OPFS. That is a flush, not an fsync: it survives a killed tab, not a power cut. The time shown is how long the flush took.
Now try to lose them
Each of these does something real to this tab or its files, and the page measures what comes back. They need this tab to be the leader and the only open tab.
Kill the tab mid-save
Saves 25 notes as fast as it can, then tears the page and its worker down while saves are still in flight: no close, no flush. Whatever was acknowledged must come back.
Crash during a checkpoint
Checkpoints, saves 3 more notes into the log, then reloads; before the store reopens, the page stages a half-written checkpoint file, the shape a tab killed mid-checkpoint leaves behind.
Open a second tab
Both tabs share one store. One is elected leader; the other proxies through it. Close the leader and watch this tab take over.
Start over deletes the store and the notes above.
Find a note
Nearest-neighbour search over the index, in this tab. With the instant embedder, search by words from the note; for meaning-based search open the Semantic search tab, which runs MiniLM vectors.
Under the hood
The store's files in OPFS, read by this page while the store is open. Two snapshot slots alternate; the log holds everything since the newest one.
// What this page calls (npm: ferrovec 0.4.0). The hashed embedder is demo-only: // a worker built from the package source that swaps MiniLM for a hashing function. import { Ferrovec } from 'ferrovec'; const db = await Ferrovec.open('notebook', { model: 'hashed-trigram-v1', requestPersistentStorage: false }); await db.insert('call the dentist tuesday'); // resolves once the log record is flushed const notes = await db.list({ limit: 12 }); // what the list above shows