Custom CFrame replication framework for Roblox, built in --!strict Luau.
Cerebrum replaces how entity positions and rotations travel across the network. Instead of relying on Roblox's built-in replication (which you can't control), Cerebrum serializes CFrames into compact binary buffers, sends them through custom channels, and reconstructs smooth movement on the receiving end with snapshot interpolation. On top of that core: dead reckoning, lag-compensated hitbox rewind, per-player visibility rules, distance-based tick rates, and NTP-style clock synchronization. Hot paths run with --!native.
Author: eternaIjoe
Roblox's default replication is a black box. You can't control who sees what, how often updates are sent, or how movement gets smoothed on the receiving end. If you've ever played a competitive Roblox game and noticed players teleporting, rubberbanding, or being hit behind walls — that's the default system showing its limits.
Cerebrum gives you full control over the replication pipeline:
- Per-player visibility — hide entities from specific players, show only to teammates, distance-gate replication
- Binary serialization — 11–21 bytes per entity per tick instead of Roblox's bloated property replication
- Snapshot interpolation — Hermite cubic splines using true physics velocities as tangents, SLERP for rotation, adaptive jitter buffers
- Dead reckoning — render entities at estimated current position instead of buffer-seconds in the past
- Lag compensation — rewind entity hitboxes to where they were on the shooter's screen for fair hit detection
- Distance-based tick rates — full rate nearby, half rate at medium range, nothing at long range
- ClockSync — NTP-style probing measures the actual uncertainty of
GetServerTimeNow()per client
| Feature | Roblox Default | Cerebrum |
|---|---|---|
| Per-player visibility control | No | Yes |
| Binary packet serialization | No | Yes (buffer API) |
| Client-side interpolation | Basic | Hermite cubic + SLERP |
| Dead reckoning | No | Yes (opt-in per type) |
| Lag-compensated raycasting | No | Yes (OBB + capsule) |
| Half-tick / distance culling | No | Yes |
| Entity mounting (parent→child) | No | Yes |
| Frustum culling | No | Yes |
| Clock error measurement | No | Yes (NTP-style Kalman) |
| Live debug overlay | No | Yes |
Cerebrum/
├── Cerebrum.lua ← Entry point
│
├── Shared/
│ ├── Config.lua ← Settings, entity type registration
│ ├── Entity.lua ← Entity lifecycle, CFrame management, constraint lock
│ ├── Holder.lua ← ID registry, model index, player-character map
│ ├── Snapshot.lua ← Ring-buffer with Hermite interpolation (stored-velocity tangents)
│ ├── Serializer.lua ← Binary buffer packing (9-bit quaternion, position, velocity)
│ ├── DeadReckoning.lua ← Velocity extrapolation + correction blending
│ ├── ClockSync.lua ← NTP-style clock error estimation (Kalman filtered)
│ ├── Ticker.lua ← Server-side tick-rate group scheduler
│ ├── Signal.lua ← Lightweight Signal/Event system
│ ├── Events.lua ← Global event bus
│ ├── Remotes.lua ← Remote creation/waiting
│ ├── ReplicationRules.lua ← Per-entity player visibility rules
│ ├── ModelHelper.lua ← CUSTOM mode model cloning/resolution
│ ├── ApplyMounts.lua ← Entity mount chain solver (cycle-safe)
│ ├── Stats.lua ← Live performance counters
│ └── Types.lua ← Exported type definitions
│
├── Server/
│ ├── Replicate.lua ← Server main loop (PreSimulation)
│ ├── Sender.lua ← Builds + fires binary packets per-player
│ ├── Receiver.lua ← Validates incoming client positions
│ ├── Grid.lua ← Spatial hash proximity grid (integer keys, priority accumulator)
│ ├── Player.lua ← Auto-registers player characters
│ ├── Clock.lua ← Per-player Kalman clock offset + adaptive buffer API
│ └── LagCompensation.lua ← Server-side hitbox rewind (Raycast, Spherecast)
│
├── Client/
│ ├── Replicate.lua ← Client main loop (RenderStep), frustum culling
│ ├── Receiver.lua ← Parses packets, pushes to Snapshot
│ ├── Sender.lua ← Sends owned-entity positions to server
│ ├── Player.lua ← Tracks the local player's entity
│ └── Clock.lua ← Adaptive jitter-compensated playback clock
│
└── Debug/
└── Debugger.lua ← Live debug overlay (F8 to toggle)
local Cerebrum = require(game.ReplicatedStorage.Cerebrum)
Cerebrum.Config.SetConfig("TELEPORT_THRESHOLD", 80)
Cerebrum.Config.RegisterEntityType("NPC", {
TICK_RATE = 1/20,
FULL_ROTATION = false,
BUFFER = 0.08,
NETWORK_MODE = "NATIVE",
})
Cerebrum.Start()require(game.ReplicatedStorage.Cerebrum).Start()Player characters are auto-registered. They replicate with snapshot interpolation, constraint-locked HRP, and full binary serialization at 60 Hz out of the box.
| Mode | What Happens | Best For |
|---|---|---|
NATIVE |
Model lives in Workspace. Cerebrum reads CFrame directly. Roblox handles physics replication. | NPCs, simple objects |
NATIVE_WITH_LOCK |
Same as NATIVE, but adds AlignPosition + AlignOrientation constraints on the HumanoidRootPart so Roblox's native replication can't fight Cerebrum's CFrame writes. | Player characters (default and recommended) |
CUSTOM |
Model is cloned per-client from a registered template. Full server authority. No native replication at all. | Projectiles, server-spawned objects, entities needing per-player visibility |
Standard interpolation renders entities buffer seconds in the past. Dead reckoning renders them at their estimated current server position using velocity extrapolation. When a new packet arrives and the prediction was wrong, the error is blended out smoothly over DR_BLEND_TIME.
Recommended for player characters. Without DR, players are seen ~25ms in the past at all times. With DR, they're rendered at the estimated current position, making movement feel immediate and the gap in the debug overlay stay green.
Enable per entity type:
Cerebrum.Config.RegisterEntityType("PLAYER", {
TICK_RATE = 1/60,
NETWORK_MODE = "NATIVE_WITH_LOCK",
BUFFER = 0,
FULL_ROTATION = true,
DR_ENABLED = true,
DR_MAX_EXTRAPOLATION = 0.100, -- max 100ms forward prediction
DR_BLEND_TIME = 0.150, -- blend corrections over 150ms
DR_CORRECTION_THRESHOLD = 0.15, -- ignore errors < 0.15 studs
})Good for balls, projectiles, and any smoothly-moving entity. For entities that teleport or change direction instantly, use standard interpolation.
Server-side hitbox rewind for fair hit detection across all ping levels. No parts are moved — pure math against the snapshot history. The rewind time accounts for each shooter's actual client-side render buffer, not just one-way latency, so hits are validated against exactly what the shooter saw on their screen.
local LagComp = Cerebrum.Server.LagCompensation
-- Raycast (optional tickRate for more accurate rewind with non-default entity types)
local hit = LagComp.Raycast(shooter, origin, direction * 300, ignoreList)
if hit then
print(hit.entity, hit.position, hit.distance, hit.rewindTime)
end
-- Spherecast (swept sphere — for melee and area abilities)
local hit = LagComp.Spherecast(shooter, origin, direction * 10, 2.5, ignoreList)Control which players receive updates for a given entity. Evaluated server-side — hidden entities produce zero network traffic.
local Rules = Cerebrum.ReplicationRules
Rules.SetRule(entity, Rules.Include({ player1, player2 }))
Rules.SetRule(entity, Rules.Exclude({ player3 }))
Rules.SetRule(entity, Rules.SameTeam)
Rules.SetRule(entity, Rules.WithinDistance(50))
Rules.SetRule(entity, Rules.SameOwner)
Rules.SetRule(entity, nil) -- visible to allSet with Cerebrum.Config.SetConfig(key, value) before Start().
| Key | Default | Description |
|---|---|---|
MIN_BUFFER |
0.033 |
Minimum interpolation buffer (seconds) |
MAX_BUFFER |
0.300 |
Maximum interpolation buffer (seconds) |
MAX_SNAPSHOTS |
32 |
Snapshot ring buffer size per entity |
DEFAULT_NETWORK_MODE |
"NATIVE_WITH_LOCK" |
Fallback network mode |
DEFAULT_NORMAL_DIST |
60 |
Full-tick replication range (studs) |
DEFAULT_HALF_DIST |
120 |
Half-tick replication range (studs) |
MOVE_THRESHOLD |
0.06 |
Minimum movement to trigger an update (studs) |
FROZEN_TIMEOUT |
4.0 |
Seconds before a stopped entity sends a stationary clock ping |
MAX_SPEED |
150 |
Speed hack rejection threshold (studs/sec) |
TELEPORT_THRESHOLD |
50 |
Position jump treated as teleport (studs) |
EXTRAP_MAX |
0.12 |
Max extrapolation past latest snapshot (seconds) |
VEL_SCALE |
200 |
Velocity quantization scale factor |
ANG_VEL_SCALE |
500 |
Angular velocity quantization scale |
MAP_BOUNDS |
3276 |
World size for position serialization precision |
PLAYER_REPLICATION |
"AUTOMATIC" |
"AUTOMATIC" or "MANUAL" |
REPLICATE_DEATHS |
"PLAYER_ENTITIES" |
"ALL", "PLAYER_ENTITIES", "NONE" |
MAX_REWIND_MS |
500 |
Max lag compensation rewind (ms) |
CORRECTION_BLEND_TIME |
0.25 |
Client-side correction blend duration (seconds) |
Cerebrum.Config.RegisterEntityType("MY_TYPE", {
TICK_RATE = 1/30, -- send rate (Hz)
NETWORK_MODE = "NATIVE", -- "NATIVE" | "NATIVE_WITH_LOCK" | "CUSTOM"
BUFFER = 0.08, -- interpolation buffer (0 = adaptive minimum)
FULL_ROTATION = false, -- true = 9-bit quaternion, false = yaw only
NORMAL_DIST = 60, -- full tick radius (studs)
HALF_DIST = 120, -- half tick radius (studs)
-- Dead Reckoning (optional)
DR_ENABLED = false,
DR_MAX_EXTRAPOLATION = 0.150,
DR_BLEND_TIME = 0.100,
DR_CORRECTION_THRESHOLD = 0.5,
})These exist by default — override with RegisterEntityType before Start().
| Type | Tick Rate | Rotation | Buffer | Mode |
|---|---|---|---|---|
DEFAULT |
30 Hz | Yaw | Adaptive | NATIVE_WITH_LOCK |
PLAYER |
60 Hz | Full quaternion | Adaptive min | NATIVE_WITH_LOCK |
NPC |
20 Hz | Yaw | 80ms | NATIVE |
- API.md — complete function reference
- TUTORIAL.md — how replication works under the hood, step-by-step examples
MIT