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 nameWire sizeNotes
f324 BSingle-precision float
f648 BDouble-precision float
u81 BUnsigned integer 0–255
u162 BUnsigned integer 0–65535
u324 BUnsigned integer 0–4294967295
i81 BSigned integer −128–127
i162 BSigned integer −32768–32767
i324 BSigned integer −2147483648–2147483647
bool1 BBoolean stored as u8
string2 + len Bu16 length-prefix. Makes schema variable-size — no delta.
Vector312 B3× f32 (X, Y, Z)
Vector28 B2× f32 (X, Y)
Vector3int166 B3× i16
Vector2int164 B2× i16
CFrame28 BPosition (3× f32) + quaternion (Shepperd method, all 4 degenerate cases)
CFrameLight16 BPosition (3× f32) + Y-yaw only. Cheaper for humanoids.
Color33 BRGB as u8 (0–255 each)
Color3float12 BRGB as f32 (full precision)
BrickColor2 Bu16 palette value
UDim8 BScale f32 + Offset i32
UDim216 B2× UDim
Rect16 BMin + Max as Vector2
NumberRange8 BMin f32 + Max f32
Ray24 BOrigin + Direction as Vector3
PhysicalProperties20 BDensity, Friction, Elasticity, FrictionWeight, ElasticityWeight as f32
{ "flags", ... }1 BUp to 8 named booleans packed into one byte
{ "enum", EnumType }2 BEnumItem → 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