# hitandrun-commonview One interactive figure, one shared view. This app shows the [hitandrun-interactive](https://github.com/concept-collection/hitandrun-interactive) hit-and-run sampling figure — just the figure, no source code — and keeps it **identical for everyone who has the page open**, in the style of [commonview](https://github.com/concept-collection/commonview): peers discover each other over nostr relays and form a WebRTC full mesh; the oldest peer is the **central** peer and owns the authoritative state. The twist over commonview's counter: the shared state is a live MATLAB computation. The central peer — and only the central peer — runs [numbl](https://numbl.org) (a MATLAB-compatible runtime) in a web worker, executing the *unmodified* `hitandrun_demo.m` from hitandrun-interactive. The figure's uihtml bridge is intercepted host-side (no iframe): control changes from **any** viewer are forwarded to the central peer, which feeds them to the script and broadcasts the results — parameter selections, the region, and the samples — to every viewer. ## What is shared - **Parameters**: sample count, convex/non-convex region, local-segment mode. - **The region and the samples**: samples travel as a Float32 blob (up to 100,000 points ≈ 800 KB), streamed in 64 KB chunks over the data channel and authenticated by a SHA-256 in a signed header. The JSON "view" message that follows it references the blob by id. - **The sampling movie**: the central peer drives the animation clock, so every viewer watches the same step at the same time. ## Graceful failover - Every message is a signed envelope (schnorr over the peer's key, which *is* its ID); state is only trusted from the current central peer. - Every peer keeps the latest sample blob, so whichever peer becomes central can serve it to late joiners. - If the **central peer leaves**, the next-oldest peer becomes central, boots its own engine (viewers see "starting engine…"), and continues from the last-known state — the script is stateless (the region rides along with each resample request), so any peer's engine can pick up where the last one left off. - If the central peer's **engine fails to boot or to compute** (a timeout counts), it announces the failure and steps down; the election skips engine-failed peers, and the next-oldest healthy peer takes over. - State is never persisted: once all peers leave, the room resets. ## Run ``` npm install # requires numbl >= 0.4.8 on npm (browser-embedding exports) npm run dev ``` Open the printed URL in two tabs (identity is per page load, so every tab is its own peer). Drag the samples slider or press "New region" in either window and watch both update; close the central window and watch the other take over. ## How the engine embedding works `src/engine/numbl.worker.ts` runs `executeCode` from the `numbl` npm package against an in-memory filesystem holding the `.m` files (verbatim copies from hitandrun-interactive, under [matlab/](matlab/)). The script's `uihtml(...)` call surfaces as a plot instruction carrying the component id and initial Data; `sendEventToHTMLSource` calls surface via the `onHtmlSourceEvent` hook; and events from the app re-enter the still-live interpreter through the `UihtmlSession` returned by `executeCode` — firing the script's `HTMLEventReceivedFcn` exactly as if the figure page had sent them. The HTML the script loads for the figure is replaced by a one-line placeholder; nothing is ever rendered from the worker.