Encoding & Wire Format
PaindaProtocol is built to minimize serialization overhead and bandwidth usage. It uses a custom Binary layout to achieve 70-90% smaller payloads compared to standard JSON WebSockets.
The Binary Frame (v2)
Instead of passing raw JSON strings natively over WebSockets, Painda encodes every message into a strict Binary Frame starting with a 16-byte header:
| Bytes | Field | Description |
|---|---|---|
| 0-3 | Magic Bytes | 0x50504E44 ("PPND") - Identifies a valid Painda frame. |
| 4-5 | Version (uint16) | Wire protocol version (currently 2). |
| 6-7 | Flags (uint16) | Bits 0-1 mode, Bit 2 compression, Bit 3 custom schema encoding. |
| 8-11 | Length (uint32) | Length of the following payload array. |
| 12-13 | Type ID (uint16) | 0 = JSON fallback, >0 = Custom Schema ID. |
| 14-15 | Reserved (uint16) | Reserved for future expansion. |
| 16+ | Payload | The encoded message bytes. |
Fallback: JSON mode
By default, if you don't define a custom schema, PaindaProtocol uses JSON encoding wrapped inside the binary frame. This means the header routing is hyper-fast, but the payload itself is standard TextEncoder().encode(JSON.stringify(msg)). This provides perfect Developer Experience (DX) for modern apps without writing schemas.
Custom Schemas (Maximum Speed)
For high-frequency game packets (like player movement), JSON is too bloated. PaindaProtocol allows you to register custom binary schemas using the PPSchemaRegistry.
const { PPSchemaRegistry, structSerializer } = require("@painda/core/schema");
// 1. Create a registry
const registry = new PPSchemaRegistry();
// 2. Register your high-freq payload
registry.register("player_move", 1, structSerializer([
{ name: "x", type: "float32" },
{ name: "y", type: "float32" }
]));
// Now { type: "player_move", payload: { x: 10.5, y: -4.2 } }
// is encoded into exactly 8 bytes of payload instead of ~50 bytes of JSON!
Compression Support
If your payload exceeds the compression threshold, the server automatically compresses it using Zlib/Deflate (for Node.js) and sets the `FLAG_COMPRESSED` bit. Browser clients decompress this seamlessly using the Native Web DecompressionStream API.