@maplibre-yaml/core
v0.2.2
Published
Core library for declarative MapLibre maps with YAML
Maintainers
Readme
@maplibre-yaml/core
Declarative web maps with YAML configuration. Build interactive MapLibre maps using simple, readable YAML syntax.
Installation
npm install @maplibre-yaml/core maplibre-glQuick Start
Web Component
The simplest way to use maplibre-yaml is with the <ml-map> web component:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://unpkg.com/maplibre-gl/dist/maplibre-gl.css">
<style>
ml-map { display: block; height: 400px; }
</style>
</head>
<body>
<ml-map src="/map.yaml"></ml-map>
<script type="module">
import '@maplibre-yaml/core/register';
</script>
</body>
</html>JavaScript API
import { parseYAMLConfig, MapRenderer } from '@maplibre-yaml/core';
const yaml = `
type: map
config:
center: [-122.4, 37.8]
zoom: 12
mapStyle: https://demotiles.maplibre.org/style.json
layers:
- id: points
type: circle
source:
type: geojson
url: https://example.com/data.geojson
paint:
circle-radius: 6
circle-color: "#3b82f6"
`;
const config = parseYAMLConfig(yaml);
const container = document.getElementById('map');
const renderer = new MapRenderer(container, config);Entry Points
The package provides multiple entry points for different use cases:
| Import | Purpose |
|--------|---------|
| @maplibre-yaml/core | Main entry: parser, renderer, data utilities |
| @maplibre-yaml/core/register | Auto-registers <ml-map> web component |
| @maplibre-yaml/core/schemas | Zod schemas for validation and types |
| @maplibre-yaml/core/components | Manual component registration |
YAML Configuration
Basic Map
type: map
id: my-map
config:
center: [-74.006, 40.7128]
zoom: 10
mapStyle: https://demotiles.maplibre.org/style.json
layers:
- id: cities
type: circle
source:
type: geojson
data:
type: FeatureCollection
features:
- type: Feature
geometry:
type: Point
coordinates: [-74.006, 40.7128]
properties:
name: New York
paint:
circle-radius: 8
circle-color: "#ef4444"Named Sources
Define sources at the block level and reference them by name across multiple layers:
type: map
id: neighborhood-map
config:
center: [-73.985, 40.674]
zoom: 14
mapStyle: https://basemaps.cartocdn.com/gl/positron-gl-style/style.json
sources:
boundary:
type: geojson
url: https://example.com/boundary.geojson
parcels:
type: vector
url: https://example.com/parcels.json
layers:
- id: boundary-fill
type: fill
source: boundary
paint:
fill-color: "#3388ff"
fill-opacity: 0.2
- id: boundary-outline
type: line
source: boundary
paint:
line-color: "#3388ff"
line-width: 2
- id: parcels-fill
type: fill
source: parcels
source-layer: parcels
paint:
fill-color: "#ccc"
fill-opacity: 0.5Sources defined at the block level are added to the map before layers, so any layer can reference them by name. This avoids duplicating source definitions when multiple layers use the same data. Inline sources on individual layers still work as before.
Real-time Data with Polling
layers:
- id: vehicles
type: circle
source:
type: geojson
url: https://api.transit.example.com/vehicles.geojson
refresh:
refreshInterval: 5000
updateStrategy: merge
updateKey: vehicleId
paint:
circle-radius: 6
circle-color:
- match
- ["get", "status"]
- "active"
- "#22c55e"
- "delayed"
- "#f59e0b"
- "#6b7280"Streaming with WebSocket
layers:
- id: live-events
type: circle
source:
type: geojson
url: https://api.example.com/initial.geojson
stream:
type: websocket
url: wss://api.example.com/events
reconnect: true
refresh:
updateStrategy: append-window
windowSize: 100
windowDuration: 300000
paint:
circle-radius: 8
circle-color: "#8b5cf6"Interactive Popups
layers:
- id: locations
type: symbol
source:
type: geojson
url: https://example.com/locations.geojson
layout:
icon-image: marker
interactions:
- type: click
popup:
content: |
<h3>{{name}}</h3>
<p>{{description}}</p>API Reference
Parser
import { YAMLParser, parseYAMLConfig, safeParseYAMLConfig } from '@maplibre-yaml/core';
// Simple parsing
const config = parseYAMLConfig(yamlString);
// Safe parsing with error handling
const result = safeParseYAMLConfig(yamlString);
if (result.success) {
console.log(result.data);
} else {
console.error(result.error);
}
// Using the class
const parser = new YAMLParser();
const config = parser.parse(yamlString);Renderer
import { MapRenderer } from '@maplibre-yaml/core';
const renderer = new MapRenderer(container, config, {
onLoad: () => console.log('Map loaded'),
onError: (error) => console.error(error),
});
// Control layers
renderer.setLayerVisibility('layer-id', false);
renderer.updateLayerData('layer-id', newGeoJSON);
// Cleanup
renderer.destroy();Data Management
DataFetcher
import { DataFetcher } from '@maplibre-yaml/core';
const fetcher = new DataFetcher({
cache: { enabled: true, defaultTTL: 300000, maxSize: 50 },
retry: { enabled: true, maxRetries: 3 }
});
const result = await fetcher.fetch('https://example.com/data.geojson');PollingManager
import { PollingManager } from '@maplibre-yaml/core';
const polling = new PollingManager();
polling.start('layer-id', {
interval: 5000,
onTick: async () => updateMap(await fetchData()),
pauseWhenHidden: true
});
polling.pause('layer-id');
polling.resume('layer-id');
polling.stop('layer-id');StreamManager
import { StreamManager } from '@maplibre-yaml/core';
const streams = new StreamManager();
await streams.connect('stream-id', {
type: 'websocket',
url: 'wss://example.com/stream',
onData: (data) => console.log(data),
reconnect: { enabled: true, maxRetries: 10 }
});
streams.disconnect('stream-id');DataMerger
import { DataMerger } from '@maplibre-yaml/core';
const merger = new DataMerger();
const result = merger.merge(existing, incoming, {
strategy: 'merge',
updateKey: 'id'
});Schemas
All schemas are built with Zod and provide TypeScript types:
import {
// Layer schemas
LayerSchema,
CircleLayerSchema,
LineLayerSchema,
FillLayerSchema,
SymbolLayerSchema,
RasterLayerSchema,
FillExtrusionLayerSchema,
HeatmapLayerSchema,
HillshadeLayerSchema,
BackgroundLayerSchema,
// Source schemas
GeoJSONSourceSchema,
VectorSourceSchema,
RasterSourceSchema,
ImageSourceSchema,
VideoSourceSchema,
// Map schemas
MapConfigSchema,
MapBlockSchema,
ControlsConfigSchema,
LegendConfigSchema,
// Scrollytelling schemas
ChapterSchema,
ScrollytellingBlockSchema,
// Page schemas
PageSchema,
RootSchema,
GlobalConfigSchema,
// Base schemas
LngLatSchema,
ColorSchema,
ExpressionSchema,
} from '@maplibre-yaml/core/schemas';
// Validation
const layer = LayerSchema.parse(data);
// Safe parsing
const result = LayerSchema.safeParse(data);
if (result.success) {
console.log(result.data);
}Type inference:
import type { z } from 'zod';
import { LayerSchema, MapBlockSchema } from '@maplibre-yaml/core/schemas';
type Layer = z.infer<typeof LayerSchema>;
type MapBlock = z.infer<typeof MapBlockSchema>;Exported types:
import type {
// Map types
MapConfig,
MapBlock,
MapFullPageBlock,
ControlPosition,
ControlsConfig,
LegendConfig,
// Scrollytelling types
Chapter,
ChapterAction,
ChapterLayers,
ScrollytellingBlock,
// Page types
Page,
Block,
MixedBlock,
GlobalConfig,
RootConfig,
} from '@maplibre-yaml/core/schemas';Web Components
import { MLMap, registerMLMap } from '@maplibre-yaml/core/components';
// Register with default name
registerMLMap();
// Or with custom name
customElements.define('my-map', MLMap);Component usage:
<!-- External YAML file -->
<ml-map src="/map.yaml"></ml-map>
<!-- Inline YAML -->
<ml-map>
<script type="text/yaml">
type: map
config:
center: [0, 0]
zoom: 2
mapStyle: "https://..."
</script>
</ml-map>
<!-- JSON attribute -->
<ml-map config='{"type":"map",...}'></ml-map>Merge Strategies
| Strategy | Description |
|----------|-------------|
| replace | Replace all data on each update |
| merge | Update/add features by unique key |
| append-window | Append with size/time-based windowing |
refresh:
updateStrategy: merge
updateKey: id
# OR for windowed appending
refresh:
updateStrategy: append-window
windowSize: 100
windowDuration: 300000
timestampField: timestampLayer Types
circle- Point data as circlesline- Linear featuresfill- Polygon fillsfill-extrusion- 3D buildings/polygonssymbol- Icons and text labelsheatmap- Density visualizationhillshade- Terrain shadingraster- Raster tilesbackground- Map background
Browser Support
- Modern browsers with ES2022 support
- Native
fetch,EventSource, andWebSocketAPIs
Related Packages
@maplibre-yaml/astro- Astro component integration@maplibre-yaml/cli- CLI for YAML validation
License
MIT
