> For the complete documentation index, see [llms.txt](https://cityweft.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://cityweft.gitbook.io/docs/getting-started/three-quick-guide.md).

# Three.js Quick Guide

This tutorial guides you through the process of integrating our API data with Three.js to enhance your 3D web experiences.

### Prerequisites

* Basic knowledge of JavaScript
* Familiarity with Three.js
* A Cityweft API key — see [Getting your API key](/docs/plugins/getting-your-api-key.md)

### Fetch data from the API

The request payload is plain JSON:

```json
{
  "polygon": [
    [51.5115, -0.1230],
    [51.5115, -0.1195],
    [51.5140, -0.1195],
    [51.5140, -0.1230],
    [51.5115, -0.1230]
  ],
  "settings": {
    "geometry": ["buildings", "surface", "barriers", "topography"],
    "topographyReturnType": "elevationMap",
    "indexedMeshes": true
  }
}
```

Send it with your API key as the Bearer token:

```javascript
const payload = {
  "polygon": [
    [51.5115, -0.1230],
    [51.5115, -0.1195],
    [51.5140, -0.1195],
    [51.5140, -0.1230],
    [51.5115, -0.1230]
  ],
  "settings": {
    "geometry": ["buildings", "surface", "barriers", "topography"],
    "topographyReturnType": "elevationMap",
    "indexedMeshes": true
  }
};

const response = await fetch("https://api.cityweft.com/v1/context", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${CITYWEFT_API_KEY}`,
  },
  body: JSON.stringify(payload),
});

const data = await response.json();
```

### Process the response

The response includes `origin` to georeference the model and a `geometry` array with one group per requested type (`buildings`, `surface`, `barriers`, `topography`, `instances`). Each group's `geometryType` tells you how to read it:

```json
{
  "origin": [51.5115, -0.1230],
  "geometry": [
    {
      "type": "buildings",
      "geometryType": "meshes",
      "meshes": [
        { "vertices": ["..."], "indices": ["..."], "descriptor": { "type": "building" } }
      ]
    },
    {
      "type": "topography",
      "geometryType": "elevationMaps",
      "elevationMaps": [
        { "info": { "width": 611.49 }, "elevationMap": ["..."] }
      ]
    }
  ]
}
```

### Rendering meshes

```javascript
data.geometry.forEach((group) => {
  if (group.geometryType !== "meshes") return; // elevationMaps & nodes: see below

  group.meshes.forEach((mesh) => {
    const geometry = new THREE.BufferGeometry();
    geometry.setAttribute(
      "position",
      new THREE.BufferAttribute(new Float32Array(mesh.vertices), 3)
    );
    if (mesh.indices) geometry.setIndex(mesh.indices);
    geometry.computeVertexNormals();

    const material = new THREE.MeshStandardMaterial({ color: "#95a5a6" });
    scene.add(new THREE.Mesh(geometry, material));
  });
});
```

<figure><img src="https://2449447963-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2ahel6HN9zgEzJ1vY9kr%2Fuploads%2FsMYg99d7sUxoruxVcpyX%2Fimage.png?alt=media&#x26;token=505abd32-a945-4a4b-8972-103267fbf966" alt=""><figcaption></figcaption></figure>

### Styling by descriptor

Each mesh carries a `descriptor` with its type and metadata — use it to style features. For example, highlighting every `asphalt` surface:

```javascript
const material = new THREE.MeshStandardMaterial({
  color: mesh.descriptor.type === "asphalt" ? "#dc0d0d" : getRandomColour(),
});
```

<figure><img src="https://2449447963-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2ahel6HN9zgEzJ1vY9kr%2Fuploads%2FB1or3ROOWupdyzCK7Htb%2Fimage.png?alt=media&#x26;token=62940442-6261-437a-a136-94e86f2d6947" alt=""><figcaption><p>Highlighted "asphalt" meshes</p></figcaption></figure>

The full descriptor reference lives at [Metadata (Descriptors)](/docs/basics/metadata-descriptors.md).

### Elevation maps

Requesting topography as an elevation map (the default) instead of meshes reduces the transferred data by \~94% and produces a smoother surface with `THREE.PlaneGeometry`:

```javascript
const topography = data.geometry.find((g) => g.geometryType === "elevationMaps");

topography.elevationMaps.forEach(({ elevationMap, info }) => {
  const { width, height, segmentsWidth, segmentsHeight, moveVector } = info;

  const planeGeometry = new THREE.PlaneGeometry(
    width,
    height,
    segmentsWidth,
    segmentsHeight
  );

  const positionAttribute = planeGeometry.attributes.position;
  for (let i = 0; i < positionAttribute.count; i++) {
    if (elevationMap[i] !== undefined) {
      positionAttribute.setZ(i, elevationMap[i]);
    }
  }
  positionAttribute.needsUpdate = true;
  planeGeometry.computeVertexNormals();

  const material = new THREE.MeshStandardMaterial({
    color: 0x95a5a6,
    side: THREE.DoubleSide,
  });

  const terrain = new THREE.Mesh(planeGeometry, material);
  terrain.position.set(moveVector.x, 0, moveVector.y);
  scene.add(terrain);
});
```

More detail on the elevation map format: [Topography](/docs/geometry/topography.md).
