Vuer RTC

API Reference

Complete reference for all exported functions, types, and hooks in Vuer-RTC.

Core Exports

Graph Factory

createGraph

Create a graph store for managing CRDT-based scene graph state.

typescript
function createGraph(options: CreateGraphOptions): GraphStore

Parameters:

ParameterTypeDescription
options.sessionIdstringUnique session identifier
options.onSend(msg: CRDTMessage) => voidCallback invoked when a message is ready to send to the server
options.onStateChange(state: ClientState) => voidOptional callback invoked on every state change
options.initialSnapshotSnapshotOptional initial snapshot to restore from

Returns: GraphStore - A store with methods to edit, commit, undo/redo, and sync state.

Example:

typescript
const store = createGraph({
  sessionId: 'user-123',
  onSend: (msg) => websocket.send(JSON.stringify(msg)),
});

store.edit({ ot: 'vector3.add', key: 'cube', path: 'position', value: [1, 0, 0] });
store.commit('Move cube');

createGraphFromServer

Create a graph store initialized from server state (snapshot + journal).

typescript
function createGraphFromServer(
  sessionId: string,
  snapshot: Snapshot,
  journal: CRDTMessage[],
  onSend?: (msg: CRDTMessage) => void
): GraphStore

Parameters:

ParameterTypeDescription
sessionIdstringUnique session identifier
snapshotSnapshotServer snapshot containing graph state and metadata
journalCRDTMessage[]Array of uncompacted messages from server
onSend(msg: CRDTMessage) => voidOptional callback for outgoing messages

Returns: GraphStore


Client Actions

Low-level state manipulation functions. Most users should use createGraph or React hooks instead.

State Initialization

createInitialState

Create initial client state.

typescript
function createInitialState(sessionId: string, initialSnapshot?: Snapshot): ClientState

initFromServer

Initialize client state from server snapshot and journal.

typescript
function initFromServer(
  sessionId: string,
  snapshot: Snapshot,
  journal: CRDTMessage[]
): ClientState

Edit Buffer Operations

onEdit

Add an operation to the edit buffer (uncommitted).

typescript
function onEdit(state: ClientState, op: Operation): ClientState

commitEdits

Commit pending edits as a single message.

typescript
function commitEdits(
  state: ClientState,
  description?: string
): { state: ClientState; msg: CRDTMessage | null }

Returns: New state and the message to send (or null if no edits).

cancelEdits

Discard all uncommitted edits.

typescript
function cancelEdits(state: ClientState): ClientState

Server Communication

onRemoteMessage

Process an incoming message from another client or server.

typescript
function onRemoteMessage(state: ClientState, msg: CRDTMessage): ClientState

onServerAck

Mark a message as acknowledged by the server.

typescript
function onServerAck(state: ClientState, msgId: string): ClientState

Undo/Redo

undo

Undo the last committed message.

typescript
function undo(state: ClientState): { state: ClientState; undoMsg: CRDTMessage | null }

Returns null when the remaining local edits are already covered by a durable server watermark. Such entries may remain in the journal behind an earlier pending message, but their effects are already part of the server checkpoint.

redo

Redo the last undone message.

typescript
function redo(state: ClientState): { state: ClientState; redoMsg: CRDTMessage | null }

Redo likewise skips targets already covered by the durable server watermark.

Compaction

compact

Compact the journal by creating a new snapshot at the current watermark.

typescript
function compact(state: ClientState): ClientState

Removes all acknowledged messages from the journal and updates the snapshot.

compactToWatermark

Apply a server vector-clock watermark by folding the locally acknowledged, causally represented safe prefix.

typescript
function compactToWatermark(state: ClientState, watermark: VectorClock): ClientState

Utilities

generateUUID

Generate a compact session ID (12-character nanoid).

typescript
function generateUUID(): string

getUnackedMessages

Get all messages that have not been acknowledged by the server.

typescript
function getUnackedMessages(state: ClientState): CRDTMessage[]

hasPendingMessages

Check if there are any unacknowledged messages.

typescript
function hasPendingMessages(state: ClientState): boolean

getPendingCount

Get the count of unacknowledged messages.

typescript
function getPendingCount(state: ClientState): number

React Hooks

Available from @vuer-ai/vuer-rtc/hooks subpath.

Provider

GraphProvider

Wrap your app to provide graph context.

typescript
function GraphProvider(props: GraphProviderProps): JSX.Element

Props:

PropTypeDescription
sessionIdstringUnique session identifier
onSend(msg: CRDTMessage) => voidCallback for outgoing messages
childrenReactNodeChild components

Example:

tsx
<GraphProvider sessionId="user-123" onSend={sendToServer}>
  <Scene />
</GraphProvider>

State Access Hooks

useGraphStore

Access the underlying graph store.

typescript
function useGraphStore(): GraphStore

useGraph

Get the current graph state. Re-renders on any graph change.

typescript
function useGraph(): SceneGraph

useNode

Subscribe to a specific node. Re-renders only when that node changes.

typescript
function useNode(key: string): SceneNode | undefined

useNodeProperty

Subscribe to a specific property of a node. Re-renders only when that property changes.

typescript
function useNodeProperty<T>(key: string, path: string): T | undefined

Example:

tsx
const position = useNodeProperty<[number, number, number]>('cube-1', 'position');

Action Hooks

useGraphActions

Get actions to modify the graph.

typescript
function useGraphActions(): {
  edit: (op: Operation) => void;
  commit: (description?: string) => CRDTMessage | null;
  cancelEdits: () => void;
  undo: () => void;
  redo: () => void;
  receive: (msg: CRDTMessage) => void;
  compact: () => void;
  compactToWatermark: (watermark: VectorClock) => void;
}

Example:

tsx
const { edit, commit, undo, redo } = useGraphActions();

const onDrag = (delta: [number, number, number]) => {
  edit({ ot: 'vector3.add', key: 'cube', path: 'position', value: delta });
};

const onDragEnd = () => {
  commit('Move cube');
};

useDrag

Helper hook for drag operations with automatic edit buffering.

typescript
function useDrag(
  key: string,
  path: string,
  description: string
): {
  onDragStart: () => void;
  onDrag: (delta: [number, number, number]) => void;
  onDragEnd: () => void;
}

Example:

tsx
const { onDragStart, onDrag, onDragEnd } = useDrag('cube-1', 'position', 'Move cube');

useUndoRedoShortcuts

Enable keyboard shortcuts for undo/redo (Cmd/Ctrl+Z, Cmd/Ctrl+Shift+Z).

typescript
function useUndoRedoShortcuts(): void

Operations

High-level operation dispatcher and validator.

Dispatcher

applyOperation

Apply a single operation to the graph.

typescript
function applyOperation(graph: SceneGraph, op: Operation): SceneGraph

applyMessage

Apply all operations in a message to the graph.

typescript
function applyMessage(graph: SceneGraph, msg: CRDTMessage): SceneGraph

applyMessages

Apply multiple messages to the graph.

typescript
function applyMessages(graph: SceneGraph, messages: CRDTMessage[]): SceneGraph

createEmptyGraph

Create an empty scene graph with root node.

typescript
function createEmptyGraph(): SceneGraph

Validation

OperationValidator

Validator for operation schemas.

typescript
class OperationValidator {
  validate(op: Operation): ValidationResult;
}

Example:

typescript
const validator = new OperationValidator();
const result = validator.validate({ ot: 'vector3.set', key: 'cube', path: 'position', value: [1, 2, 3] });
if (!result.valid) {
  console.error(result.errors);
}

Text CRDT Utilities

getTextDocument

Get the TextRope instance from a node property.

typescript
function getTextDocument(graph: SceneGraph, key: string, path: string): TextRope | null

CRDT - TextRope

High-performance text CRDT with B-tree storage. Available from @vuer-ai/vuer-rtc/crdt.

Factory

create

Create a new TextRope instance.

typescript
function create(agentId: string): TextRope

Queries

getText

Get the visible text content.

typescript
function getText(rope: TextRope): string

getLength

Get the visible character count.

typescript
function getLength(rope: TextRope): number

getItems

Get all items (including deleted).

typescript
function getItems(rope: TextRope): Item[]

getStats

Get statistics about the rope structure.

typescript
function getStats(rope: TextRope): {
  items: number;
  visibleChars: number;
  deletedChars: number;
  agents: number;
  maxSeq: number;
}

Local Edits

insert

Insert text at a position.

typescript
function insert(rope: TextRope, pos: number, content: string): TextRope

remove

Remove text range.

typescript
function remove(rope: TextRope, from: number, to: number): DeleteOp

replace

Replace text range.

typescript
function replace(rope: TextRope, from: number, to: number, content: string): ReplaceOp

move

Move text range to a new position.

typescript
function move(rope: TextRope, from: number, to: number, targetPos: number): MoveOp

Remote Operations

apply

Apply a remote insert operation.

typescript
function apply(rope: TextRope, op: InsertOp): TextRope

applyDelete

Apply a remote delete operation.

typescript
function applyDelete(rope: TextRope, op: DeleteOp): TextRope

applyReplace

Apply a remote replace operation.

typescript
function applyReplace(rope: TextRope, op: ReplaceOp): TextRope

applyMove

Apply a remote move operation.

typescript
function applyMove(rope: TextRope, op: MoveOp): TextRope

Merging & Snapshots

merge

Merge two ropes (used for reconciliation).

typescript
function merge(rope1: TextRope, rope2: TextRope): TextRope

snapshot

Create a deep copy of the rope.

typescript
function snapshot(rope: TextRope): TextRope

compact

Remove tombstones (deleted items) from the rope.

typescript
function compact(rope: TextRope): TextRope

Serialization

toRaw

Serialize to plain object.

typescript
function toRaw(rope: TextRope): RawTextRope

fromRaw

Deserialize from plain object.

typescript
function fromRaw(raw: RawTextRope): TextRope

fromSnapshot

Create from a snapshot object.

typescript
function fromSnapshot(snapshot: RawTextRope): TextRope

Item Utilities

findItemById

Find an item by its ID.

typescript
function findItemById(rope: TextRope, id: ItemId): Item | null

itemIdEquals

Compare two item IDs for equality.

typescript
function itemIdEquals(a: ItemId | null, b: ItemId | null): boolean

itemIdCompare

Compare two item IDs for ordering.

typescript
function itemIdCompare(a: ItemId, b: ItemId): number

RangeTree (B-tree)

Low-level B-tree implementation used by TextRope.

typescript
class RangeTree {
  constructor(order?: number);
  insert(item: Item, ord: number): void;
  splitAt(ord: number): void;
  getAt(ord: number): Item | null;
  totalVisible(): number;
  totalItems(): number;
  // ... additional methods
}

State Management

VectorClockManager

Causal ordering utilities.

typescript
class VectorClockManager {
  create(sessionId: string): VectorClock;
  increment(clock: VectorClock, sessionId: string): VectorClock;
  merge(clock1: VectorClock, clock2: VectorClock): VectorClock;
  compare(clock1: VectorClock, clock2: VectorClock): number;
}

Example:

typescript
const manager = new VectorClockManager();
const clock = manager.create('session-1');
const newClock = manager.increment(clock, 'session-1');
const merged = manager.merge(clock, remoteClock);

DType

Data type registry for server-side conflict resolution.

typescript
class DType {
  static register<T>(
    dtype: string,
    defaultValue: T,
    mergeFn: MergeFn<T>
  ): void;

  static getDefault(dtype: string): unknown;
  static merge<T>(dtype: string, a: ValueWithMeta<T>, b: ValueWithMeta<T>): ValueWithMeta<T>;
}

ConflictResolver

Server-side conflict resolution.

typescript
class ConflictResolver {
  resolve(existing: PropertyLWW, incoming: PropertyLWW, otype: string): PropertyLWW;
}

function parseOtype(otype: string): { dtype: string; verb: string }

Sync Utilities

Efficient message reconciliation using bloom filters.

BloomFilter

Probabilistic set for message ID reconciliation.

typescript
class BloomFilter {
  constructor(numBits: number, numHashes: number);

  static create(expectedItems: number, falsePositiveRate?: number): BloomFilter;

  add(key: string): void;
  has(key: string): boolean;

  toBytes(): Uint8Array;
  static fromBytes(bytes: Uint8Array): BloomFilter;
}

Example:

typescript
const filter = BloomFilter.create(1000, 0.01); // 1000 items, 1% false positive rate
filter.add('msg-123');
filter.add('msg-456');

if (filter.has('msg-123')) {
  console.log('Message probably in set');
}

Sync Digest

buildSyncDigest

Build a sync digest from client state for reconciliation.

typescript
function buildSyncDigest(state: ClientState): SyncDigest

Returns: SyncDigest object containing:

  • vectorClock: Covers all compacted messages
  • filter: Bloom filter covering uncompacted journal
  • count: Journal length

Example:

typescript
const digest = buildSyncDigest(state);
websocket.send(JSON.stringify(digest));

Types

Core Types

typescript
interface CRDTMessage {
  id: string;
  sessionId: string;
  clock: VectorClock;
  lamportTime: number;
  timestamp: number;
  ops: Operation[];
}

interface SceneGraph {
  nodes: Record<string, SceneNode>;
  rootKey: string;
}

interface SceneNode {
  key: string;
  tag?: string;
  children?: string[];
  _crdt: CRDTEnvelope;
  [key: string]: unknown; // Dynamic properties
}

interface ClientState {
  graph: SceneGraph;
  journal: JournalEntry[];
  edits: EditBuffer;
  snapshot: Snapshot;
  /** Latest durable server watermark; blocks undo/redo for retired retained entries. */
  serverWatermark?: VectorClock;
  lamportTime: number;
  vectorClock: VectorClock;
  sessionId: string;
}

interface Snapshot {
  graph: SceneGraph;
  vectorClock: VectorClock;
  lamportTime: number;
  journalIndex: number;
}

TextRope Types

typescript
interface ItemId {
  agent: string;
  seq: number;
}

interface Item {
  id: ItemId;
  content: string;
  isDeleted: boolean;
  parentId: ItemId | null;
  seq: number;
}

interface InsertOp {
  id: ItemId;
  content: string;
  parentId: ItemId | null;
  seq: number;
}

interface DeleteOp {
  deletions: Array<{ id: ItemId; length: number }>;
}

Operation Types

All operations extend BaseOp:

typescript
interface BaseOp {
  ot: string;  // e.g., 'vector3.add', 'string.set'
  key?: string;   // Target node key ('.' = root)
  path?: string;  // Property path ('.' = node root)
  value?: unknown;
  // Additional fields per operation type
}

See the Operations page for the complete list of operation types.


Wire Serialization

encode

Serialize a message using msgpack.

typescript
function encode(msg: CRDTMessage | SyncDigest): Uint8Array

decode

Deserialize a message from msgpack.

typescript
function decode(bytes: Uint8Array): CRDTMessage | SyncDigest

Example:

typescript
import { encode, decode } from '@vuer-ai/vuer-rtc';

const msg: CRDTMessage = { /* ... */ };
const bytes = encode(msg);
websocket.send(bytes);

// On receive:
const received = decode(new Uint8Array(event.data));

Advanced Usage

Edit Buffer Utilities

isAdditiveOp

Check if an operation is additive (can be merged).

typescript
function isAdditiveOp(op: Operation): boolean

mergeValues

Merge two operation values for the same key+path.

typescript
function mergeValues(otype: string, prev: unknown, next: unknown): unknown

Graph Rebuilding

rebuildGraph

Rebuild the graph from snapshot + journal (used internally after undo/redo).

typescript
function rebuildGraph(state: ClientState): ClientState

Related Pages