KravasNet
KravasNet is a lightweight abstraction layer built on top of ByteNet (opens in a new tab), designed to simplify networking inside the Kravas framework for Roblox Studio.
ByteNet already gives you fast, typed, buffer-packed networking. KravasNet adds an organizational layer on top of it: Namespaces and Channels, so packet definitions read like a small, chainable API surface instead of a pile of raw ByteNet.definePacket() calls scattered across scripts.
Version note. As of KravasNet v0.5, every packet is registered through
ByteNet.defineNamespace() under the hood, matching the requirements of
ByteNet 0.4.x. This is a breaking internal change from earlier
KravasNet releases (which called ByteNet.definePacket() standalone) —
the public API you write against is unchanged, but the timing of when a
namespace becomes "live" on the network is new. See
Building Namespaces and
Best Practices before shipping.
Why KravasNet?
| Problem with raw ByteNet | How KravasNet helps |
|---|---|
Every packet needs its own defineNamespace(name, function() ... end) boilerplate | One KravasNet.createNamespace() call groups everything |
Server methods take (data, player), client differs by context | Unified Channel API: sendTo(player, data) on both read naturally |
| No place to validate or sanitize incoming data | Built-in Middleware pipeline |
| Easy to forget a packet must be declared before the namespace is used | Explicit :build() step with a clear error if you add too late |
Core Concepts
KravasNet is built around three ideas:
- Namespace — a named container that groups related channels together (e.g.
"Combat","Player","Queue"). Maps 1:1 to oneByteNet.defineNamespace()call. - Channel — a single typed packet definition (one ByteNet packet), with its own schema, reliability mode, and middleware chain.
- Build — the moment a namespace's pending channels are handed to ByteNet as a single batch. This happens automatically on first use, or explicitly via
:build()(recommended — see Best Practices).
local CombatNet = KravasNet.createNamespace("Combat")
:add("Damage", { amount = KravasNet.float32, target = KravasNet.inst })
:add("Position", { pos = KravasNet.vec3 }, { reliability = "unreliable" })
CombatNet:build() -- registers everything with ByteNet right now
-- Server
CombatNet.Damage:sendTo(player, { amount = 50, target = someCharacter })
-- Client
CombatNet.Position:on(function(data)
print(data.pos)
end)Notice KravasNet.float32, KravasNet.vec3, KravasNet.int8, etc. are
used without parentheses — they are pre-built type descriptors, not
factory functions. Only KravasNet.optional(), KravasNet.array(),
KravasNet.struct(), and KravasNet.map() are actual functions you call.
See Data Types for the full breakdown.
Continue to the Quick Start guide, or jump to Best Practices if you're migrating from an older KravasNet version.