# landxml

> Parse LandXML surfaces on the modern web.

Latest version **0.9.1** (published 2026-04-07) · MIT license · 0 weekly downloads

## Install

```sh
npm install landxml
pnpm add landxml
yarn add landxml
bun add landxml
```

## Health

**Score 65/100 (B)** — status: stable.

Positive: has types; esm support; no vulnerabilities; has provenance; high quality score.

Warnings: low downloads; pre 1.0.

## Facts

| | |
|---|---|
| Version | 0.9.1 |
| Published | 2026-04-07 |
| First published | 2023-11-20 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 6 |
| Unpacked size | 76.4 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Provenance | attested (GitHub Actions) |
| GitHub stars | 2 |
| Author | Matthew Abrman |
| Maintainers | abrman |
| Keywords | landxml, geojson, gltf |

## Links

- npm: https://www.npmjs.com/package/landxml
- Repository: https://github.com/abrman/landxml
- Homepage: https://github.com/abrman/landxml#readme
- Issues: https://github.com/abrman/landxml/issues
- npm.io page: https://npm.io/package/landxml

## Dependencies (6)

- [sax](https://npm.io/package/sax.md) ^1.4.1
- [mproj](https://npm.io/package/mproj.md) ^0.0.7
- [xml-js](https://npm.io/package/xml-js.md) ^1.6.11
- [easy-web-worker](https://npm.io/package/easy-web-worker.md) ^6.2.0
- [@vitest/web-worker](https://npm.io/package/@vitest/web-worker.md) ^3.2.4
- [@gltf-transform/core](https://npm.io/package/@gltf-transform/core.md) ^3.9.0

## Alternatives

- [@mapbox/jsonlint-lines-primitives](https://npm.io/package/@mapbox/jsonlint-lines-primitives.md) — 5.3M weekly downloads
- [reftools](https://npm.io/package/reftools.md) — 3.5M weekly downloads
- [@hey-api/openapi-ts](https://npm.io/package/@hey-api/openapi-ts.md) — 3.5M weekly downloads
- [@mapbox/geojson-rewind](https://npm.io/package/@mapbox/geojson-rewind.md) — 2.4M weekly downloads
- [turbo-stream](https://npm.io/package/turbo-stream.md) — 1.7M weekly downloads

## Recent versions

- 0.9.1 (latest) — 2026-04-07
- 0.9.0 — 2026-04-07
- 0.8.1 — 2026-02-26
- 0.8.0 — 2026-02-20
- 0.7.1 — 2026-02-19
- 0.6.6 — 2025-08-29
- 0.6.4 — 2024-05-31
- 0.6.3 — 2024-05-29
- 0.6.2 — 2024-05-22
- 0.6.1 — 2024-05-21
- 0.6.0 — 2024-05-21
- 0.5.2 — 2023-12-06
- 0.5.1 — 2023-12-04
- 0.5.0 — 2023-12-03
- 0.4.2 — 2023-11-27
- … 6 more at https://npm.io/package/landxml/versions

## 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

```bash
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.

```typescript
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

```typescript
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

```typescript
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.

```typescript
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.

```typescript
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.

---

---
_Source: https://npm.io/package/landxml · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
