# PhantomStream Architecture This document describes the system as it shipped inside FSB (milestone v0.9.9.1 "Phantom Stream" plus the reliability hardening of phases 211 and 276). File references point at the verbatim copies under `reference/`. For runnable package setup paths, see [QUICKSTARTS.md](QUICKSTARTS.md). ## 1. Overview PhantomStream mirrors a live browser tab to a remote viewer by streaming the page as **structured DOM data** rather than pixels: 1. **Snapshot** — a one-time serialization of `document.body`, rebuilt by the viewer into a sandboxed iframe. Default `styleMode: 'computed'` inlines curated computed styles; opt-in `styleMode: 'cssom'` transports scoped `styleSources[]` and `styleStrategy`. Standalone Phase 8 extends the snapshot with `nodeIds`, `shadowRoots[]`, and `frames[]` sidecars for scoped identity. 2. **Diffs** — incremental MutationObserver batches (`add` / `rm` / `attr` / `text` ops) addressed by stable node IDs, applied surgically to the mirror. Phase 8 also streams `shadow-root` replacement ops and narrow `value` ops; Phase 9 adds CSSOM `style-source` ops. 3. **Side channels** — scroll position, automation overlays (action glow, progress), and native dialog mirroring. 4. **Reverse path** — remote control: clicks, typing, and scrolling performed on the mirror are reverse-mapped and replayed in the real browser. ``` page (content script) extension SW relay server viewer (dashboard) dom-stream.js → background.js → ws-handler.js → dashboard.js snapshot + rAF-batched LZ envelope, fan-out, decompress, iframe diffs, scroll, overlay, session stamps, 1 MiB/msg cap srcdoc render, nid- dialogs, watchdog #1 watchdog #2 addressed diff apply ``` ## 2. Capture (`reference/extension/dom-stream.js`) ### 2.1 Node identity The original FSB reference design stamped every serialized element with `data-fsb-nid`, a monotonically increasing string ID, on **both** the live DOM and the serialized clone (`assignNodeId`). That attribute was the original addressing keystone: every diff op, overlay rect, and remote-control action addressed nodes by nid, and nodes added after the snapshot got nids in `processAddedNode`. The standalone framework design after Phase 7 keeps the same opaque nid wire contract but removes live-page identity mutation. Capture owns identity in an internal `WeakMap` plus reverse lookup, emits `nodeIds` sidecars on snapshots and add ops, and exposes `getNodeId(element)` for trusted host code. The renderer rebuilds a private `Map` from `nodeIds` after sanitization, so page-owned `data-fsb-nid` attributes remain ordinary page data rather than PhantomStream identity. ### 2.2 Full snapshot (`serializeDOM`) - Clones `document.body`, then walks original and clone **in parallel** with two TreeWalkers so live state can be read while the copy is transformed. - Strips `