28f8ec1mesh-pde-solver: upload a quad mesh, solve PDEs on the surface in-browserJeremy Magland 1# CLAUDE.md
3Tips for future agents working in this repo.
5## Architecture
7```
f4de30dSimplify the solver to run-per-solve; drop the uihtml event bridgeJeremy Magland 8matlab/ the MATLAB project each solve runs standalone
9 main.m `mip load --install surfacefun` -> jsondecode params.json
10 -> solve_pde('mesh.msh', params) -> write result.json
28f8ec1mesh-pde-solver: upload a quad mesh, solve PDEs on the surface in-browserJeremy Magland 11 solve_pde.m mesh -> surfacemesh -> resample -> surfaceop -> per-patch data
12 load_gmsh_quads.m minimal MSH 2.2 ASCII reader (canonical form only)
13 surfacemesh_from_quads.m replaces surfacemesh.fromGmsh (see below)
14src/mesh/ Pyodide + meshio upload pipeline (bridge.py runs in Pyodide)
f4de30dSimplify the solver to run-per-solve; drop the uihtml event bridgeJeremy Magland 15src/engine/ run-per-solve wrapper over numbl/browser's
16 createNumblSession: solve() boots a fresh session with
17 mesh.msh + params.json staged, reads result.json back via
18 session.readFile, and disposes the worker. numbl owns the
19 worker, VFS, mip bootstrap, and IndexedDB package
20 persistence; prewarm() at page load triggers the one-time
21 package download.
28f8ec1mesh-pde-solver: upload a quad mesh, solve PDEs on the surface in-browserJeremy Magland 22src/pde/presets.ts PDE definitions, presets, size limits
23src/render/ three.js SurfaceView (mesh preview / solution) + parula
24scripts/engine-test.mjs headless Node check of the whole MATLAB pipeline
25```
27## Key gotchas
f4de30dSimplify the solver to run-per-solve; drop the uihtml event bridgeJeremy Magland 29- **numbl >= 0.4.10 from npm** (`NumblSession.readFile`, which the engine
30 uses to fetch result.json, landed in 0.4.10; the `numbl/browser` entry and
31 executeCode searchPaths scanning landed in 0.4.9). To develop against a
32 local numbl checkout, point package.json at `file:../../numbl` and run
28f8ec1mesh-pde-solver: upload a quad mesh, solve PDEs on the surface in-browserJeremy Magland 33 `npm run build:lib && npm run build:browser` there after source changes.
34- **surfacemesh.fromGmsh is not used.** It locates the QUADS field via
35 `startsWith(fieldnames(...), 'QUADS')` (cellstr startsWith — unsupported in
36 numbl) and handles high-order gmsh quads. Our converter only emits 4-node
37 quads, so `surfacemesh_from_quads.m` builds the 2x2 patches directly.
38- **Canonical .msh only.** `load_gmsh_quads.m` assumes what
39 `src/mesh/bridge.py` writes: MSH 2.2 ASCII, sequential 1-based node ids,
40 type-3 elements, two tags. Uploaded .msh files in other layouts are fine —
41 they pass through meshio and get rewritten canonically.
f4de30dSimplify the solver to run-per-solve; drop the uihtml event bridgeJeremy Magland 42- **Solve errors reject the solve() promise** with the MATLAB error message
43 (a failed script run is a numbl bootError). Each solve is a fresh session,
44 so nothing needs to stay alive across failures.
28f8ec1mesh-pde-solver: upload a quad mesh, solve PDEs on the surface in-browserJeremy Magland 45- **jsonencode collapses 1-element vectors to scalars.** Patch arrays are
46 (p+1)^2 >= 9 long so it never bites here, but remember it when adding
47 payload fields.
48- Package caching: numbl/browser persists /system (mip + installed
f4de30dSimplify the solver to run-per-solve; drop the uihtml event bridgeJeremy Magland 49 packages) in IndexedDB, wiped after 24 h of inactivity — the prewarm
50 session at page load re-downloads ~28 MB on a fresh day; solves after
51 that only pay a per-run `mip load` (~1 s). Delete the
52 `numbl-embed-system` IndexedDB database to test cold boots.
54## Testing
56- `npm run engine-test` — full headless solve in Node against the local
57 numbl build (dist-lib), including a quantitative eigenfunction check. It
f4de30dSimplify the solver to run-per-solve; drop the uihtml event bridgeJeremy Magland 58 runs matlab/main.m standalone per solve (as the browser does), sharing
59 one VFS across solves as the stand-in for IndexedDB persistence, and
28f8ec1mesh-pde-solver: upload a quad mesh, solve PDEs on the surface in-browserJeremy Magland 60 passes the mip search path explicitly, exercising the same
61 searchPaths-scan behavior the numbl/browser session relies on. Downloads
62 are cached in `.cache/` keyed by URL; delete the cache to test fresh
63 installs.
64- `python3 <venv>/bin/python` with meshio 5.3.5 can exercise
65 `src/mesh/bridge.py` outside Pyodide (redirect its `/work` constant).
66- Browser verification (Pyodide upload path, session boot, IndexedDB
67 persistence across reloads, 3D view) is manual: `npm run dev`.