Merge branch 'ocaml-vm' into sx-tools

This commit is contained in:
2026-03-26 12:11:27 +00:00

View File

@@ -132,13 +132,41 @@
(li (code "wt-send") " — send SX expression on stream")
(li (code "wt-listen") " — register handler for incoming messages")))
(~docs/subsection :title "2d. Deliverables"
(~docs/subsection :title "2d. Shared Signals Over WebTransport"
(p "Signals synchronized across peers. The same reactive primitive "
"that drives local UI drives multiplayer state. A " (code "shared-signal") " "
"is a signal whose writes propagate over WebTransport to all subscribed peers.")
(~docs/code :src (highlight
";; Shared signal — local writes propagate to peers, remote writes update locally\n(define player-x (shared-signal room \"player-x\" 0))\n(define player-y (shared-signal room \"player-y\" 0))\n\n;; Local code uses normal signal ops — no awareness of networking\n(reset! player-x 42) ;; updates local + sends to peers\n(deref player-x) ;; reactive, triggers re-render\n(swap! player-y inc) ;; same — local update + peer sync\n\n;; Under the hood:\n;; (reset! shared-sig val)\n;; → (reset! local-signal val)\n;; → (peer-send room (signal-update \"player-x\" val))\n;;\n;; incoming (signal-update \"player-x\" val) from peer\n;; → (reset! local-signal val)\n;; → reactive DOM updates fire as normal"
"lisp"))
(p "A " (code "room") " is a WebTransport channel with a set of shared signals. "
"Peers join a room, receive current state, and get incremental updates. "
"The signal names are the contract — any SX component that reads "
(code "(deref player-x)") " works whether the signal is local or shared.")
(~docs/code :src (highlight
";; Room: a named set of shared signals over WebTransport\n(define room (join-room home-peer \"game-lobby\"\n {:signals {:player-x 0 :player-y 0 :chat-messages (list)}\n :on-join (fn (peer-id) (announce peer-id))\n :on-leave (fn (peer-id) (remove-player peer-id))}))\n\n;; Game loop reads shared signals — identical to local signals\n(effect (fn ()\n (draw-player (deref player-x) (deref player-y))))\n\n;; Chat is shared too — append a message, all peers see it\n(reset! chat-messages (append (deref chat-messages)\n (dict :from (node-id) :text \"hello\")))"
"lisp"))
(p "Protocol messages for shared state:")
(~docs/code :src (highlight
";; Added to sx-sync protocol\n:join-room (fn (room-id signal-names) ...) ;; subscribe to room\n:room-state (fn (room-id signals) ...) ;; full state snapshot\n:signal-update (fn (room-id name value) ...) ;; incremental update\n:leave-room (fn (room-id) ...) ;; unsubscribe\n\n;; Conflict resolution: last-writer-wins by default\n;; Opt-in CRDT merge for collaborative data (lists, sets, maps)\n:signal-merge (fn (room-id name op args) ...) ;; CRDT operation"
"text"))
(p "Games, collaborative editors, chat, multiplayer tools — all the same primitive. "
"A " (code "shared-signal") " is a signal. Existing components work unchanged. "
"The networking is invisible to the reactive layer."))
(~docs/subsection :title "2e. Deliverables"
(ul :class "list-disc pl-6 mb-4 space-y-1"
(li (code "web/lib/sx-sync.sx") " — protocol definition (~200 LOC)")
(li (code "web/lib/sx-sync.sx") " — protocol definition incl. shared signals (~300 LOC)")
(li (code "web/lib/peer.sx") " — browser peer client (~150 LOC)")
(li "Server: WebTransport endpoint in Quart/Hypercorn (~200 LOC Python)")
(li (code "web/lib/shared-signal.sx") " — shared signal primitive (~120 LOC)")
(li "Server: WebTransport endpoint + room relay (~300 LOC Python)")
(li "Platform primitives: " (code "wt-connect, wt-send, wt-listen") " (~50 LOC JS)")
(li "Peer relay logic on server nodes (~100 LOC Python)"))))
(li "Conflict resolution: LWW default + CRDT opt-in (~150 LOC SX)"))))
;; =====================================================================
;; Phase 3: In-Browser Authoring