How the Mesh Repair Node Processes 3D Models in Modly
The mesh repair node validates the input file, loads the geometry with @gltf-transform, optionally welds duplicate vertices, reduces polygon count using the meshoptimizer WASM library, and writes an optimized GLB to the workspace.
The mesh repair node (internally named mesh-optimizer) is a critical processor in the lightningpixel/modly workflow engine that prepares 3D assets for downstream consumption. According to the source code in src/areas/workflows/nodes/mesh-optimizer/processor.ts, the node executes a nine-stage pipeline to repair and optimize mesh geometry while preserving visual fidelity.
Input Validation and Mesh Loading
The processor begins by enforcing strict input requirements. At lines 17–18 of processor.ts, the code validates that the filePath parameter exists:
if (!input.filePath) throw new Error('mesh-optimizer: input.filePath is required')
Once validated, the node initializes the @gltf-transform NodeIO class to parse the source file. The NodeIO instance reads the GLB or GLTF data and constructs a document scene graph that serves as the foundation for all subsequent operations (lines 22–34).
Triangle Analysis and Early Exit Optimization
Before performing expensive computations, the processor calculates the current polygon budget. It iterates through all meshes in the document root, summing the indices or positions of every primitive to determine the total triangle count (lines 35–47).
If the current face count is already below the target threshold—defaulting to 10,000 triangles—the node triggers an early exit at lines 50–54. It returns the original file path unchanged, avoiding unnecessary processing overhead:
if (currentFaces <= targetFaces) {
return { filePath: input.filePath }
}
Geometry Repair and Simplification Pipeline
When reduction is required, the node calculates a simplification ratio and error tolerance. The ratio equals targetFaces / currentFaces (capped at 1.0), while the error tolerance derives from Math.max(0.001, 1 - ratio) (lines 56–61).
Vertex Welding for Duplicate Removal
For meshes containing fewer than 500,000 faces, the processor executes a weld operation via @gltf-transform/functions. This step deduplicates vertices to repair topological inconsistencies. The 500k threshold prevents O(N²) performance degradation on large assets (lines 62–66):
if (currentFaces < 500_000) await doc.transform(weld())
Polygon Reduction with Meshoptimizer
The actual simplification leverages the meshoptimizer library compiled to WebAssembly. The code first awaits MeshoptSimplifier.ready to ensure the WASM binary is loaded, then applies the simplify transform with the calculated ratio and error parameters (lines 28–33 and 70–73):
await MeshoptSimplifier.ready
await doc.transform(simplify({
simplifier: MeshoptSimplifier,
ratio,
error,
lockBorder: false
}))
This reduces triangle count while maintaining edge boundaries, effectively "repairing" the mesh density for real-time rendering workflows.
Output Generation and Progress Tracking
After optimization, the node writes the repaired document to the workspace directory at Workflows/mesh-optimizer-<timestamp>.glb using io.write() (lines 75–85). Throughout the pipeline, the processor reports incremental progress (10% → 100%) via context.progress() and emits diagnostic logs via context.log(), providing real-time feedback in the Modly UI.
Implementation Example
You can configure the mesh repair node in a workflow JSON definition by specifying the mesh-optimizer extension ID and desired triangle target:
{
"type": "meshNode",
"id": "repair1",
"extensionId": "mesh-optimizer",
"params": {
"target_faces": 8000
},
"inputs": [{ "source": "importNode", "port": "mesh" }]
}
For testing or custom integrations, invoke the processor directly with the required context interface:
import processor from './src/areas/workflows/nodes/mesh-optimizer/processor'
const result = await processor(
{ filePath: '/assets/source.glb' },
{ target_faces: 5000 },
{
workspaceDir: '/my/workspace',
tempDir: '/tmp',
log: console.log,
progress: (pct, label) => console.log(`${pct}% – ${label}`)
}
)
console.log('Optimized output:', result.filePath)
Summary
- The mesh repair node requires a valid
filePathinput and throws immediately if missing. - It uses
@gltf-transform/core(NodeIO) to parse GLB/GLTF files into a manipulable scene graph. - Meshes with fewer than 10,000 triangles bypass processing to prevent over-optimization.
- Vertex welding repairs duplicate geometry only on meshes under 500,000 faces to avoid performance penalties.
- The
meshoptimizerWASM library performs the final polygon reduction using calculated ratio and error tolerance values. - Optimized files are written to the workspace with timestamped filenames and full progress telemetry.
Frequently Asked Questions
What file formats does the mesh repair node support?
The node supports GLB and GLTF formats through the @gltf-transform/core library. The NodeIO class handles the parsing and serialization of these formats, ensuring compatibility with standard glTF 2.0 assets commonly used in web-based 3D workflows.
How does the node decide when to skip simplification?
The processor compares the current triangle count against the target_faces parameter (defaulting to 10,000). If the mesh already meets this budget, the code returns the original file path at line 50 without invoking the meshoptimizer pipeline, preserving disk I/O and computation time.
Why does vertex welding skip on large meshes?
The weld operation has O(N²) complexity, making it prohibitively expensive for high-poly assets. The processor explicitly checks if (currentFaces < 500_000) before calling weld(), ensuring that large production meshes do not trigger performance bottlenecks during the repair process.
Can I adjust the target triangle count?
Yes. Pass the target_faces parameter in the node configuration or processor arguments. The system calculates the reduction ratio as Math.min(1, targetFaces / currentFaces), allowing you to specify precise polygon budgets for different target platforms like mobile VR or web viewers.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →