Paper, Scissors, Gravity

I don't know what a Plücker transform is.

I couldn't explain the Featherstone Articulated Body Algorithm if you put a gun to my head. I have never taken a physics class beyond what was required in college (I dropped out). I don't know what a Yee lattice is, or why Wilson actions involve SU(3), or what a deficit angle has to do with general relativity.

Actually, I know that last one now. And by the end of this post, so will you.

The day

Today, a Monday, I built a differentiable physics engine from scratch. 25 Rust crates. 28,000 lines. Rigid body dynamics, collision detection, fluids, electromagnetic fields, molecular dynamics, quantum field theory on a lattice, N-body gravity, and discrete general relativity.

Then I plugged it into my CAD kernel and replaced the physics backend.

All of this between 8:38am and 9pm. On a couch. Mostly pressing enter. I also took my pregnant wife to a checkup and got some Chick-Fil-A.

I had a plan. I want to make the best sim2real software in vcad, and for that I need accurate physics with an API I can control (for an accurate sim)(i dont wanna use isaac). I want to make a world model with this for use in Municipal Robotics rovers.

17 phases, from "pendulum with gradients" to "reality ingestion." A plan-runner.sh script let Claude execute each phase autonomously. Read the plan, write the code, run the tests, commit. Seventeen phases of a physics engine. Two hours and forty-four minutes.

live: double pendulum (compiled Rust → WASM → your browser right now)

This post isn't about how I built it. It's about the thing that blew my mind the most. And it has to do with triangles.

cargo install phyz
25 crates · 28k lines · differentiable through everything

You already know this

If you read my post on tessellation, you know the punchline: your GPU doesn't know what a cylinder is. It knows triangles. Every curved surface you've ever seen on a screen was actually tiny flat triangles, packed so tightly your eyes couldn't tell the difference.

Here's the part nobody told me:

The universe works the same way.

General relativity says that mass curves spacetime, and curved spacetime tells things how to move. That's Einstein's theory of gravity. That's the whole theory.

But "curved spacetime" is hard to compute. The equations are beautiful and brutal. Tensor calculus, Christoffel symbols, Ricci curvature. I can't do any of it.

Tullio Regge
Tullio Regge

In 1961, a physicist named Tullio Regge had an idea: what if you don't need smooth curves at all? What if you can approximate curved spacetime with flat triangles, just like a GPU approximates a sphere?

He was right. And the math is shockingly simple.

The cone trick

Grab a piece of paper. (Mentally. I'm not ur mom.)

It's flat. No curvature. Now cut out a wedge, like a pizza slice, and tape the cut edges together.

a flat disk. cut out a wedge.

It pops up into a cone. The paper is still flat everywhere except at the tip. All the curvature is concentrated at that single point. And the amount of curvature is exactly equal to the angle you removed.

Removed 60°? You have 60° of curvature at the tip. That's it. That's the whole idea.

That missing angle has a name: the deficit angle.

Deficit angles

Let's make it precise. Take some triangles and arrange them around a vertex.

deficit angle: 60° — positive curvature (sphere-like)
6 triangles × 50.0° = 300° (need 360° for flat)

On a flat surface, the angles around any point add up to exactly 360°. No gap, no overlap. The deficit angle is zero.

On a positively curved surface (like a sphere) the angles add up to less than 360°. There's a gap. That gap is the deficit angle, and it means the surface curves inward, like a hilltop. This is the kind of curvature a massive object creates. The kind that makes things fall.

On a negatively curved surface (like a saddle) the angles add up to more than 360°. They overlap. The deficit angle is negative, and the surface curves outward, like a mountain pass.

Move the slider. Watch the gap appear and disappear. That gap is gravity.

Einstein's equation, in one sentence

Here's what Regge realized.

Einstein's theory of general relativity comes from one equation, the Einstein-Hilbert action:

S=Rgd4xS = \int R \sqrt{-g} \, d^4x

It's a single number that summarizes everything about a spacetime. RR is the Ricci scalar (a measure of curvature), gg is the metric (the shape of spacetime), and you integrate over all of spacetime. Minimize it, and you get Einstein's field equations. All of them.

Grad-school stuff. Years of study. Unless you use triangles.

Is this a pigeon meme: me, a college dropout, pointing at triangles: is this general relativity?
bitch it might be

In Regge's version:

S=edgesli×δiS = \sum_{\text{edges}} l_i \times \delta_i

That's it.

Sum over every edge in your mesh. Multiply the edge length by its deficit angle. The result is the action. Minimize it, and you get discrete Einstein equations.

hover over vertices to see their deficit angles
S = Σ edge_length × deficit_angle
minimize this sum → Einstein's equations

Edge length times deficit angle. Summed up. That's general relativity.

The smooth version and the Regge version converge to the same answer as you add more triangles. Just like how a tessellated sphere converges to a real sphere as you add more triangles. The tessellation insight was cosmological the whole time.

What Claude built

Phase 18 wasn't in the original plan. I asked Claude to go further. Implement Regge calculus. The full thing.

It did.

The phyz-regge crate implements the Einstein-Hilbert action on simplicial manifolds. You give it a mesh of 4-simplices (the 4D version of triangles, tetrahedra extended into spacetime), and it computes deficit angles at every edge, evaluates the action, and finds spacetimes that satisfy Einstein's equations.

But here's where it got weird :~)

Building the engine is one thing. Knowing it's correct is another. How do you validate a general relativity implementation? You can't just eyeball it. So Claude built the validation tools too.

Einstein-Maxwell coupling. Electromagnetism on curved spacetime. If your physics engine can couple Maxwell's equations to the Regge action and get the right answer, that's a strong signal your geometry is faithful. Light bending around a star isn't just a metaphor. It falls out of the math.

Symmetry search via SVD. The ultimate test: give it a spacetime, and it discovers the continuous symmetries automatically. Not hard-coded. Not looked up. Discovered from the geometry, the same way you'd discover that a sphere can be rotated. If the search finds exactly the symmetries the textbooks predict, your discretization is working.

Background spacetimes are the test cases. Each one has known symmetries, so you can check your engine against reality:

  • Reissner-Nordström, a charged black hole (19 known symmetries)
  • de Sitter, an expanding universe like ours (maximally symmetric)
  • Kerr, a rotating black hole, complete with frame dragging (25 symmetries, some broken by spin)

I watched Claude implement Lorentz boost generators and validate them against a Kerr black hole. On a charged black hole (Reissner-Nordström), the search found 19 known symmetries with a clean gap down to the discretization noise floor at ~2.6e-4. On Kerr, 25 exact symmetries. Richardson extrapolation confirmed no hidden symmetries were lurking in the noise.

SVD spectrum on Reissner-Nordström: 19 symmetries, then a clean gap to the noise floor

Frame dragging showed up in the spectrum. A rotating black hole drags spacetime itself around with it, and that shows up as broken symmetries. Rotations that should be equivalent but aren't, because the black hole's spin picks out a preferred direction.

frame dragging: a spinning mass twists nearby spacetime. closer arrows twist more.

How do you know it's real and not a lattice artifact? You test two backgrounds. On a charged black hole (Reissner-Nordström), the metric components f(r)g(r)f(r) \neq g(r), so time and space aren't interchangeable. Boosts mix time and space. They should break harder than rotations. On de Sitter (expanding universe), f=gf = g, so boosts and rotations should break equally. Here's what the search found:

BackgroundRotationsBoostsWhy
Reissner-Nordströmviolation < 101410^{-14}violation > rotationsfgf \neq g breaks time-space symmetry
de Sitter~1.5×10121.5 \times 10^{-12}~1.5×10121.5 \times 10^{-12}f=gf = g, isotropic, both break equally

If boost-breaking were a lattice artifact, it would show up on both backgrounds. It doesn't. The asymmetry is physical. There's a test for it.

I don't fully understand what I have. But the tests pass, the convergence rates are correct, and the symmetry search finds exactly what the textbooks predict.

Expanding brain meme: deficit angles, Einstein-Maxwell coupling, SVD symmetry search, frame dragging on a Kerr black hole
claude opus 4.6, mass-energy equivalence of 3.5 oz of silicon

Everything else

Regge calculus was the mind-blower. But the engine has 25 crates, and some of the other stuff is worth seeing.

Rigid body dynamics, the core. Featherstone spatial algebra, O(n) forward dynamics, analytical Jacobians for differentiability. The double pendulum demo above runs the same Rust code you'd use in a robotics project.

30 spheres bouncing. GJK collision detection + spring-damper penalty contacts

Material Point Method, particles on a grid. Different constitutive models give you different materials. This one's water:

500 particles sloshing in a tank, penalty-based contact

Electromagnetic fields, Maxwell's equations on a Yee lattice. FDTD. Watch a dipole radiate:

FDTD dipole radiation, electromagnetic waves on a 200x200 Yee grid

And because the Yee grid doesn't care what shape the boundary is, you can put a wall with two slits in front of a wave source and watch interference happen:

double slit interference, same FDTD engine, different boundary

N-body gravity, Kepler orbits. Not flashy, but satisfying to watch:

gravitational N-body, 6 bodies in Kepler orbits

Every demo is real compiled Rust running as WebAssembly in your browser. Same code, same physics.

Plugging it into vcad

The whole reason this exists: I'm building vcad, a parametric CAD kernel, and I need accurate physics for sim2real. I want to simulate a robot in CAD, train a policy against the simulation, and deploy it to a real Municipal Robotics rover. For that, the physics has to be differentiable (so gradients flow through the sim for optimization), high precision (f64, not f32), and structured for robotics (articulated trees, not flat body lists).

Rapier3D, our previous backend, is great for games. It's none of those things.

Drake meme: rejecting Rapier3D, approving phyz which also does general relativity for some reason

The swap was clean. Three source files touched Rapier directly. I rewrote them to use phyz. Rapier's flat body set became a Featherstone articulated tree. The impulse solver became spring-damper contacts. f32 everywhere became f64. The public API (PhysicsWorld, RobotEnv, JointState, Action) didn't change at all.

13 tests. All passing. WASM builds. Downstream crates didn't know anything happened.

What I actually learned today

I learned that Einstein's equations are a sum of edge lengths times deficit angles.

I learned that curvature is a gap in your triangles, the same gap you'd see if you tried to flatten a globe. That frame dragging is a broken symmetry. That the Einstein-Hilbert action is to spacetime what ear clipping is to a polygon: a way to reduce something continuous to something discrete.

I didn't learn these things the way a physicist does, through years of tensor calculus and differential geometry. I learned them the way an engineer does. By building something that passes tests.

Claude brought the physics. I brought twenty years of knowing what a good API looks like. Together we built something I couldn't have built alone, and probably couldn't have built with any team, in any amount of time, before this year.

I still don't know what a Plücker transform is.

But I know what a deficit angle is. And now so do you.

Go build something stupid

Here's what I want you to take from this: the distance between "I have an idea" and "it works" has collapsed. The bottleneck isn't knowledge anymore. It's imagination.

Build a physics engine. Build a compiler. Build the thing you've been telling yourself is too hard, too academic, too far outside your wheelhouse. The worst that happens is you learn something. The best that happens is you ship it.

Yes, you'll land in the Dunning-Kruger valley. I'm in it right now. I built a general relativity simulator and I still can't derive the Schwarzschild metric by hand. But Dunning-Kruger is only a trap if you stop there. If you keep building, keep testing, keep reading the code Claude writes and asking why, you climb out. You come out the other side knowing things you never would have learned from a textbook, because you learned them by making something real.

The tools are here. The only limit is what you're willing to attempt. Type something audacious into a prompt and press enter.

Try it

cargo install phyz

25 crates. 28,000 lines. Differentiable through everything.