preview-leaflet
npx skills add https://github.com/veelenga/preview-skills --skill preview-leaflet
Agent 安装分布
Skill 文档
Preview Leaflet Skill
Interactive map visualization viewer using Leaflet library for geographic data, markers, routes, and custom overlays.
Agent Usage
When the user asks to create a map visualization, write the Leaflet code and pipe it to the script. Use the Bash tool to execute this skill’s run.sh script:
# Pipe Leaflet code
cat route.js | ./run.sh
# Or from a file
./run.sh city-map.leaflet
The script handles all HTML generation and automatically opens the result in the browser. Do NOT open the file manually to avoid duplicate tabs.
Usage
# Preview a Leaflet map file
/preview-leaflet city-map.leaflet
# Or use .map extension
/preview-leaflet route.map
# Pipe Leaflet code (preferred for temporary content)
cat route.js | /preview-leaflet
echo "const map = L.map('map').setView([51.505, -0.09], 13);" | /preview-leaflet
Best Practice: For temporary or generated maps, prefer piping over creating temporary files. This avoids cluttering your filesystem and the content is automatically cleaned up.
Options
The script works with sensible defaults but supports these flags for flexibility:
-o, --output PATH– Custom output path--no-browser– Skip browser, output file path only
Features
- Interactive maps with pan and zoom
- Markers and popups for locations
- Routes and paths with polylines
- Shapes and areas with polygons and circles
- Multiple tile layers (OpenStreetMap, CartoDB, etc.)
- Tooltips on hover
- Fit bounds to show all points
- Reset view button
- Code viewer toggle
- Responsive design adapts to window size
When to Use This Skill
Use this skill when the user wants to:
- Visualize geographic data on maps
- Plot locations with markers
- Draw routes between points
- Show service areas or regions
- Create interactive location-based visualizations
Leaflet Code Requirements
Your code should:
- Initialize the map with
L.map('map').setView([lat, lng], zoom) - Add a tile layer (provides map imagery)
- Add markers, paths, or other features
Execution Context
Your code runs with:
- Leaflet v1.9.4 available as
L - Map container
#mapsized and ready in DOM
Complete Example – Simple Map with Marker
// Initialize map centered on London
const map = L.map('map').setView([51.505, -0.09], 13);
// Add OpenStreetMap tiles (REQUIRED - map is blank without this)
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors',
maxZoom: 18,
}).addTo(map);
// Add a marker
L.marker([51.505, -0.09]).addTo(map).bindPopup('Hello World!').openPopup();
Complete Example – Route with Multiple Points
// Initialize map
const map = L.map('map').setView([40.7128, -74.006], 12);
// Add tiles (REQUIRED)
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors',
maxZoom: 18,
}).addTo(map);
// Define route points
const route = [
[40.7128, -74.006], // New York
[40.758, -73.9855], // Times Square
[40.7614, -73.9776], // Central Park
];
// Draw route
L.polyline(route, {
color: 'red',
weight: 3,
}).addTo(map);
// Add markers
route.forEach((point, i) => {
L.marker(point)
.addTo(map)
.bindPopup(`Stop ${i + 1}`);
});
// Fit map to show all points
map.fitBounds(L.latLngBounds(route), { padding: [50, 50] });
Common Patterns
Markers
// Simple marker
L.marker([51.5, -0.09]).addTo(map);
// With popup
L.marker([51.5, -0.09]).addTo(map).bindPopup('Location name');
// Circle marker (fixed pixel size)
L.circleMarker([51.5, -0.09], {
radius: 8,
fillColor: '#3498db',
color: 'white',
weight: 2,
fillOpacity: 0.9,
}).addTo(map);
Lines and Shapes
// Polyline (route/path)
L.polyline(
[
[51.5, -0.09],
[51.51, -0.08],
[51.52, -0.07],
],
{
color: 'red',
weight: 3,
}
).addTo(map);
// Polygon (area)
L.polygon(
[
[51.5, -0.09],
[51.51, -0.08],
[51.52, -0.09],
],
{
color: 'blue',
fillOpacity: 0.5,
}
).addTo(map);
// Circle (fixed radius in meters)
L.circle([51.5, -0.09], {
radius: 500, // meters
color: 'red',
fillOpacity: 0.5,
}).addTo(map);
Popups and Tooltips
// HTML in popup
marker.bindPopup(`
<div>
<h3>Location Name</h3>
<p>Description here</p>
</div>
`);
// Tooltip (shows on hover)
marker.bindTooltip('Tooltip text', {
permanent: false,
direction: 'top',
});
// Permanent tooltip (always visible)
marker.bindTooltip('Always visible', {
permanent: true,
direction: 'right',
});
View Control
// Set view (instant)
map.setView([51.5, -0.09], 13);
// Fly to (animated)
map.flyTo([51.5, -0.09], 13, {
duration: 2, // seconds
});
// Fit bounds to show all features
const bounds = L.latLngBounds([
[51.49, -0.1],
[51.51, -0.08],
]);
map.fitBounds(bounds, {
padding: [50, 50],
});
Tile Layers (Map Styles)
OpenStreetMap (free, default)
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors',
maxZoom: 18,
}).addTo(map);
CartoDB Light (clean, minimal)
L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap, © CartoDB',
maxZoom: 18,
}).addTo(map);
CartoDB Dark
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap, © CartoDB',
maxZoom: 18,
}).addTo(map);
Complete Example – Multiple Locations
// Initialize map
const map = L.map('map').setView([37.7749, -122.4194], 10);
// Add tiles
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors',
}).addTo(map);
// Locations data
const locations = [
{ name: 'San Francisco', coords: [37.7749, -122.4194], type: 'city' },
{ name: 'Oakland', coords: [37.8044, -122.2712], type: 'city' },
{ name: 'Berkeley', coords: [37.8715, -122.273], type: 'city' },
];
// Add markers
locations.forEach((loc) => {
const color = loc.type === 'city' ? 'blue' : 'red';
L.circleMarker(loc.coords, {
radius: 8,
fillColor: color,
color: 'white',
weight: 2,
fillOpacity: 0.8,
})
.addTo(map)
.bindPopup(`<strong>${loc.name}</strong><br/>Type: ${loc.type}`);
});
// Fit map to show all locations
const allCoords = locations.map((loc) => loc.coords);
map.fitBounds(L.latLngBounds(allCoords), { padding: [50, 50] });
Coordinate Format
Leaflet uses [latitude, longitude] format:
- Latitude: -90 to 90 (South to North)
- Longitude: -180 to 180 (West to East)
Examples:
- New York:
[40.7128, -74.0060] - London:
[51.5074, -0.1278] - Tokyo:
[35.6762, 139.6503] - Sydney:
[-33.8688, 151.2093]
Common mistake: Reversing coordinates to [lng, lat] – always use [lat, lng]!
Built-in Features
- Pan/zoom – Click and drag to pan, scroll to zoom
- Zoom buttons – +/- controls in top-left
- Reset view – Button to restore initial view
- Code viewer – Toggle to show/hide source
- Responsive – Automatically resizes with window
Zoom Levels
- 1: World view
- 5: Continent
- 10: City
- 15: Streets
- 18: Buildings
Best Practices
- Always add tile layer – Map is blank without it
- Use appropriate zoom – 1 (world) to 18 (street level)
- Use fitBounds() for multi-point maps – Shows all features
- Embed data in code – Include coordinates directly
- Verify coordinate order –
[lat, lng]not[lng, lat]
Troubleshooting
Map appears blank/gray
- Ensure tile layer is added with
.addTo(map) - Check coordinates are valid (
[lat, lng]format) - Verify internet connection (tiles load from CDN)
- Check browser console for 404 errors on tiles
Markers don’t appear
- Check coordinate format:
[latitude, longitude] - Ensure
.addTo(map)is called on marker - Verify coordinates are in current view
- Try using fitBounds() to see all markers
Tiles don’t load
- Check internet connection
- Verify tile URL is correct
- Look for 404 errors in browser console
- Try a different tile provider
Wrong location shown
- Verify coordinates are correct
- Check coordinate order (lat first, lng second)
- Ensure zoom level is appropriate
Technical Details
File Requirements
- File extension:
.leaflet - Maximum size: 10MB (configurable)
- Valid JavaScript code
- Self-contained (no external data files)
Browser Compatibility
- Modern browsers (Chrome, Firefox, Safari, Edge)
- Requires JavaScript enabled
- Requires internet connection for tiles
- CDN-dependent: Leaflet v1.9.4
Output
The skill generates a standalone HTML file at:
/tmp/preview-skills/preview-leaflet-{filename}.html
Development
This skill is standalone and includes all dependencies:
- Shared libraries bundled in
lib/ - Templates bundled in
templates/ - External CDN dependencies: Leaflet v1.9.4
To modify the skill:
- Edit
config.shfor configuration - Edit
templates/scripts/leaflet-renderer.jsfor behavior - Edit
templates/styles/leaflet.cssfor styling - Run
run.shto test changes
Learn More
- Leaflet Documentation: https://leafletjs.com/
- Leaflet Tutorials: https://leafletjs.com/examples.html
- Tile Providers: https://leaflet-extras.github.io/leaflet-providers/preview/