Skip to main content

Animate Map Camera

Bring your map to life with smooth, cinematic camera animations — rotate, fly, zoom, and pitch dynamically using flyTo, easeTo, or requestAnimationFrame.

Perfect for:

  • App intros & onboarding
  • Property tours
  • City flyovers
  • Storytelling & presentations
  • 3D building showcases

Full Working Example

<!DOCTYPE html>
<html lang="en">
<head>
<title>Cinematic Camera Animation - Barikoi GL</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />

<!-- Barikoi GL -->
<link
rel="stylesheet"
href="https://unpkg.com/bkoi-gl@latest/dist/style/bkoi-gl.css"
/>
<script src="https://unpkg.com/bkoi-gl@latest/dist/iife/bkoi-gl.js"></script>

<style>
body {
margin: 0;
padding: 0;
background: #0f172a;
}
html,
body,
#map {
height: 100%;
}

.controls {
position: absolute;
top: 20px;
left: 20px;
z-index: 10;
background: rgba(15, 23, 42, 0.95);
padding: 8px;
width: 170px;
border-radius: 16px;
backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
font-family: system-ui, sans-serif;
}
.btn {
background: #0066ff;
color: white;
border: none;
padding: 6px 6px;
margin: 6px 0;
border-radius: 12px;
font-weight: 600;
cursor: pointer;
width: 100%;
transition: all 0.3s;
}
.btn:hover {
background: #0052cc;
transform: translateY(-2px);
}
.btn.active {
background: #10b981;
}
</style>
</head>
<body>
<div id="map"></div>

<div class="controls">
<button class="btn active" id="orbit">Orbital View</button>
<button class="btn" id="flyover">Dhaka Flyover</button>
<button class="btn" id="reset">Reset View</button>
</div>

<script>
const map = new bkoigl.Map({
container: "map",
style: "https://map.barikoi.com/styles/barikoi-dark-mode/style.json",
center: [90.4074, 23.7925], // Dhaka
zoom: 16,
pitch: 60,
bearing: 0,
accessToken: "YOUR_BARIKOI_API_KEY",
});

let animationId = null;

// 1. Continuous orbital rotation
function startOrbit() {
stopAnimation();
const startTime = performance.now() / 1000;

function rotate() {
const elapsed = performance.now() / 1000 - startTime;
const bearing = (elapsed * 15) % 360; // 15° per second
map.setBearing(bearing);
animationId = requestAnimationFrame(rotate);
}
rotate();
}

// 2. Cinematic flyover tour
function startFlyover() {
stopAnimation();
const locations = [
{ center: [90.4074, 23.7925], zoom: 17, pitch: 65, bearing: 0 },
{ center: [90.393, 23.78], zoom: 16.5, pitch: 60, bearing: 90 },
{ center: [90.42, 23.81], zoom: 17, pitch: 70, bearing: 180 },
{ center: [90.4074, 23.7925], zoom: 18, pitch: 75, bearing: 360 },
];

let i = 0;
function fly() {
map.flyTo({
...locations[i],
duration: 6000,
essential: true,
});

i = (i + 1) % locations.length;
setTimeout(fly, 7000);
}
fly();
}

function stopAnimation() {
if (animationId) cancelAnimationFrame(animationId);
}

map.on("load", () => {
// Remove labels for cleaner cinematic look
const layers = map.getStyle().layers;
layers.forEach((layer) => {
if (
layer.type === "symbol" &&
layer.layout &&
layer.layout["text-field"]
) {
map.removeLayer(layer.id);
}
});

// Start default animation
startOrbit();
});

// Button controls
document.getElementById("orbit").addEventListener("click", (e) => {
document
.querySelectorAll(".btn")
.forEach((b) => b.classList.remove("active"));
e.target.classList.add("active");
startOrbit();
});

document.getElementById("flyover").addEventListener("click", (e) => {
document
.querySelectorAll(".btn")
.forEach((b) => b.classList.remove("active"));
e.target.classList.add("active");
startFlyover();
});

document.getElementById("reset").addEventListener("click", () => {
stopAnimation();
document
.querySelectorAll(".btn")
.forEach((b) => b.classList.remove("active"));
map.easeTo({
center: [90.4074, 23.7925],
zoom: 16,
pitch: 0,
bearing: 0,
duration: 2000,
});
});
</script>
</body>
</html>

Camera Animation Methods

MethodBest ForSmoothness
map.flyTo()Cinematic jumps, toursHighest
map.easeTo()Gentle transitionsVery High
map.jumpTo()Instant (no animation)None
setBearing() + requestAnimationFrame()Continuous rotationUltra-smooth

Pro Tip: Always use duration: 0 with requestAnimationFrame for 60fps rotation.


Advanced: Orbital + Tilt Animation

let time = 0;
function animate() {
time += 0.01;
map.setBearing(time * 20);
map.setPitch(45 + Math.sin(time) * 20);
requestAnimationFrame(animate);
}

Creates a breathing orbital effect — mesmerizing!


Make your map breathtaking — literally.