npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

landxml

v0.9.1

Published

Parse LandXML surfaces on the modern web.

Readme

LandXML Parser for Contour GeoJSON and 3D Models

Easily transform LandXML surfaces into GeoJSON contours or GLB 3D models for use in ThreeJS, Cesium, QGIS, or any popular 3D/GIS software.


Features

  • toGlbAndContours — Generate both a GLB model and GeoJSON contours in a single pass (fastest when you need both outputs).
  • toGlb — Generate a GLB 3D model from LandXML surfaces.
  • toGeojsonContours — Convert LandXML surfaces into contour line GeoJSON.
  • reprojectGeoJson — Reproject GeoJSON coordinates to any projection using mproj.

Installation

npm install landxml

Examples

Get contours and a GLB model together (recommended)

When you need both outputs, use toGlbAndContours — it parses the XML once and shares computed data between both outputs, making it significantly faster than calling toGlb and toGeojsonContours separately.

import { toGlbAndContours, reprojectGeoJson } from "landxml";

const landXmlString = `<?xml version="1.0"?>...<LandXML>...</LandXML>`;

const surfaces = await toGlbAndContours(
  landXmlString,
  2, // contour interval (LandXML units)
  true, // generate outline
  "auto", // GLB center: "auto" | "origin" | [x, y]
);

const { glb, center, geojson, wktString, download } = surfaces[0];

// Download the GLB file in the browser
download();

// Reproject contours from the LandXML CRS to WGS84
const reprojected = reprojectGeoJson(geojson, wktString, "WGS84", false);

Get GeoJSON contours only

import { toGeojsonContours, reprojectGeoJson } from "landxml";

const landXmlString = `<?xml version="1.0"?>...<LandXML>...</LandXML>`;

const surfaces = await toGeojsonContours(
  landXmlString,
  2, // contour interval (LandXML units)
  true, // include surface outline as a z=0 feature
);

const { geojson, wktString } = surfaces[0];

// Reproject from the LandXML coordinate system to WGS84 for web mapping
const reprojected = reprojectGeoJson(geojson, wktString ?? "WGS84", "WGS84", false);

console.log(reprojected.features.length); // number of contour + outline features

Convert to a GLB 3D model

import { toGlb } from "landxml";

const landXmlString = `<?xml version="1.0"?>...<LandXML>...</LandXML>`;

const surfaces = await toGlb(
  landXmlString,
  "auto", // centre strategy: "auto" | "origin" | [x, y]
);

const { glb, center, download } = surfaces[0];

// Trigger a browser download of the .glb file
download();

// Or use the raw binary (Uint8Array) directly — e.g. load into Three.js
const loader = new GLTFLoader();
loader.parse(glb.buffer, "", (gltf) => {
  scene.add(gltf.scene);
});

Work with a specific surface in a multi-surface LandXML

LandXML files can contain multiple surfaces. Use surfaceId to select one by name or by index.

import { toGeojsonContours } from "landxml";

const landXmlString = `<?xml version="1.0"?>...<LandXML>...</LandXML>`;

// By name
const byName = await toGeojsonContours(landXmlString, 2, true, "ExistingGround");

// By index (0-based)
const byIndex = await toGeojsonContours(landXmlString, 2, true, 1);

Reproject GeoJSON

reprojectGeoJson wraps mproj and works with both WKT strings (exported by Civil 3D when a drawing is geo-referenced) and standard proj4 definition strings.

import { reprojectGeoJson } from "landxml";

// wktString is available on every surface returned by toGeojsonContours / toGlbAndContours
const reprojected = reprojectGeoJson(
  geojson,
  wktString, // source CRS — WKT or proj4 string
  "WGS84", // target CRS (default)
  true, // keep original geometry as feature property "_rawGeometry"
);

API Reference

toGlbAndContours(landXmlString, contourInterval?, generateOutline?, center?, surfaceId?)

| Parameter | Type | Default | Description | | ----------------- | ------------------------------ | -------- | -------------------------------------------------- | | landXmlString | string | — | Raw LandXML XML string | | contourInterval | number | 2 | Vertical interval between contour lines | | generateOutline | boolean | true | Append surface boundary as a z=0 GeoJSON feature | | center | "auto" \| "origin" \| [x, y] | "auto" | GLB model origin strategy | | surfaceId | string \| number | -1 | Surface name or index; -1 returns all surfaces |

Returns Promise<GlbAndContoursResult[]> where each element contains name, description, sourceFile, timeStamp, wktString, glb, center, download, and geojson.


toGeojsonContours(landXmlString, contourInterval?, generateOutline?, surfaceId?)

| Parameter | Type | Default | Description | | ----------------- | ------------------ | ------- | -------------------------------------------------- | | landXmlString | string | — | Raw LandXML XML string | | contourInterval | number | 2 | Vertical interval between contour lines | | generateOutline | boolean | true | Append surface boundary as a z=0 GeoJSON feature | | surfaceId | string \| number | -1 | Surface name or index; -1 returns all surfaces |

Returns Promise<{ name, description, sourceFile, timeStamp, wktString?, geojson }[]>.


toGlb(landXmlString, center?, surfaceId?)

| Parameter | Type | Default | Description | | --------------- | ------------------------------ | -------- | ----------------------------------------------------------------------------------------------------------- | | landXmlString | string | — | Raw LandXML XML string | | center | "auto" \| "origin" \| [x, y] | "auto" | GLB model origin strategy. 3D models are sensitive to large coordinates — "auto" offsets to the XY median | | surfaceId | string \| number | -1 | Surface name or index; -1 returns all surfaces |

Returns Promise<{ name, description, sourceFile, timeStamp, glb, center, download }[]>.


reprojectGeoJson(geojson, sourceProjection, targetProjection?, keepOriginalGeometry?)

| Parameter | Type | Default | Description | | ---------------------- | ------------------- | --------- | ------------------------------------------------------------------ | | geojson | FeatureCollection | — | GeoJSON to reproject | | sourceProjection | string | — | Proj4 or WKT string of the source CRS | | targetProjection | string | "WGS84" | Proj4 or WKT string of the target CRS | | keepOriginalGeometry | boolean | true | Store original coordinates under feature.properties._rawGeometry |

Returns the mutated FeatureCollection with updated coordinates.


Multi-surface center behaviour

When a LandXML file contains multiple surfaces and center is set to "auto" (the default), the package computes a single shared median center across all surfaces' points. Every GLB produced in that call is offset by the same origin, so the surfaces remain correctly positioned relative to each other in your 3D scene. This happens automatically — no extra configuration is needed.

If you need each surface to be individually centered (e.g. you are processing them in isolation), pass an explicit [x, y] pair instead.