3d-camera-position

Sample code supporting Google Maps Platform JavaScript API documentation. author(s): Geo Developer IX Documentation Team

HTML

<!doctype html>
<!--
@license
Copyright 2026 Google LLC. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
-->

<html>
  <head>
    <title>Google Maps 3D - Camera Position Controller</title>
    <script>
      // prettier-ignore
      (g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})({
            });
    </script>
  </head>

  <body>
    <gmp-map-3d
      center="40.7811,-73.9599,0"
      mode="HYBRID"
      tilt="76"
      range="3270"
      heading="-154"></gmp-map-3d>
    <div id="ui-container">
      <div class="panel">
        <div class="control-group">
          <label for="heading">
            Heading: <span id="heading-val">0</span>&deg;
          </label>
          <input
            type="range"
            id="heading"
            name="heading"
            min="-180"
            max="180"
            value="0"
            step="1" />
        </div>

        <div class="control-group">
          <label for="tilt"> Tilt: <span id="tilt-val">45</span>&deg; </label>
          <input
            type="range"
            id="tilt"
            name="tilt"
            min="0"
            max="90"
            value="45"
            step="1" />
        </div>

        <div class="control-group">
          <label for="range"> Range: <span id="range-val">1000</span>m </label>
          <input
            type="range"
            id="range"
     ...

CSS

/*
 * @license
 * Copyright 2026 Google LLC. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0
 */

html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
  font-family:
    'Inter',
    -apple-system,
    BlinkMacSystemFont,
    'Segoe UI',
    Roboto,
    Oxygen,
    Ubuntu,
    Cantarell,
    'Open Sans',
    'Helvetica Neue',
    sans-serif;
  background-color: #0f172a;
  color: #e2e8f0;
}

gmp-map-3d {
  height: 100%;
  width: 100%;
}

/* Glassmorphism UI Overlay */
#ui-container {
  position: absolute;
  top: 20px;
  left: 20px;
  width: 320px;
  z-index: 10;
}

.panel {
  background: rgba(15, 23, 42, 0.75);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 16px;
  padding: 24px;
  margin-top: 10px;
  box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
}

h1 {
  font-size: 1.25rem;
  font-weight: 700;
  margin: 0 0 4px 0;
  background: linear-gradient(to right, #38bdf8, #818cf8);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

.sub-title {
  font-size: 0.85rem;
  color: #94a3b8;
  margin: 0 0 20px 0;
}

h2 {
  font-size: 0.95rem;
  font-weight: 600;
  margin: 16px 0 8px 0;
  color: #f8fafc;
}

.control-group {
  margin-bottom: 16px;
}

label {
  display: block;
  font-size: 0.85rem;
  margin-bottom: 6px;
  color: #cbd5e1;
}

span {
  font-weight: 600;
  color: #38bdf8;
}

.row {
  display: flex;
  gap: 12px;
}

.col {
  flex: 1;
}

input[type='number'] {
  font-family: 'Fira Code', monospace;
  background: rgba(15, 23, 42, 0.5);
  border: 1px solid rgba(255, 255, 255, 0.1);
  color: #f8fafc;
  padding: 4px 8px;
  border-radius: 6px;
  outline: none;
}

input[type='range'] {
  width: 100%;
  height: 4px;
  background: #334155;
  border-radius: 2px;
  outline: none;
  -webkit-appearance: none;
}

input[type='range']::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #38bdf8;
 ...

JavaScript

'use strict';
/*
 * @license
 * Copyright 2026 Google LLC. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0
 */

async function init() {
  // Declare the needed libraries.
  await google.maps.importLibrary('maps3d');

  const map3DElement = document.querySelector('gmp-map-3d');

  // Elements from HTML
  const headingSlider = document.getElementById('heading');
  const tiltSlider = document.getElementById('tilt');
  const rangeSlider = document.getElementById('range');
  const latSlider = document.getElementById('lat');
  const lngSlider = document.getElementById('lng');
  const fovSlider = document.getElementById('fov');
  const rollSlider = document.getElementById('roll');

  const headingVal = document.getElementById('heading-val');
  const tiltVal = document.getElementById('tilt-val');
  const rangeVal = document.getElementById('range-val');
  const altitudeVal = document.getElementById('altitude-val');
  const fovVal = document.getElementById('fov-val');
  const rollVal = document.getElementById('roll-val');
  const codeElem = document.getElementById('generated-code');
  const copyBtn = document.getElementById('copy-btn');

  let currentAltitude = 30;
  let isUserInteracting = false;

  // Update values on UI when the map changes.
  const updateUI = () => {
    const heading = map3DElement.heading?.toFixed(0) ?? '0';
    const tilt = map3DElement.tilt?.toFixed(0) ?? '0';
    const range = map3DElement.range?.toFixed(0) ?? '0';
    const rawFov = parseFloat(map3DElement.fov?.toFixed(0) ?? '45');
    const fovClamped = Math.min(80, Math.max(5, rawFov));
    const fov = fovClamped.toString();
    const roll = map3DElement.roll?.toFixed(0) ?? '0';
    const center = map3DElement.center;
    const mode = map3DElement.mode;

    headingVal.textContent = heading;
    tiltVal.textContent = tilt;
    rangeVal.textContent = range;
    fovVal.textContent = fov;
    rollVal.textContent = roll;

    if (!isUserInteracting) {
      fovSlider.value = fov;
     ...