Rectangular plate FEA using Mindlin-Reissner theory, for concrete slabs on walls and columns. The solver's kernel exists in JavaScript and in C++ compiled to WebAssembly; the workspace around it is plain DOM and raw WebGL.
It is for structural engineers and students who want a slab's deflections, moments and reactions to follow every change they make, in the browser, with nothing to install.
npm install
npm run devsrc/solver.js. Four-node elements with three unknowns a node (deflection and two rotations). Bending is integrated 2 × 2; the shear strain is tied at the middle of each element side (MITC4), which neither locks on a thin slab nor leaves a spurious mode.
- Supports are imposed exactly: a held unknown gets a unit row and column.
- Reactions come from
K u − fat the held unknowns, and their sum is checked against the load. - Moments come from the curvature at the nodes, second order on the edges too.
- Factor reuse — while only the load changes, the Cholesky factor is kept and a solve is one substitution.
- Bandwidth — nodes are numbered along the shorter side of the mesh.
The first version of this solver sampled the shear once, at the element centre. That leaves an hourglass mode in the deflection which only a supported edge holds down, so a slab standing on columns alone was singular. That element is still there behind reduced: true, for the test and the Verification page that show the difference.
Assembly, factorisation and substitution are a kernel with two builds behind the same four calls:
- JavaScript — in
src/solver.js. Always available. - WebAssembly —
wasm/solver.cpp, loaded bysrc/wasm.js. Two to three times faster.
Both keep the lower band of the stiffness a row at a time, so factorising multiplies runs that are contiguous in memory. The C++ is freestanding (no libc, no allocator, no JS glue): the module is 8 kB and loads with one WebAssembly.instantiate.
The kernel is chosen in the Solve panel (Auto / WASM / JS). Auto uses WebAssembly where it loads and JavaScript otherwise.
src/solver.wasm is committed. To rebuild it you need Zig, whose zig c++ is clang with a wasm linker:
npm run build:wasmnpm test runs them all in Node, on both kernels.
| Test | What it checks |
|---|---|
infinite |
The opening example solves to finite numbers |
symmetry |
Mirrored supports give mirrored deflections |
rank |
Held slabs solve; mechanisms and the hourglass element are refused |
equilibrium |
Reactions sum to the load, with and without a reused factor |
kernels |
JavaScript and WebAssembly agree to rounding |
closed-form |
Second-order convergence to Navier's series; Timoshenko's coefficients for simply supported and fixed squares within 1% |
reference |
Six shell models from reference software on the same 0.25 m mesh, within 2% |
| Command | Description |
|---|---|
npm run dev |
Dev server |
npm run build |
Production build |
npm run build:wasm |
Compile wasm/solver.cpp to src/solver.wasm (needs Zig) |
npm run test |
Run all tests |
npm run benchmark |
CLI benchmark: both kernels over a range of meshes |
npm run lint |
ESLint |
plate-analysis/
├── index.html
├── src/
│ ├── main.js # Entry: worker and workspace
│ ├── app.js # Inputs, section diagram and results over one state object
│ ├── viewer.js # WebGL slab: contour bands, supports, drawn annotations
│ ├── checks.js # Verification and Performance pages
│ ├── charts.js # Log-log line chart in SVG
│ ├── solver.js # The analysis and the JavaScript kernel
│ ├── wasm.js # Loads the WebAssembly kernel
│ ├── solver.worker.js # Runs the solver off the main thread
│ ├── solver.wasm # Built from wasm/solver.cpp
│ ├── workspace.css # The workspace
│ └── styles.css # The page around it
├── wasm/ # C++ kernel (solver.cpp, build.mjs)
└── tools/ # Tests, benchmark, export-demo.mjs
ROADMAP.md: any outline with openings, columns with a size, load combinations, reinforcement and punching checks, and open verification models.
