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

> Learn how Modly's export endpoint converts GLB, STL, and OBJ formats. Discover its mesh-exporter processor and deterministic writers for seamless format conversion.

- Repository: [lightningpixel/modly](https://github.com/lightningpixel/modly)
- Tags: how-to-guide
- Published: 2026-08-15

---

**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`](https://github.com/lightningpixel/modly/blob/main/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:

```ts
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:

```ts
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`](https://github.com/lightningpixel/modly/blob/main/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`](https://github.com/lightningpixel/modly/blob/main/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.