# `entity-sync` _(no submodules)_ ## Purpose Top-level manager for networked entity state. Tracks every entity by id, buffers remote-peer history for interpolation, samples local entities at the configured send rate, and exposes the diagnostic snapshot needed by HUD overlays. Hot-path methods stay allocation-free except for the result array returned by `collectLocalUpdates`. ## Features - Per-entity `StateBuffer` for remote sources, automatic `EntityInterpolator` binding. - Per-frame `updateRemoteEntities(serverTime)` walks every remote and writes the interpolated transform back to the entity record. - `shouldSend(currentTime)` gates outbound messages against the configured send rate. - Records `r3f_net.snapshots_total{outcome}` for every receive, including the `out_of_order` outcome surfaced from `StateBuffer.push`. - Zod-validated options; bad input throws `R3F_NET.INVALID_OPTIONS`. ## Usage: Basic Example ```ts import { EntitySyncManager } from "@suaveplan/r3f-networking"; const sync = new EntitySyncManager({ sendRate: 20 }); sync.registerEntity("e1", "me", true); sync.registerEntity("e2", "peer", false); sync.receiveUpdate({ entityId: "e2", transform: { position: [1, 0, 0], rotation: [0,0,0,1], scale: [1,1,1] }, timestamp: 1000, seq: 1, }); sync.updateRemoteEntities(1100); ``` ## Usage: Advanced Example Drive sync from a transport receive callback and a per-frame R3F hook: ```ts transport.onMessage((peer, env) => { const msg = decodeUpdate(env.payload); sync.receiveUpdate(msg); }); useFrame((state) => { const t = state.clock.elapsedTime * 1000; sync.updateRemoteEntities(t); if (sync.shouldSend(t)) { for (const m of sync.collectLocalUpdates(t)) transport.broadcast(m); } }); ``` ## API Reference - `new EntitySyncManager(config?: EntitySyncConfig)` - `registerEntity(id, ownerId, isLocal, initial?)` / `unregisterEntity(id)` - `receiveUpdate(message: EntityUpdateMessage)` - `updateRemoteEntities(serverTime: number)` - `updateLocalEntity(id, transform)` - `shouldSend(currentTime): boolean` - `collectLocalUpdates(timestamp): EntityUpdateMessage[]` - `getSnapshot(): SyncSnapshot` - `getEntityCount(): number` / `clear()` ## Implementation Notes The send-rate gate uses wall-clock time on each frame rather than a setInterval so missed frames cannot accumulate. Remote `out_of_order` errors are swallowed and reported through the OTel counter — surfacing them as exceptions would cascade-kill the consuming r3f frame loop on transient jitter. The `enablePrediction` flag is consumed by hooks that wire `ClientPredictor` externally; the manager itself does not predict.