Four shells, one library
Sign in on one device, show a pairing code, type the six digits on the next one. From then on the two are the same library — and neither of them needs the network to keep working.
Web
React and Vite over a SQLite database in the browser's own origin-private file system, running in a dedicated worker. It is an installable PWA, so it gets an icon and a window and keeps working when the wifi does not. Nothing to deploy to a lab machine, and still a full replica rather than a thin client.
Windows and Linux
The same shared core inside a Tauri 2 shell, which adds the three things a browser cannot: a real file on disk — open, save and hand over a .mcq pack like any other document — a lockdown mode for the exam hall, and seeing another Zayeed device on the same network so two machines can sync with no server involved. macOS builds from the same source.
Android
Expo and React Native, with the database in expo-sqlite. It sits papers and it writes them: questions, the leniency stops, the live tester, sets and rules, certificates, and saving or opening a .mcq through the share sheet — the same shared core the browser renders, not a cut-down phone edition. It also sees the other Zayeed devices on the same network and syncs with them directly, which on Android means two small native modules: a multicast socket holding the wifi multicast lock Android otherwise uses to drop these packets, and a TCP listener. Above them the phone runs the unmodified discovery, pairing and merge code the desktop runs, so a phone's edits are not a special case of the merge. A teacher whose only computer is a phone is not an edge case in most of the world. The proof that none of it needs a server is a test that replaces the network with something that throws, then writes a question, builds a quiz, sits it, marks it and carries the result to a second device as a file. iOS builds from the same source, but no iOS build has been produced yet.
How they stay one library
Every shell holds a full local replica and writes to it immediately. Writes are recorded as operations in a log ordered by hybrid logical clocks, and replicas exchange operations when they can reach each other. There is no "the server is the truth and you are a cache" moment, because there is no moment when a candidate mid-exam can afford one.
When the two devices are not in the same building
Then they meet at a rendezvous relay. One device asks for a meeting code — nine characters, read down the phone or typed into a message — and the other types it in. The relay seats exactly two devices per code and forwards frames between them without opening one: the two shells run the same handshake they run on a local network, so what crosses the relay is already sealed, and the six digits the two screens show are derived from the handshake transcript. A relay that swapped a key would change that transcript and the two numbers would differ, which is the whole reason a relay in the middle is safe rather than trusted. Nothing is stored: a frame with no peer waiting is refused, not queued, and when either side leaves, the meeting and the code are spent.
Honest limit: no relay is hosted for the public. This is the server component, so the route is available to anyone running their own server — and there is still no hole-punching, so the two devices never form a direct connection through NAT.
The offline case is the normal case
- A candidate can lose the network mid-sitting and lose nothing.
- A grade earned offline is queued and delivered when the network returns — including back to a VLE gradebook.
- The whole author → deliver → grade → report loop is tested with no network at all, and must produce identical scores.
- A pack on a memory stick is a complete exam, media included — and a sync bundle on the same stick merges two devices that have never met a server.
System requirements
| Shell | Requires | Storage | Notes |
|---|---|---|---|
| Web | Any current Chromium, Firefox or Safari | OPFS | Installable; no extension, no plugin. |
| Windows | Windows 10 or later, WebView2 | SQLite file | Lockdown mode for invigilated sittings. |
| Linux | WebKitGTK | SQLite file | Same build pipeline as Windows. |
| Android | Android 8 or later | SQLite file | Authoring, sitting and marking. Share-sheet save and open. Direct sync on the local network. |
| Server | Node 20+, SQLite or Postgres | Your choice | Optional. Only needed for sync, LTI and join-by-code. |
Write one question. Mark it four ways.
Install the desktop build, open the browser app, or scan into the Android shell. They are the same library, the same marks and the same rules — with or without a network.