- Python 64.8%
- TypeScript 31.5%
- CSS 3.5%
- Dockerfile 0.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
Build and deploy MATHEMA / build (push) Successful in 7m55s
Layer displacement along the normals was capped per vertex at sharp concave corners (0.8 x curvature radius), but the uncapped neighbours, whose normals converge on the corner, reached over the notch and the ring self-intersected. displace_along_normals then scaled the whole row by 0.5, 0.25 or 0, and as the outline changed with height that factor flipped between rows: square-toothed meanders with strong flutes showed steps over height (381 row evaluations reduced in one design). - arc_envelope: the largest values below a bound that change by at most a given slope per unit arc length around the ring (min-plus spread, vectorised over three laps). - Inward and outward caps are spread with CAP_SLOPE = 0.25, so the offset tapers into corners and narrow inlets. The largest cut is unchanged; the whole-row fallback no longer triggers for that design. - Regression test: tulip meander with squareness 1.2 and 2.6 mm flutes has no reduced rows. |
||
| .forgejo/workflows | ||
| backend | ||
| docs | ||
| frontend | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| docker-compose.yml | ||
| Dockerfile | ||
| LICENSE | ||
| README.md | ||
MATHĒMA (μάθημα)— Mathematics into Form
MATHĒMA turns equations into physical vases. It generates mathematically defined 3D objects — primarily vases for FDM printing in spiral vase mode — and exports real, validated, watertight STL files.
Every vase is a surface in generalized cylindrical coordinates,
$$x = r(\theta,z)\cos\theta,\quad y = r(\theta,z)\sin\theta,\quad z = z,\qquad
r(\theta,z) = R(z),T(z),S(\theta',z) + \sum_i A_i(z),F_i(\theta',z)
built from a silhouette R, a cross-section S, vertical transforms and a stack of
mathematical modulation layers F_i (Fourier series, harmonic interference, rose
curves, prime and Fibonacci harmonics, quasiperiodic waves, Bessel functions, Perlin
noise, Voronoi cells, hand-drawn meanders, glitch cubes, Julia and Mandelbrot sets, orbit traps, or your own safely
parsed expression). Experimentally, the cross-section itself can also be the boundary of
a filled Julia set whose parameter c evolves with height (Julia boundary lofting).
Try it at https://works.baumann.gr/mathema/, or run it locally with Docker.
Features
- Live 3D workbench — orbit/pan/zoom, perspective/orthographic, wireframe, normals, build-plate grid, dimension indicators, lighting and material presets, auto framing.
- Works on phones — split screen with the vase on top, a Design / 3D view / Analysis tab bar, an icon toolbar and full-screen dialogs; landscape puts the vase beside the controls. The desktop layout is a three-column workbench.
- 16 generator families through one shared evaluation pipeline; new families need only a function and a parameter declaration (docs/adding-generators.md).
- 8 silhouettes incl. a draggable custom profile; 7 cross-sections incl. the Gielis superformula, Fourier series and a meander outline whose teeth hook back over each other (lofted as a contour); morphing between cross-sections.
- Layer composition: add, subtract, multiply (scales the radius built so far), max, min, blend and true coordinate warping.
- Vertical transforms: keyframed twist and taper (linear, smoothstep, cubic, Bézier easing), bulge, amplitude envelopes, phase variation, frequency crossfades.
- Expression editor:
30 + 5*sin(pi*z/H) + 2*cos(12*theta + z/15)with LaTeX preview, whitelisted parser, NaN/periodicity/negative-radius validation. - Julia boundary lofting (experimental) — cross-sections extracted from filled Julia
sets, with keyframed or elliptic paths for
c, a Mandelbrot explorer, a cross-section preview and explicit failure codes (disconnected, clipped, …) instead of silent fixes. - Solid walls (optional): instead of a spiral-vase surface, export a closed shell with a true wall thickness (minimum distance through the material) and an open or closed bottom and top.
- Printability analysis: contour-displacement overhang, bead overlap, nozzle-scale curvature, feature spacing, build volume, material and time estimates, colour heatmap.
- Accurate meshes: frequency-aware sampling, refined until off-grid probes measure the mesh within the deviation tolerance; true Gaussian smoothing; triangle budget enforced.
- Explicit validation of mathematical and mesh invariants (positive radius, closed contours, watertight, 2-manifold, consistent winding, Euler characteristic 2 …), repeated on the coordinates exactly as written to the exported file.
- 36 editable presets (27 classic, 9 Julia boundary), constrained Randomize, subtle/moderate/radical Mutate, and a nine-variation gallery — all reproducible from stored seeds.
- Accounts and projects — everything works without logging in; saving and loading on
the server need an account confirmed by email. Designs are stored per user as versioned
JSON (
<username>/<design>/design.json) with migration, undo/redo and import/export. - Exports: binary STL (default), 3MF, OBJ, PNG preview, SVG profile/cross-section, Markdown provenance, project JSON. High-resolution exports run as cancellable background jobs with progress.
Quick start (Docker Compose)
docker compose up --build
Open http://localhost:8000. A vase is already generated.
Projects are stored in the named volume mathema-data. The listening address and port
are configurable (default 127.0.0.1:8000):
MATHEMA_BIND=0.0.0.0 MATHEMA_PORT=8080 docker compose up --build -d
Accounts are optional: without mail settings the confirmation link for a new account is
printed in docker compose logs. To send real email, set the SMTP variables in .env
(see .env.example and docs/deployment.md). Put the
server behind HTTPS before exposing it beyond your own network.
Your first vase
- Open the app — the default Spiral Tulip is already shown.
- Click Presets and pick a family, or 🎲 Randomize.
- Adjust a few sliders (Silhouette → Maximum radius, Modulation layers → Angular frequency n).
- Turn on Printability in the viewport toolbar and read the right-hand panel.
- Click ⬇ Export STL → Generate & download STL. (On a phone: the Analysis tab shows printability, ⬇ exports.)
- Slice with spiral vase mode enabled (see docs/user-guide.md).
Development
Requirements: Python ≥ 3.12, Node ≥ 20.
Backend
python3 -m venv .venv
.venv/bin/pip install -r backend/requirements-dev.txt
cd backend
../.venv/bin/python -m pytest
MATHEMA_PORT=8000 ../.venv/bin/python -m mathema
Frontend
cd frontend
npm ci
npm run dev # Vite on http://127.0.0.1:5173, proxies /api to 127.0.0.1:8000
npm test # Vitest
npm run build # type-check (strict) + production build into frontend/dist
Set MATHEMA_BACKEND to proxy to a different backend URL. To serve a built frontend from the
backend, set MATHEMA_STATIC_DIR=frontend/dist.
Tests in Docker
docker build --target frontend-test . # Vitest, type-check, production build
docker build --target test . # backend pytest suite inside the runtime image
Deployment
Production runs at https://works.baumann.gr/mathema/ on the k3s cluster:
- Every push to
maintriggers.forgejo/workflows/build-and-deploy.yml: both test targets, then the runtime image built for the/mathema/path, pushed asgit.baumann.gr/adebaumann/mathema-vase-generator:<commit-sha>. - The workflow sets that tag in
mathema/kustomization.yamlof the GitOps repository websites-config. - Argo CD (one Application per folder, from the ApplicationSet in that repository) syncs the change.
Manifests, the SMTP ConfigMap and operations notes live in websites-config/mathema/;
configuration variables and Docker Compose are described in
docs/deployment.md.
Documentation
| Document | Contents |
|---|---|
| docs/user-guide.md | Using the workbench, exporting, slicer verification procedure |
| docs/mathematics.md | Conventions, units, every equation and generator |
| docs/geometry.md | Sampling, mesh topology, invariants and validation |
| docs/printability.md | What is analysed and how to read the results |
| docs/architecture.md | Module boundaries, data flow, API |
| docs/adding-generators.md | Writing a new mathematical family / plugin |
| docs/deployment.md | Docker, configuration, accounts, mail, CI, storage |
| docs/julia-boundary-api.md | Julia boundary lofting: schema, endpoints, numerical limits |
| docs/julia-verification.md | How the Julia boundary source was verified |
Status and known limitations
See docs/user-guide.md#known-limitations. In short:
- Slicer compatibility has been designed for and verified with mesh checks, but has not yet been confirmed in PrusaSlicer/OrcaSlicer — please follow the documented procedure.
- Julia boundary lofting is experimental: finite-resolution approximations of fractal boundaries; some parameter paths are rejected rather than lofted.
- There is no password reset or account deletion yet.
License
GPL-3.0 — see LICENSE.
