Catalog npm
PACKAGE EXPLORERView in registry

3d-file-parsers

npm

Lightweight, zero-dependency parsers for niche 3D file formats (M3D, X3D, IrrMesh, Terragen, PTS) that major libraries don't support. Returns raw typed arrays — works with Three.js, Babylon.js, or any WebGL framework.

3d3d-converterbabylonjsbrowserfile-formatirrlichtirrmeshm3dmeshparserpoint-cloudptsterragenthreejstyped-arraywasm
All keywords (18)
webglx3d
Versions collected1
Direct dependencies3From release 1.0.0
Last observed20 Oct, 19:34 UTC

README

Current package documentation

3d-file-parsers

Lightweight, framework-agnostic parsers for niche 3D file formats that Three.js, Babylon.js, and Assimp.js don't natively support.

All parsers return raw Float32Array / Uint32Array data — plug them into any WebGL/WebGPU renderer with zero adapter code.

Used in production at 3D Tools by FabRapid — a free, browser-based 3D file converter supporting 70+ input formats and 23 output formats with zero server uploads.

Supported Formats

ParserFormatExtensionDescription
parseM3DModel3D.m3dBinary mesh format with optional zlib compression. Supports int16/float32/float64 vertex precision and polygon meshes.
parseX3DX3D.x3dXML-based 3D scene format (ISO standard). Handles IndexedFaceSet, IndexedTriangleSet, and Box primitives with material colors.
parseIrrMeshIrrlicht Mesh.irrmeshXML mesh format from the Irrlicht Engine. Supports standard, 2tcoords, and tangents vertex types.
parseTerragenTerragen.terBinary heightmap terrain format. Automatically triangulates the elevation grid into a renderable mesh.
parsePTSLeica PTS.ptsASCII point cloud format used by Leica laser scanners. Supports XYZ, XYZ+intensity, and XYZ+intensity+RGB columns.

Why This Exists

When building 3d-tools.fabrapid.com, we needed to support dozens of 3D formats in the browser. Most common formats (GLTF, OBJ, STL, FBX) are well-covered by Three.js loaders and Assimp WASM. But several formats — M3D, X3D, IrrMesh, Terragen, and PTS — had no JavaScript parser available, or the existing implementations were tightly coupled to a specific rendering engine.

We wrote these parsers from scratch based on the official format specifications, tested them against real-world files, and extracted them into this standalone package so others don't have to.

Design principles:

  • Zero framework dependency — returns plain typed arrays, not Three.js objects
  • Isomorphic — works in browsers and Node.js (XML parsers accept a custom DOMParser)
  • Tiny footprint — only fflate (3KB gzipped) for M3D's zlib decompression; everything else is zero-dep
  • TypeScript-first — full type definitions with documented interfaces

Installation

# pnpm
pnpm add 3d-file-parsers

# npm
npm install 3d-file-parsers

# yarn
yarn add 3d-file-parsers

Quick Start

Import everything

import { parseM3D, parseX3D, parseIrrMesh, parseTerragen, parsePTS } from '3d-file-parsers';

Or import individual parsers (tree-shakeable)

import { parseM3D } from '3d-file-parsers/m3d';
import { parseX3D } from '3d-file-parsers/x3d';
import { parseIrrMesh } from '3d-file-parsers/irrmesh';
import { parseTerragen } from '3d-file-parsers/terragen';
import { parsePTS } from '3d-file-parsers/pts';

Usage

Parse M3D (Model3D)

import { parseM3D } from '3d-file-parsers';

const response = await fetch('model.m3d');
const buffer = await response.arrayBuffer();

const { positions, normals, indices, vertexCount, faceCount } = parseM3D(buffer);

console.log(`Vertices: ${vertexCount}, Faces: ${faceCount}`);
// positions: Float32Array — flat xyz array (length = vertexCount * 3)
// normals:   Float32Array | null — auto-computed face normals
// indices:   Uint32Array — triangle indices

Parse X3D

import { parseX3D } from '3d-file-parsers';

const response = await fetch('scene.x3d');
const text = await response.text();

const { meshes } = parseX3D(text);

for (const mesh of meshes) {
  console.log(`Mesh: ${mesh.indices.length / 3} triangles`);
  // mesh.positions: Float32Array
  // mesh.normals:   Float32Array | null
  // mesh.indices:   Uint32Array
  // mesh.color?:    [r, g, b] — diffuse material color (0-1)
}

Node.js usage (X3D / IrrMesh)

XML-based parsers need a DOMParser. In Node.js, pass one from @xmldom/xmldom:

import { DOMParser } from '@xmldom/xmldom';
import { parseX3D } from '3d-file-parsers';

const { meshes } = parseX3D(xmlString, new DOMParser());

Parse IrrMesh (Irrlicht)

import { parseIrrMesh } from '3d-file-parsers';

const response = await fetch('model.irrmesh');
const text = await response.text();

const { buffers } = parseIrrMesh(text);

for (const buf of buffers) {
  console.log(`Buffer: ${buf.vertexCount} vertices, ${buf.faceCount} faces`);
  // buf.positions: Float32Array
  // buf.normals:   Float32Array
  // buf.indices:   Uint32Array
}

Parse Terragen Terrain

import { parseTerragen } from '3d-file-parsers';

const response = await fetch('terrain.ter');
const buffer = await response.arrayBuffer();

const { positions, indices, normals, xpts, ypts } = parseTerragen(buffer);

console.log(`Terrain grid: ${xpts} x ${ypts} (${xpts * ypts} vertices)`);
// Automatically triangulated — ready to render as a mesh

Parse PTS Point Cloud

import { parsePTS } from '3d-file-parsers';

const response = await fetch('scan.pts');
const buffer = await response.arrayBuffer();

const { positions, colors, pointCount, hasColor } = parsePTS(buffer);

console.log(`Points: ${pointCount}, Has color: ${hasColor}`);
// positions: Float32Array — flat xyz (length = pointCount * 3)
// colors:    Float32Array | null — flat rgb normalized to 0-1

Using with Three.js

The parsers return raw typed arrays. Here's how to create Three.js geometry:

import * as THREE from 'three';
import { parseM3D } from '3d-file-parsers';

const data = parseM3D(buffer);
const geometry = new THREE.BufferGeometry();

geometry.setAttribute('position', new THREE.Float32BufferAttribute(data.positions, 3));

if (data.normals) {
  geometry.setAttribute('normal', new THREE.Float32BufferAttribute(data.normals, 3));
}

if (data.indices.length > 0) {
  geometry.setIndex(new THREE.BufferAttribute(data.indices, 1));
}

const mesh = new THREE.Mesh(geometry, new THREE.MeshStandardMaterial());
scene.add(mesh);

Point cloud with Three.js

import * as THREE from 'three';
import { parsePTS } from '3d-file-parsers';

const data = parsePTS(buffer);
const geometry = new THREE.BufferGeometry();

geometry.setAttribute('position', new THREE.Float32BufferAttribute(data.positions, 3));

if (data.colors) {
  geometry.setAttribute('color', new THREE.Float32BufferAttribute(data.colors, 3));
}

const material = new THREE.PointsMaterial({
  size: 0.01,
  vertexColors: data.hasColor,
});

const points = new THREE.Points(geometry, material);
scene.add(points);

Using with Babylon.js

import * as BABYLON from '@babylonjs/core';
import { parseM3D } from '3d-file-parsers';

const data = parseM3D(buffer);
const mesh = new BABYLON.Mesh('model', scene);
const vertexData = new BABYLON.VertexData();

vertexData.positions = Array.from(data.positions);
vertexData.indices = Array.from(data.indices);

if (data.normals) {
  vertexData.normals = Array.from(data.normals);
}

vertexData.applyToMesh(mesh);

Using with Raw WebGL

import { parseM3D } from '3d-file-parsers';

const data = parseM3D(buffer);

const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, data.positions, gl.STATIC_DRAW);

const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, data.indices, gl.STATIC_DRAW);

gl.drawElements(gl.TRIANGLES, data.indices.length, gl.UNSIGNED_INT, 0);

API Reference

parseM3D(buffer: ArrayBuffer): M3DData

PropertyTypeDescription
positionsFloat32ArrayFlat xyz vertex positions
normalsFloat32Array | nullAuto-computed vertex normals
indicesUint32ArrayTriangle indices
vertexCountnumberNumber of vertices
faceCountnumberNumber of triangles

parseX3D(xmlText: string, domParser?): X3DData

PropertyTypeDescription
meshesX3DMesh[]Array of parsed meshes
meshes[].positionsFloat32ArrayFlat xyz vertex positions
meshes[].normalsFloat32Array | nullComputed vertex normals
meshes[].indicesUint32ArrayTriangle indices
meshes[].color[r, g, b]?Diffuse material color (0-1)

parseIrrMesh(xmlText: string, domParser?): IrrMeshData

PropertyTypeDescription
buffersIrrMeshBuffer[]Array of mesh buffers
buffers[].positionsFloat32ArrayFlat xyz vertex positions
buffers[].normalsFloat32ArrayVertex normals from file
buffers[].indicesUint32ArrayTriangle indices
buffers[].vertexCountnumberVertices in this buffer
buffers[].faceCountnumberTriangles in this buffer

parseTerragen(buffer: ArrayBuffer): TerragenData

PropertyTypeDescription
positionsFloat32ArrayFlat xyz vertex positions
indicesUint32ArrayTriangle indices (2 per grid quad)
normalsFloat32ArrayComputed vertex normals
xptsnumberGrid points along X axis
yptsnumberGrid points along Y axis

parsePTS(buffer: ArrayBuffer): PTSData

PropertyTypeDescription
positionsFloat32ArrayFlat xyz point positions
colorsFloat32Array | nullRGB colors normalized 0-1 (null if no color data)
pointCountnumberNumber of points
hasColorbooleanWhether the file contained color data

Browser Support

Works in all modern browsers with ArrayBuffer and DataView support (Chrome 49+, Firefox 42+, Safari 10+, Edge 14+).

For Node.js, XML-based parsers (X3D, IrrMesh) require a DOM parser like @xmldom/xmldom.

  • 3D Tools by FabRapid — Free online 3D file converter (70+ formats, zero uploads, browser-only)
  • 3D File Viewer — Online 3D model viewer with support for all major formats
  • 3D Model Compressor — Browser-based GLB compression with before/after comparison
  • Assimp — The industry-standard C++ import library (covers most common formats)
  • Three.js — WebGL rendering library with many built-in loaders
  • fflate — Fast JavaScript compression library (used for M3D zlib decompression)

Contributing

Contributions are welcome! If you need support for additional niche 3D formats, please open an issue.

License

MIT

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Versions 1

Collected releases
VersionPublishedDirect dependenciesOpen version
1.0.0Registry latest25 Mar 20263

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Repository

PENDING
rotfeat/3d-file-parsers

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 19:34 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:0230e010f881459460c5ac55d59c2ead254be1e5fbe5a948b160bb3f0bf85997