---
title: "Add a 3D model on a map | 3D JS | JavaScript maps SDK"
description: "Add 3D glTF models to maps using MapTiler SDK."
---

> For AI agents: a documentation index is available at [/llms.txt](https://docs.maptiler.com/llms.txt). Markdown versions of all pages are available by appending .md to any URL.

# Add a 3D model on a map

Use the MapTiler SDK 3D JS module to add 3D objects to your map from glTF/glb files! These can be meshes, groups of meshes, point clouds, or a mix of all these.

[Model credit](#fn:1)

1.  Since the 3D model is going to be added to a Map, let’s instantiate a map first. Copy the following code, paste it into your favorite text editor, and save it as a `.html` file.
    
    ```html
    <!DOCTYPE html>
       <html lang="en">
       <head>
         <meta charset="UTF-8">
         <meta name="viewport" content="width=device-width, initial-scale=1.0">
         <title>Display an AR control</title>
         <script src="https://cdn.maptiler.com/maptiler-sdk-js/v4.2.0/maptiler-sdk.umd.min.js"></script>
         <link href="https://cdn.maptiler.com/maptiler-sdk-js/v4.2.0/maptiler-sdk.css" rel="stylesheet" />
         <script src="https://cdn.maptiler.com/maptiler-3d/v4.0.1/maptiler-3d.umd.min.js"></script>
         <style>
           body { margin: 0; padding: 0; }
           #map { position: absolute; top: 0; bottom: 0; width: 100%; }
         </style>
       </head>
       <body>
         <div id="map"></div>
         <script>
             maptilersdk.config.apiKey = 'YOUR_MAPTILER_API_KEY_HERE';      
             const map = new maptilersdk.Map({
               container: 'map', // container's id or the HTML element to render the map
               style: maptilersdk.MapStyle.DATAVIZ,
               center: [-3.0615632, 56.4547039], // starting position [lng, lat]
               zoom: 18, // starting zoom
             });
         </script>
       </body>
       </html>
    ```
    
2.  Replace `YOUR_MAPTILER_API_KEY_HERE` with [your own API key](https://cloud.maptiler.com/account/keys/). Make sure to [secure the key](https://docs.maptiler.com/guides/developer/credentials/api-key/#secure-key) before you publish it.
    
3.  Waiting for the map to be ready to add the 3D layer. An instance of `Layer3D` is a custom type of layer that contain a 3D scene, where multiple 3D meshes and lights can be added. Like any other layer in MapTiler SDK JS, it must have an ID and then be added to a `Map` instance.
    
    ```js
    // Waiting for the map to be ready
     map.on('ready', async () => {
       // Create a Layer3D and add it
       const layer3D = new maptiler3d.Layer3D("custom-3D-layer");
       map.addLayer(layer3D);
    
     });
    ```
    

1.  Install the npm package.
    
    ```bash
    npm install --save @maptiler/sdk @maptiler/3d
    ```
    
2.  Include the CSS file.
    
    If you have a bundler that can handle CSS, you can [`import`](#) the CSS or include it with a [`<link>`](#) in the head of the document via the CDN
    
    ```js
    import "@maptiler/sdk/dist/maptiler-sdk.css";
    ```
    
    ```html
    <link href='https://cdn.maptiler.com/maptiler-sdk-js/v4.2.0/maptiler-sdk.css' rel='stylesheet' />
    ```
    
3.  Include the following code in your JavaScript file (Example: app.js).
    
    ```js
    import { Map, MapStyle, config } from '@maptiler/sdk';
     import { Layer3D } from '@maptiler/3d';
        
     config.apiKey = 'YOUR_MAPTILER_API_KEY_HERE';
     const map = new Map({
       container: 'map', // container's id or the HTML element to render the map
       style: MapStyle.DATAVIZ,
       center: [-3.0615632, 56.4547039], // starting position [lng, lat]
       zoom: 18, // starting zoom
     });
    ```
    
4.  Replace `YOUR_MAPTILER_API_KEY_HERE` with [your own API key](https://cloud.maptiler.com/account/keys/). Make sure to [secure the key](https://docs.maptiler.com/guides/developer/credentials/api-key/#secure-key) before you publish it.
    
5.  Waiting for the map to be ready to add the 3D layer. An instance of `Layer3D` is a custom type of layer that contain a 3D scene, where multiple 3D meshes and lights can be added. Like any other layer in MapTiler SDK JS, it must have an ID and then be added to a `Map` instance.
    
    ```js
    // Waiting for the map to be ready
     map.on('ready', async () => {
       // Create a Layer3D and add it
       const layer3D = new Layer3D("custom-3D-layer");
       map.addLayer(layer3D);
     });
    ```
    

1.  Once created and added, a mesh can be added. In this version any glTF and their binary counterpart glb files can be added. Add a mesh to the layer. In this example we will use the model [The COLLADA duck. One texture. Credit: © 2006, Sony. SCEA Shared Source License, Version 1.0](https://github.com/KhronosGroup/glTF-Sample-Assets/tree/main)
    
    ```js
    // The call can be awaited for the whole download of the mesh to complete
     await layer3D.addMeshFromURL(
       // ID to give to this mesh, unique within this Layer3D instance
       "duck",
    
       // The URL of the mesh
       "https://docs-media.maptiler.com/docs/models/duck.glb",
    
       // A set of options, these can be modified later
       {
         lngLat: [-3.0615632, 56.4547039],
         heading: 150,
         scale: 10
       }
     );
    
     layer3D.cloneMesh("duck", "duck-baby", {
       lngLat: [-3.0617744, 56.4545475],
       heading: 45,
       scale: 3,
     });
    
     layer3D.cloneMesh("duck", "duck-baby-1", {
       lngLat: [-3.0613331, 56.4546995],
       heading: 180,
       scale: 4,
     });
    
     layer3D.cloneMesh("duck", "duck-baby-2", {
       lngLat: [-3.0611772, 56.4546843],
       heading: 190,
       scale: 3,
     });
    ```
    

### Complete source code

```html
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>MapTiler AR Control</title>
    <!-- Importing MapTiler SDK -->
    <script src="https://cdn.maptiler.com/maptiler-sdk-js/v4.2.0/maptiler-sdk.umd.min.js"></script>
    <link href="https://cdn.maptiler.com/maptiler-sdk-js/v4.2.0/maptiler-sdk.css" rel="stylesheet" />

    <!-- Importing MapTiler 3D js -->
    <script src="https://cdn.maptiler.com/maptiler-3d/v4.0.1/maptiler-3d.umd.min.js"></script>

    <style>
      body { margin: 0; padding: 0; }
      #map { position: absolute; top: 0; bottom: 0; width: 100%; }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script>
      maptilersdk.config.apiKey = 'YOUR_MAPTILER_API_KEY_HERE';
      
      // Creating a map
      const map = new maptilersdk.Map({
        container: 'map',
        style: maptilersdk.MapStyle.DATAVIZ,
        center: [-3.0615632, 56.4547039], // starting position [lng, lat]
        zoom: 18, // starting zoom
      });

      // Waiting for the map to be ready
      map.on('ready', async () => {
        // Create a Layer3D and add it
        const layer3D = new maptiler3d.Layer3D("custom-3D-layer");
        map.addLayer(layer3D);

        // Increasing the intensity of the ambient light
        layer3D.setAmbientLight({intensity: 2});

        // Adding a point light
        layer3D.addPointLight("point-light", {intensity: 30});

        /*
        "Duck, © 2006, Sony. SCEA Shared Source License, Version 1.0 - https://github.com/KhronosGroup/glTF-Sample-Assets/tree/main
        */

        // The call can be awaited for the whole download of the mesh to complete
        await layer3D.addMeshFromURL(
          // ID to give to this mesh, unique within this Layer3D instance
          "duck",

          // The URL of the mesh
          "https://docs-media.maptiler.com/docs/models/duck.glb",

          // A set of options, these can be modified later
          {
            lngLat: [-3.0615632, 56.4547039],
            heading: 150,
            scale: 10
          }
        );

        layer3D.cloneMesh("duck", "duck-baby", {
          lngLat: [-3.0617744, 56.4545475],
          heading: 45,
          scale: 3,
        });

        layer3D.cloneMesh("duck", "duck-baby-1", {
          lngLat: [-3.0613331, 56.4546995],
          heading: 180,
          scale: 4,
        });

        layer3D.cloneMesh("duck", "duck-baby-2", {
          lngLat: [-3.0611772, 56.4546843],
          heading: 190,
          scale: 3,
        });

      });

    </script>
  </body>
</html>
```

### Complete source code

```bash
npm install --save @maptiler/sdk @maptiler/3d
```

#### main.js

```js
import { Map, MapStyle, config } from '@maptiler/sdk';
import '@maptiler/sdk/dist/maptiler-sdk.css';
import { Layer3D } from '@maptiler/3d';

config.apiKey = 'YOUR_MAPTILER_API_KEY_HERE';

// Creating a map
const map = new Map({
  container: 'map',
  style: MapStyle.DATAVIZ,
  center: [-3.0615632, 56.4547039], // starting position [lng, lat]
  zoom: 18, // starting zoom
});

// Waiting for the map to be ready
map.on('ready', async () => {
  // Create a Layer3D and add it
  const layer3D = new Layer3D("custom-3D-layer");
  map.addLayer(layer3D);

  // Increasing the intensity of the ambient light
  layer3D.setAmbientLight({intensity: 2});

  // Adding a point light
  layer3D.addPointLight("point-light", {intensity: 30});

  /*
  "Duck, © 2006, Sony. SCEA Shared Source License, Version 1.0 - https://github.com/KhronosGroup/glTF-Sample-Assets/tree/main
  */

  // The call can be awaited for the whole download of the mesh to complete
  await layer3D.addMeshFromURL(
    // ID to give to this mesh, unique within this Layer3D instance
    "duck",

    // The URL of the mesh
    "https://docs-media.maptiler.com/docs/models/duck.glb",

    // A set of options, these can be modified later
    {
      lngLat: [-3.0615632, 56.4547039],
      heading: 150,
      scale: 10
    }
  );

  layer3D.cloneMesh("duck", "duck-baby", {
    lngLat: [-3.0617744, 56.4545475],
    heading: 45,
    scale: 3,
  });

  layer3D.cloneMesh("duck", "duck-baby-1", {
    lngLat: [-3.0613331, 56.4546995],
    heading: 180,
    scale: 4,
  });

  layer3D.cloneMesh("duck", "duck-baby-2", {
    lngLat: [-3.0611772, 56.4546843],
    heading: 190,
    scale: 3,
  });

});
```

#### index.html

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="robots" content="noindex">
  <title>Add a 3D model on a map | NPM example</title>
  <link rel="stylesheet" href="./style.css">
</head>
<body>
  <div id="map"></div>
  <script type="module" src="./main.js"></script>
</body>
</html>
```

#### style.css

```css
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
```

[COLLADA duck](https://github.com/KhronosGroup/glTF-Sample-Assets/tree/main) One texture Credit: © 2006, Sony. [SCEA Shared Source License, Version 1.0](https://spdx.org/licenses/SCEA.html) [↩](#fnref:1)

## Related examples

### [Add multiple 3D models](https://docs.maptiler.com/sdk-js/examples/3d-js-multi/)

Examples

Incorporate multiple 3D models with adjustable parameters on maps.

### [Animate a 3D plane flight](https://docs.maptiler.com/sdk-js/examples/3d-js-flight/)

Examples

Simulate and animate a 3D plane flight between cities.

### [Start with AR maps](https://docs.maptiler.com/sdk-js/examples/ar-control/)

Examples

Add an AR control button to map 3D viewports.

### [3D terrain map](https://docs.maptiler.com/sdk-js/examples/3d-map/)

Tutorials

Create and display 3D terrain maps on web pages.
