Start
Quickstart
Clone the repo, start the Durable Object Worker and the playground, then open two clients on the same workspace. The shortest API loop is hello, mutate, onFrame, view.
Install
git clone https://github.com/dinosaurav/yttrium.git cd yttrium npm install npm test
Tests are deterministic. They run the reducer and a seeded fake network; they do not open sockets.
Run the playground
Use two terminals:
npm run worker # demo identity adapter, Durable Object on :8787 npm run playground # Vite UI on :5173
Open http://localhost:5173/. Home is the lab: Ada and Beau side by side in a fresh workspace of your own (the URL gains ?ns=room-…; share it to bring others in). Type in #general, draw on board, or edit notes. The other pane should see the commit without a refresh.
Useful routes:
/ two live clients (Ada + Beau) /app/demo/ada one client as Ada /app/demo/beau one client as Beau /app/demo/ada/notes Ada, notes already selected /docs this site
Vite talks to ws://localhost:8787. The hosted Worker serves the same UI at ytt.rium.dev and uses same-origin wss:.
?as= and workspace=), not a login. Ada starts as admin and Beau as writer. Same-origin pages can use it; a mismatched Origin is rejected.
Send a mutation
A client holds a Session. The host holds a DomainServer. Both call the same apply.
import { Session } from "yttrium-engine/client";
import { ROOT_ID, encodeFrame, decodeFrame } from "yttrium-engine/protocol";
const session = new Session("ada");
ws.send(encodeFrame(session.hello()));
ws.send(encodeFrame(session.mutate({
type: "add_child",
parent_id: ROOT_ID,
slice_id: session.createSliceId(),
fields: { text: "hi" },
})));
ws.onmessage = (event) => {
session.onFrame(decodeFrame(typeof event.data === "string" ? event.data : new TextDecoder().decode(event.data)));
session.view();
};
mutate writes an overlay entry immediately. view() folds that overlay over authoritative state. When an ack arrives, the overlay entry retires. Persist the outbox before sending if the edit must survive reload; the playground does this through Outbox.
Talk to a domain
The Worker upgrades GET /domain/:encoded-name to a WebSocket. Demo domain names look like:
ws/demo/acl ws/demo/catalog ws/demo/user/ada ws/demo/channel/general ws/demo/document/notes ws/demo/canvas/board
The playground attaches ?as=ada&workspace=demo so the development adapter can bind a principal. A real application supplies its own authenticate hook and does not treat a query parameter as proof of identity.
Deploy
npm run deploy # build playground assets, then wrangler deploy
That publishes the Worker, the Durable Object class, and the playground/docs assets. See Host for persistence, hibernation, and logs.
Next
- Concepts — the one-page model.
- Playground — rooms, streams, roles, and what is demo-only.
- API — Session, Hub, DomainServer, and the text battery.