{"id":28576970,"url":"https://github.com/maptiler/maptiler-3d-js","last_synced_at":"2025-06-11T00:08:29.047Z","repository":{"id":265046513,"uuid":"853314289","full_name":"maptiler/maptiler-3d-js","owner":"maptiler","description":"3D objects for MapTiler SDK","archived":false,"fork":false,"pushed_at":"2025-05-13T16:12:21.000Z","size":122704,"stargazers_count":6,"open_issues_count":2,"forks_count":0,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-05-13T17:28:13.751Z","etag":null,"topics":["3d","gltf","map","maptiler-sdk-plugin","webgl"],"latest_commit_sha":null,"homepage":"https://docs.maptiler.com/sdk-js/modules/3d/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/maptiler.png","metadata":{"files":{"readme":"readme.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-09-06T12:14:08.000Z","updated_at":"2025-05-09T06:09:10.000Z","dependencies_parsed_at":"2025-05-05T10:33:44.008Z","dependency_job_id":"6d10625b-8003-4839-a1c2-2f7e05c30443","html_url":"https://github.com/maptiler/maptiler-3d-js","commit_stats":null,"previous_names":["maptiler/maptiler-3d-js"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maptiler%2Fmaptiler-3d-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maptiler%2Fmaptiler-3d-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maptiler%2Fmaptiler-3d-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maptiler%2Fmaptiler-3d-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/maptiler","download_url":"https://codeload.github.com/maptiler/maptiler-3d-js/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maptiler%2Fmaptiler-3d-js/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259172986,"owners_count":22816560,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["3d","gltf","map","maptiler-sdk-plugin","webgl"],"created_at":"2025-06-11T00:08:27.002Z","updated_at":"2025-06-11T00:08:29.033Z","avatar_url":"https://github.com/maptiler.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n\u003ca href=\"https://docs.maptiler.com/sdk-js/modules/3d/\"\u003eofficial page →\u003c/a\u003e\u003cbr\u003e\n  \u003cimg src=\"images/maptiler-3d-logo.svg\" width=\"400px\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\" style=\"color: #AAA\"\u003e\n  Add 3D objects and lighting to your \u003ca href=\"https://docs.maptiler.com/sdk-js\"\u003eMapTiler SDK JS\u003c/a\u003e maps\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://cdn.maptiler.com/assets/images/JS-logo.svg\" width=\"20px\"\u003e\n  \u003cimg src=\"https://cdn.maptiler.com/assets/images/TS-logo.svg\" width=\"20px\"\u003e\n  \u003cimg src=\"https://img.shields.io/npm/v/@maptiler/3d\"\u003e\u003c/img\u003e\n  \u003cimg src=\"https://img.shields.io/twitter/follow/maptiler?style=social\"\u003e\u003c/img\u003e\n\u003c/p\u003e\n\n## 3D objects on MapTiler maps\nWith this MapTiler SDK module, you can add 3D objects to your basemap with plenty of customizations from glTF/glb files! Those can be meshes, groups of meshes, point clouds and a mix of all these.\n\n**Here are some examples:**  \n\n[![](images/plane.jpeg)Add an airplane 3D model to your map using the MapTiler 3D JS Module](https://docs.maptiler.com/sdk-js/examples/3d-js-plane/)\n\n[![](images/ducks-and-posts.jpeg)Add multiple 3D models to the map with the MapTiler 3D JS Module](https://docs.maptiler.com/sdk-js/examples/3d-js-multi/)\n\n[![](images/cad.jpeg)Display a building model based on point cloud data on a map with the MapTiler 3D JS Module](https://docs.maptiler.com/sdk-js/examples/3d-js-point-cad/) \n\n[![](images/dundee.jpeg)Display a 3D building model generated with photogrammetry software with the MapTiler 3D JS Module](https://docs.maptiler.com/sdk-js/examples/3d-js-point-cloud-dundee/)\n\n[![](images/dundee2.jpeg)Display a 3D building model generated with photogrammetry software with the MapTiler 3D JS Module](https://docs.maptiler.com/sdk-js/examples/3d-js-point-cloud-dundee/)\n\n[![](images/nhm.jpeg)Display a point cloud 3D building model on a map with the MapTiler 3D JS Module](https://docs.maptiler.com/sdk-js/examples/3d-js-point-cloud-nmh/)\n\n### Installation\nFrom NPM and using the ES module, in a terminal, in your project:\n```shell\nnpm install @maptiler/3d\n```\n\nThen to import:\n```ts\nimport { Layer3D } from \"@maptiler/3d\";\n// or\nimport * as maptiler3d from \"@maptiler/3d\";\n```\n\nFrom CDN and using the UMD bundle, in the `\u003chead\u003e\u003c/head\u003e` section of your HTML file:\n```html\n\u003cscript src=\"https://cdn.maptiler.com/maptiler-3d/v1.0.0/maptiler-3d.umd.js\"\u003e\u003c/script\u003e\n```\n\nWith the UMD bundle (on CDN), the namespace for this project is `maptiler3d`. So the `layer3D` class is available at `maptiler3d.Layer3D`.\n\n### Basic usage\nAn 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/Maplibre GL JS, it must have an ID and then be added to a `Map` instance:\n\n```js\n// Create a map;\nconst map = new Map({\n  container: \"map\",\n  // ...\n});\n\n// Waiting that the map is ready. You can also wait for the \"load\" event.\nmap.on(\"ready\", () =\u003e {\n  // Create a Layer3D and add it\n  const layer3D = new maptiler3d.Layer3D(\"custom-3D-layer\");\n  map.addLayer(layer3D);\n})\n```\n\nOnce created and added, a mesh can be added. In this version any *glTF* and their binary counterpart *glb* files can be added.\n\nTo add a mesh:\n```ts\n// The call can be awaited for the whole download of the mesh to complete\nawait layer3D.addMeshFromURL(\n  // ID to give to this mesh, unique within this Layer3D instance\n  \"flatiron\",\n\n  // The URL of the mesh\n  \"https://example.com/meshes/flatiron_building.glb\",\n\n  // A set of options, these can be modified later\n  {\n    lngLat: {lat: 40.74072950731568, lng: -73.98918779556983}, // can also be an array [lng, lat]\n    heading: 91.1,\n    scale: 39.5,\n    visible: true,\n    altitude: 74.38,\n    altitudeReference: maptiler3d.AltitudeReference.GROUND,\n  }\n);\n```\n\nHere are all the options for meshes:\n- `lngLat` location of the center of the 3D object, as longitude and latitude\n- `altitude` the altitude in meters above the reference point (to the origin of the mesh, that is not always the bottom)\n- `altitudeReference` reference point of altitude (ground or mean sea level)\n- `visible` whether the mesh is visible\n- `sourceOrientation` applies a correction from the original orientation of the mesh\n- `scale` scaling factor applied to the mesh\n- `heading` orientation in degrees (0-360), where 0 and 360 are true north and 90 is east\n- `opacity` opacity of the mesh. If the mesh is a group of meshes, this is applied to all the child nodes that can deal with transparency\n- `pointSize` applicable only to point clouds, set the size of the points\n- `wireframe` applicable only to non-point cloud, applies a wireframe rendering to all the child nodes of the mesh that are compatible with the option\n\n### Reference documentation\nThe constructor of the `Layer3D` class takes two arguments:\n- a layer ID (as in the example above)\n- an option object, with TypeScript, this object is of type `Layer3DOptions`\n\nHere are more details about the `Layer3DOptions` type:\n```ts\ntype Layer3DOptions = {\n  /**\n   * Bellow this zoom level, the meshes are not visible\n   * Default: 0\n   */\n  minZoom?: number;\n\n  /**\n   * Beyond this zoom level, the meshes are not visible.\n   * Default: 22\n   */\n  maxZoom?: number;\n\n  /**\n   * Default: true\n   */\n  antialias?: boolean;\n\n  /**\n   * Ambient light color.\n   * Default: `0xffffff` (white)\n   */\n  ambientLightColor?: ColorRepresentation,\n\n  /**\n   * Ambient light intensity.\n   * Default: `1`\n   */\n  ambientLightIntensity?: number,\n};\n```\n\nOther important types that are exported:\n\n- About the reference for altitude:\n```ts\nenum AltitudeReference {\n  /**\n   * Use the ground as a reference point to compute the altitude\n   */\n  GROUND = 1,\n\n  /**\n   * Uses mean sea level as a reference point to compute the altitude\n   */\n  MEAN_SEA_LEVEL = 2\n};\n```\n\n**Example:** A mesh that is add with the option `altitudeReference` being `AltitudeReference.GROUND` and an altitude of `10` will always \"fly\" 10 meters above the ground, regardless the terrain or the terrain exaggeration. If the provided altitude were to be a negative number, then it would always be beneath the ground surface by this amount (in meters). This mode is convenient for any item that needs to be positions relatively to the ground: cars, buildings, lap post, etc.\nOn the other hand, mesh that is add with the option `altitudeReference` being `AltitudeReference.MEAN_SEA_LEVEL` and the altitude of `1000` means the item will be at an absolute altitude of 1000 meters (3280 feet) above the mean sea level. If located in a place where the terrain shows mountains higher than 1000 meters, then the mesh will be underneath the ground surface and as such not visible. This mode is more convenient for flying objects such as planes, paraglydings, etc. as those thend to measure altitude with an absolute reference.\n\n- Going from the original 3D space the mesh was created in, to the map 3D space:\n```ts\nenum SourceOrientation {\n  /**\n   * The mesh was originaly created in a 3D space that uses the x axis as the up direction\n   */\n  X_UP = 1,\n\n  /**\n   * The mesh was originaly created in a 3D space that uses the Y axis as the up direction\n   */\n  Y_UP = 2,\n\n  /**\n   * The mesh was originaly created in a 3D space that uses the Z axis as the up direction\n   */\n  Z_UP = 3,\n};\n```\nNote that regardless of the original up axis, this module as well as MapTiler SDK/Maplibre GL JS only deal with 3D spaces that follow the [right-hand rule](https://en.wikipedia.org/wiki/Right-hand_rule).\n\n- Generic options that apply to both point lights and meshes:\n```ts\ntype GenericObject3DOptions = {\n  /**\n   * Position.\n   * Default: `[0, 0]` (Null Island)\n   */\n  lngLat?: LngLatLike,\n\n  /**\n   * Altitude above the reference (in meters).\n   * Default: `0` for meshes, or `2000000` for point lights.\n   */\n  altitude?: number,\n\n  /**\n   * Reference to compute and adjust the altitude.\n   * Default: `AltitudeReference.GROUND` for meshes and `AltitudeReference.MEAN_SEA_LEVEL` for point lights.\n   */\n  altitudeReference?: AltitudeReference,\n\n  /**\n   * Make the object visible or not.\n   * Default: `true`\n   */\n  visible?: boolean;\n};\n```\n\n- Options for adding meshes specifically:\n```ts\ntype MeshOptions = GenericObject3DOptions \u0026 {\n  /**\n   * Rotation to apply to the model to add, as a Quaternion.\n   * Default: a rotation of PI/2 around the x axis, to adjust from the default ThreeJS space (right-hand, Y up) to the Maplibre space (right-hand, Z up)\n   */\n  sourceOrientation?: SourceOrientation,\n\n  /**\n   * Scale the mesh by a factor.\n   * Default: no scaling added\n   */\n  scale?: number,\n\n  /**\n   * Heading measured in degrees clockwise from true north.\n   */\n  heading?: number,\n\n  /**\n   * Opacity of the mesh\n   */\n  opacity?: number;\n\n  /**\n   * Point size, applicable only to point clouds.\n   * Default: 1\n   */\n  pointSize?: number;\n\n  /**\n   * Displays a mesh as wireframe if true (does not apply to point cloud)\n   * Default: `false`\n   */\n  wireframe?: boolean;\n};\n```\n\n- Options for adding a point light specifically:\n```ts\ntype PointLightOptions = GenericObject3DOptions \u0026 {\n  /**\n   * Light color.\n   * Default: `0xffffff` (white)\n   */\n  color?: ColorRepresentation,\n\n  /**\n   * Intensity of the light.\n   * Default: `75`\n   */\n  intensity?: number,\n\n  /**\n   * Decay of the light relative to the distance to the subject.\n   * Default: `0.5`\n   */\n  decay?: number,\n};\n```\n\nHere is the list of instance methods:\n- **`.setAmbientLight(options: {color?: ColorRepresentation, intensity?: number} = {})`**\nTo adjust the settings of the ambient light. The type `ColorRepresentation` means the color can be a `number` (such as a hex notation `0xff0000`, for red), a hex string (such as `\"#FF0000\"`, for red), or a ThreeJS color ([read more about these here](https://threejs.org/docs/#api/en/math/Color)).\nℹ️ By default, the ambiant light is white (`0xffffff`) with an intensity of `0.5`.\n\n- **`.addMeshFromURL(id: string, meshURL: string, options: MeshOptions = {})`** *async*\nAdds a mesh from a URL to a glTF of glb file, given a mesh ID (will throw if not unique) and a set of options.\n\n- **`.addMesh(id: string, mesh: Mesh | Group | Object3D, options: MeshOptions = {})`**\nAdds a ThreeJS mesh/Group/Object3D, given a mesh ID (will throw if not unique) and a set of options.\nℹ️ By default, the mesh will have some settings (if not overwritten by the options):\n  * sourceOrientation: `SourceOrientation.Y_UP`\n  * altitude: `0`\n  * lngLat: `[0, 0]`\n  * heading: `0`\n  * visible: `true`\n\n- **`.modifyMesh(id: string, options: MeshOptions)`**\nModify the settings of a mesh (scale, lntLat, etc.)\nℹ️ Only the settings provided in the option object will be updated, the others will be left as they already are.\n\n- **`.cloneMesh(sourceId: string, id: string, options: MeshOptions)`**\nClones a mesh that has a given ID (`sourceId`) and create another one with a new ID (`id`). The provided options will overwrite the settings of the source mesh.\n\n- **`.addPointLight(id: string, options: PointLightOptions = {})`**\nAdds a point light with a unique ID (will throw if not unique) and some options.\nℹ️ By default, the light will have some settings (if not overwritten by the options):\n  * lngLat: `[0, 0]` (null island)\n  * altitude: `2_000_000` meters\n  * altitudeReference: `AltitudeReference.MEAN_SEA_LEVEL`\n  * color: `0xffffff` (white)\n  * intensity: `75`\n  * decay: `0.2`\n\n- **`.modifyPointLight(id: string, options: PointLightOptions)`**\nModify a point light given its ID.\nℹ️ Only the settings provided in the option object will be updated, the others will be left as they already are.\n\n- **`.removeMesh(id: string)`**\nRemove a mesh or point light from the scene and frees the GPU memory associated to it\n\n- **`.clear()`**\nRemoves all the meshes and point lights from the scene and frees the GPU memory associated with them\n\n## E2E Testing\n\nThis project uses a combination of [Vite](https://vitejs.dev/) for building and serving fixtures and [Playwright](https://playwright.dev) for browser automation to perform end-to-end testing.\n\nCurrently we are unable to use Vitest as a test runner at present due to [this issue](https://github.com/microsoft/playwright/issues/15800) with Playwright.\n\n### Test Structure\n\nThe testing setup consists of:\n- Configuration files:\n  - `vite.config-e2e.ts`: Vite configuration for e2e testing\n  - `playwright.config.ts`: Playwright browser configuration\n\n- Test files are organized under the `e2e` directory:\n  - `public/`: HTML files that run the test fixtures\n  - `src/`: Test fixture implementation files\n  - `mocks/`: Mock data and objects for testing\n  - `snapshots/`: image snapshots for comparison\n  - A dedicated `tsconfig.json` that extends the base project config\n\n### Adding New Tests\n\nTo add new test fixtures, add entry points to the rollup options in `vite-config-e2e.ts`.\n\n### Running Tests\n\nTwo npm scripts are available for testing; they must be run simultaneously:\n\n```shell\n# Start the test server that serves test fixtures\nnpm run e2e:serve\n\n# Run the e2e tests against local test server\nnpm run e2e:local\n\n# to update the snapshots pass the appropriate flag\nnpm run e2e:local -- --update-snapshots\n\n# to run in ui mode...\nnpm run e2e:local -- --ui\n```\n\n\u003e **Note:** GitHub Actions integration for automated testing will be implemented in upcoming versions.\n\n## License\nMapTiler JS Module\n\nCopyright © 2024 MapTiler AG. All rights reserved.\n\nThe software and files (collectively “Software”) in this repository are licensed for use only with MapTiler service(s).\n\nFor the license terms, please reference  [MapTiler JavaScript Module Terms and Conditions](https://www.maptiler.com/terms/jsmodule/).\n\nThis license allows users with an active MapTiler account to modify and integrate authorized portions of the Software for use with the relevant MapTiler service(s) in accordance with the MapTiler Terms. This license terminates automatically if a user no longer maintains a MapTiler account or their usage breaches MapTiler Terms.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaptiler%2Fmaptiler-3d-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaptiler%2Fmaptiler-3d-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaptiler%2Fmaptiler-3d-js/lists"}