2026Active Development

absenceEngine

C++20 · Vulkan · GLSL · box3d · ENet · Go · Next.js 16

Overview

A competitive shooter is the goal, and CS2's hit registration is the grudge. So the engine, the netcode and the backend get written from scratch.

absence is a competitive 5v5 shooter where the engine, the netcode and the backend are all first-party: C++20 on Vulkan, a 128 Hz server-authoritative tick with lag-compensated hitscan, deterministic movement, a Go portal running accounts and matches. The starting shot was a CS2 replay: a bullet through a head, counted as a wall miss.

Today it plays end to end: a client with full menus, dedicated servers running the 128 Hz match, wallrunning and bhop movement CS and Valorant never offered, and a Go portal handling accounts and matchmaking. The maps are blockouts and the weapons fire tracers; real environments, characters and weapons arrive with the alpha later this year.

absenceEngine poster, deferred PBR scene
deferred PBR · cascaded shadow maps · IBL

Why build an engine out of spite?

Because watching the game rot got tiresome. A content drop a month (skins, chickens) while every other match fills with cheaters and VAC Live waves the leaderboard's spinbotters through. Hit registration is the part that hurt most, and it doubles as the design brief: every bullet gets resolved on the server, against where the target actually was when the trigger got pulled.

Unreal was rejected on arithmetic, not ideology: its head start dissolves the moment optimizing someone else's engine to this standard costs more than writing the renderer. Vulkan won over D3D12 on preference. And the physics pick has a punchline. Valve's Source 2 physics is Box2D ported in-house and never released, so absence runs box3d, the Box2D author's own 3D engine, the family's public branch.

Why is it called absence?

Counter-Strike runs on the Source engine. No source, absent. The name is the grudge, compressed.

What came before?

maksiuEngine, the v1: a D3D12 renderer held together by nails, glue and wood. It was archived without ceremony because nothing in it deserved preserving, and the comparison is not kind to v1. absenceEngine started clean-room in July 2026: same goal, nothing carried over.

How does the netcode stay honest?

Movement is a deterministic state machine; the player was never a physics object. The client sends inputs, the server runs the same 128 Hz simulation, and the server never accepts a position claim. Client prediction and server reconciliation keep both sides 1:1. Drift inside a small ignore-zone gets absorbed; anything beyond snaps the body back to the authoritative pose and re-runs every queued input. Inputs, snapshots and voice ride separate unreliable ENet channels so none can starve the others, and a reliable lane carries lifecycle and events.

The scar that taught this: early netcode compressed floats by dropping the decimals, and spectated players began to drift server-side, then teleport when the error cashed out. Quantization stayed, but by design this time. Positions ride the wire as fixed-point integers with 2 mm resolution, yaw as one uint16, chosen so both predictions land identical instead of approximately equal. When the first transport couldn't carry that guarantee, it was deleted wholesale rather than deprecated. There is one protocol.

How does a shot register?

Every shot is resolved server-side against hitboxes rewound to what the shooter saw: half their RTT plus interpolation delay, capped near 200 ms, interpolated sub-tick. Mesh-accurate traces were never on the table, because ten players at 15k to 30k triangles each is too much math per shot. So the Hitbox Editor assigns one primitive per limb (head, neck, three torso segments, shoulders, upper and lower arms and legs, hands, feet, pelvis), positioned on the bones, each free to be a capsule, box or sphere. A candidate costs 19 capsule ray tests. Damage pays 4× on the head, 0.75× on the leg.

The server broadcasts intent, not results: a shot's seed and angles ship with the fire command, so the simulation everyone sees is the simulation that happened.

How does it handle cheaters?

Server authority is the foundation; visibility is the second half. Each player's snapshot withholds the pawns they can't see, and a hidden mask in the header marks what was culled while the integrity checksum still covers full state. A wallhack against absence sees the server's fog, not the map. The big shooters started shipping the same idea afterwards; noted in the log, nowhere else.

Why is there a backend before there's a game?

The proof-of-concept didn't need beautiful graphics, so the boring half got built first: accounts, parties, matchmaking, allocator, seasons, leaderboards, integrity. That's 22 Go packages with 33 test files, all coded against one written API contract that the Go portal, the Next.js frontend and the C++ client read too. Docker Compose, Caddy and GitHub Actions push to the VPS on merge. The portal isn't public yet. Accounts can be registered (usernames are first-come), Steam linking is next, and nothing is playable by strangers until the public alpha.

What runs today?

From menus to matches: a server-authoritative 5v5 with twelve game modes, MR15 rules and halftime side swaps, CS:GO's 1:1 recoil model, dedicated servers, Opus voice, Steam sign-in. The editor suite is a product of its own, from Hammer-style brush CSG in the Map Creator to a Weapon Editor with spray canvases, the Hitbox Editor, Play-In-Editor with undo/redo, and a WYSIWYG UI editor. Around the day job it gets eight hours a night, most nights.

Still unsolved, honestly: the jagged shadow edges the CSM keeps winning along its seams. Still placeholder: the UE5 mannequin, until the first self-made character retires him.

Field notes

  • 128 Hz fixed-tick simulation, 64 Hz snapshots on the wire, four ENet channels, so inputs, state and voice each get their own backpressure.
  • ~105,000 lines of C++/GLSL across ~1,010 engine files; 70 shaders compiled to SPIR-V by the build.
  • Hit registration rewinds hitboxes to what the shooter saw (half RTT plus interpolation delay, capped near 200 ms), then traces 19 per-limb capsules per candidate, sub-tick interpolated.
  • Wire quantization is designed, not truncated: 2 mm fixed-point positions, one uint16 of yaw. The spectator drift scar taught that lesson.
  • The engine checks itself: --self-check, --movement-self-check, --net-self-check and the rest of the gate family run headless before anything pretends to work.
  • One API contract read by the Go portal, the Next.js frontend and the C++ client alike; compose + Caddy + Actions push-to-deploy.
  • 1,035 dynamic boxes standing in one instanced draw call: the box3d large-pyramid benchmark, retired from the demos but not from the log.
absenceEngine in motion, mid-frame capture
CS-style movement · bhop · GPU skinning
absenceEngine gameplay capture with netcode
server-authoritative netcode · ImGui editor

Source

github.com/notdezzi/absenceEngine