← back to projects

2026 · Live

Scalpal.

VR surgical trainer where the operating room lives in the database — headset, browser, and AI coach all play in the same one.

★ MHacks 2026 — Best Use of SpacetimeDB

Scalpal preview
TypeScriptSpacetimeDBReactNodeWebRTCDockerFly.ioVR

The full experience runs on a Meta Quest 3S.

In Scalpal, a learner picks a patient with a synthetic health record, interviews them in a voiced VR doctor's office, briefs on the anatomy, then performs an open appendectomy while an AI coach talks them through it. A teammate in a browser can join as scrub nurse, and the run ends with a scored debrief and a simulated robot arm replaying the move. I built the shared state underneath all of it. SpacetimeDB isn't storage here; it is the room. The patient's physiology ticks inside the database once a second, so bleeding and mistakes change the vitals for every client at once. The headset, the browser scrub nurse, viewers, and the AI coach are all roles checked inside reducers, reading only through identity-scoped views over private tables. One event log drives the Live OR dashboard, the timeline, the debrief, and the robot pipeline. Around the module sits a containerized Node gateway on Fly.io that does the I/O reducers can't: signed-URL artifact transfer to Cloudflare R2, short-lived TURN and voice credentials so API keys never reach a client, and a lease-based job API for the motion worker. I also built the React dashboard, including a WebRTC live view of the headset that uses SpacetimeDB for signaling.

System numbers

Tables
25
Role-checked reducers
52
Identity-scoped views
23
Headset → database
42–429 ms
Events in one run
1,930
End-to-end tests
41/41

Latency and event counts come from a recorded headset session. End-to-end suites ran against SpacetimeDB Maincloud; the gateway's own integration suite passes 23/23 against a local instance.

What I learned

Humans and AI share one authorization model

The coach can hand the learner an instrument, but only through the same reducer the human scrub nurse uses, and the module rejects the move if it isn't legal at that point in the procedure. No client gets a side channel: every write is a role-checked reducer, and every read goes through a view scoped to the caller's identity, so a viewer can't see or change what it shouldn't. Adding the AI as a peer rather than a privileged backend process meant there was no second permission system to keep in sync.

Retries that can't overwrite each other

Motion jobs run on an external worker, and both dispatch and computation can repeat. Claiming a job requires the caller to name the run it expects; the reducer increments the run and attaches a lease, and only the worker holding the current run can heartbeat or complete it. A late completion from an expired lease gets a 409 instead of clobbering the retry. One edge case took real thought: if a claim succeeds but never shows up in the gateway's subscription cache, moving on to another job would strand this one until its lease expired, so the gateway requeues it immediately instead.

Scalpal is a hackathon project and a teaching simulator, not clinical guidance. Patients are synthetic, the robot replay is a simulated MuJoCo policy rather than real hardware, and AR placement on a volunteer is an approximate overlay.