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
| Method | Best For | Smoothness |
|---|---|---|
map.flyTo() | Cinematic jumps, tours | Highest |
map.easeTo() | Gentle transitions | Very High |
map.jumpTo() | Instant (no animation) | None |
setBearing() + requestAnimationFrame() | Continuous rotation | Ultra-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.