A cross-platform library for efficient 3D mesh serialization and transport between Python and TypeScript/JavaScript applications.
meshly enables you to:
- Serialize 3D meshes efficiently - Compress mesh data (vertices, indices, normals, etc.) using meshoptimizer for optimal GPU-friendly storage
- Transport meshes from Python to the browser - Create meshes in Python (NumPy/JAX) and load them in TypeScript/JavaScript for WebGL/THREE.js rendering
- Extend with custom data - Inherit from
PackableorMeshto add your own array attributes that are automatically serialized
- Web-based 3D visualization - Generate meshes server-side in Python, serve compressed zip files, render in browser with THREE.js
- Simulation pipelines - Store simulation results with mesh geometry and field data in a single portable format
- CAD/CAM workflows - Exchange mesh data between Python tools and web-based viewers
- Machine learning - Serialize mesh datasets with associated feature arrays for training pipelines
This repository contains two libraries that work together:
pip install meshly- Create and manipulate 3D meshes with NumPy/JAX arrays
- Serialize meshes to compressed zip files using meshoptimizer
- Extend with custom array attributes via Pydantic models
- Mesh operations: triangulate, optimize, simplify, combine, extract
npm install meshly
# or
pnpm add meshly- Decode Python-generated mesh zip files in the browser
- Convert to THREE.js BufferGeometry for WebGL rendering
- Full TypeScript type definitions
Python (server-side):
import numpy as np
from meshly import Mesh
# Create a mesh
mesh = Mesh(
vertices=np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0]], dtype=np.float32),
indices=np.array([0, 1, 2], dtype=np.uint32)
)
# Save compressed (uses meshoptimizer)
mesh.save_to_zip("mesh.zip")TypeScript (browser):
import { Mesh } from 'meshly'
import * as THREE from 'three'
// Load and decode
const response = await fetch('mesh.zip')
const mesh = await Mesh.decode(await response.arrayBuffer())
// Render with THREE.js
const geometry = mesh.toBufferGeometry()
const material = new THREE.MeshStandardMaterial({ color: 0x2194ce })
scene.add(new THREE.Mesh(geometry, material))- Python README - Full Python API documentation
- TypeScript README - Full TypeScript API documentation
- Python Examples - Jupyter notebooks with usage examples
mesh.zip
├── metadata.json # Class info + non-array fields
├── vertices.bin # Meshoptimizer-encoded vertices
├── indices.bin # Meshoptimizer-encoded indices (optional)
└── arrays/ # Standard compressed arrays
├── normals/
│ ├── array.bin
│ └── metadata.json
└── ...
Both Python and TypeScript support custom field encoding via _get_custom_fields():
# Python
@classmethod
def _get_custom_fields(cls) -> Dict[str, CustomFieldConfig]:
return {
'vertices': CustomFieldConfig(
file_name='vertices',
encode=Mesh._encode_vertices,
decode=Mesh._decode_vertices,
),
}// TypeScript
protected static override getCustomFields(): Record<string, CustomFieldConfig> {
return {
vertices: { fileName: 'vertices', decode: Mesh._decodeVertices },
}
}MIT