{"_id":"@ternlight/mini","_rev":"2-cf0d036578341e3b9dfbdd0d0af1864a","name":"@ternlight/mini","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@ternlight/mini","version":"0.1.0","keywords":["embeddings","semantic-search","vector-search","nearest-neighbor","on-device","edge","wasm","bitnet","ternary","minilm","sentence-embeddings"],"license":"MIT","_id":"@ternlight/mini@0.1.0","maintainers":[{"name":"wenshutang","email":"wenshutang@gmail.com"}],"homepage":"https://github.com/soycaporal/ternlight","bugs":{"url":"https://github.com/soycaporal/ternlight/issues"},"dist":{"shasum":"14978ee8cbc5e4eb1c614630211cbf4dc5f29573","tarball":"https://registry.npmjs.org/@ternlight/mini/-/mini-0.1.0.tgz","fileCount":16,"integrity":"sha512-YuBODYpRoXWuH3fTw2pSvlm39VkbVuKybXJwgybzMSZQjck92ZWD1MEQj5K/ANdlW3EvsqrH/NZxbKE5rwSOzA==","signatures":[{"sig":"MEYCIQDlP7LaSMwCkIydie1Q8jrulwTSkfOBjvNsn9fXfYi7xAIhAKd6OiUAZWbq7Y4HYr27HTsr25BztEER0kyMLFRKmkFX","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":15189782},"main":"src/index.js","type":"commonjs","types":"src/index.d.ts","module":"src/index.mjs","engines":{"node":">=18"},"exports":{".":{"node":{"import":"./src/index.mjs","require":"./src/index.js"},"types":"./src/index.d.ts","browser":"./src/index.browser.mjs","default":"./src/index.browser.mjs"},"./package.json":"./package.json"},"gitHead":"f655666f30b1e22232726790943171a77d49cd82","scripts":{"test":"node --test tests/","build":"PKG=packages/mini BIN=training/pack/out/model-int4.bin bash ../../scripts/build-engine.sh"},"_npmUser":{"name":"wenshutang","email":"wenshutang@gmail.com"},"repository":{"url":"git+https://github.com/soycaporal/ternlight.git","type":"git","directory":"packages/mini"},"_npmVersion":"10.5.0","description":"On-device semantic embeddings for JavaScript — the small, fast tier. 1.58-bit BitNet-style sentence embedder via WASM. ~5.5 MB on the wire, <2 ms per embedding, no API calls.","directories":{},"_nodeVersion":"20.12.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/mini_0.1.0_1783289204468_0.8361093367409482","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@ternlight/mini","version":"0.1.1","description":"On-device semantic embeddings for JavaScript — the small, fast tier. 1.58-bit BitNet-style sentence embedder via WASM. ~5 MB on the wire, ~2.5 ms per embedding, no API calls.","license":"MIT","repository":{"type":"git","url":"git+https://github.com/soycaporal/ternlight.git","directory":"packages/mini"},"homepage":"https://github.com/soycaporal/ternlight","bugs":{"url":"https://github.com/soycaporal/ternlight/issues"},"keywords":["embeddings","semantic-search","vector-search","nearest-neighbor","on-device","edge","wasm","bitnet","ternary","minilm","sentence-embeddings"],"type":"commonjs","main":"src/index.js","module":"src/index.mjs","types":"src/index.d.ts","exports":{".":{"types":"./src/index.d.ts","node":{"import":"./src/index.mjs","require":"./src/index.js"},"browser":"./src/index.browser.mjs","default":"./src/index.browser.mjs"},"./web":{"types":"./pkg-web/tern_engine.d.ts","default":"./pkg-web/tern_engine.js"},"./package.json":"./package.json"},"publishConfig":{"access":"public"},"engines":{"node":">=18"},"scripts":{"build":"PKG=packages/mini BIN=training/pack/out/model-int4.bin bash ../../scripts/build-engine.sh","test":"node --test tests/"},"gitHead":"c6d2c0a35d14c574ed2898b3dbf95977bca07208","_id":"@ternlight/mini@0.1.1","_nodeVersion":"24.18.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-nD+4U+lgwpvPY/iklZSbOGVsIcTpv78ptFThbRUSe+i8pMQlNAVaf8A8aiRDKIF0w7xmxi0gWfkssN8gFWyFBw==","shasum":"82b629b97acec5fd149ec10efdefab9f5d1ceacd","tarball":"https://registry.npmjs.org/@ternlight/mini/-/mini-0.1.1.tgz","fileCount":22,"unpackedSize":22791597,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIANojUIh8ggCUiIhp+mcI85C7LddytZbREu5hmO3t0IcAiEAqsRtncRJqeNXh6lNxT8G3v5JIRO3uEgmQvBzyy3IVos="}]},"_npmUser":{"name":"wenshutang","email":"wenshutang@gmail.com"},"directories":{},"maintainers":[{"name":"wenshutang","email":"wenshutang@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/mini_0.1.1_1785561118287_0.981754394563612"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-05T22:06:44.279Z","modified":"2026-08-01T05:11:59.011Z","0.1.0":"2026-07-05T22:06:44.785Z","0.1.1":"2026-08-01T05:11:58.762Z"},"bugs":{"url":"https://github.com/soycaporal/ternlight/issues"},"license":"MIT","homepage":"https://github.com/soycaporal/ternlight","keywords":["embeddings","semantic-search","vector-search","nearest-neighbor","on-device","edge","wasm","bitnet","ternary","minilm","sentence-embeddings"],"repository":{"type":"git","url":"git+https://github.com/soycaporal/ternlight.git","directory":"packages/mini"},"description":"On-device semantic embeddings for JavaScript — the small, fast tier. 1.58-bit BitNet-style sentence embedder via WASM. ~5 MB on the wire, ~2.5 ms per embedding, no API calls.","maintainers":[{"name":"wenshutang","email":"wenshutang@gmail.com"}],"readme":"# @ternlight/mini\n\n**On-device semantic embeddings for JavaScript - the small, fast tier. 5 MB on the wire, ~2.5 ms per embedding, zero API calls.**\n\nA 1.58-bit (BitNet-style ternary) sentence encoder compiled to WebAssembly. Give it text, get back a 384-dimensional unit vector for semantic search, FAQ matching, deduplication, or clustering — computed entirely on the user's CPU. No network, no GPU, no ML runtime, no model download at runtime: the model ships inside the wasm.\n\n```bash\nnpm install @ternlight/mini\n```\n\n```js\nimport { embed, cosineSim, similar } from '@ternlight/mini';\n\n// embed() → Float32Array(384), L2-normalized — compare any two with a dot product\ncosineSim(embed('reset my password'), embed('I forgot my password'));   // 0.91\n\n// or top-K semantic search over any list of strings\nconst results = similar('how do I reset my password', faqEntries, { topK: 3 });\n// [{ text: 'Resetting a forgotten password', sim: 0.80 }, ...]\n```\n\nWorks in Node ≥ 18, browsers (via any bundler), Cloudflare Workers, Vercel Edge, Deno, and Bun — one package, the right loader is picked automatically.\n\n## mini vs base\n\n`mini` is the size/speed tier; [`@ternlight/base`](https://www.npmjs.com/package/@ternlight/base) is the quality tier with the same API:\n\n| | **@ternlight/mini** | @ternlight/base |\n|---|---|---|\n| Wire size (gzipped wasm) | **~5.0 MB** | ~7.2 MB |\n| Embed latency (p50, M-series CPU) | **~2.5 ms** | ~5 ms |\n| Teacher fidelity (Spearman) | 0.820 | 0.844 |\n| Paraphrase handling | good | noticeably stronger |\n\nRule of thumb: browser bundles and latency-critical UI → `mini`; server-side, retrieval quality, or paraphrase-heavy matching → `base`. Switching later is a one-line import change.\n\n## API\n\n| Function | Description |\n|---|---|\n| `embed(text)` | → `Float32Array(384)`, unit-length. Sync, ~2.5 ms. Truncates at 128 tokens. |\n| `cosineSim(a, b)` | Cosine similarity of two embeddings (a dot product — they're normalized). |\n| `similar(query, corpus, { topK })` | Embed query + corpus, return top-K `{ text, sim }` sorted. |\n| `engineInfo()` | Build/model info string — dimensions, quantization format. |\n| `TernError` | Typed error (`INVALID_INPUT`, `DIM_MISMATCH`). |\n\nFor repeated searches, embed your corpus once and reuse the vectors:\n\n```js\nconst index = docs.map((d) => ({ d, v: embed(d.text) }));\nconst q = embed(query);\nindex.sort((a, b) => cosineSim(q, b.v) - cosineSim(q, a.v));\n```\n\n## Bundler setup (browsers)\n\nThe wasm is imported as an ES module. Webpack 5 needs one flag; Vite needs the wasm plugin:\n\n```js\n// webpack.config.js\nexperiments: { asyncWebAssembly: true }\n\n// vite.config.js\nimport wasm from 'vite-plugin-wasm';\nexport default { plugins: [wasm()] };\n```\n\nNode needs nothing — `require()` or `import` and go.\n\n**No bundler at all?** (plain `<script type=\"module\">`, hand-rolled setups) — use the `/web` subpath, which has an explicit `init()` that fetches the wasm:\n\n```js\nimport init, { embed } from '@ternlight/mini/web';\nawait init();                    // fetches + compiles the wasm (once, then cached)\nconst v = embed('hello world');  // Float32Array(384)\n```\n\nNote: `/web` exposes the raw engine exports (`embed`, `tokenize`, `config_summary`) without the JS helper layer — `cosineSim` is a dot product one-liner if you need it.\n\n## How it works\n\nThree ideas stacked: **(1)** a small transformer student is distilled from [all-MiniLM-L6-v2](https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2) *while being trained as a ternary model* (QAT), so quantization costs almost nothing; **(2)** ternary weights pack to 2 bits each, putting the whole model + tokenizer + engine in one wasm file; **(3)** the forward pass is hand-written Rust compiled to WASM with explicit SIMD, so it runs at near-native speed in every JS runtime. Details in the [repo docs](https://github.com/soycaporal/ternlight/tree/main/docs).\n\n## License\n\nMIT\n","readmeFilename":"README.md"}