I'm William Eklund, a systems and game developer in Sweden working in C# and .NET:
backend, cloud, networking, performance and game engines.
My largest project is Krut, a 3D game engine I build solo. Two games run on it
so far, one of them an online racing game with a dedicated server and a backend. Below is what
the engine does today, the games and backend built on it, and where it's going next.
C# / .NET 10 · ASP.NET Core · PostgreSQL · Docker · Direct3D 12 or Vulkan · Native AOT · ~82k LOC
Architecture: about 82k lines built and maintained alone, split into subsystems that only know about each other when they have to.
Testing: xUnit tests for every subsystem that must pass before anything ships, and a deterministic simulation that can be tested headless.
Backend and data: ASP.NET Core API, PostgreSQL with EF Core, an append-only ledger and exactly-once payouts, Steam sign-in.
Networking and distributed systems: an authoritative server per race, client prediction and reconciliation, and HMAC-signed results that the backend verifies. Open source in Krut.Netcode.
Cloud and operations: Docker, self-hosted today and moving to Azure with infrastructure as code and GitHub Actions.
Performance: my own Forward+ renderer on Direct3D 12 and Vulkan, and Native AOT builds.
The engine
Krut.Engine · closed source
A courtyard showcase rendered in Krut with PBR materials, parallax occlusion mapping, reflection probes, SSAO, screen-space reflections and a prototype HDRI sky.
Every system (rendering, physics, audio, networking, navigation and asset loading) is a
separate part that only knows about the others when it has to. A game includes the engine as a
git submodule, inherits from a shared Core loop and overrides the parts it wants to
change. Builds are Native AOT, so players don't need .NET installed, and every subsystem
has xUnit tests that must pass before anything ships.
Most of Krut is written by hand, by me. I use libraries for a few low-level pieces, listed
further down, but the systems built on top of them are my own code.
The target is a modern, optimized game engine built on the old-school BSP workflow (like Quake, GoldSrc and the Source engine), with modern features like PBR, real-time lighting and a Forward+ renderer.
Platform: the engine owns its window, loop, GPU layer (Krut.Engine.Gpu) and input. Math is System.Numerics with a small supplement of its own. Debug UI is ImGui.
Rendering: my own Forward+ (clustered forward) renderer with MSAA (2x, 4x or 8x), PBR for skinned models, cascaded sun shadows, a shadow atlas for spot and point lights, a depth pre-pass, particles, decals, bloom and colour grading.
Lighting: my own GI lightmapper that bakes the levels, light probes for moving objects, and light styles for flickering and switchable lights.
Render features: linear colour with HDR and tonemapping, PBR on level geometry (metallic/roughness, normal maps, ORM and emissive) with specular anti-aliasing, directional lightmaps so normal maps respond to baked light, reflection probes with box-projected parallax, SSAO, screen-space reflections that fall back to probes, and volumetric light and fog. Local smoke and dust volumes, and particles such as tyre and muzzle smoke, are lit and shadowed by the sun and lights.
Picking features: every render feature toggles at run time. A game chooses which ones it uses and which the player may change. Classic, Modern and Ultra are example presets.
Image clarity: MSAA, sharp post-process AA (CMAA2) as an option next to or instead of MSAA. A game should look sharp at native resolution. No TAA, no upscaler, no smear: what you render is what you see. Target: the Modern example preset at 144 fps (6.9 ms) on an RTX 3060 at 1440p.
Graphics backends: Direct3D 12 or Vulkan, chosen with -driver d3d12|vulkan. Shaders are HLSL, compiled offline to DXIL and SPIR-V.
Visibility: portal culling for indoor levels, plus frustum culling.
Collision and movement: my own capsule-vs-triangle collision against level geometry with a triangle BVH, and the character controller on top of it.
Networking: the client/server layer is mine: fixed tick, quantized messages, client prediction, reconciliation, snapshot interpolation, a jitter buffer and clock sync. LiteNetLib only carries the UDP packets. Extracted into Krut.Netcode.
Audio: occlusion, reverb zones per room type and music streaming, on FMOD Core with WAV and Ogg decoding.
Levels: TrenchBroom .map/.bsp import, and splines for tracks and paths.
An authoritative-server netcode library for .NET built on LiteNetLib, extracted from
Krut.Racing. It handles the low-level synchronization and prediction primitives needed to keep
multiplayer games responsive and fair over noisy, high-latency internet connections.
The library is decoupled from any specific engine or physics model: games define their own
messages, snapshots and simulation step, while Krut.Netcode manages the wire protocol,
clock synchronization, client prediction rollbacks, entity interpolation and simulated network degradation.
Authoritative server & sessions: handshake with protocol versioning, application id validation, readable rejection reasons, peer state tracking and automatic reconnection loops.
Fixed tick clock & time sync: frame-rate independent fixed tick with catch-up capping. NTP-style median clock sync over lowest-RTT samples to eliminate drift and queue jitter.
Client prediction & reconciliation: local inputs apply immediately; upon receiving an authoritative server snapshot, state rewinds to the acknowledged tick, replays unacknowledged inputs, and smoothly blends visible corrections.
Snapshot interpolation: state-ring buffer interpolating remote entities in the past with bounded extrapolation to eliminate hitching under packet jitter.
Zero-allocation messaging: hand-written serialization via NetDataReader/NetDataWriter with object pooling — steady-state packet processing generates 0 B of garbage collection allocations.
Link simulator: built-in simulation of latency, jitter, packet loss bursts, duplication, reordering and outages (configurable via presets or KRUT_NET_* environment variables) to test and prove resilience under adverse conditions.
Modern .NET & Native AOT: reflection-free, uses System.Numerics, and ships with xUnit tests, BenchmarkDotNet suites, and a headless multi-client prediction demo.
Commute is a 10-minute vertical slice and tech demo for Krut.Engine 1.8, testing the engine in a real game, and it borrows a lot from Source engine
games. The demo is one level, Subway Station: from the ticket hall down to the platform,
through the tunnels and out into the depot. It's built in TrenchBroom with a custom texture
set and lit by Krut's own GI lightmapper. Along the way there are button puzzles, live wires and
explosive barrels.
There are three kinds of enemies: melee, ranged, and bombers that beep faster as they get
closer. They path on the navmesh, stay away from live electricity, and don't all rush you when
they can't see you. They only throw a grenade when they have a clear line.
Baton, pistol, SMG, shotgun, grenade launcher and hand grenades, with ADS, shell casings, ricochets and tracers.
Hitmarkers, hit-stop on kills, chained explosions that leave scorch marks.
Soft real-time shadows from the sun, the flashlight, muzzle flashes and explosions.
Ragdolls, dismemberment, and crates you can pick up and throw.
Krut.Racing (working title)
online multiplayer racing · in development
Gameplay from the current build.
A spec racer: every car performs exactly the same. You can change how your car looks and
sounds, but not how it drives. The server enforces this, because clients never touch vehicle
parameters.
The car physics is my own vehicle sim, written for this game: a kinematic simcade model with a
friction ellipse, weight transfer, anti-roll, suspension, downforce,
drafting and FWD, RWD or AWD drivetrains. It runs on a fixed step, so the same code runs headless on a dedicated server per race,
and clients only send their inputs. The netcode is built to keep racing smooth at pings of 150-200 ms (see Krut.Netcode).
Krut.Racing backend
accounts, results, economy and server orchestration · built, being connected
The game server is authoritative for the race, and the backend is authoritative for everything
that outlives it. Clients never report their own results: when a race ends, the dedicated server
builds the result from its own state, signs it with HMAC-SHA256 and hands it to the backend, which
verifies the signature before anything is stored or paid out.
API: ASP.NET Core, containerised with Docker, the same image locally and in the cloud.
Identity: players sign in with a Steam session ticket that the backend verifies against the Steam Web API. Joining a race takes a ticket the race server checks.
Database: PostgreSQL through EF Core with migrations: accounts, garage, race results and statistics.
Economy: an append-only ledger instead of a balance column, and a race pays out exactly once, even if the server sends its result twice.
Server orchestration: one headless server process per race, started for a match and stopped when it ends, with health checks so a crashed race is cleaned up.
Hosting: runs on my own server today. Next it moves to Azure, with infrastructure as code, deploys from GitHub Actions, secrets in Key Vault, and tracing from the game server through the API into the database.
What's next
after 2.0.0 · in progress
Krut 2.0.0 was released on 2026-10-26 with a new GPU layer and Forward+ rendering.
Volumetric light and smokeplanned
Froxel-based volumetric light and fog, lit and shadowed by the sun and the clustered lights. Local smoke and dust volumes, and particles such as tyre and muzzle smoke, write into the volume and cast light shafts.
Real-time global illuminationplanned
Stochastic ray tracing in compute against the level's own BVH into a world-space probe grid, so moving and switchable lights bounce. No screen-space accumulation.