How the Modly Export Endpoint Converts Between GLB, STL, and OBJ Formats

Modly's export endpoint uses a dedicated mesh-exporter processor that parses GLB input via @gltf-transform, extracts raw vertex geometry, and serializes it into binary STL or ASCII OBJ formats using deterministic, format-specific writers.

The lightningpixel/modly repository handles 3D model interoperability through a workflow-based export pipeline. When you configure an export node in Modly, the system invokes a specialized processor that accepts GLB files—the internal standard—and transforms them into production-ready formats through a multi-stage conversion process.

Architecture of the Mesh-Exporter Processor

The conversion logic resides in src/areas/workflows/nodes/mesh-exporter/processor.ts, which implements Modly’s process extension interface. This design isolates format conversion from the core application, allowing the exporter to operate as a discrete node within visual workflows.

Parameter Handling and Format Mapping

When the processor executes, it receives a configuration object containing export_format (accepting glb, stl, obj, or ply) and an optional output_path. The extension maps these values to file extensions using a static EXT_MAP lookup table defined around lines 77–82, then creates a dedicated output directory if one is not provided.

GLB Loading and Geometry Extraction

The processor loads the source GLB using @gltf-transform’s NodeIO class, which fully resolves the GLTF document structure into accessible meshes and primitives. For non-GLB targets, the code extracts raw geometry via the extractPrimitives helper:

const prims = extractPrimitives(doc);

This helper iterates over every mesh and primitive in the document, gathering POSITION attributes along with optional NORMAL and TEXCOORD_0 arrays to build PrimGeometry objects. This normalization step ensures consistent data structures regardless of the input GLB’s internal complexity.

Format-Specific Serialization Logic

Once geometry is extracted, the processor branches into format-specific writers that handle byte-level serialization for binary formats and structured text generation for ASCII formats.

GLB Pass-Through Export

When the target format is GLB, the processor delegates entirely to the library’s native capabilities. The document is written directly using io.write without geometry manipulation, preserving the original structure and extensions.

Binary STL Generation

For STL output, the processor constructs a binary buffer sized precisely to the mesh topology. The implementation calculates total triangles and allocates a buffer of 84 + totalTri * 50 bytes. The serialization process follows the STL binary specification:

  1. Writes an 80-byte header (reserved, typically empty)
  2. Appends a 4-byte unsigned integer indicating the triangle count
  3. For each triangle:
    • Computes a normal vector using faceNormal if the primitive lacks explicit normals
    • Writes three 32-bit floating-point values for the normal
    • Writes nine 32-bit floating-point values for the three vertex coordinates
    • Appends a 2-byte attribute count (usually zero)

The completed buffer is persisted using fs.writeFileSync.

ASCII OBJ Generation

For OBJ export, the processor emits a human-readable text file with structured vertex and face definitions. The writer tracks index offsets across multiple meshes using vOff, vnOff, and vtOff counters to ensure correct face indexing:

  • Vertex data: Emits v lines for positions, vn for normals (if available), and vt for UV coordinates (if present)
  • Face definitions: Generates f lines that reference vertices by index, properly offset to account for preceding mesh data
  • File encoding: Concatenates all lines and writes UTF-8 output to the destination path

This approach preserves mesh separation while creating a valid, parseable OBJ file compatible with most 3D software.

Workflow Integration and Usage

The mesh-exporter operates as a first-class citizen in Modly’s workflow engine, reporting progress via context.progress() and logging actions through context.log(). Upon completion, the processor returns the absolute path of the generated file, enabling downstream nodes to reference the asset immediately.

You can invoke the processor programmatically:

import processor from './src/areas/workflows/nodes/mesh-exporter/processor';

await processor(
  { filePath: '/tmp/model.glb' },
  { export_format: 'stl', output_path: '/tmp/exports' },
  {
    workspaceDir: '/my/workspace',
    tempDir: '/my/temp',
    log: console.log,
    progress: (pct, label) => console.log(`${pct}% – ${label}`)
  }
);

When configured through the UI, add a Mesh Exporter node to your workflow, set the Export Format parameter to your desired format, and connect an input mesh. The node automatically generates timestamped files (e.g., export-1700123456789.stl) in the workspace’s Exports folder.

Summary

  • Modly’s export endpoint is implemented as a process extension in processor.ts that converts internal GLB files to STL, OBJ, or other supported formats.
  • GLB parsing relies on @gltf-transform’s NodeIO to resolve document structures before extracting raw primitive data via extractPrimitives.
  • STL output uses a custom binary writer that allocates 84 + (triangleCount * 50) bytes, writes an 80-byte header, and serializes triangles with computed face normals.
  • OBJ output generates ASCII text with indexed face definitions, tracking vertex offsets across multiple meshes to maintain valid references.
  • Integration supports both programmatic invocation and visual workflow configuration, returning absolute file paths for downstream processing.

Frequently Asked Questions

Does the Modly export endpoint support both binary and ASCII STL formats?

According to the source code in processor.ts, Modly currently implements binary STL only. The writer explicitly allocates binary buffers and writes the 80-byte header and 4-byte triangle count required by the binary specification. ASCII STL output is not implemented in the current version.

How does Modly handle missing normal vectors when exporting to STL?

If the source GLB lacks normal data for a primitive, the processor calculates surface normals dynamically using the faceNormal function during serialization. Each triangle in the binary STL output requires a normal vector, so the system computes this geometrically from the vertex positions if not explicitly provided in the source mesh.

Can the export endpoint convert multiple meshes into a single OBJ file?

Yes. The extractPrimitives helper aggregates geometry from all meshes in the GLB document, and the OBJ writer manages global index offsets (vOff, vnOff, vtOff) to ensure that face definitions reference the correct vertices across concatenated mesh data. The resulting OBJ file contains all geometry while maintaining proper index references.

What dependencies power the GLB parsing in Modly’s export pipeline?

The conversion relies on @gltf-transform/core and @gltf-transform/extensions, as declared in the project’s dependencies. The processor specifically uses the NodeIO class from this library to read GLB files and access their internal mesh structures, primitives, and vertex attributes.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →