MATHĒMA Mathematical Vase Generator
  • Python 64.8%
  • TypeScript 31.5%
  • CSS 3.5%
  • Dockerfile 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Adrian A. Baumann 8c047f06e6
All checks were successful
Build and deploy MATHEMA / build (push) Successful in 7m55s
Normal-offset caps taper along the arc instead of notching corners
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.
2026-10-29 11:21:10 +01:00
.forgejo/workflows CI: update GitOps config path to websites-config/mathema 2026-10-18 10:57:58 +02:00
backend Normal-offset caps taper along the arc instead of notching corners 2026-10-29 11:21:10 +01:00
docs Meander cross-section: an outline whose teeth hook back over each other 2026-10-27 21:36:45 +01:00
frontend Meander cross-section: an outline whose teeth hook back over each other 2026-10-27 21:36:45 +01:00
.dockerignore Docker deployment, documentation, example plugin and UI fixes 2026-10-17 23:33:36 +02:00
.env.example Configure mail delivery through the internal SMTP relay 2026-10-18 10:18:27 +02:00
.gitignore gitignore added 2026-10-18 02:52:14 +02:00
docker-compose.yml Configure mail delivery through the internal SMTP relay 2026-10-18 10:18:27 +02:00
Dockerfile Add Forgejo CI: test, build, push image and update the GitOps tag 2026-10-18 10:32:02 +02:00
LICENSE Initial commit 2026-10-17 20:37:56 +00:00
README.md Meander cross-section: an outline whose teeth hook back over each other 2026-10-27 21:36:45 +01:00

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.

MATHĒMA workbench

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

  1. Open the app — the default Spiral Tulip is already shown.
  2. Click Presets and pick a family, or 🎲 Randomize.
  3. Adjust a few sliders (Silhouette → Maximum radius, Modulation layers → Angular frequency n).
  4. Turn on Printability in the viewport toolbar and read the right-hand panel.
  5. Click ⬇ Export STL → Generate & download STL. (On a phone: the Analysis tab shows printability, ⬇ exports.)
  6. 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:

  1. Every push to main triggers .forgejo/workflows/build-and-deploy.yml: both test targets, then the runtime image built for the /mathema/ path, pushed as git.baumann.gr/adebaumann/mathema-vase-generator:<commit-sha>.
  2. The workflow sets that tag in mathema/kustomization.yaml of the GitOps repository websites-config.
  3. 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.