BlinkBlox | Buffer networking that checks everything a client sends

BlinkBlox

Buffer networking for Roblox whose server is safe to point at the open internet.

GitHub · Documentation · Quick start

First, a big thank you to @1Axen for Blink. It has helped me a lot, and the schema language they designed is a genuinely great way to describe networking. It was a shame to see the project move to a from-scratch rewrite, though: I needed bug fixes and new features now, and the version everyone uses was only getting major fixes. So I forked it, and ended up reworking pretty much everything - the runtime, the wire format, the security layer, the plugin - keeping the .blink schema you already have in your project. The language only grew, so your schemas carry over.

TL;DR - how it compares

BlinkBlox Blink zap ByteNet Packet QuickNet Warp
Server decode, 100 structs ×1000 a frame 3.58 ms 21.83 ms 21.16 ms 42.49 ms 52.70 ms 11.37 ms 26.91 ms
Client send, 1000 booleans (interpreted) 16.26 ms 29.34 ms 65.52 ms 54.15 ms 53.99 ms 16.78 ms 38.47 ms
Bytes for a boolean[1000] 128 B 1003 B 1003 B 1003 B 1003 B 128 B 128 B
FireAll of 100 structs to 50 players 0.020 ms, 1 call 0.711 ms, 50 calls 0.734 ms, 50 calls 0.044 ms, 1 call 0.084 ms, 1 call 0.306 ms, 50 calls 2.350 ms, 50 calls
Studio FPS at 1000 random structs a frame (RemoteEvents: 15) 60* 45 44 34 27 57 32

* Studio caps the frame rate at 60. Intel i7-13700K, on LuneBlox 0.10.9 (the Luau version Roblox runs, with Roblox’s flags); BlinkBlox 0.42.0 (Studio: 0.41.2), Blink 0.18.9, zap 0.6.29, ByteNet 0.4.3, Packet 1.7.0, QuickNet 0.3.5, Warp 1.1.0-pre7; medians of three to five runs. Don’t trust us - run it: luneblox run Rivals in benchmark/. Full methodology: Benchmarks.

Why another networking library?

It isn’t a new one - it’s Blink, continued. The 0.18 line was left with reported bugs open, including a hostile client buffer that could be parsed without bounds (upstream issue #45). BlinkBlox fixed those, then kept going for over twenty releases.

Every library on this forum is fast. BlinkBlox is fast and treats every client as an attacker. Exploiters don’t use your client code - they write packets by hand. Your server shouldn’t care.

The libraries around it leave that gap open: zap has no rate limiting at all (its maintainer’s position in issue #219 is that throttling is the game’s job) and no pcall around each event, so one malformed event throws away the rest of that player’s batch. Packet matches a function’s reply by slot alone and has no schema check between client and server. QuickNet allocates whatever length a packet names before checking it. Blink’s 0.18 line left the unbounded parse open.

How it works

Describe your events once in a .blink schema. The compiler generates plain Luau modules (and TypeScript definitions) for the server and the client.

event Damage {
    From: Client,
    Type: Reliable,
    Call: SingleSync,
    Rate: 10,
    Data: struct { Target: Instance(Humanoid), Amount: u8(1..100) }
}
-- Server: runs only after the rate limit passed, Target is a Humanoid and Amount is 1..100
Net.Damage.On(function(Player, Hit)
    Combat.Apply(Player, Hit.Target, Hit.Amount)
end)

-- Client
Net.Damage.Fire({ Target = Humanoid, Amount = 25 })

No validation code, no type checks, no rate limiter to write. It’s all generated.

What you get

Security

  • Per-player, per-event token buckets (Rate, Burst, option DefaultRate), a per-player inbound byte budget, and Concurrency for functions whose listeners yield.
  • Packet size, event count and Instance count are capped before anything is parsed.
  • Every length is checked before the read and the allocation it pays for - a lying length prefix buys the attacker nothing.
  • A malformed event ends its packet cleanly: the events before it are still delivered.
  • A client and a server built from different schemas refuse each other instead of decoding one event as another.
  • Hooks for your anti-cheat: SetPacketDropHandler, SetDecodeErrorHandler and a rate-limit handler, each told which player did what. Nobody is kicked automatically - you decide.

Performance and bandwidth

  • One buffer per frame, and a FireAll is a single FireAllClients no matter how many players.
  • Booleans, optionals, enums and tags share one bitfield; boolean[] packs eight to a byte.
  • Lengths are sent relative to their range, usually in one byte.
  • Quantized floats: f32<0.01>(-1..1) is 1 byte instead of 4.
  • u24, i24, f24: vector<f24> is 9 bytes instead of 12. CFrame<quat> fits a rotation in 7 bytes.
  • A per-player outbound budget: events marked Priority: Low are the first to be left out when a player’s connection is full.
  • An unreliable event that can’t fit in a packet is refused at compile time, not dropped silently in production.
  • Streams for world state, and Stamp for lag-compensated hit checks the server clamps.

Tooling

  • A Studio plugin with syntax highlighting, autocomplete and live diagnostics.
  • A CLI with watch mode, @profile builds that keep debug remotes out of release, and --check --json for editors and AI assistants.
  • TypeScript output for roblox-ts.
  • The generated modules pass their own --!strict.
  • Converters from zap, ByteNet, Packet, QuickNet and Warp: blinkblox <definitions> --from <library> writes a draft schema from what your game already defines.
Full benchmarks

In Studio - 1000 events a frame for ten seconds, medians. “ms” is the client CPU time the frame’s fires took; bytes are per event after Roblox’s compression. Warp only queues a value on fire and encodes it later in the frame, so its fire time can’t be measured - its cost shows in the FPS.

Payload RemoteEvents BlinkBlox Blink zap ByteNet Packet QuickNet Warp
1000 booleans 15 FPS, 26.0 ms 60 FPS, 1.92 ms 60 FPS, 4.52 ms 60 FPS, 12.15 ms 30 FPS, 17.45 ms 35 FPS, 27.31 ms 60 FPS, 1.89 ms 60 FPS
1000 random booleans 15 FPS, 29.1 ms 60 FPS, 4.81 ms, 128.4 B 60 FPS, 9.89 ms, 193.9 B 46 FPS, 18.08 ms, 193.8 B 23 FPS, 21.40 ms, 193.3 B 28 FPS, 31.79 ms, 194.2 B 60 FPS, 7.12 ms, 128.1 B 55 FPS, 128.6 B
100 entities 15 FPS, 72.7 ms 60 FPS, 1.98 ms 44 FPS, 2.81 ms 45 FPS, 7.35 ms 35 FPS, 15.79 ms 27 FPS, 19.24 ms 58 FPS, 6.21 ms 33 FPS
100 random entities 15 FPS, 74.5 ms 60 FPS, 2.38 ms 45 FPS, 3.16 ms 44 FPS, 7.77 ms 34 FPS, 16.55 ms 27 FPS, 19.93 ms 57 FPS, 6.74 ms 32 FPS

On LuneBlox, the Luau Roblox runs, without Roblox - ms a frame: send interpreted (as most clients run it) / decode natively (as a server runs it), and bytes per event before compression.

Payload BlinkBlox Blink zap ByteNet Packet QuickNet Warp
1000 booleans 16.26 / 6.72, 128 B 29.34 / 10.66, 1003 B 65.52 / 11.49, 1003 B 54.15 / 50.99, 1003 B 53.99 / 50.95, 1003 B 16.78 / 7.48, 128 B 38.47 / 11.47, 128 B
100 entities 12.09 / 3.58, 602 B 12.75 / 21.83, 603 B 33.39 / 21.16, 603 B 42.69 / 42.49, 603 B 39.90 / 52.70, 603 B 21.69 / 11.37, 603 B 65.72 / 26.91, 602 B

Game scenarios, natively, fifty players - send ms, decode ms, remote calls a frame.

Scenario BlinkBlox Blink zap ByteNet Packet QuickNet Warp
100 structs to everyone, FireAll 0.020, 0.012, 1 call 0.711, 0.026, 50 calls 0.734, 0.025, 50 calls 0.044, 0.109, 1 call 0.084, 0.170, 1 call 0.306, 0.034, 50 calls 2.350, 0.113, 50 calls
8 unreliable inputs a frame, BatchUnreliable 0.002, 0.001, 1 call 0.002, 0.003, 8 calls 0.003, 0.002, 8 calls 0.003, 0.008, 1 call no unreliable channel 0.002, 0.003, 1 call 0.004, 0.009, 1 call
100 events carrying a Part 0.005, 0.011 0.005, 0.013 0.006, 0.009 0.031, 0.093 0.038, 0.126 0.014, 0.027 0.031, 0.091
16 units a frame to 50 players, unreliable 0.002, 0.001, 1 call 0.002, 0.004, 1 call 0.003, 0.004, 1 call 0.008, 0.009, 1 call no unreliable channel 0.014, 0.003, 50 calls 0.198, 0.006, 50 calls
Each player their own unit, unreliable 0.012, 0.000 0.013, 0.001 0.016, 0.001 0.033, 0.002 no unreliable channel 0.025, 0.001 0.046, 0.002

The one place BlinkBlox isn’t first is decoding Instances, where zap is faster: zap doesn’t check that what arrives is an Instance at all, while BlinkBlox verifies each one’s class before your code sees it.

The fine print. Studio caps at 60 FPS and compiles LocalScripts natively, which most clients don’t - that’s why the LuneBlox numbers exist. Inbound limits are raised for the flood: BlinkBlox’s through the schema, Packet’s and Warp’s hard-coded 8000 bytes patched in the downloaded copy, QuickNet’s per-event rate limit lifted the way its own benchmark does. Every check still runs and is counted. Identical payloads compress to almost nothing, which is why the random benches exist. Warp sends each reliable packet XORed against the last, so the random benches never repeat a frame. The harness and full percentiles are in benchmark/.

Install

rokit add XopoIII/BlinkBlox blinkblox
pesde add xopoiii/blinkblox --dev --target lune

Binaries for every platform and the plugin .rbxm are attached to each release.

MIT licensed. Originally written by Axen;

10 Likes

Solid work, you’ve left me curious as to how honest those benchmarks are- They look too good to be true, you’re not hiding any major hurdles here are you?

4 Likes

I don’t particularly trust something that uses AI-generated imagery and AI-adjacent writing styles[1]


  1. Rules of three, Emojis for titles, “It’s not just X, It’s Y” ↩︎

16 Likes

gotta agree with you there ngl

1 Like

Everything is publicly available; you can run your own tests and share the results. I’m developing a game and went all-in on optimization—I used Blink, but it wasn’t enough.

Are you suggesting I draw in Paint? Why bother when AIs draw better?

3 Likes

That’s the problem, you think more of the result itself rather than the trust that comes with releasing a resource to the public.

As I stated; The result is not what I am looking for, it is the trust that isn’t good.

11 Likes

I second this ^
I would vastly prefer a poorly drawn MS paint image that I knew a human made over the robot

4 Likes

Given that you’re willing to use AI to write your post and create your images, how do you expect us to trust you that this resource is not just vibecoded slop?

4 Likes

oh, I see, my apologies, then. But if you don’t like it, just move on.

2 Likes

Thanks for your opinion; if you can draw it, send it over and I’ll publish it.

3 Likes

There are people in this world that absolutely hate AI and anything related to AI. It is their opinion but when it comes down to calling other people out, I would highly recommend just reporting their post and moving on. There are people who’d support your work, and people who’d criticize it.

It’s understandable that even drawing something in MS paint won’t be as good as one by AI, so using AI isn’t anything bad at all, yet a few specific groups of people just don’t like it.

4 Likes

Well, you can always test it out, I’m not asking you to just take my word for it; I shared it because I use it myself.

2 Likes

Thank you, I understand, I just need not to take it to heart, but that’s hard.

4 Likes

The problem is that AI doesn’t actually draw better. It’s more an imitation of quality visuals with a distinct, weird look, making it incredibly easy to recognize.

I believe he’s simply suggesting you don’t put AI-generated images in your post, even if that means having zero images. The AI-generated “drawings” add zero value, and work against you, as it signals a lack of care and effort to most people.

You’re essentially putting a massive “AI Slop” mark on your resource and expecting people to take it seriously.

4 Likes

Im not against AI as I am also using it to speed up work and crank up those boring documentations. But in your post, youre using an image which adds noise (AI generated image is no big deal but its not really that relevant to the post), a simple intro description, “your benchmark”, use-case of what problem this resource is meant to solve and a simple example (just brief) on how to use your resource (if you dont have a separate documentation) will do. AND those emojiiiiiiiiissss, are those intentional (which is weird)? Or “you dont bother checking the template the AI generated for you” (if this is the case then highly likely the codebase… you know that what I mean)?

And lastly… While reading comments, it seems you do use AI for this resource, just disclose it loudly and properly (whats the point of your ego or indenial if the reality says so).

2 Likes

Also known as using AI as it was intended to: as a tool as opposed to the creator.

1 Like

Ok, I caved and deleted them. Better now?

But I’m not denying it. I just said that I can’t draw, so what else was I supposed to do? What’s the issue here?

dont care the entire post and page are ai generated, just want to see the results, the benchmarks look interesting so i will try this out.

3 Likes