Cymatics Engine — a Chladni-plate eigenvalue solver as a service
A numerical physics core that computes the vibration modes of a free-boundary plate — the patterns sand forms on a vibrating Chladni plate — by solving the biharmonic eigenvalue problem with the Morley finite element in scikit-fem. Exposed as a headless FastAPI service and deployed on Coolify.
The source is private: it is the core of a commercial service. The design above is described from the repository's own documentation and verification suite.
Architecture
- 1Mesh — the plate geometry
- 2Assemble — biharmonic stiffness and mass matrices with the Morley element
- 3Solve — the generalised eigenvalue problem
- 4Filter — identify and drop the rigid-body modes
- 5Serve — FastAPI endpoint, deployed via Coolify
The problem
Cymatics visualisations are usually faked with noise or drawn by hand. Real Chladni figures are eigenfunctions of a fourth-order PDE with free edges — the awkward boundary condition — and the solver also produces zero-energy rigid-body modes that have to be recognised and excluded, or the first few “modes” are nonsense.
Approach & decisions
- A non-conforming Morley element handles the fourth-order biharmonic operator without requiring C¹-continuous basis functions.
- The verification gate asserts that computed eigenfrequencies match published analytical references within tolerance, and that rigid-body modes are correctly identified and excluded — the two ways this class of solver quietly produces plausible garbage.
- Standalone by decision: numerical physics with no model calls and nothing to gate shares no surface with the content pipeline it sits beside, so it does not depend on it. The decision is recorded in its ADRs, as is the choice of a FastAPI service layer and the deployment shape.
Results
- A verification gate checks the solver against analytical references and exits non-zero on regression.
- Deployed as a staging API on a real host.
- Architecture decision records cover the service layer and the deployment, so the reasoning survives the code.