A streaming, binary-first alternative to JSON designed for low-latency, incremental data transmission. BiWi encodes messages in raw binary, allowing clients to send fields and chunks as they arrive, and servers to start processing instantly.
๐ AI Git Commit Comments - Thanks for that github, saved me time.
โจ Binary-First Design - Compact, efficient binary encoding
๐ Low-Latency - Minimal overhead, optimized for real-time communication
๐ก Streaming Support - Send data in chunks for incremental processing
๐ฎ Game Networking - Perfect for multiplayer games and real-time apps
๐ Type System - Full support for typed fields (int32, int64, float32, float64, strings, binary, arrays, objects)
โก Real-Time - Process messages as they arrive without waiting for completion
๐งฉ Modular - Clean separation between core, server, and client modules
Command: npm run test:benchmark
- BiWi: ~84k msgs/sec (1000 msgs, 200-msg warm-up)
- JSON (NDJSON): ~124k msgs/sec (1000 msgs, 200-msg warm-up)
- Protobuf (len-prefix): ~125k msgs/sec (1000 msgs, 200-msg warm-up)
Notes:
- Throughput tests include an 8s safety timeout to prevent hangs.
- Warm-up requests stabilize JIT/GC before timing.
Its not on npm so wont work lol
npm install binarywire import { BiWiServer, BiWiMessage } from 'binarywire/server';
const server = new BiWiServer({ port: 3000 });
// Handle incoming messages
server.on(1, (connection, value) => {
console.log('Received:', value);
// Send response
const response = new BiWiMessage();
response.setField(2, 'Got it!');
connection.send(response);
});
server.listen();import { BiWiClient, BiWiMessage } from 'binarywire/client';
const client = new BiWiClient({ host: 'localhost', port: 3000 });
await client.connect();
// Send message
const msg = new BiWiMessage();
msg.setField(1, 'Hello Server!');
await client.send(msg);
// Handle responses
client.on('field', ({ fieldId, value }) => {
console.log(`Field ${fieldId}:`, value);
});Each BiWi message consists of one or more fields:
[Field 1][Field 2][Field 3]...
โ โ โ
โโโ [fieldId: 2 bytes][fieldType: 1 byte][value]
โโโ [fieldId: 2 bytes][fieldType: 1 byte][value]
โโโ [fieldId: 2 bytes][fieldType: 1 byte][value]
- NULL (0x00) - Null value
- BOOLEAN (0x01) - True/False
- INT32 (0x02) - 32-bit integer
- INT64 (0x03) - 64-bit integer
- FLOAT32 (0x04) - Single-precision float
- FLOAT64 (0x05) - Double-precision float
- STRING (0x06) - UTF-8 string
- BINARY (0x07) - Raw binary data
- ARRAY (0x08) - Ordered collection
- OBJECT (0x09) - Key-value mapping
- CHUNK_START (0x0A) - Begin streaming chunk
- CHUNK_DATA (0x0B) - Chunk payload
- CHUNK_END (0x0C) - End streaming
Send large data in chunks without waiting for completion:
const encoder = new BiWiEncoder();
encoder.encodeChunkStart(1, totalSize);
encoder.encodeChunkData(0, chunk1);
encoder.encodeChunkData(1, chunk2);
encoder.encodeChunkEnd();
const buffer = encoder.toBuffer();Low-level encoding/decoding:
import { BiWiEncoder, BiWiDecoder, BiWiTypes } from 'binarywire/core';
// Encode
const encoder = new BiWiEncoder();
encoder.encodeField(1, 'Hello');
encoder.encodeField(2, 42);
const buffer = encoder.toBuffer();
// Decode
const decoder = new BiWiDecoder(buffer);
const fields = decoder.decodeAll();Server implementation:
import { BiWiServer } from 'binarywire/server';
const server = new BiWiServer({ port: 3000 });
server.listen();Client implementation:
import { BiWiClient } from 'binarywire/client';
const client = new BiWiClient({ host: 'localhost', port: 3000 });
await client.connect();Run the example server:
npm run example:serverRun the example client (in another terminal):
npm run example:client- Game Networking - Low-latency, efficient multiplayer communication
- Real-Time Applications - Live dashboards, monitoring systems
- IoT Devices - Minimal bandwidth overhead
- Microservices - Fast inter-service communication
- Streaming Data - Incremental data transmission
- Live Updates - Push updates with minimal latency
- Fixed-size types: 5-9 bytes per field (type + value)
- Variable-size types: 3 bytes overhead + payload
- Field headers: 3 bytes (2 bytes field ID + 1 byte type)
- No framing overhead - Pack multiple fields into a single message
const msg = new BiWiMessage();
msg.setField(fieldId, value);
msg.getField(fieldId);
msg.toBuffer();
msg.getSize();const server = new BiWiServer(options);
server.listen();
server.on(fieldId, handler);
server.broadcast(message);
server.sendToClient(connectionId, message);
server.close();const client = new BiWiClient(options);
await client.connect();
client.send(message);
client.onField(fieldId, handler);
client.disconnect();Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0)
Contributions are welcome! Please feel free to submit pull requests. Probably wont see it but heck do it anyway.