edd4e73Mesh converter: upload, view, and export meshes across formatsJeremy Magland 1# mesh-converter
3A static web app for converting meshes between formats: upload a mesh file,
50876cdConvert real mesh formats with meshio via PyodideJeremy Magland 4inspect it in an interactive 3D view (shaded, wireframe, shaded + wireframe,
5or points), and download it in a format of your choice. Formats differ in what they can store, and the UI shows exactly which
6attributes (normals, colors) would be dropped by a lossy conversion.
50876cdConvert real mesh formats with meshio via PyodideJeremy Magland 8Conversion is powered by [meshio](https://github.com/nschloe/meshio) running
9in the browser via [Pyodide](https://pyodide.org) — no server, all mesh I/O
10happens client-side. The first visit downloads the Python runtime (~15 MB from
11the jsDelivr CDN, cached afterwards).
50876cdConvert real mesh formats with meshio via PyodideJeremy Magland 13| Format | Extension | positions/faces | normals | colors | notes |
edd4e73Mesh converter: upload, view, and export meshes across formatsJeremy Magland 14| --- | --- | --- | --- | --- | --- |
50876cdConvert real mesh formats with meshio via PyodideJeremy Magland 15| PLY (Polygon File Format) | `.ply` | ✓ | ✓ | ✓ | |
16| Wavefront OBJ | `.obj` | ✓ | ✓ | — | |
17| STL | `.stl` | ✓ | — | — | binary |
18| OFF (Object File Format) | `.off` | ✓ | — | — | |
19| VTK legacy | `.vtk` | ✓ | ✓ | ✓ | |
20| VTU (VTK XML) | `.vtu` | ✓ | ✓ | ✓ | |
dfa5737Export by converting the original file natively; fix gmsh/tecplot capabilitiesJeremy Magland 21| Gmsh MSH | `.msh` | ✓ | ✓ | ✓ | |
50876cdConvert real mesh formats with meshio via PyodideJeremy Magland 22| XDMF | `.xdmf` | ✓ | ✓ | ✓ | h5py† |
23| MED (Salome) | `.med` | ✓ | ✓ | ✓ | h5py† |
24| H5M (MOAB) | `.h5m` | ✓ | ✓ | ✓ | h5py† |
25| AVS-UCD | `.avs` | ✓ | ✓ | ✓ | |
26| Abaqus | `.inp` | ✓ | — | — | |
27| Nastran | `.bdf` | ✓ | — | — | |
28| Medit | `.mesh` | ✓ | — | — | |
29| Netgen | `.vol` | ✓ | — | — | |
30| MDPA (Kratos) | `.mdpa` | ✓ | — | — | |
dfa5737Export by converting the original file natively; fix gmsh/tecplot capabilitiesJeremy Magland 31| Tecplot | `.dat` | ✓ | ✓ | ✓ | |
50876cdConvert real mesh formats with meshio via PyodideJeremy Magland 32| DOLFIN XML | `.xml` | ✓ | — | — | |
33| PERMAS | `.post` | ✓ | — | — | |
35† HDF5-based formats need the h5py Pyodide package (~4 MB); it is loaded
36lazily the first time such a format is used, so the default footprint stays
37small.
dfa5737Export by converting the original file natively; fix gmsh/tecplot capabilitiesJeremy Magland 39A loaded file is kept in its original bytes, in its original format — that is
40the source of truth. Export runs meshio directly on those bytes
41(`read` the original, `write` the target), so a conversion drops only what the
42target format genuinely cannot express, and exporting back to the *same* format
43returns the original file byte-for-byte with no conversion at all. During
44conversion the app translates vertex normals and colors between the formats'
45native representations (so PLY's `nx/ny/nz` properties become `vn` lines in
46OBJ, and so on), normalizes byte order and integer widths where meshio's
47writers are picky about dtypes, and strips data that meshio 5.3.5 would write
48corruptly (MDPA mesh data) or crash on (H5M and DOLFIN XML cell data). The 3D
49view is fed by a separate, triangle-only "common" representation: quads and
50polygons are fan-triangulated and volume cells are skipped *for display*, but
51none of that touches what gets exported.
53✓ marks the attributes the app tracks for its loss warnings, and is how it
54writes the generated sample mesh (which, unlike an uploaded file, has no
55original bytes): vertex normals map to each format's native representation
56(`nx/ny/nz` scalars in PLY and Tecplot, `vn` lines in OBJ, a `Normals`
57point-data array elsewhere) and vertex colors likewise (`red/green/blue` in
58PLY and Tecplot, an `RGB` point-data array elsewhere).
50876cdConvert real mesh formats with meshio via PyodideJeremy Magland 59
60Some meshio formats are deliberately absent: ansys, cgns, su2, and ugrid
61cannot roundtrip their own output in meshio 5.3.5; exodus fails writing under
62wasm; flac3d holds volume cells only; wkt's reader hangs on non-toy meshes;
63tetgen spans two files; svg is write-only.
65A built-in sample mesh (a rainbow torus with normals and vertex colors) is
50876cdConvert real mesh formats with meshio via PyodideJeremy Magland 66available from the UI for trying things out without a file, and `examples/`
67holds it pre-exported in a few formats. An on-demand "estimate export sizes"
68action serializes the loaded mesh to every format in memory and shows the
69resulting file sizes in the format table and export dropdown.
bd1359eShare meshes as self-contained URLsJeremy Magland 71A loaded mesh can be shared as a self-contained link: "Copy share link" packs
72the original uploaded file (byte-identical, in its original format) together
73with the chosen export format and view mode into the URL fragment —
74deflate-compressed and base64url-encoded after `#share=`. Nothing is uploaded;
75the data lives in the URL itself, so whoever opens the link sees the mesh and
76can download it in any format. Links are capped at 65,000 characters (roughly
77a 100–300 KB mesh file, depending on how well it compresses); beyond that the
78app says the mesh is too large to share by URL.
edd4e73Mesh converter: upload, view, and export meshes across formatsJeremy Magland 80## Development
82```bash
83npm install
84npm run dev # local dev server
85npm run build # static build in dist/
86```
88Built with Vite, React, TypeScript, and three.js (react-three-fiber).
dfa5737Export by converting the original file natively; fix gmsh/tecplot capabilitiesJeremy Magland 92- `src/mesh/bridge.py` runs inside Pyodide with three entry points:
93 `parse_mesh_file` (native file → the triangle-only common form that feeds the
94 viewer), `convert_mesh` (native → native, straight through meshio, the export
95 path for uploaded files), and `serialize_mesh` (common form → native, used
96 only for the generated sample). It exchanges arrays with JS as raw
97 little-endian buffers through Pyodide's in-memory filesystem.
50876cdConvert real mesh formats with meshio via PyodideJeremy Magland 98- `src/mesh/meshio.ts` loads Pyodide (script tag in `index.html`), installs
dfa5737Export by converting the original file natively; fix gmsh/tecplot capabilitiesJeremy Magland 99 meshio via micropip, and wraps the bridge in typed async functions:
100 `parseMeshFile` for the viewer's `MeshData` (typed arrays of positions,
101 triangle indices, optional normals/colors), `convertMesh` for lossless
102 native-to-native export, and `serializeMesh` for the sample. `App.tsx` keeps
103 the loaded file's original bytes as the source of truth and routes export
104 through them — same-format exports skip meshio entirely.
50876cdConvert real mesh formats with meshio via PyodideJeremy Magland 105- `src/mesh/formats.ts` declares the supported formats and which attributes
106 each preserves; the upload, capability table, and loss-warning UI derive
107 from it. To add a meshio-supported format, add a descriptor there (with
108 `pyodidePackages` if it needs extra prebuilt packages such as h5py) and, if
109 it stores normals/colors in a format-specific way, teach
110 `bridge.py` how to map them.