Repository navigation
Releases: munimtechnologies/munim-maps
Release list
munim-maps 0.5.2
Fixed
- The README in the npm package was the 0.5.0 one without the MapLibre GL JS renderer (globe, 3D terrain, sky) or
MapModelLayerover@rnmapbox/mapsand react-native-maps on Android; it now matches the repository's. No code changes.
munim-maps 0.5.1
Google's photorealistic 3D map on iOS, a globe, 3D terrain and sky for MapLibre (through MapLibre GL JS), and MapModelLayer over @rnmapbox/maps and react-native-maps on Android.
Added
- MapLibre: globe, 3D terrain and sky through a second renderer for the
maplibreprovider, MapLibre GL JS 5 in a WebView, since MapLibre Native has neither.maplibre={{ renderer: 'auto' | 'native' | 'web' }}:auto(default) keeps MapLibre Native unless the map asks for something only GL JS has (theglobeprop,maplibre.projectionother than Mercator,maplibre.terrain,maplibre.sky, or astyleJsonwith its own projection, terrain or sky;resolveMapLibreRenderer()tells you which and why). New options:projection: 'globe' | 'vertical-perspective' | {…},terrain(truefor keyless AWS Terrain Tiles, or yourraster-demtiles, withexaggeration),sky(true,falseor a style-specsky, with the globe's atmosphere),fov,fadeDuration,allowEvaluate. The same API as the Native renderer (markers with dragging and continuousonMarkerDrag, clustering, callouts,MarkerView, shapes with dashes and gradients, tile overlays, camera, regions, fitting, flights, conversions on the terrain, the whole style spec at runtime, the MapLibre commands,onProviderEvent), plusmaplibreCommands(ref)getRenderer,setProjection,getProjection,isGlobe,setTerrain,getTerrain,queryTerrainElevation,setSky,getSky,easeTo,jumpToandevaluate, and therendererandprojectionTransitionevents. - munim-maps' 3D layer drawn inside GL JS (a custom layer rendered with three.js in GL JS's own WebGL context): GLB models, shapes, avatars, labels, stems, zones, paths and effects stay on the map on the flat map, on the globe and through the globe-to-Mercator transition, stand on the terrain under them and are hidden by terrain and the style's 3D buildings.
measureAlignment()measures them against GL JS's own projection. - GL JS 5.24.0 and three.js 0.186.1 load from jsDelivr through the engine's URL handler (same origin, cached on disk). To bundle them, add
maplibre-gl@5.24.0(andthree@0.186.1) to the app and turn onmaplibre: { bundledWeb: true }(Expo),munimMaps.maplibreBundled=true(Gradle) orMUNIM_MAPS_MAPLIBRE_BUNDLED=1(CocoaPods);scripts/maplibre/copy-maplibre-web.jscopies them with their licences. The npm package carries neither (the renderer's page is about 160 KB). - iOS: the
NitroMunimMaps/MapLibreWebsubspec (included by/MapLibre;MUNIM_MAPS_PROVIDERS=maplibre-webbuilds GL JS alone). Android:munimMaps.maplibreWeb(on with MapLibre). - Swift and Kotlin:
MunimMapEngine.variant(an engine can have more than one implementation; the container swaps when it changes),MunimMapEngines.variant(for:options:), andfetchCamera,fetchVisibleRegion,fetchPoint,fetchCoordinate,fetchAlignmentandfetchOverlayHithooks (defaulted to the synchronous getters) that JavaScript's promises now use, so WebView engines answer exactly. - Example:
munimmapsexample://maplibre/web(globe, city and Alps cameras) andmunimmapsexample://maplibre/web/checks. MapModelLayerover@rnmapbox/mapson Android: the layer finds the MapboxMapView(bymapTestID, or the nearest one) and draws with Mapbox's own camera (centre, zoom on 512-point tiles, pitch, bearing, padding, Mapbox's 36.87° field of view), every frame. No flag: the adapter compiles whenever@rnmapbox/maps(or munim-maps' Mapbox engine) is in the app, against the Mapbox SDK version@rnmapbox/mapsbuilds with (compileOnly, nothing added to the APK). Taps on models fireonModelPressthrough Mapbox's gestures plugin, next to@rnmapbox/maps' ownonPress. On a Galaxy A14: within 0.09 pt of Mapbox'spixelForCoordinateat seven cameras (one padded) and during an animation, within 2 pt on screenshots while dragging.MapModelLayerover react-native-maps on Android (Google Maps) without munim-maps' Google engine: the Google adapter compiles whenever react-native-maps is in the app. It finds the camera's centre with Google's projection, so react-native-maps'mapPaddingis followed. On a Galaxy A14: within 0.35 pt of Google's projection, within 2 pt on screenshots while dragging. NoonModelPresshere: Google's map has a single click listener, react-native-maps'.- Example:
munimmapsexample://layer/rnmapboxandlayer/rnmaps-google(Android): vehicles, avatars, shapes, effects, zones and paths over each library's map;/checkmeasures them against the host's own projection at seven cameras (one with map padding) and during a host-driven animation (MUNIM_MAPS_LAYER_OVERlog lines),/pan,/pan45and/pan45pad(/tex: the Mapbox map in a TextureView) show a probe (the host's magenta circle under munim-maps' green tile) for screenshots while dragging:example/scripts/layer-pan.shdrags and saves frames,layer-probe.pymeasures them,run-check.shruns a deep link and keeps its log.@rnmapbox/mapsis in the example for Android only (example/react-native.config.js), its token from the same keys file as the others. - Google's photorealistic 3D map on iOS:
google={{ mode: '3d' }}now works on both platforms, with the same API as Android: munim models drawn as Google's own glTF models (modelRenderingauto/native;overlayfalls back to native with an error), polylines, polygons and markers drawn natively,googleMap(ref).flyTo,flyAround,stopCameraAnimation,getCamera3d,setCamera3d, and themap3dReady,map3dSteady,cameraAnimationEndandmodeChangeevents. Turn it on with the Expo plugin'sgoogleMaps3d: true(now for iOS too) or"munimMaps.googleMaps3d": "true"inios/Podfile.properties.json(MUNIM_MAPS_GOOGLE_MAPS_3D=1); the key needs the Maps 3D SDK for iOS. Google ships that SDK only as a SwiftUI Swift package (GoogleMaps3D1.0.0): the newNitroMunimMaps/Google3Dsubspec hosts its map in the Google engine's view, the podspec adds the package to the pod with React Native'sspm_dependency, and the config plugin adds a Run Script phase to the app target that embeds its framework and resource bundle (scripts/google3d/embed-google-maps-3d.sh; without Expo, add a Run Script phase at the end of the app target that runsbash "${SRCROOT}/../node_modules/munim-maps/scripts/google3d/embed-google-maps-3d.sh"). On iOS,screenSizeis approximated from the camera's distance andtintrecolours the model'spaint*materials. See docs/providers.md. googleMap(ref).map3dDiagnostics()(iOS): how munim-maps drives the 3D map (camera log, flights, models).
Fixed
- Android, Google photorealistic 3D map: munim models stood on their tails (the bus upright on its back end, the balloon on its side), because Google's Maps 3D SDK reads glTF files Z-up and turns a model's +Z to its heading. They are now stood up (
tilt-90) and turned 180°, as on iOS, so they stand upright and heading 0 faces north (checked from the side and from above on a Galaxy A14). Example:munimmapsexample://google/3d/cam/<lat>,<lng>,<altitude>,<heading>,<tilt>,<range>starts the 3D map at that camera. - Android, Google photorealistic 3D map:
screenSizewas ignored, so every model was drawn at its real size (a 26-point bus was a few pixels from 2 km away). It now scales from the camera's distance, as on iOS: the model's height is read from its glTF (remote models are downloaded and cached first), and since the Maps 3D SDK (0.2.0) keeps drawing a model at the scale it was added with, a model whose scale changes is added again. On a Galaxy A14 ascreenSize: 60balloon is 59 points tall from 2.4 km. - Cesium:
getCamera()andgetVisibleRegion()could answer with the previous camera, because the page posts its region 150 ms after the camera stops: on a Galaxy A14 the region after afitToCoordinateswas still the one before it. Both now ask the page (thefetchCamera/fetchVisibleRegionhooks), on iOS and Android. - Android: the 3D layer stayed one frame behind once the map stopped moving whenever Filament skipped the last frame (the GPU busy during a fast drag); a skipped frame is now drawn on the next one.
- Android, Mapbox engine: models were off with camera padding on a pitched map (38 pt with 160 points of top padding at 50°, measured over
@rnmapbox/mapswith the same camera code): Mapbox moves its centre of perspective to the padded centre, whichMapCameraStatenow models (principalX/principalY, drawn with Filament's camera shift). - Android, Google: with map padding the camera's field of view was measured as if the target were straight ahead (17.6° instead of 30°, 11 pt off). Padded cameras now use the field of view measured without padding, and Google's starting field of view is the 30° measured on Android.
Changed
- Android:
MapModelLayerkeeps its 3D view exactly over the map's view (position and size, before every draw), so it lines up even when the layer and the map are not the same size, and finds the map again after it is remounted. - Android:
MapViewAdaptersfinds its built-in adapters by class name (like the engines);MapCameraSource.setTapListener(default: none) lets an adapter pass map taps to the layer. - iOS: two-format model sources (
munim-maps-vehicles) resolve to GLB on the Google engine in 3D mode (modelFormatFor(provider, modelRendering, googleMode)). - Swift: Mapbox's glTF reader moved to the shared
GLBInfo(Core/GLBInfo.swift), which also writes tinted GLB copies.
Found running Google's photorealistic 3D map on an iPad (Maps 3D SDK for iOS 1.0.0), and worked around:
- The SDK's
flyCameraTo/flyCameraAroundmodifiers fly to the camera of the previous SwiftUI update, so munim-maps flies the camera itself through the map's camera binding. - Changes to a model the map already shows are applied one SwiftUI update late, so a still model t...
v0.5.0
munim-maps is one API over five map engines (MapKit, Google Maps, Mapbox, MapLibre and Cesium) on iOS and Android, and ships no 3D models any more: the vehicle catalogue is the separate munim-maps-vehicles package. See docs/providers.md.
Breaking
munim-maps/vehiclesandmunim-maps/vehicles-glbthrow an error that points tomunim-maps-vehicles. The npm package no longer carries the 34 MB of models, and apps no longer bundle all 57: installmunim-maps-vehiclesandimport { VEHICLES } from 'munim-maps-vehicles'(remote, cached on the device) orimport car from 'munim-maps-vehicles/bundled/car-ev'(one model in the app). The Swift Package'sMunimMapsVehicleshas the names and remote URLs (MunimVehicles.url(_:),glbURL(_:),baseURL) and no resources.- The Cesium engine loads CesiumJS from jsDelivr by default, and the npm package no longer carries CesiumJS (13 MB). To bundle it, add
cesiumto the app (npm install cesium@1.146.0, the version the engine is written for; other versions build with a warning) and turn oncesium: { bundled: true }(Expo),munimMaps.cesiumBundled=true(Gradle) orMUNIM_MAPS_CESIUM_BUNDLED=1(CocoaPods): the minified build, itsLICENSE.mdandThirdParty.jsonare copied from the app'scesiumpackage atpod install(into theMunimMapsCesiumresource bundle) and by a Gradle task (munimMapsCopyCesium, generated assets).MUNIM_MAPS_CESIUM_DIR/munimMaps.cesiumDirpoint at anothercesiumfolder. - Android with Mapbox: Mapbox's Maven repository comes from the Expo config plugin (or your
android/build.gradle), no longer from arootProject.allprojectshook in munim-maps' build file.
Added
Engines and setup
provideronMunimMapView:'mapkit'(default on iOS),'google','mapbox','maplibre'(default on Android without Google) or'cesium', withstyleUrland per-engine options ingoogle,mapbox,maplibre,cesiumandmapkitprops. Engines that are not built in show a placeholder and reportonError.configureMunimMaps({ googleMapsApiKey, mapboxAccessToken, cesiumIonToken, maplibreStyleUrl, mapboxStyleUrl, defaultProvider }),availableProviders(),installedProviders(),isProviderAvailable()andMAP_PROVIDERS.- Expo config plugin (
"plugins": [["munim-maps", { "providers": [...], ...keys }]]): turns engines on (CocoaPods subspecs throughPodfile.properties.json, Gradle properties) and writes their keys into Info.plist, the manifest and strings.xml. It also adds Mapbox's Maven repository on Android,googleMaps3dandcesium: { bundled }. - Opt-in engines:
NitroMunimMaps/Google,/Mapbox,/MapLibreand/Cesiumsubspecs on iOS (the default install is still MapKit only),munimMaps.google,mapbox,maplibreandcesiumGradle properties on Android. - Swift: the
MunimMapEngineprotocol,MunimMapContainerView,MunimMapEngines,MunimMapsConfiguration, andMapCameraSource/MapCameraState, soMunimModelLayer.attach(to:)can draw over any engine's map.
Shared API on every engine
modelRendering: 'auto' | 'native' | 'overlay'onMunimMapView: who drawsmodels.autolets Mapbox (its model layer), Cesium (entities) and Google's photorealistic 3D map (Android) draw them, and uses munim-maps' 3D layer on MapKit, MapLibre and the Google 2D map; whatever an engine cannot draw stays on the 3D layer, except on Cesium.google.modelRendering,mapbox.modelRenderingandcesium.modelRenderingare aliases.- Engine-only methods and events through one channel:
ref.current.providerCommand(command, argsJson)andonProviderEvent({ provider, name, data }), withproviderCommand(ref, name, args),parseProviderEvent,callProvider/addProviderEventListenerfor engine-level commands that need no map, and typed wrappers per engine (googleMap,googleEvent,mapboxMap,maplibreCommands,cesiumCommands,parseCesiumEvent). onMarkerDrag: a marker's position while it is dragged, betweenonMarkerDragStartandonMarkerDragEnd, on every engine (MapKit reads the dragged view on a display link).- react-native-maps' region API:
initialRegion, a controlledregion,onRegionChangeStart,onRegionChangeComplete(region)andref.animateToRegion(region, ms);initialCamerais optional when a region is given. MarkerViewon Android, on every engine: the views are drawn into a bitmap (again on change withtracksViewChanges); Mapbox shows them as view annotations, Google, MapLibre and Cesium as image markers.selectableMapFeaturesreaches every Android engine (Mapbox: Standard's POI, landmark and place-label featuresets).- Remote models (
http(s)://, such as munim-maps-vehicles') are cached on disk on Android too, and Mapbox's model layer and Cesium read the cached files, so maps work offline after the first load. Two-format sources ({ uri, usdz, glb }) let munim-maps pick USDZ or GLB per engine and platform.
Vehicle catalogue package
munim-maps-vehicles: the 57 models as USDZ and GLB;VEHICLES[name](jsDelivr URLs at the package's version),VEHICLE_NAMES,VehicleName,vehicleSource(name),configureMunimMapsVehicles({ baseUrl })for self-hosting, andmunim-maps-vehicles/bundled/<name>/bundled/glb/<name>(one file per model).scripts/vehicles/write-catalogue.mjsgenerates its files from the modelsmake-vehicles.swiftwrites.
Android
- Android:
MunimMapViewandMapModelLayerare Kotlin Nitro views.MunimMapViewdraws MapLibre Native with OpenFreeMap (no key) and GLB / glTF models through a Filament 3D layer driven by the same camera model as iOS (position, altitude, heading, scale,screenSize,tint, spin,motion,onModelPress,measureAlignment), with the camera API, regions, conversions, gestures and map events. - Android 3D layer at parity with iOS, on every engine (it reads only
MapCameraState): built-in shapes, pictures (avatars with rings and badges), labels, stems,lift, ground shadows, embedded glTF animations, effects (exhaust,smoke,contrail),occludermodels, zones, 3D paths,occlusion="buildings"(vector tiles), the Earth hiding the globe's far side,altitudeReference: 'sea'andfollowTerrain(Terrarium terrain tiles), andflyCamera/stopFlightstepped on the layer's frame clock for any engine that can set its camera. groundElevation()on Android.- Android:
hasLookAround/openLookAroundgo to the engine (Google's Street View);MapModelLayercan draw over react-native-maps' GoogleMapViewwhen the Google engine is built in.
Google Maps
- Google Maps engine (
provider="google") on iOS (Maps SDK for iOS 10 + Google Maps Utils 7,NitroMunimMaps/Google) and Android (Maps SDK 20 + android-maps-utils 3.20,munimMaps.google=true): map types, cloud styling (google.mapId) and JSON styles, dark mode, buildings, traffic, transit, indoor maps with level events andsetIndoorLevel, lite mode (Android), every gesture and UI control (compass, my-location button, zoom controls and map toolbar on Android), padding, zoom limits and camera target bounds; markers of every style with info windows, dragging, flat / rotated markers, advanced markers with pins and collision behaviour,MarkerView, clustering withclusterStyles; polylines with gradients, spans, patterns, caps, joints and texture / sprite stamps, polygons with holes, circles, overlay taps, tile overlays ({x}{y}{z},{-y},{quadkey},file://), ground overlays, heatmaps, KML and GeoJSON layers, data-driven styling of boundaries and datasets; Street View (openLookAround,hasLookAround,googleMap(ref).streetView); snapshots, reverse geocoding, POI taps, camera-move reasons; and the 3D layer on Google's camera, with Google's field of view measured from its projection. - Google photorealistic 3D mode on Android (
google={{ mode: '3d' }}, Maps 3D SDKplay-services-maps3d0.2.0 behindmunimMaps.googleMaps3d=true/ the Expo plugin'sgoogleMaps3d): models as native Google glTF models (modelRendering: 'auto' | 'native' | 'overlay'), native polylines, polygons and markers,flyTo/flyAround. Needs the Map Tiles API and the Maps 3D SDK for Android on the key. googleMapsServices({ apiKey }): Places API (New) autocomplete, details, text and nearby search and photos, the Geocoding API and the Routes API (routes with decoded lines, route matrices), for keys with those APIs on;googleGeometryandencodePolyline/decodePolylinein JavaScript.
Mapbox
- Mapbox engine (
provider="mapbox", Mapbox Maps SDK 11.32 on iOS and Android): Mapbox Standard and Standard Satellite with light presets, themes and the rest of their config, globe, terrain, atmosphere, lights, snow and rain, style imports and colour themes; every style-spec source and layer type, images and glTF models from the declarativemapbox={{ … }}options (MapboxMapOptions); markers as point annotations with clustering and dragging, shapes and tile overlays as layers in Standard's slots,MarkerViews as view annotations; the location puck (2D / 3D, heading, pulsing), follow and follow-with-heading through Mapbox's viewport; featureset taps; Mapbox map events; munim-maps' 3D layer aligned to Mapbox's camera.mapboxMap(ref)methods (queries, feature state, clusters, runtime styling, Mapbox's camera, free camera, viewport,Snapshotter, elevation, location override, tile cover, statistics),MapboxOffline(style packs, tile regions) andMapboxServices(Geocoding, Search Box, Directions, Matrix, Isochrone). See the checklist in docs/providers.md. - Mapbox draws glTF / GLB
modelsnatively in its model layer (mapbox={{ modelRendering: 'auto' | 'native' | 'overlay' }},autoby default): lit, shadowed and hidden by Mapbox's buildings and terrain, with motion, spin,screenSizeandtint; avatars, labels, stems, effects, zones and paths stay on munim-maps' 3D...
v0.4.0
Added
- Terrain height. MapKit does not expose it, so munim-maps reads the free public Terrarium elevation tiles on AWS (zoom 14, bilinear, cached in memory and on disk, one request per tile at a time):
altitudeReference: 'sea'on models and paths:altitudeis metres above sea level, such as a phone's GPS altitude, and the ground height there is taken off natively. The model shows once its tile has loaded; moving models load the tiles along their keyframes ahead of time.followTerrainonMapModelLayerandMunimMapView(followsTerrainin Swift): on satellite imagery with realistic elevation, where MapKit draws real 3D terrain, models, paths and zones stay on the mountains instead of at the height of the ground at the map's centre. Models above sea level always follow the terrain.groundElevation(coordinates): the height of the ground above sea level, from JavaScript, andMunimTerrain.shared.groundElevations(for:)in Swift.
MapModelLayeris tested over expo-maps'AppleMaps.View(SwiftUIMap) on device: it finds theMKMapViewinside, and the self-test measures it within 1.6 points at three zoom levels.- Example: Yosemite in 3D with heights above sea level (
munimmapsexample://terrain), models over expo-maps (munimmapsexample://expomaps), and terrain and expo-maps checks in the self-test. - MapKit parity on
MunimMapView:userTrackingMode="followWithHeading"is handed to MapKit, which owns the following (heading beam included, nothing recentres from JavaScript);onUserTrackingModeChangereports when MapKit drops it after a pan or zoom, or the tracking button changes it. Camera moves from code end tracking the same way. Location access is requested when needed. The old'follow-with-heading'spelling still works.- Controls:
compassVisibilityandscaleVisibility(adaptive,visible,hidden),showsUserTrackingButton,pitchButtonVisibility(iOS 17+), and standaloneMapCompass,MapScaleandMapUserTrackingButtonthat drive the map with the samemapScope. selectionAccessory: Apple's place card for tapped places (MKSelectionAccessory, iOS 18+), andmapItemForFeature(id)for the full place behindonMapFeaturePress.- Markers:
displayPriority,collisionMode,titleVisibility/subtitleVisibility, SF Symbol glyphs (glyphSymbol,selectedGlyphSymbol),glyphColor,animatesWhenAdded, callout buttons and pictures (calloutLeft,calloutRight,onCalloutAccessoryPress) andcalloutDetail. clusterStyles(balloon colour,{count}glyph and title) andonClusterPresswith the member ids.<MarkerView>: React Native views as markers, drawn into a real MapKit marker (tracksViewChangesfor live content).- Overlays: gradient polylines (
strokeColors,strokeColorLocations),lineJoin,strokeStart/strokeEnd(updated in place, to animate a route),level(aboveRoads,aboveLabels) on every overlay, andonOverlayPresswithtappablehit-testing for polylines, polygons and circles (overlayAtPoint(point)on the ref). pointsOfInterestaccepts short category names such as'cafe'.
<LookAroundView>: Apple's Look Around embedded in your layout (coordinateormapItemId,showsRoadLabels,pointsOfInterest,navigationEnabled,badgePosition,onSceneChange,onFullScreenChange).- MapKit services, no map needed:
searchPlaces,createSearchCompleter(autocomplete, resolved to places),pointsOfInterest,directionsandeta(transport types, alternates, dates, avoiding tolls and highways, steps),geocodeandreverseGeocode(iOS 26MKGeocodingRequest/MKReverseGeocodingRequest,CLGeocoderbefore),mapItem(id),openInMaps,mapSnapshot,hasLookAround,lookAroundSnapshot,formatDistance, androutePolylineto draw a route. - Example: a MapKit screen with all of it (
munimmapsexample://parity,/follow,/callout) and 16 more self-test checks (services, overlay hit-testing,MarkerView, user tracking).
Fixed
- The self-test's render check looked at one pixel in the middle of each model, which fell between the beams of the lattice Starbase tower at "close, pitched 70, heading 315" (on both
MunimMapViewand react-native-maps). It now looks for the model's pixels anywhere in its projected bounding box; alignment there was always within 1.7 points. - Updating markers no longer re-configures unchanged ones, which closed an open callout.
Changed
- The vehicle catalogue is rebuilt to the jets' level of detail. Bodies are skinned through measured cross-sections, wings and tails are airfoil sections, and windows, seams, lights, stripes and markings are laid onto the skin, so they follow its curves instead of sitting on it as flat boxes:
- Cars: beltline creases, flush glass split by the pillars, door seams and handles, lamps, grilles and bumpers on the body, arch-cut wheel openings and dished alloy wheels; the convertible has an open cabin.
- Vans, trucks and buses: fitted windscreens and windows, sliding and swing doors, arch flares, DOT tape and roll-up doors; a long-hood semi tractor with a chrome grille and air cleaners, a crew-cab pumper, a 40 ft city bus and a conventional school bus.
- Motorcycles: twin-spar, cradle and perimeter frames, swingarms, forks through triple clamps, round-profile tyres on cast or laced wheels with discs, an inline-four, a finned V-twin and a single, exhausts and lofted bodywork; a step-through scooter.
- Boats: deep-V hulls with chines; a bowrider with an outboard, a 33 ft sloop, a 35 m superyacht and a personal watercraft.
- Aircraft: airliners with winglets, nacelles, window rows and gear (
plane-widebodyis now its own twin-aisle, not a scaled narrow-body), a business jet with a T-tail, a Cessna 172-style high wing and a Bell 407-style helicopter. - Rail: a two-section tram and a high-speed train with a sculpted nose, bogies and pantographs.
- Rockets: the Space Shuttle orbiter (double delta, tiles, OMS pods, main engines) now faces the front of the stack; Falcon 9 and Saturn V gain engines, legs, grid fins, fins and paint patterns.
- Vehicle models share vertices across their markings and drop body sections that add no shape, so the jets are about 40% lighter; the whole catalogue is 15 MB.
munim-maps 0.3.0
Added
MunimMapViewis now a full MapKit map, so apps no longer need react-native-maps on iOS: markers (pins, balloons with glyphs, images, round avatars with ring and corner badges, label pills, dots) with clustering, dragging, callouts and z-order; polylines (dashed, geodesic), polygons with holes, circles and tile overlays; point-of-interest filters, traffic, compass, scale, user location and tracking modes, gesture switches, camera distance limits and boundaries, map padding and tappable map features.MunimMapViewevents and methods:onMapReady,onPress,onLongPress,onCameraMove,onCameraChange, marker and callout events,onUserLocationChange,onMapFeaturePress;setCamera,animateCamera,getCamera,setRegion,getVisibleRegion,fitToCoordinates,fitToMarkers,pointForCoordinate,coordinateForPoint,selectMarker,deselectMarker,takeSnapshot,addressForCoordinate,hasLookAround,openLookAround.globe: the standard map becomes a globe when zoomed far out, like Apple Maps. It uses a MapKit switch that is not public API; see the README.- Models, labels, stems and zones are placed on the sphere whenever MapKit draws a globe (the standard map with
globe, orhybrid/imagerywith realistic elevation), and hidden when they go round the far side. paths: lines drawn in 3D, a fixed number of points wide, at any height and on the globe (orbits, flight paths). They also work over react-native-maps.occlusion="buildings": models are hidden behind buildings, using OpenStreetMap footprints and heights from vector tiles around the camera (OpenFreeMap by default, orbuildingTilesUrl). Avatars, labels and stems stay visible.- glTF 2.0 models (
.glb,.gltf): PBR materials and textures, skins and the first animation, from bundles, URLs (with their buffers and images) or files. PLY, STL and Alembic files load through Model I/O alongside OBJ. effect: particle effects,exhaust(a methane engine plume with shock diamonds, sized to the model and stopping at the ground),smoke(a launch-pad cloud) andcontrail(trails left in the sky), witheffectIntensityto throttle them.occluder: a model that draws nothing but hides other models behind it, for stand-ins such as a bridge's railings and towers.effectOrigins: where an effect starts on a model, such as one contrail per engine.motionon models andflyCameraonMunimMapView: keyframes interpolated natively every frame on one shared clock, so moving models and camera moves stay smooth and locked to the map whatever JavaScript is doing.animateCameranow steps the camera the same way instead of a UIKit animation, during which MapKit reported the destination camera and models slid.- The four fighter jets are rebuilt from measured three-view drawings, with intakes, control surfaces, nozzles, canopies, camouflage and markings.
- Seven spacecraft in the vehicle catalogue: the ISS, a Starlink satellite, Hubble, a GPS III satellite, a 3U CubeSat, Crew Dragon and the James Webb Space Telescope.
- Starbase:
starbase-tower(the launch tower with its chopsticks and quick-disconnect arm) andstarbase-mount(the orbital launch mount), and a rebuiltrocket-starshipwith grid fins, chines, the hot-staging ring, 33 Raptors and the ship's heat shield and flaps (57 models). realisticElevationonMapModelLayer: keeps a map library's flat style on realistic elevation.- Swift Package Manager: the
MunimMapsandMunimMapsVehiclesproducts bringMunimMapKitView, the SwiftUIMunimMapandMunimModelLayerto native apps without React Native. - Example: satellites orbiting the globe (
munimmapsexample://orbit), cities on the globe, scripted demo shots (munimmapsexample://demo/<shot>, with traffic on real Chicago streets from OpenStreetMap and a GLB sample), and globe checks in the self-test.
Fixed
- Badges longer than the picture (
Floor 103) were cut off; the badge now widens to fit. - Geodesic polylines crashed:
MKGeodesicPolyline's initialiser never returns a subclass, so the overlay's own properties were written past the end of the object.
Install
npx expo install munim-maps react-native-nitro-modulesOr in Swift, add https://github.com/munimtechnologies/munim-maps with Swift Package Manager.
The demo video (munim-maps-demo.mp4) is attached; every shot was recorded on an iPhone 17 Pro.
v0.2.0
Added
- Vehicle catalogue in
munim-maps/vehicles: 48 detailed models (13 cars including EV, off-roader, supercar, pickup, taxi and police; vans, trucks, fire engine and buses; bikes, scooters and motorcycles; tram and high-speed train; boats; airliners, business jet, prop plane, F-16, F-22, F-35, YF-23, helicopter, hot air balloon; Starship, Falcon 9, Saturn V and the Space Shuttle), generated byscripts/vehicles/make-vehicles.swift. tint: recolours a model's paint (materials namedpaint…) at runtime.- Avatar models:
imagedraws a round picture that always faces the camera, withimageBorderand abadgepill (such as5F), sized in points byscreenSize. stem: a line from the ground up to a floating model, with a dot on the ground, for people on upper floors.lift: raises a model by a number of points at any zoom, to float an avatar over a vehicle.label: a text pill floating above any model.gemshape, for power-ups.zones: circles or polygons drawn as see-through walls with solid top and bottom edges.- Example: friends on Chicago skyscrapers, the vehicle catalogue with tints, power-ups and zones, an Orbit toggle, and a lag test (
munimmapsexample://lagtest).
Fixed
- Models trailed the map by a frame or more while it moved, and stayed slightly off once it stopped. SceneKit's transaction is now flushed before each frame, and frames are presented straight from the GPU. Mid-animation the models now stay within 0.2 px of MapKit's own overlays.
- Screen-size models no longer redraw every frame while the map is still.
- Badge pills stay readable on light rings.
v0.1.0
Added
MapModelLayer: draws 3D models over an existing MapKit map, such asreact-native-maps'MapViewon iOS, found bytestIDor as the nearest map on screen.MunimMapView: a MapKit map with models built in, withstandard,muted,hybridandimagerystyles, flat or realistic elevation, andsetCamera/getCamera.- Models from USDZ, USD, SCN or OBJ files (bundled,
file://or cachedhttp(s)://) or built-in shapes, with altitude, heading, scale, spin, embedded animations, screen-constant sizing, ground shadows and day/night lighting. - Camera matching that measures MapKit's focal length from the map itself, and same-frame rendering through a pre-commit run-loop observer.
onModelPresstaps andmeasureAlignment()for checking the drawing against MapKit.