- 06 Dec, 2025 *

In the late evenings, when everything finally slows down, I find myself replaying Half-Life 2 on my Linux workstation - the one powered by an RTX 5080. It’s a ridiculous mismatch, I know. With a GPU like that I should be stress‑testing cutting‑edge engines, ray tracing showcases, tech demos that melt silicon. And yet, instead, I’m back in City 17. Back with Gordon Freeman. Back with wooden crates, metal shelves, and that strangely comforting “thunk” when physics does exactly what your brain expects.
And there is something familiar about it - not just the game itself, but the memories tied to it. Because years ago, Marco and I played Half-Life 2 endlessly. We didn’t just f…
- 06 Dec, 2025 *

In the late evenings, when everything finally slows down, I find myself replaying Half-Life 2 on my Linux workstation - the one powered by an RTX 5080. It’s a ridiculous mismatch, I know. With a GPU like that I should be stress‑testing cutting‑edge engines, ray tracing showcases, tech demos that melt silicon. And yet, instead, I’m back in City 17. Back with Gordon Freeman. Back with wooden crates, metal shelves, and that strangely comforting “thunk” when physics does exactly what your brain expects.
And there is something familiar about it - not just the game itself, but the memories tied to it. Because years ago, Marco and I played Half-Life 2 endlessly. We didn’t just finish it; we lived inside it, replaying sequences, experimenting with physics, laughing at every object we could stack, break, throw, or launch into orbit. It wasn’t just a game — it was a kind of shared language, a world we kept coming back to without ever getting tired.
Meanwhile, in 2025, I’m here trying to make sure my own character in Lilly.Engine doesn’t casually clip through the ground.
The Beating Heart of My Engine: PhysicWorld3d
Every engine has a place where the world comes alive. For me, in Lilly.Engine, that place is a single class:
PhysicWorld3d
Located at PhysicWorld3d.cs
It is not a big subsystem. It isn’t fancy. But it is mine — the space where I try to recreate even a fraction of what Havok pulled off in 2004.
How It Begins
Initialization is quiet. A memory pool is created. A thread dispatcher spins up. The renderer registers its callback.
Nothing cinematic. No magic sparks. Just the careful construction of a simulation environment:
Simulation = Simulation.Create(
Pool,
new DefaultNarrowPhaseCallbacks(),
_poseIntegratorCallbacks,
new SolveDescription(8, 1)
);
That single call is the birth of the entire physics world. In HL2, the same moment happened invisibly inside Havok — a black box of brilliance Valve relied on to build everything from floating barrels to collapsing scaffolding.
Bodies, Shapes, and Objects That Want to Exist
Whenever a new object enters my world — a crate, a player, a piece of environment — I assemble it piece by piece:
- its shape (box, sphere, capsule, or mesh),
- its mass and inertia,
- its collision boundaries,
- its activity rules (sleeping, waking, reacting).
var bodyDesc = BodyDescription.CreateDynamic(
new BepuRigidPose(config.Pose.Position, config.Pose.Rotation),
inertia,
new CollidableDescription(shapeIndex, config.SpeculativeMargin),
new BodyActivityDescription(0.01f)
);
It looks clinical. Mathematical. But this is the moment an object goes from data to presence.
Half-Life 2 did this too — every “physics prop” you kicked, picked up, or launched with the Gravity Gun was born through a similar process.
The Moment Everything Moves: Update()
Each frame, the world holds its breath. And then:
Simulation.Timestep(1 / 60f, ThreadDispatcher);
One line, hiding an entire universe of motion:
- forces applied
- velocities integrated
- collisions detected
- contacts resolved
- constraints enforced
- bodies put to sleep
- numerical chaos tamed
This is the heartbeat. This is where stillness becomes motion.
Havok did all of this with a level of stability and elegance that still feels unreal today. I am trying — slowly, stubbornly — to follow the same path.
Keeping the World Together
After the simulation, I take BEPU’s version of reality and push it back onto the engine’s entities:
entry.Transform.Position = pose.Position;
entry.Transform.Rotation = pose.Orientation;
Position becomes truth. Rotation becomes intent. And the visual world aligns with the physical one.
It’s a quiet reconciliation — the moment rendering, physics, and gameplay all agree on what “now” looks like.
Half-Life 2 excelled at this. It’s why its objects never felt disconnected from the world around them.
Shapes, Meshes, and the Art of Touching Reality
Some collisions are simple. Boxes, spheres. Others are messy, chaotic, full of edges and corners. For those, I build triangle meshes:
triangles[i] = new Triangle(vertices[i0], vertices[i1], vertices[i2]);
HL2 did the same — a simplified collision mesh separate from the pretty one. It’s the invisible version of the world that objects actually collide with. It is rarely appreciated. But without it, everything falls apart.
Understanding Half-Life 2 Again
Replaying HL2 now, while building Lilly.Engine, is a strange and humbling experience.
The crates that roll believably. The ragdolls that collapse naturally. The seesaws, the gates, the bridges, the boats, the swinging doors.
None of this is accidental. None of this is easy.
It is the product of a physics engine engineered by people who understood motion, friction, stability, constraints, and — above all — how to make simulation serve gameplay.
Meanwhile, I’m here:
- battling colliders that misbehave,
- tuning multithreaded tasks,
- refining shape caches,
- synchronizing transforms,
- fixing tunneling and jitter,
- celebrating when something “just works” for once.
And somehow, that makes HL2 feel even more heroic.
What Comes Next
Soon, I’ll start sharing some videos of Lilly.Engine. They won’t be perfect. They won’t be polished. But they’ll be real — the honest record of a physics world learning how to breathe.
Because behind every crate that falls almost correctly, there is the quiet joy of understanding how the games I loved as a kid were truly built.