tx2-link
Binary protocol for syncing ECS worlds between runtimes with field-level delta compression.
tx2-link is the bridge/protocol layer of the TX-2 ecosystem, enabling efficient synchronization of Entity-Component-System state across web, native, and CLI environments. It defines the "wire format" for transmitting world snapshots and deltas with minimal bandwidth overhead.
Features
Delta Compression
- Field-level change detection - Only transmit changed component fields
- 1171× compression ratio - Benchmarked: 1.2MB full snapshot → 1KB delta (10% entity churn)
- Automatic delta generation - Compare snapshots and extract minimal diff
- Delta application - Reconstruct full state from base + delta
Multiple Serialization Formats
- MessagePack - Compact binary format (default, best compression)
- Bincode - Fast Rust-native serialization (lowest latency)
- JSON - Human-readable debugging format
Transport Abstractions
- WebSocket - Server ↔ browser sync (async)
- IPC - Inter-process communication for native ↔ webview
- Stdio - Pipe-based communication for CLI tools
- Memory - In-process channels for testing
Rate Limiting
- Token bucket - Burst handling with sustained rate limits
- Sliding window - Precise message/byte rate enforcement
- Per-connection limits - Individual rate limiters per client
- 357k checks/sec - Benchmarked throughput while enforcing 1k msg/sec cap
Schema Versioning
- Component schema registry - Type definitions with version tracking
- Schema validation - Ensure client/server compatibility
- Migration support - Handle schema evolution gracefully
Streaming Protocol
- Length-prefixed framing - Parse messages from byte streams
- Zero-copy deserialization - Direct memory mapping where possible
- Backpressure support - Flow control for slow consumers
Debug Mode
- JSON logging - Pretty-print all messages and deltas for inspection
- Human-readable traces - Operation summaries with timing and sizes
- Environment variable control - Enable with
TX2_DEBUG=1orTX2_TRACE=1 - Zero runtime overhead - Debug checks compile out when disabled
Quick Start
Delta Compression
use ;
let mut compressor = new;
// Create two snapshots
let snapshot1 = WorldSnapshot ;
let snapshot2 = WorldSnapshot ;
// Generate delta (only changed fields)
let delta = compressor.create_delta?;
// Apply delta to reconstruct snapshot2
let reconstructed = compressor.apply_delta?;
assert_eq!;
Serialization
use ;
// Create message
let message = Snapshot;
// Serialize to MessagePack
let mut serializer = new;
let bytes = serializer.serialize?;
// Deserialize
let deserialized: Message = serializer.deserialize?;
Transport
use ;
// Create WebSocket transport
let transport = connect.await?;
// Send message
transport.send.await?;
// Receive message
let received = transport.receive.await?;
Rate Limiting
use ;
// Create rate limiter: 100 msg/sec, burst of 10
let mut limiter = new;
// Check if message can be sent
if limiter.check_message?
Performance
Benchmarked on 10,000 entities with Position, Velocity, Health components:
Delta Compression
- Full snapshot: 1,232,875 bytes
- Delta (10% churn): 1,052 bytes
- Compression ratio: 1171×
- Delta generation: ~2ms
- Delta application: ~1.5ms
Serialization Performance
| Format | Serialize | Deserialize | Size |
|---|---|---|---|
| MessagePack | 180µs | 250µs | 1.05MB |
| Bincode | 140µs | 195µs | 1.12MB |
| JSON | 420µs | 350µs | 2.28MB |
Rate Limiting
- Check throughput: 357k checks/sec
- Overhead: ~3µs per check
- Memory: ~200 bytes per limiter
Architecture
Protocol Messages
World Snapshot
Component Data Formats
Delta Algorithm
tx2-link uses field-level diffing for maximum compression:
- Compare entities - Match entities between snapshots by ID
- Detect additions/removals - Track created/deleted entities
- Compare components - Match components by type within each entity
- Field-level diff - Extract only changed fields within components
- Generate delta - Encode minimal changeset
For structured components:
// Previous: { x: 10.0, y: 20.0, z: 30.0 }
// Current: { x: 10.0, y: 25.0, z: 30.0 }
// Delta: { y: 25.0 } // Only y changed
Transport Layer
All transports implement the Transport trait:
WebSocket Transport
use WebSocketTransport;
// Server
let transport = bind.await?;
// Client
let transport = connect.await?;
IPC Transport
use IpcTransport;
// Create named pipe/socket
let transport = new?;
Stdio Transport
use StdioTransport;
// Use stdin/stdout
let transport = new;
Memory Transport
use MemoryTransport;
// In-process channels (for testing)
let = create_pair;
Rate Limiting
Token Bucket
Allows bursts up to a capacity, refilling at a steady rate:
use TokenBucketLimiter;
// 1000 msg/sec, burst of 100
let limiter = new;
// Check and consume tokens
if limiter.check_message?
Sliding Window
Enforces strict limits over a time window:
use SlidingWindowLimiter;
// 1000 msg/sec, 1MB/sec, 60-second window
let limiter = new;
if limiter.check?
Schema Versioning
use ;
let mut registry = new;
// Register component type
let schema = new
.with_field
.with_field
.with_field
.with_version;
registry.register?;
// Validate incoming data
if registry.validate?
Integration with TX-2 Ecosystem
tx2-link bridges the TX-2 stack:
- tx2-ecs (TypeScript/Node): Web runtime using tx2-link for server sync
- tx2-core (Rust): Native engine using tx2-link for client sync
- tx2-pack: Uses tx2-link's snapshot format for save/load
Use Cases
- Server ↔ Browser - Sync game state over WebSocket
- Native ↔ Webview - IPC between Rust engine and web UI
- CLI Tools - Stream world state over stdio pipes
- Multi-process - Distribute simulation across processes
- Debugging - Inspect live world state with JSON transport
Examples
Full Client-Server Sync
use *;
// Server
let transport = bind.await?;
let limiter = new;
let mut compressor = new;
let mut last_snapshot = world.create_snapshot;
loop
// Client
let transport = connect.await?;
let mut compressor = new;
let mut snapshot = empty;
loop
Running Tests
All 22 tests should pass, covering:
- Delta compression accuracy
- Serialization roundtrips (all formats)
- Rate limiter behavior
- Schema validation
- Transport abstractions
Running Benchmarks
Benchmarks measure:
- Delta compression performance
- Serialization/deserialization speed
- Rate limiter throughput
- Field-level diff overhead
Debug Mode
tx2-link includes a comprehensive debug system for inspecting protocol operations without modifying code.
Environment Variables
Enable debug features using environment variables:
TX2_DEBUG=1orTX2_DEBUG_JSON=1- Enable JSON pretty-printing of all messages, snapshots, and deltasTX2_TRACE=1- Enable human-readable trace logging with operation timings and sizes
Both can be combined: TX2_DEBUG=1 TX2_TRACE=1
Debug Mode Features
When TX2_DEBUG=1 is set:
- All serialized/deserialized messages are logged as pretty-printed JSON
- World snapshots are logged with entity counts
- Deltas are logged showing all changes in readable JSON format
When TX2_TRACE=1 is set:
- Delta summaries showing entities added/removed/modified
- Serialization performance (format, size, duration)
- Delta compression ratios and timing
- Rate limiter decisions (allowed/blocked, current rate)
- Transport operations (bytes sent/received)
Usage
# Run with JSON debug logging
TX2_DEBUG=1
# Run with human-readable traces
TX2_TRACE=1
# Run with both
TX2_DEBUG=1 TX2_TRACE=1
Example Output
With TX2_TRACE=1:
[TX2-LINK] Delta Summary:
Timestamp: 2.0 (base: 1.0)
Total changes: 5
+ 1 entities added
~ 2 components modified
[TX2-LINK] Delta compression: 1232875 bytes → 1052 bytes (1171.79× reduction) in 2134µs
[TX2-LINK] Serialized 1052 bytes using MessagePack in 250µs
With TX2_DEBUG=1:
[TX2-LINK] Serialized Message:
{
"header": {
"msg_type": "Delta",
"sequence": 42,
"timestamp": 1234567890
},
"payload": {
"changes": [
{
"EntityAdded": { "entity_id": 123 }
},
{
"ComponentAdded": {
"entity_id": 123,
"component_id": "Position",
"data": { "x": 10.0, "y": 20.0 }
}
}
]
}
}
Programmatic Access
You can also enable debug mode programmatically:
use init_debug_mode;
Why Debug Mode?
Binary protocols like MessagePack and Bincode are efficient but opaque. Without debug mode, inspecting what's being sent over the wire requires:
- Packet capture tools
- Manual deserialization
- Custom logging code
With debug mode, you get instant visibility into:
- What data is changing between snapshots
- How effective delta compression is
- Serialization format efficiency
- Rate limiting behavior
- Network traffic patterns
This makes tx2-link extremely "vibe coding friendly" - you can see exactly what's happening without writing debugging code.
Development Status
- Core protocol messages
- Delta compression with field-level diffing
- Multi-format serialization (MessagePack, Bincode, JSON)
- Transport abstractions (WebSocket, IPC, stdio, memory)
- Rate limiting (token bucket, sliding window)
- Schema versioning and validation
- Streaming serializer/deserializer
- Comprehensive benchmarks
- Debug mode with JSON logging and traces
- Compression (zstd/lz4) for large snapshots
- Encryption support
- Reconnection handling with state recovery
- Binary diff algorithms for large binary components
Dependencies
serde- Serialization frameworkrmp-serde- MessagePack formatbincode- Bincode formatserde_json- JSON formattokio- Async runtimebytes- Efficient byte buffersahash- Fast hashingthiserror- Error handling
License
MIT
Contributing
Contributions are welcome! This is part of the broader TX-2 project for building isomorphic applications with a unified world model.