## 1. Project Overview & Quickstart (maplibre/maplibre-gl-js)

## File: README.md

# MapLibre GL JS

[](LICENSE.txt) [](https://www.npmjs.com/package/maplibre-gl) [](https://github.com/maplibre/maplibre-gl-js/actions/workflows/test-all.yml) [](https://opensource.org/licenses/BSD-3-Clause) [](https://codecov.io/gh/maplibre/maplibre-gl-js)

**[MapLibre GL JS](https://maplibre.org/maplibre-gl-js/docs/API/)** is an open-source library for publishing maps on your websites or webview based apps. Fast displaying of maps is possible thanks to GPU-accelerated vector tile rendering.

It originated as an open-source fork of [mapbox-gl-js](https://github.com/mapbox/mapbox-gl-js), before their switch to a non-OSS license in December 2020. The library's initial versions (1.x) were intended to be a drop-in replacement for the Mapbox’s OSS version (1.x) with additional functionality, but have evolved a lot since then.

## Getting Started

Include the CSS file in the `<head>` of your HTML file.

```html
<link href='https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.css' rel='stylesheet' />
```

Include the following code in the `` of your HTML file.

```html

<script type='module'>
import * as maplibregl from 'https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.mjs';

const map = new maplibregl.Map({
  container: 'map',
  style: 'https://demotiles.maplibre.org/style.json', // stylesheet location
  center: [-74.5, 40], // starting position [lng, lat]
  zoom: 9 // starting zoom
});
</script>
```

Enjoy the map!



## Documentation

Full documentation for this library [is available here](https://maplibre.org/maplibre-gl-js/docs/API/).

Check out the features through [examples](https://maplibre.org/maplibre-gl-js/docs/examples/).

| Showcases                                                                                                              |                                                                                                                            |
| ---------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
|                            |                  |
|  |              |
|                   |  |



Want an example? Have a look at the official [MapLibre GL JS Documentation](https://maplibre.org/maplibre-gl-js/docs/examples/).

Use MapLibre GL JS bindings for [React](https://visgl.github.io/react-map-gl/docs/get-started) and [Angular](https://github.com/maplibre/ngx-maplibre-gl). Find more at [awesome-maplibre](https://github.com/maplibre/awesome-maplibre).



## Contribution

### Getting Involved

Join the #maplibre slack channel at OSMUS: get an invite at https://slack.openstreetmap.us/
Read the [CONTRIBUTING.md](CONTRIBUTING.md) guide in order to get familiar with how we do things around here.

### Avoid Fragmentation

If you depend on a free software alternative to `mapbox-gl-js`, please consider joining our effort! Anyone with a stake in a healthy community-led fork is welcome to help us figure out our next steps. We welcome contributors and leaders! MapLibre GL JS already represents the combined efforts of a few early fork efforts, and we all benefit from "one project" rather than "our way". If you know of other forks, please reach out to them and direct them here.

> **MapLibre GL JS** is developed following [Semantic Versioning (2.0.0)](https://semver.org/spec/v2.0.0.html).

## Sponsors

We thank everyone who supported us financially in the past and special thanks to the people and organizations who support us with recurring donations!

Read more about the MapLibre Sponsorship Program at [https://maplibre.org/sponsors/](https://maplibre.org/sponsors/).

Gold:

[](https://www.microsoft.com/)

[](https://aws.amazon.com/location)


Silver:

[](https://www.mierune.co.jp/?lang=en)

[](https://komoot.com/)

[](https://www.jawg.io/)

[](https://www.radar.com/)

[](https://www.mapme.com/)

[](https://www.maptiler.com/)

[](https://www.caltopo.com/)

[](https://www.caltopo.com/)

Backers and Supporters:

[](https://opencollective.com/maplibre/backer/0/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/1/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/2/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/3/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/4/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/5/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/6/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/7/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/8/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/9/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/10/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/11/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/12/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/13/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/14/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/15/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/16/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/17/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/18/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/19/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/20/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/21/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/22/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/23/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/24/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/25/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/26/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/27/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/28/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/29/website?requireActive=false)
[](https://opencollective.com/maplibre/backer/30/website?requireActive=false)



## Thank you Mapbox 🙏🏽

We'd like to acknowledge the amazing work Mapbox has contributed to open source. The open source community is sad to part ways with them, but we simultaneously feel grateful for everything they already contributed. `mapbox-gl-js` 1.x is an open source achievement that now lives on as `maplibre-gl`. We're proud to develop on the shoulders of giants, thank you Mapbox 🙇🏽‍♀️.

Please keep in mind: Unauthorized backports are the biggest threat to the MapLibre project. It is unacceptable to backport code from mapbox-gl-js, which is not covered by the former BSD-3 license. If you are unsure about this issue, [please ask](https://github.com/maplibre/maplibre-gl-js/discussions)!



## License

**MapLibre GL JS** is licensed under the [3-Clause BSD license](./LICENSE.txt).

---

## File: docs/index.md

# Introduction

MapLibre GL JS is a TypeScript library that uses WebGL to render interactive maps from vector tiles in a browser.
The map’s appearance is controlled by a style document whose structure and properties are defined by the [MapLibre Style Spec](https://maplibre.org/maplibre-style-spec).
It is part of the MapLibre ecosystem, with a counterpart for Android, iOS and other platforms called [MapLibre Native](https://github.com/maplibre/maplibre-native).

## Quickstart



```html
<link rel="stylesheet" href="https://unpkg.com/maplibre-gl@^6.3.0/dist/maplibre-gl.css" />

<script type="module">
    import * as maplibregl from 'https://unpkg.com/maplibre-gl@^6.3.0/dist/maplibre-gl.mjs';

    const map = new maplibregl.Map({
        container: 'map', // container id
        style: 'https://demotiles.maplibre.org/globe.json', // style URL
        center: [0, 0], // starting position [lng, lat]
        zoom: 2 // starting zoom
    });
</script>
```

## Reading this documentation

This documentation is divided into several sections:

* [**Main**](./API/README.md) - The Main section holds the following classes
    * [`Map`](./API/classes/Map.md) object is the map on your page. It lets you access methods and properties for interacting with the map's style and layers, respond to events, and manipulate the user's perspective with the camera.
    * [`Global Functions`](./API/functions/addProtocol.md) let you set global properties and options that you might want to access while initializing your map or accessing information about its status.
* [**Markers and Controls**](./API/README.md#markers-and-controls) - This section describes the user interface elements that you can add to your map. The items in this section exist outside of the map's `canvas` element. This consists of `Marker`, `Popup` and all the controls.
* [**Geography and geometry**](./API/README.md#geography-and-geometry) - This section includes general utilities and types that relate to working with and manipulating geographic information or geometries.
* [**User interaction handlers**](./API/README.md#handlers) - The items in this section relate to the ways in which the map responds to user input.
* [**Sources**](./API/README.md#sources) - This section describes the source types MapLibre GL JS can handle besides the ones described in the [MapLibre Style Specification](https://maplibre.org/maplibre-style-spec/).
* [**Event Related**](./API/README.md#event-related) - This section describes the different types of events that MapLibre GL JS can raise.

Each section describes classes or objects as well as their **properties**, **parameters**, **instance members**, and associated **events**. Many sections also include inline code examples and related resources.

In the examples, we use vector tiles from our [Demo tiles repository](https://github.com/maplibre/demotiles) and from [MapTiler](https://maptiler.com). Get your own API key if you want to use MapTiler data in your project.

## npm

Install the MapLibre GL JS package via [npm](https://www.npmjs.com/package/maplibre-gl).

```bash
npm install maplibre-gl
```

You can then import the MapLibre GL JS module in your project.

```html

```

```javascript
import {Map} from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';

const map = new Map({
    container: 'map', // container id
    style: 'https://demotiles.maplibre.org/globe.json', // style URL
    center: [0, 0], // starting position [lng, lat]
    zoom: 1 // starting zoom
});
```

See the [ESM](#esm) section below for setting up the worker URL with your bundler.

## ESM

MapLibre GL JS v6 ships as ES modules only (`maplibre-gl.mjs`). The `"module"` field in `package.json` points at the ESM bundle, so bundlers pick it up automatically.

For minimal runnable apps per bundler (Vite, webpack, esbuild, Rollup, Turbopack), see [`test/integration/bundler/`](https://github.com/maplibre/maplibre-gl-js/tree/main/test/integration/bundler).

Upgrading from v5? See the [v5 to v6 migration guide](./guides/v5-to-v6-migration-guide.md).

### Installation

Pick your setup:

=== "Vite"

    Use Vite's `?worker&url` query to get a bundled, self-contained worker URL:

    ```ts
    import {Map, setWorkerUrl} from 'maplibre-gl';
    import 'maplibre-gl/dist/maplibre-gl.css';
    import workerUrl from 'maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url';

    setWorkerUrl(workerUrl);

    const map = new Map({/* … */});
    ```

    Use `?worker&url` rather than plain `?url`: the dist worker imports its
    sibling `maplibre-gl-shared.mjs`, and `?url` emits the worker file verbatim
    in production builds without that sibling — the worker then fails on its
    first import and no vector tiles load. `?worker&url` routes the file
    through Vite's worker pipeline, emitting a self-contained chunk. Dev mode
    works with either.

    If your build uses SSR (TanStack Start, Astro, etc.) and Vite resolves the CommonJS entry on the server, also add:

    ```ts title="vite.config.ts"
    export default defineConfig({
        ssr: {noExternal: ['maplibre-gl']}
    });
    ```

=== "webpack 5+"

    ```ts
    import {Map, setWorkerUrl} from 'maplibre-gl';
    import 'maplibre-gl/dist/maplibre-gl.css';

    setWorkerUrl(new URL('maplibre-gl/dist/maplibre-gl-worker.mjs', import.meta.url).toString());

    const map = new Map({/* … */});
    ```

    rspack and rsbuild use the same pattern.

    Next.js is an exception, including in its `next build --webpack` mode. See the Turbopack tab.

=== "esbuild"

    ```js title="build.js"
    import * as esbuild from 'esbuild';
    import {copyFileSync} from 'fs';

    await esbuild.build({
        entryPoints: ['src/main.ts'],
        bundle: true,
        outdir: 'dist',
        format: 'esm'
    });

    copyFileSync(
        'node_modules/maplibre-gl/dist/maplibre-gl-worker.mjs',
        'dist/maplibre-gl-worker.mjs'
    );
    ```

    ```ts title="src/main.ts"
    import {Map, setWorkerUrl} from 'maplibre-gl';
    import 'maplibre-gl/dist/maplibre-gl.css';

    setWorkerUrl(new URL('./maplibre-gl-worker.mjs', import.meta.url).toString());

    const map = new Map({/* … */});
    ```

=== "Rollup"

    ```ts title="rollup.config.js"
    import copy from 'rollup-plugin-copy';

    export default {
        plugins: [
            copy({
                targets: [
                    {src: 'node_modules/maplibre-gl/dist/maplibre-gl-worker.mjs', dest: 'dist'}
                ]
            }),
            /* ... */
        ]
    };
    ```

    ```ts title="src/main.ts"
    import {Map, setWorkerUrl} from 'maplibre-gl';
    import 'maplibre-gl/dist/maplibre-gl.css';

    setWorkerUrl(new URL('./maplibre-gl-worker.mjs', import.meta.url).toString());

    const map = new Map({/* … */});
    ```

=== "Turbopack"

    Turbopack ships as the default bundler in Next.js, which is where you are most likely to meet it, so the setup below is written for a Next.js app.

    Turbopack turns `new URL('maplibre-gl/dist/maplibre-gl-worker.mjs', import.meta.url)` into a hashed asset without emitting the worker's `maplibre-gl-shared.mjs` sibling next to it. The worker then fails on its first import, and the map mounts but never requests a tile. Serve both files from `public/` instead and point `setWorkerUrl` at the worker:

    ```js title="scripts/copy-maplibre-worker.mjs"
    import {copyFileSync, mkdirSync} from 'node:fs';
    import {createRequire} from 'node:module';
    import path from 'node:path';

    const dist = path.join(path.dirname(createRequire(import.meta.url).resolve('maplibre-gl/package.json')), 'dist');
    const dest = path.join(process.cwd(), 'public', 'maplibre');

    mkdirSync(dest, {recursive: true});
    for (const file of ['maplibre-gl-worker.mjs', 'maplibre-gl-shared.mjs']) {
        copyFileSync(path.join(dist, file), path.join(dest, file));
    }
    ```

    ```json title="package.json"
    {
        "scripts": {
            "prebuild": "node ./scripts/copy-maplibre-worker.mjs",
            "predev": "node ./scripts/copy-maplibre-worker.mjs"
        }
    }
    ```

    ```ts title="app/map.tsx"
    'use client';

    import {Map, setWorkerUrl} from 'maplibre-gl';
    import 'maplibre-gl/dist/maplibre-gl.css';

    setWorkerUrl('/maplibre/maplibre-gl-worker.mjs');

    const map = new Map({/* … */});
    ```

    The script copies both files, not just the worker.
    This is because the worker imports `maplibre-gl-shared.mjs` by relative path, so both have to land in the same directory.

    The copy happens at build time, from `node_modules`, so it always matches the installed version.
    npm lifecycle prefixes match the exact script name, so `prebuild` and `predev` run before `build` and `dev`, but **not** before a custom script like `build:local` - add a matching `pre` hook for those if necessary.
    `postinstall` alone won't do it since package managers skip lifecycle scripts when an install has no work to do, and `--ignore-scripts` skips them entirely.

    Next.js needs this in both of its bundler modes, `next build` (Turbopack) and `next build --webpack`, since the asset handling above is Next's rather than Turbopack's alone.

=== "CDN / No bundler"

    Load MapLibre directly from UNPKG as an ES module via a `<script type="module">` tag. See [unpkg.com](https://unpkg.com) for instructions on selecting specific versions and semver ranges.

    ```html
    <link rel="stylesheet" href="https://unpkg.com/maplibre-gl@^6.3.0/dist/maplibre-gl.css" />
    
    <script type="module">
        import * as maplibregl from 'https://unpkg.com/maplibre-gl@^6.3.0/dist/maplibre-gl.mjs';

        const map = new maplibregl.Map({
            container: 'map',
            style: 'https://demotiles.maplibre.org/style.json',
            center: [0, 0],
            zoom: 1
        });
    </script>
    ```

    The worker is auto-detected from the imported module's URL and laundered through a same-origin Blob URL, so cross-origin CDN loading works out of the box.

    Under a strict CSP that disallows `blob:` in `worker-src`, set the worker URL explicitly to a same-origin location:

    ```js
    maplibregl.setWorkerUrl('/path/to/maplibre-gl-worker.mjs');
    ```

    See the [Display a map](./examples/display-a-map.md) example for a runnable version.

## CSP Directives

As a mitigation for Cross-Site Scripting and other types of web security vulnerabilities, you may use a [Content Security Policy (CSP)](https://developer.mozilla.org/en-US/docs/Web/Security/CSP) to specify security policies for your website. If you do, MapLibre GL JS requires the following CSP directives:

```
worker-src 'self' ;
img-src data: blob: 'self' ;
```

## MapLibre CSS

The CSS referenced in the Quickstart is used to style DOM elements created by MapLibre code. Without the CSS, elements like Popups and Markers won't work.

Including it with a `<link>` in the head of the document via the UNPKG CDN is the simplest and easiest way to provide the CSS, but it is also bundled in the MapLibre module, meaning that if you have a bundler that can handle CSS, you can import the CSS from `maplibre-gl/dist/maplibre-gl.css`.

Note too that if the CSS isn't available by the first render, as soon as the CSS is provided, the DOM elements that depend on this CSS should recover.

## 2. Official Technical Reference & Guides (maplibre/maplibre-gl-js-docs)

## File: README.md

# ⚠️This repo is now archived⚠️

### All the code related to the generation of the docs, that now resides in https://maplibre.org/maplibre-gl-js/docs can be found in the at the [main repo](https://github.com/maplibre/maplibre-gl-js). 

<hr/>




# MapLibre GL JS Documentation

The source code for https://maplibre.org/maplibre-gl-js-docs/, the website that hosts [API documentation](#writing-api-documentation) and [examples](#writing-examples) for [MapLibre GL JS](https://github.com/maplibre/maplibre-gl-js). A GitHub Actions Workflow is triggered on push to the ```main``` branch. This Action builds the static website and deploys it to GitHub Pages by pushing to the ```gh-pages``` branch.

## Requirements

* Node 18
* npm 9

If you're not sure if your Node and NPM versions are up to date, run `nvm use` before installing dependencies. If you don't have NVM installed, you can [find installation instructions here](https://github.com/nvm-sh/nvm/blob/master/README.md#installing-and-updating).

The NPM scripts will not run on Windows, but work perfectly with [WSL2](https://en.wikipedia.org/wiki/Windows_Subsystem_for_Linux).

## Setting up the Development Environment

After cloning this repository, run:

```bash
npm ci # install dependencies with npm
```

## Writing API Documentation

API documentation is written as [JSDoc comments](http://usejsdoc.org/) and processed with [documentationjs](http://documentation.js.org/) **in the source code of [maplibre-gl-js](https://github.com/maplibre/maplibre-gl-js)**. This repository fetches the source code through npm packages.

* Classes, methods, events, and anything else in the public interface must be documented with JSDoc comments. Everything outside of the public interface may be documented and must be tagged as `@private`.
* Text within JSDoc comments may use markdown formatting. Code identifiers must be surrounded by \`backticks\`.
* Documentation must be written in grammatically correct sentences ending with periods.
* Documentation must specify measurement units when applicable.
* Documentation descriptions must contain more information than what is obvious from the identifier and JSDoc metadata.
* Class descriptions should describe what the class *is*, or what its instances *are*. They do not document the constructor, but the class. They should begin with either a complete sentence or a phrase that would complete a sentence beginning with "A `T` is..." or "The `T` class is..." Examples: "Lists are ordered indexed dense collections." "A class used for asynchronous computations."
* Function descriptions should begin with a third person singular present tense verb, as if completing a sentence beginning with "This function..." If the primary purpose of the function is to return a value, the description should begin with "Returns..." Examples: "Returns the layer with the specified id." "Sets the map's center point."
* `@param`, `@property`, and `@returns` descriptions should be capitalized and end with a period. They should begin as if completing a sentence beginning with "This is..." or "This..."
* Functions that do not return a value (return `undefined`), should not have a `@returns` annotation.
* Member descriptions should document what a member represents or gets and sets. They should also indicate whether the member is read-only.
* Event descriptions should begin with "Fired when..." and so should describe when the event fires. Event entries should clearly document any data passed to the handler, with a link to MDN documentation of native Event objects when applicable.

## Writing Examples

Examples are written as [Batfish](https://github.com/mapbox/batfish) pages in `docs/pages/example`. Each example requires two files: an `.html` file containing the source
code for the example, and a `.js` file containing example boilerplate and front matter. The front matter should include the following items:

* `title`: A short title for the example in **sentence case** as a **verb phrase**.
* `description`: A one sentence description of the example in plain text. This description will appear alongside a thumbnail and title on the examples page.
* `topics`: An array of topics for the example, see `docs/data/topics.json` for a list of topics.
* `thumbnail`: The filename of the example's thumbnail image (without the file extension).
* `contentType: example`: Set the contentType to equal example.

In content area of the markdown page include an extended description of the example and add links to documentation or other important resources where possible.

In the `.html` file, write the HTML and JavaScript constituting the example.

* Do **not** include a MapTiler access token in the example code. The access token will be inserted automatically by the template, using the current logged in user's default public token, or a placeholder `` string if the user is not logged in.
* On commit, Prettier will format the code for all files, including HTML.

Every example **must** have an accompanying image.

1. Ensure that you have a build of the latest `maplibre-gl-js` in the neighboring directory (see below).
2. Run `npm run create-image <example-file-name>`. The script will take a screenshot of the map in the example and save it to `docs/img/src/`. Commit the image.
3. Run `npm start` to verify that your example image is loading as expected.

For some examples, `npm run create-image` does not generate an ideal image. In these cases, you can interact with the map after running the command before the screenshot is taken, or take a screenshot yourself by running the site locally with `npm start`, take a screenshot and save it in the `docs/img/src` folder.

To regenerate all images, run `npm run create-image all`. Note that this doesn't support interaction and examples that require manual interaction (e.g. popups) will need to be manually redone afterward. This feature is experimental and may crash before sucessfully generating all examples.

## Running the Documentation Server Locally

To start a documentation server locally, run:

```bash
npm start
```

The command will print the URL you can use to view the documentation.

The examples section of the locally run documentation will use the GL JS version located in `../maplibre-gl-js/dist`,
so make sure to have a working minified build in your local copy of the `maplibre-gl-js` repo; clone `maplibre-gl-js` into the same directory as `maplibre-gl-js-docs` and run `npm run build-dist` there).


## Committing and Publishing Documentation

When a new GL JS release goes out, the release manager will make a PR that updates this repo's `maplibre-gl` npm dependency to point to the new release. When updating the npm package, you may need to run `npm test -- -u` to update Jest snapshots related to the sidebar navigation.

To update or add a new example, PR the relevant changes to this repo. The example will be live once the PR is merged.  If this example uses a version of GL JS that isn't yet released, the PR should not be merged until the release is out.

---

## File: docs/pages/example/3d-buildings.md

---
title: Display buildings in 3D
topics:
  - Layers
thumbnail: 3d-buildings
contentType: example
layout: example
hideFeedback: true
language:
- JavaScript
products:
- MapLibre GL JS
prependJs:
- "import Example from '../../components/example';"
- "import html from './3d-buildings.html';"
---

Use [extrusions](https://maplibre.org/maplibre-style-spec/layers/#fill-extrusion) to display buildings' height in 3D.

{{ <Example html={html} {...this.props} /> }}

---

## File: docs/pages/example/3d-extrusion-floorplan.md

---
title: Extrude polygons for 3D indoor mapping
topics:
  - Layers
thumbnail: 3d-extrusion-floorplan
contentType: example
layout: example
hideFeedback: true
language:
- JavaScript
products:
- MapLibre GL JS
prependJs:
- "import Example from '../../components/example';"
- "import html from './3d-extrusion-floorplan.html';"
---

Create a 3D indoor map with the [`fill-extrude-height`](https://maplibre.org/maplibre-style-spec/layers/#paint-fill-extrusion-fill-extrusion-height) paint property.

{{ <Example html={html} {...this.props} /> }}

---

## File: docs/pages/example/3d-terrain.md

---
title: 3D Terrain
topics:
  - Layers
thumbnail: 3d-terrain
contentType: example
layout: example
hideFeedback: true
language:
- JavaScript
products:
- MapLibre GL JS
prependJs:
- "import Example from '../../components/example';"
- "import html from './3d-terrain.html';"
---

Use 3D terrain to show mountains and valleys.

{{ <Example html={html} {...this.props} /> }}

---

## File: docs/pages/example/add-3d-model.md

---
title: Add a 3D model with three.js
topics:
  - Layers
thumbnail: add-3d-model
contentType: example
layout: example
hideFeedback: true
language:
- JavaScript
products:
- MapLibre GL JS
prependJs:
- "import Example from '../../components/example';"
- "import html from './add-3d-model.html';"
---

Use a [custom style layer](https://maplibre.org/maplibre-gl-js-docs/api/properties/#customlayerinterface) with [three.js](https://threejs.org) to add a 3D model to the map.

{{ <Example html={html} {...this.props} /> }}

---

## File: docs/pages/example/add-3d-model-babylon.md

---
title: Add a 3D model with babylon.js
topics:
  - Layers
thumbnail: add-3d-model-babylon
contentType: example
layout: example
hideFeedback: true
language:
- JavaScript
products:
- MapLibre GL JS
prependJs:
- "import Example from '../../components/example';"
- "import html from './add-3d-model-babylon.html';"
---

Use a [custom style layer](https://maplibre.org/maplibre-gl-js-docs/api/properties/#customlayerinterface) with [babylon.js](https://babylonjs.com/) to add a 3D model to the map.

{{ <Example html={html} {...this.props} /> }}

---

## File: docs/pages/example/add-a-marker.md

---
title: Add a default marker
topics:
  - Styles
thumbnail: add-a-marker
contentType: example
layout: example
hideFeedback: true
language:
- JavaScript
products:
- MapLibre GL JS
prependJs:
- "import Example from '../../components/example';"
- "import html from './add-a-marker.html';"
---

Add a default [`Marker`](https://maplibre.org/maplibre-gl-js-docs/api/markers/#marker) to the map.

{{ <Example html={html} {...this.props} /> }}

---

## File: docs/pages/example/add-image.md

---
title: Add an icon to the map
topics:
  - Styles
  - Layers
thumbnail: add-image
contentType: example
layout: example
hideFeedback: true
language:
- JavaScript
products:
- MapLibre GL JS
prependJs:
- "import Example from '../../components/example';"
- "import html from './add-image.html';"
---

Add an icon to the map from an external URL and use it in a [symbol layer](https://maplibre.org/maplibre-style-spec/layers/#symbol).

{{ <Example html={html} {...this.props} /> }}

---

## File: docs/pages/example/add-image-animated.md

---
title: Add an animated icon to the map
topics:
  - Styles
  - Layers
thumbnail: add-image-animated
contentType: example
layout: example
hideFeedback: true
language:
- JavaScript
products:
- MapLibre GL JS
prependJs:
- "import Example from '../../components/example';"
- "import html from './add-image-animated.html';"
---

Add an animated icon to the map that was generated at runtime with the [Canvas API](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API).

{{ <Example html={html} {...this.props} /> }}

---

## File: docs/pages/example/add-image-generated.md

---
title: Add a generated icon to the map
topics:
  - Styles
  - Layers
thumbnail: add-image-generated
contentType: example
layout: example
hideFeedback: true
language:
- JavaScript
products:
- MapLibre GL JS
prependJs:
- "import Example from '../../components/example';"
- "import html from './add-image-generated.html';"
---

Add an icon to the map that was generated at runtime.

{{ <Example html={html} {...this.props} /> }}