Remix.run Logo
Ternlight – 7 MB embedding model that runs in browser (WASM)(ternlight-demo.vercel.app)
65 points by soycaporal 2 hours ago | 17 comments
soycaporal 2 hours ago | parent | next [-]

Hobby project, I wanted to "ship a useful model in a web browser". so I distilled a small sentence encoder from MiniLM with ternary quantization-aware training. Also wrote the inference engine from scratch and shipped in Rust → WASM SIMD.

It's an embeddings model, not an LLM: text goes in, a 384-dim vector comes out, and cosine similarity between two vectors tells you how related the texts are — regardless of shared words ("reset my password" ↔ "I forgot my password" → 0.88). Used for semantic search, FAQ/intent matching, and clustering. Running it on-device means search-as-you-type semantic search is performant with no API dependencies.

Demo (2k React docs, fully on-device): https://ternlight-demo.vercel.app

Two tiers on npm: - @ternlight/base (7 MB, ~5 ms/embed, more capable embedings) - @ternlight/mini (5 MB wire, ~2.5 ms/embed).

Bundled for Node and browsers.

Repo - see technical details (MIT, training pipeline included): https://github.com/soycaporal/ternlight

Curious if this is something useful, what are the use cases for on-device embeddings.

fellowniusmonk 2 hours ago | parent [-]

Awesome! Besides size, how does this compare to gte-small?

soycaporal an hour ago | parent [-]

gte-small outscores all-MiniLM-L6 on MTEB (~61 vs ~56 avg per the GTE paper). MiniLM is ternlight's teacher (ternlight holds 0.84 Spearman fidelity to teacher). I haven't run a head-to-head yet; STS-B/MTEB numbers are on the roadmap. Also on the roadmap is to distill gte-small as teacher.

dirteater_ 2 hours ago | parent | prev | next [-]

This is cool!

but also maybe you could put a button on the landing page to trigger the demo because it's a bit startling to hear my fans go crazy when opening a webpage.

Waterluvian an hour ago | parent [-]

Agree. But this also reminds me fondly of the days where the sounds of my computer so intimately indicated what’s going on.

mwcz 42 minutes ago | parent [-]

Amiga floppy disk sounds are the deepest of sense memories.

wazzup_im an hour ago | parent | prev | next [-]

I added an offline search engine to app.wazzup.im/search (no login or payment required).

First search downloads the model from the internet and subsequent runs are from the cache.

The model is very small so it's not the best for everything but it's good for basic math and coding.

Give it a try.

aetherspawn 2 hours ago | parent | prev | next [-]

Can the 30 second embedding time be done beforehand and sent to the browser?

Inference is nice and quick after that.

soycaporal 2 hours ago | parent [-]

yes, you could run a 1 time indexing run on the server side, and just ship the embeddings to frontend

CobrastanJorji an hour ago | parent | prev | next [-]

Great, now my websites are gonna push entire LLMs onto my browser in order to use my CPU to make inferences about my shopping habits or whatever.

paytonjjones 30 minutes ago | parent | next [-]

Ha, I was literally thinking this but from the other side.

"Hmm, 7MB would barely make a dent in the size of the app and allow us to do some of our basic ML without calling the backend"

Probably a lot more practical to use this though: https://developer.apple.com/apple-intelligence/

antonvs an hour ago | parent | prev [-]

Disabling WASM is the new disable JavaScript

rvz an hour ago | parent | prev | next [-]

Why do these things download into the browser automatically? This could be used to distribute malware and also or hog excessive browser memory.

newspaper1 an hour ago | parent | prev | next [-]

Very cool! I'd love to point it at my own corpus to index/embed. Would be cool if you could give it a link to a markdown file or even a website to crawl.

esafak an hour ago | parent | prev [-]

What we need is a W3C LLM API.

yesidoagree an hour ago | parent | next [-]

If it was like Math (Math.round, Math.PI, etc.) it could be Language, as in:

    Language.complete('the quick brown fox jumped over the lazy') 
and maybe even static methods on Image

    Image.generate('a spaceship flying toward a planet')
soycaporal an hour ago | parent | prev [-]

I think standardizing the runtime is pretty effective, it then open up portability