One-line install
Add LandMapMagic layers to MapLibre, Mapbox, Leaflet, or Google Maps with a single import. The landmapmagic npm package fetches a target-shaped style from /v1/styles and mounts it for you.
Install
npm install landmapmagicpnpm add landmapmagicyarn add landmapmagicleaflet for Leaflet, @deck.gl/core + @deck.gl/google-maps + @deck.gl/geo-layersfor Google + deck.gl. They're peer dependencies, so you only pull in what you actually use.MapLibre / Mapbox (React)
The React component fetches the style internally on mount and handles hover / click feature state for you. MapLibre GL JS and Mapbox GL JS both consume the same MapLibre Style Spec v8 doc, so pick whichever renderer fits your stack — the underlying style is identical.
import { LandMap } from 'landmapmagic';
export default function App() {
return (
<LandMap
apiKey="YOUR_API_KEY"
layers={['clu', 'counties']}
initialView={{ center: [-93.5, 42.0], zoom: 12 }}
/>
);
}import { LandMap } from 'landmapmagic/mapbox';
export default function App() {
return (
<LandMap
apiKey="YOUR_API_KEY"
mapboxAccessToken="pk...."
layers={['clu', 'counties']}
initialView={{ center: [-93.5, 42.0], zoom: 12 }}
/>
);
}MapLibre / Mapbox (vanilla)
If you already manage your own map instance, fetch the style and merge it manually. fetchLandStyle caches per-session and returns the renderer-shaped object directly.
import { fetchLandStyle } from 'landmapmagic';
const style = await fetchLandStyle({
apiKey: 'YOUR_API_KEY',
target: 'maplibre',
layers: ['clu', 'counties'],
});
// MapLibre style spec v8 — drop directly into setStyle, or merge sources/layers.
map.setStyle(style);
// Or merge into an existing style:
for (const [id, source] of Object.entries(style.sources)) {
if (!map.getSource(id)) map.addSource(id, source);
}
for (const layer of style.layers) {
if (!map.getLayer(layer.id)) map.addLayer(layer);
}Leaflet
The landmapmagic/leaflet adapter mounts vector layers with L.vectorGrid and rasters with L.tileLayer, and handles label deduplication via lmm_label_id.
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import 'leaflet.vectorgrid';
import { mountLeafletLandMap } from 'landmapmagic/leaflet';
const map = L.map('map').setView([42.0, -93.5], 12);
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap',
}).addTo(map);
const handle = await mountLeafletLandMap({
apiKey: 'YOUR_API_KEY',
map,
layers: ['clu', 'counties'],
});
// handle.unmount() removes every added layer.Google Maps + deck.gl
The landmapmagic/google adapter wraps deck.gl's GoogleMapsOverlay with MVTLayer / TileLayer / TextLayer and resolves accessor descriptors (static, by-zoom, by-property) automatically.
import { Loader } from '@googlemaps/js-api-loader';
import { GoogleMapsOverlay } from '@deck.gl/google-maps';
import { mountGoogleLandMap } from 'landmapmagic/google';
const loader = new Loader({ apiKey: 'GMAPS_KEY', version: 'weekly' });
await loader.load();
const map = new google.maps.Map(document.getElementById('map'), {
center: { lat: 42.0, lng: -93.5 },
zoom: 12,
mapId: 'YOUR_VECTOR_MAP_ID',
});
const overlay = new GoogleMapsOverlay({});
overlay.setMap(map);
const handle = await mountGoogleLandMap({
apiKey: 'YOUR_API_KEY',
map,
overlay,
layers: ['clu', 'counties'],
});
// handle.unmount() clears the deck.gl layers.Working with multiple CDL years
Each CDL year is its own layer entry. Repeat cdl:YYYY in your layers array; the API returns a unique source/layer per year so you can toggle them independently.
await fetchLandStyle({
apiKey: 'YOUR_API_KEY',
target: 'maplibre',
layers: ['clu', 'cdl:2024', 'cdl:2023', 'cdl:2022'],
});