FurkMAPS for developers

← Back to map Русский

Vector maps built on OpenStreetMap open data: 3D buildings, globe view, terrain, light and dark themes. Embed them on a website with a single line or plug them into an app as a MapLibre style. No API key required.

1. Iframe: the easiest way

Move the map in the preview and the code below updates automatically.

/embed URL parameters

ParameterValue
lat, lon, zCenter and zoom level (0–20)
bearing, pitchBearing in degrees and pitch (0–75)
themelight, dark or auto (default: follows the system theme)
langLanguage of labels and buttons: en or ru. Without it, the viewer's browser language is used
worldviewHow to show the borders of Crimea: ru as part of Russia, ua as part of Ukraine, intl as a dashed disputed border. Without it, the viewer's country (by IP) is used
marker1 for a marker in the center, or lat,lon
titleMarker label
colorMarker color: e53935 (without #), f00 or a CSS color name such as green
iconIcon inside the marker: an emoji or 1–2 characters, such as ☕ or A
pinCustom image instead of the marker: an https://… link (PNG, SVG, WebP). The map point is the middle of the image's bottom edge
pinsizeMarker width in pixels: drop 20–64 (30 by default, 34 with an icon), image 16–96 (40 by default)
3d, controls, scroll, link1/0: tilt, buttons, scroll zoom without Ctrl, the “Open map” link

Controlling the map from your page (postMessage)

const frame = document.querySelector('iframe').contentWindow
frame.postMessage({ type: 'furkmaps:flyTo', center: [30.3158, 59.9391], zoom: 15 }, '*')
frame.postMessage({ type: 'furkmaps:setTheme', theme: 'dark' }, '*')
frame.postMessage({ type: 'furkmaps:addMarker', lngLat: [30.3158, 59.9391], title: 'Hermitage', color: '7b1fa2', icon: '🏛' }, '*')
frame.postMessage({ type: 'furkmaps:clearMarkers' }, '*')

// The map reports moves and clicks
window.addEventListener('message', (e) => {
    if (e.data?.type === 'furkmaps:click') console.log('click', e.data.lngLat)
    if (e.data?.type === 'furkmaps:moveend') console.log('center', e.data.center, 'zoom', e.data.zoom)
})

2. JS SDK

A thin wrapper around MapLibre GL JS that sets up styles, theme and 3D. It returns a regular maplibregl.Map.

<div id="map" style="height: 480px"></div>
<script src="https://maps.furkkinov.com/sdk.js"></script>
<script>
  FurkMaps.createMap('map', {
    theme: 'auto',            // 'light' | 'dark' | 'auto'
    lang: 'auto',             // 'en' | 'ru' | 'auto' (browser language)
    worldview: 'auto',        // Crimea borders: 'ru' | 'ua' | 'intl' | 'auto' (viewer's country)
    center: [37.6175, 55.752], // [longitude, latitude]
    zoom: 15,
    pitch: 55,
  }).then(function (map) {
    FurkMaps.addMarker(map, [37.6175, 55.752], { popup: 'Red Square', color: '#c62828', icon: '★' })
    // custom image instead of the drop: { image: 'https://example.com/logo.png', size: 48 }
    // map.setTheme('dark')
  })
</script>

As an ES module

<script type="module">
  import { createMap, addMarker, maplibregl } from 'https://maps.furkkinov.com/sdk.mjs'

  const map = createMap('map', { theme: 'dark', center: [30.3158, 59.9391], zoom: 14 })
  addMarker(map, [30.3158, 59.9391], { popup: 'Hermitage', icon: '🏛' })

  // Fully custom look: any HTML element
  const el = document.createElement('div')
  el.textContent = 'We are here'
  new maplibregl.Marker({ element: el, anchor: 'bottom' }).setLngLat([30.3165, 59.9398]).addTo(map)
</script>

3. Your own MapLibre: styles

If you already use MapLibre (plain web, React, Vue), all you need is a style URL.

StyleURL
Light, Russian labelshttps://maps.furkkinov.com/styles/light.json
Dark, Russian labelshttps://maps.furkkinov.com/styles/dark.json
Light, English labelshttps://maps.furkkinov.com/styles/light-en.json
Dark, English labelshttps://maps.furkkinov.com/styles/dark-en.json

These styles show the borders of Crimea the international way (a dashed disputed border). Variants for Russia and Ukraine live in the ru/ and ua/ folders: https://maps.furkkinov.com/styles/ru/light.json, https://maps.furkkinov.com/styles/ua/dark-en.json and so on. Only the border lines differ; layers and their ids are the same.

import maplibregl from 'maplibre-gl'
import 'maplibre-gl/dist/maplibre-gl.css'

const map = new maplibregl.Map({
  container: 'map',
  style: 'https://maps.furkkinov.com/styles/light-en.json',
  center: [37.6175, 55.752],
  zoom: 14,
})
// Switch the theme without reloading
map.setStyle('https://maps.furkkinov.com/styles/dark-en.json', { diff: true })
// 3D terrain
map.setTerrain({ source: 'dem', exaggeration: 1.4 })

4. Mobile apps

The styles work with MapLibre Native: Android, iOS, Flutter, React Native. Not every Native version supports the globe and sky; the map still works without them.

Android (Kotlin)

// build.gradle: implementation("org.maplibre.gl:android-sdk:<version>")
mapView.getMapAsync { map ->
    map.setStyle("https://maps.furkkinov.com/styles/light-en.json")
    map.cameraPosition = CameraPosition.Builder()
        .target(LatLng(55.752, 37.6175)).zoom(14.0).tilt(45.0).build()
}

iOS (Swift)

import MapLibre

let mapView = MLNMapView(frame: view.bounds,
    styleURL: URL(string: "https://maps.furkkinov.com/styles/dark-en.json"))
mapView.setCenter(CLLocationCoordinate2D(latitude: 55.752, longitude: 37.6175),
                  zoomLevel: 14, animated: false)
view.addSubview(mapView)

Flutter / React Native

// Flutter (maplibre_gl)
MapLibreMap(styleString: 'https://maps.furkkinov.com/styles/light-en.json', initialCameraPosition: ...)

// React Native (@maplibre/maplibre-react-native)
<MapView mapStyle="https://maps.furkkinov.com/styles/light-en.json" />

In a WebView, the iframe page is the simplest option: https://maps.furkkinov.com/embed?lat=55.752&lon=37.6175&z=14&lang=en.

5. Direct data access

WhatURL
Vector tiles (MVT, Protomaps schema)https://maps.furkkinov.com/tiles/planet/{z}/{x}/{y}.mvt
TileJSONhttps://maps.furkkinov.com/tiles/planet.json
Terrain (Terrarium PNG)https://maps.furkkinov.com/dem/{z}/{x}/{y}.png
Searchhttps://maps.furkkinov.com/api/search?q=Hermitage&lat=59.94&lon=30.31&limit=5&lang=en
Business detailshttps://maps.furkkinov.com/api/place?lat=55.65962&lon=37.74979&name=Yves%20Rocher
Opening hours, phones, website, social links from OSM: the business is matched by name near the point
Reverse geocodinghttps://maps.furkkinov.com/api/reverse?lat=55.752&lon=37.6175&lang=en
Both requests accept lang=ru|en and worldview=ru|ua|intl: with ru, addresses in Crimea read “Republic of Crimea, Russia”, otherwise “Autonomous Republic of Crimea, Ukraine”

Tiles and styles are served with CORS *. Search is limited to 5 requests per second per IP. With lang=en, search returns English names where OpenStreetMap has them.

Data and licenses

Everything is built on open data and open-source software. Keep the attribution on the map when embedding it; the iframe and the SDK show it automatically.

Map data© OpenStreetMap contributors, ODbL
Tile schema and buildProtomaps Basemap (Natural Earth, OSM)
TerrainMapzen Terrain Tiles (SRTM, GMTED, ETOPO1 and others)
SearchPhoton on OpenStreetMap data
EngineMapLibre GL JS, BSD-3-Clause
FontsNoto Sans, SIL Open Font License