A simulation software to simulate a strandbeest, large kinetic sculptures made by dutch artist - theo jansen
Simulate walking movement of a strandbeest, change lengths (bars), add legs, chaneg speed and view data.
It simulates a Strandbeest's leg/s, walking movement — the same kind used in Theo Jansen's Strandbeest sculptures with reference to the 13 holy numbers.
The canvas shows the full linkage animating in real time. Every joint is solved frame-by-frame using circle-circle intersection geometry.
- Live linkage solver — all 13 bar lengths are editable. Change the values of each bar in the controls panel, and click save.
- Mirror leg — a horizontally mirrored / duplicated version of the innitial leg.
- Multi-leg mode — select 1–4 legs. Extra legs are phase-offset equally around the crank circle (180°, 120°, 90°).
- Per-leg color picker — each leg gets its own color, applied to both the main and mirrored copy.
- Play / pause — play / pause simulation.
- Speed control — (slider).
- Joint labels — labels all points (joints) on each leg
- data panel — displays ground angle and ground distance
- Foot trace — the full path of the foot (joint h) is drawn every frame.
| Control | Where |
|---|---|
| bar lengths (A–C to M–N) | right panel --> Controls (Measurements)ts) |
| save / revert | inside the measurements panel |
| play / pause | right panel --> toptop |
| speed | below the preview panel |
| mirror leg | top left corner [CHECK BOX] |
| label joints | below mirror leg [CHECK BOX] |
| Number of legs | right panel, below the play / pause button [DROP DOWN] |
| data | above the play / pause button |
src/App.jsx— main app, all logic + code are contained inside this.src/App.jsx → solve_leg()— leg movement logicsrc/App.jsx → solve_leg_mirror()— mirrored varient of leg movementinter_mirror()src/App.jsx → draw_scene()— canvas drawings: bars, joints, traces, labels etc...src/App.jsx → make_transform()— auto-fit + rotate the scene to canvassrc/App.jsx → PreviewCanvas— the animated canvas component, " ref" based state
Each frame, solve_leg(theta, lengths) places the crank pin at (m·cos θ, m·sin θ) and resolves the rest of the linkage through a chain of circle–circle intersections (inter()). The intersection root is chosen by cross-product sign to always pick the same branch of the solution.
The mirror version uses inter_mirror() which picks the opposite root, producing the fliped version of the mechanism.
please give it a ⭐
Siddharthan Pradeep — GitHub · [email protected]