{"id":"xopoiii/blinkblox","name":"blinkblox","scope":"xopoiii","platform":"roblox","description":"The BlinkBlox compiler as a library: a schema in, the generated network modules out","version":"1.0.1","latest":"1.0.1","versions":["1.0.1"],"license":"MIT","licenseRating":"safe","licenseCaveats":[],"licenseVerified":true,"dependencies":{},"integrity":"2cebf339a836c455ebef705560455a0b680f133b8739e7fc0d0dca32d1a6c418","likes":0,"downloads":0,"install":"forest install xopoiii/blinkblox","url":"https://forest.dev/p/roblox/xopoiii/blinkblox","files":"https://api.forest.dev/ai/package/roblox/xopoiii/blinkblox/files","readme":"<div align=\"center\">\n  <img src=\"./docs/src/assets/logo.png\" alt=\"BlinkBlox logo\" width=\"160\">\n\n# BlinkBlox\n\n**An IDL compiler for Roblox buffer networking whose generated server is safe to point at the open internet.**\n\n[![License](https://img.shields.io/github/license/XopoIII/BlinkBlox?style=flat-square&color=%23a350af)](LICENSE)\n[![Release](https://img.shields.io/github/v/release/XopoIII/BlinkBlox?style=flat-square&color=%23a350af)](https://github.com/XopoIII/BlinkBlox/releases/latest)\n[![Docs](https://img.shields.io/badge/docs-xopoiii.github.io-a350af?style=flat-square)](https://xopoiii.github.io/BlinkBlox/)\n\n[Documentation](https://xopoiii.github.io/BlinkBlox/) ·\n[Quick start](https://xopoiii.github.io/BlinkBlox/getting-started/quick-start/) ·\n[Changelog](CHANGELOG.md)\n\n</div>\n\nYou describe your events and functions, and what they carry, in a `.blink` schema. The compiler\ngenerates a server module and a client module in plain Luau. They pack every call into one buffer\nper frame, check everything a client sends before your code sees it, and keep working when a client\nis hostile.\n\n```blink\nevent Damage {\n\tFrom: Client,\n\tType: Reliable,\n\tCall: SingleSync,\n\tRate: 10,\n\tData: struct { Target: Instance(Humanoid), Amount: u8(1..100) }\n}\n```\n\n```luau\n-- Server: the listener runs only after the rate limit has passed and Amount is 1..100.\nNet.Damage.On(function(Player, Hit)\n\tCombat.Apply(Player, Hit.Target, Hit.Amount)\nend)\n\n-- Client\nNet.Damage.Fire({ Target = Humanoid, Amount = 25 })\n```\n\n## Why BlinkBlox\n\n- **Bounded inbound traffic.** Packet size, the number of events in a packet and the number of\n  instance references are capped before anything is parsed. Each player also gets a byte budget.\n- **Rate limits per player and per event.** Set `Rate` and `Burst` on an event, or a default for\n  the whole schema, and `Concurrency` on a function to bound the calls still running. Refused events\n  go to a handler you provide, and nobody is kicked automatically.\n- **Hostile input costs the attacker, not the server.** Every length is checked before the read and\n  the allocation it pays for. A malformed event ends its packet without throwing: the events\n  before it are delivered, and the failure goes to a handler you provide.\n- **A missing Instance costs one event, not the packet.** Under StreamingEnabled an Instance the\n  sender had often is not there on arrival. That event alone is refused and reported; the rest of the\n  packet is still read, at no cost to decoding when everything arrives.\n- **Mistakes other libraries leave silent are named.** A second copy of the module in an Actor errors\n  at require, a send made with `:` instead of `.` says so, a function's listener replaced by a second\n  `.On` warns, a client left waiting for a server that never started says why, and a file of events\n  imported twice warns at compile time. The client's queues are capped as the server's are.\n- **Mismatched builds refuse each other.** A client and a server built from different schemas stop\n  at startup instead of decoding one event as another.\n- **The Roblox types games send.** `Vector2`, `UDim`, `UDim2`, `NumberRange`, `ColorSequence`,\n  `TweenInfo`, and a Roblox enum's items as `Enum(Material)` -- sent by `Value`, never by list\n  position, which can differ between client and server during an engine rollout.\n- **Small on the wire.** Booleans, optional flags, enum values and tags share a bitfield, and\n  `boolean[]` packs eight to a byte. A length is sent relative to its range, a short one in a single\n  varint byte, `CFrame<quat>` fits a rotation in 7 bytes, and\n  `u24`, `i24` and `f24` fill the gap between 16 and 32 bits, so `vector<f24>` is 9 bytes instead of\n  12. A float with a step and a range is quantized: `f32<0.01>(-1..1)` is one byte. An unreliable event\n  that cannot fit is refused at compile time.\n- **Few remote calls.** A `FireAll` goes to every player in one `FireAllClients`, streams to\n  everyone share one packet a frame, and `BatchUnreliable` gathers a frame's unreliable events the\n  same way. A client cuts its batch to fit the server's limits, so an honest player is never refused,\n  and sends at most 60 times a second, since every remote call costs about 11 bytes of its own.\n- **An outbound budget.** Give each player a byte budget for what the server sends, and mark the\n  events and streams that may wait with `Priority: Low`; nothing else is ever held back.\n- **Tooling.** The CLI has watch mode and `@profile` builds that keep debug remotes out of release,\n  `--check --json` reports every diagnostic as JSON for editors and AI assistants, and `--verify`\n  fails a pre-commit hook or CI step when the committed modules no longer match the schema. The generated\n  modules pass their own `--!strict`, and keep their types under the new type solver however many\n  events the schema has. You also get TypeScript definitions and a Studio plugin with\n  live diagnostics.\n\n## Performance\n\nEach tool fires 1000 events a frame from client to server. Blink is the original project BlinkBlox\nforked from, at its last release, 0.18.9. The runs were made on 2026-09-28 on an Intel Core\ni7-13700K: in Studio on BlinkBlox 0.41.2, on LuneBlox on 0.42.0.\n\nIn Studio, the numbers are the median frame rate and the milliseconds a frame's thousand fires took.\nWarp's Fire only queues its value and encodes it later in the frame, where the bench cannot time it,\nso only its frame rate is shown.\n\n| Tool | 1000 booleans | 1000 booleans, each different | 100 entities | 100 entities, each different |\n|---|---|---|---|---|\n| Roblox remotes | 15 FPS, 26.0 ms | 15 FPS, 29.1 ms | 15 FPS, 72.7 ms | 15 FPS, 74.5 ms |\n| **BlinkBlox** | **60 FPS**\\*, 1.9 ms | **60 FPS**\\*, 4.8 ms | **60 FPS**\\*, 2.0 ms | **60 FPS**\\*, 2.4 ms |\n| Blink | **60 FPS**\\*, 4.5 ms | **60 FPS**\\*, 9.9 ms | 44 FPS, 2.8 ms | 45 FPS, 3.2 ms |\n| zap | **60 FPS**\\*, 12.2 ms | 46 FPS, 18.1 ms | 45 FPS, 7.4 ms | 44 FPS, 7.8 ms |\n| ByteNet | 30 FPS, 17.5 ms | 23 FPS, 21.4 ms | 35 FPS, 15.8 ms | 34 FPS, 16.6 ms |\n| Packet | 35 FPS, 27.3 ms | 28 FPS, 31.8 ms | 27 FPS, 19.2 ms | 27 FPS, 19.9 ms |\n| QuickNet | **60 FPS**\\*, 1.9 ms | **60 FPS**\\*, 7.1 ms | 58 FPS, 6.2 ms | 57 FPS, 6.7 ms |\n| Warp | **60 FPS**\\* | 55 FPS | 33 FPS | 32 FPS |\n\n\\* Studio caps the frame rate at 60.\n\nOn [LuneBlox](https://github.com/XopoIII/LuneBlox), without Roblox -- the Luau version and flags\nRoblox runs -- on an Intel Core i7-13700K with BlinkBlox 0.42.0, each figure the median of three\nruns, every tool in a process of its own. \"Send\" is a frame's thousand fires and the flush into a\npacket, interpreted, as most players' clients run it; \"decode\" is the server decoding them, natively\ncompiled, as a Roblox server runs it; bytes are one event before compression.\n\n| Tool | 1000 booleans: send / decode | 100 entities: send / decode | Bytes, booleans / entities |\n|---|---|---|---|\n| **BlinkBlox** | **16.3** / **6.7 ms** | **12.1** / **3.6 ms** | **128** / **602** |\n| Blink | 29.3 / 10.7 ms | 12.8 / 21.8 ms | 1003 / 603 |\n| zap | 65.5 / 11.5 ms | 33.4 / 21.2 ms | 1003 / 603 |\n| ByteNet | 54.2 / 51.0 ms | 42.7 / 42.5 ms | 1003 / 603 |\n| Packet | 54.0 / 51.0 ms | 39.9 / 52.7 ms | 1003 / 603 |\n| QuickNet | 16.8 / 7.5 ms | 21.7 / 11.4 ms | **128** / 603 |\n| Warp | 38.5 / 11.5 ms | 65.7 / 26.9 ms | **128** / **602** |\n\nA game also sends the other way. Send then decode, natively, medians of five runs; the broadcast\nreaches fifty players, and the inputs go from one client to the server:\n\n| Tool | 100 structs a frame to everyone, `FireAll` | 8 unreliable inputs a frame |\n|---|---|---|\n| **BlinkBlox** | **0.020 / 0.012 ms, 1 remote call** | 0.002 / 0.003 ms, 8 calls; **0.002 / 0.001 ms, 1 call** with [`BatchUnreliable`](https://xopoiii.github.io/BlinkBlox/language/options/#batchunreliable) |\n| Blink | 0.711 / 0.026 ms, 50 calls | 0.002 / 0.003 ms, 8 calls |\n| zap | 0.734 / 0.025 ms, 50 calls | 0.003 / 0.002 ms, 8 calls |\n| ByteNet | 0.044 / 0.109 ms, 1 call | 0.003 / 0.008 ms, 1 call |\n| Packet | 0.084 / 0.170 ms, 1 call | no unreliable channel |\n| QuickNet | 0.306 / 0.034 ms, 50 calls | 0.002 / 0.003 ms, 1 call |\n| Warp | 2.350 / 0.113 ms, 50 calls | 0.004 / 0.009 ms, 1 call |\n\nA client receiving 100 events a frame spread over 128 declarations decodes them in 0.008 ms\nnatively and 0.020 ms interpreted: the event an index names is found by halving the range rather\nthan one comparison after another.\n\nThe methodology, the bandwidth, the random payloads, streams and the full percentiles are in\n[Benchmarks](https://xopoiii.github.io/BlinkBlox/guides/benchmarks/) and\n[`benchmark/Benchmarks.md`](benchmark/Benchmarks.md). What 1.0.0 changed is in\n[What's new in 1.0](https://xopoiii.github.io/BlinkBlox/guides/whats-new/).\n\n## Where it comes from\n\nBlinkBlox is a maintained fork of [Blink](https://github.com/1Axen/blink). Upstream froze this line\nof the compiler and began a rewrite. It left reported defects open, including an unbounded parse of\na hostile client buffer. This fork fixes them and continues from `v0.18.8`. See\n[Migrating from Blink](https://xopoiii.github.io/BlinkBlox/guides/migrating-from-blink/).\n\n## Install\n\n```sh\nrokit add XopoIII/BlinkBlox blinkblox             # CLI through Rokit\npesde add xopoiii/blinkblox --dev --target lune   # or through pesde\n```\n\nBinaries for every platform, and the Studio plugin (`blinkblox-plugin.rbxm`), are attached to each\n[release](https://github.com/XopoIII/BlinkBlox/releases/latest). The plugin is also on the Creator\nStore as **BlinkBlox Editor**. Code that runs the compiler inside Roblox -- a plugin, an in-Studio\nbuild step -- can take it from Wally as `xopoiii/blinkblox`. See [Installation](https://xopoiii.github.io/BlinkBlox/getting-started/installation/).\n\n## Contributing\n\n```sh\nrokit install              # toolchain\nsh scripts/run-tests.sh    # test suite\ncd docs && npm install && npm run dev   # documentation site\n```\n\n`CLAUDE.md` describes the architecture and the gates that CI and the git hooks run.\n\n## Credits\n\nOriginally written by [Axen](https://github.com/1Axen). This fork continues from v0.18.8 and remains\nMIT licensed.\n","readmeTruncated":false}