Serialization
One tagged binary codec carries values across the SSR ↔ hydration boundary: island props, island state structs, and anything you encode yourself.
The codec
try verve.serialize.encode(value, &buf, alloc); // append tagged bytes
const v = try verve.serialize.decode(T, bytes, alloc);
const owned = try verve.serialize.encodeToBytes(value, alloc);Supported types: bool, all int widths, f32/f64, []const u8, optionals, slices, structs, enums (tag int). Decode errors are explicit: Corrupt, TypeMismatch, EndOfStream.
The positional contract
Structs encode in declaration order, not by field name. This is the single most important fact about Verve serialization:
// islands.zig (server side)
pub const Props = struct {
xs: []const f64, // field 0
ys: []const f64, // field 1
};
// chunk side — MUST mirror field-for-field
const Props = struct {
xs: []const f64,
ys: []const f64,
};Reorder, add, or remove a field on one side only and hydration silently decodes garbage — no error, just wrong values. The framework convention is a WARNING comment on both sides naming the mirror file; keep it.
Props schema strings
The registry's props_schema documents the wire shape for the build manifest:
pub const props_schema: []const u8 =
"{\"xs\":\"f64[]\",\"ys\":\"f64[]\",\"layout\":\"u32\",\"label\":\"string\"}";Wire types: i32, u32, f32, f64, bool, string, plus [] array variants. No fixed-array tag — flatten [3]f32 into three scalars (the GL scene's light_dir_x/y/z is the canonical example).
Encoding props at render time
const props = try verve.encodeProps(ctx, islands.VizGraph.Props{ .xs = xs, .ys = ys });
const island = verve.island(ctx, .{ .name = "VizGraph", .props = props }, inner);Chunk side: verve.decodeProps(Props, bytes, alloc).
Next: Security.