Design the controller,
watch the real plant obey.

C++ and Eigen compiled to WebAssembly. A ball balances on a tilting three-legged table while you tune the controller that holds it there — no MATLAB, no install, no account.

Primary demoBall-Balancer

The plate is a 3-RRS parallel mechanism: three servo-driven legs under a circular table, with a ball rolling on it under real rigid-body contact dynamics. It opens with the loop already closed and the ball already tracing a circle, so there is nothing to press to see it work.

Takes a few seconds to load — it is fetching a 1.5 MB WebAssembly binary. The layout wants a desktop-sized window: on a phone it loads and runs, but the panels are small.Open fullscreen →

What you are looking at

The point of the application is the join between two halves that are each only half a story: a linear design surface on the left, and the nonlinear consequence of that design on the right, live and side by side.

The plate

The 3D view and Plate Control. Drag to orbit, scroll to zoom. Nudge the ball and watch the loop reject the disturbance, or send it round a square instead of a circle and watch it stumble at the corners.

The design surface

Model Configuration holds the plate's linearised state-space model and the controller designed against it — LQR state feedback, with editable state and input weights, plus the analyzer's PID and lead/lag.

The consequence

Bode, Nyquist, pole-zero and step response, all driven off that one linearised model. Move the weights and the closed-loop poles move — and so does the ball, in the same frame.

Where linear stops

The gain is designed against a linearisation; the plate simulated beside it is not linear. Push the design hard enough and the servos saturate, the ball overshoots, and the two stop agreeing. That gap is the thing worth looking at.

Also publishedLinear System Analyzer

The frequency-domain half on its own, without the plate: pick a plant from the presets — a DC motor, a mass-spring-damper, the ball-on-plate rig — close a loop around it, and read the consequences off four synchronised views. It also carries the loop-pairing tooling for multi-input plants: an RGA grid showing which input should drive which output, and which channels are structurally dead.

It stays published because it is a smaller, faster thing to open than the full application, and because keeping it live means this page always has something working on it.

Drag the sliders in the Model panel. The Bode, Nyquist, pole-zero and step-response views update together.Open fullscreen →