web-ttt / README.md
LJTSG's picture
web-TTT: browser-native test-time-trainable memory toolkit
78bc0e4 verified
metadata
license: mit
tags:
  - web-ttt
  - test-time-training
  - in-browser
  - webgpu
  - associative-memory
  - minilm
  - transformers-js
library_name: transformers.js

web-TTT — a browser-native, test-time-TRAINABLE memory

A tiny method + toolkit for an associative memory that learns from use, entirely in the browser — no server, no API, no backend. To our knowledge, the first published browser-trainable TTT (test-time training) memory.

It is the memory layer behind a fully in-browser AI companion, extracted here as a clean, reusable method you can drop onto any corpus (it does not contain anyone's private data — just the process + a generic demo).

The idea

  • Embed each fact with Xenova/all-MiniLM-L6-v2 (via transformers.js) → a 384-d vector.
  • Recall a query as score(fact) = cosine( normalize(W · embed(query)) , fact_vec ), top-K — where W is a learnable 384×384 projection matrix (identity at first).
  • Train at test time: clicking a result runs ~25 steps of cross-entropy gradient descent on W, pulling that query toward that fact. The matrix learns which queries should surface which memories — on the user's device, in the browser. W persists in localStorage, so the memory keeps what you taught it across sessions.

That's the whole thing: a frozen embedder + a small matrix you train by example, live, client-side. It runs on WebGPU/WASM and needs nothing but a browser.

Files

  • web-ttt.js — the toolkit (ES module). WebTTT class: init(), load(corpus), recall(query, k), teach(query, targetIndex), exportW()/importW()/resetW().
  • demo/index.html + demo/facts.json — a working demo on a generic corpus.

Quick start

import { WebTTT } from "./web-ttt.js";

const ttt = new WebTTT({ storageKey: "my_ttt" });
await ttt.init();                                   // loads MiniLM (CDN by default)
await ttt.load([
  { key: "the sun", text: "The Sun is the star at the center of the Solar System." },
  { key: "the moon", text: "The Moon is Earth's only natural satellite." },
]);

const hits = await ttt.recall("what's at the center of the solar system?", 3);
// → [{ key: "the sun", score: 0.6x, index: 0, ... }, ...]

await ttt.teach("center of the solar system", 0);   // reinforce: 25-step W update, persists

Run the demo: serve the folder over http://localhost (WebGPU/transformers.js need a real origin, not file://) and open demo/index.html in Chrome/Edge/Brave.

Fully offline

Pass local asset paths to init():

await ttt.init({
  transformersUrl: "./vendor/transformers/transformers.min.js",
  localModelPath: "./models/",          // contains Xenova/all-MiniLM-L6-v2
  wasmPaths: "./vendor/transformers/",  // ort-wasm*.wasm
});

Format / publishing your own TTT

A "trained TTT" is just: your corpus ([{key, text}]), optionally the precomputed 384-d vec per fact, and the learned W (384×384, from exportW()). Ship those three and any browser can load and keep training it. That's the publishable artifact — the method, on your data, your choice.

License

MIT. The embedder (Xenova/all-MiniLM-L6-v2) and transformers.js carry their own licenses.