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