Stream → Schema
Schema
Compiles an ordered field list into a binary schema. Fixed-size schemas — those with no string fields — pre-compute byte offsets at compile time and are eligible for delta compression.
Stream.Schema.New()
Stream.Schema.New(definition: {{ string | {any} }}) → Schema
Pass an ordered array of { fieldName, typeName } pairs. The order determines wire layout — both server and client must use the same definition.
local Stream = RoExpress("Stream")
-- Fixed-size: all fields have known byte widths → delta eligible
local moveSchema = Stream.Schema.New({
{ "pos", "Vector3" }, -- 12 B
{ "vel", "Vector3" }, -- 12 B
{ "cf", "CFrameLight" }, -- 16 B
{ "state", { "flags", "jumping", "sprinting", "crouching" } }, -- 1 B
{ "health", "u16" }, -- 2 B
}) -- total: 43 bytes per packet
-- Variable-size: string field → not delta eligible
local chatSchema = Stream.Schema.New({
{ "name", "string" },
{ "message", "string" },
})
Fixed-size vs variable-size. A schema is fixed-size when every field has a known byte width at compile time. Adding even one
string field makes the whole schema variable-size, which disables delta compression for that channel.Built-in types
| Type name | Wire size | Notes |
|---|---|---|
f32 | 4 B | Single-precision float |
f64 | 8 B | Double-precision float |
u8 | 1 B | Unsigned integer 0–255 |
u16 | 2 B | Unsigned integer 0–65535 |
u32 | 4 B | Unsigned integer 0–4294967295 |
i8 | 1 B | Signed integer −128–127 |
i16 | 2 B | Signed integer −32768–32767 |
i32 | 4 B | Signed integer −2147483648–2147483647 |
bool | 1 B | Boolean stored as u8 |
string | 2 + len B | u16 length-prefix. Makes schema variable-size — no delta. |
Vector3 | 12 B | 3× f32 (X, Y, Z) |
Vector2 | 8 B | 2× f32 (X, Y) |
Vector3int16 | 6 B | 3× i16 |
Vector2int16 | 4 B | 2× i16 |
CFrame | 28 B | Position (3× f32) + quaternion (Shepperd method, all 4 degenerate cases) |
CFrameLight | 16 B | Position (3× f32) + Y-yaw only. Cheaper for humanoids. |
Color3 | 3 B | RGB as u8 (0–255 each) |
Color3float | 12 B | RGB as f32 (full precision) |
BrickColor | 2 B | u16 palette value |
UDim | 8 B | Scale f32 + Offset i32 |
UDim2 | 16 B | 2× UDim |
Rect | 16 B | Min + Max as Vector2 |
NumberRange | 8 B | Min f32 + Max f32 |
Ray | 24 B | Origin + Direction as Vector3 |
PhysicalProperties | 20 B | Density, Friction, Elasticity, FrictionWeight, ElasticityWeight as f32 |
{ "flags", ... } | 1 B | Up to 8 named booleans packed into one byte |
{ "enum", EnumType } | 2 B | EnumItem → u16 value |
Custom types
Register additional types with Stream.Types.Register() before calling Stream.Init().
Stream.Types.Register("hp", {
size = 2,
write = function(buf, offset, value)
buffer.writeu16(buf, offset, value)
end,
read = function(buf, offset)
return buffer.readu16(buf, offset)
end,
})
Example — movement schema
-- shared.luau — required on both server and client
local RoExpress = require(game.ReplicatedStorage.RoExpress)
local Stream = RoExpress("Stream")
local moveSchema = Stream.Schema.New({
{ "pos", "Vector3" }, -- 12 B
{ "vel", "Vector3" }, -- 12 B
{ "cf", "CFrameLight" }, -- 16 B
{ "state", { "flags", "jumping", "sprinting", "crouching" } }, -- 1 B
{ "health", "u16" }, -- 2 B
}) -- 43 bytes per packet | fixed-size | delta eligible
return moveSchema
See also
← Stream · Channels | using a schema to define a channel · Server Side | delta send methods · FPS Guide | full movement schema walkthrough