
Map Generator
- 13 installs
- 2 repo stars
- Updated August 1, 2026
- vishalsachdev/claude-skills
Helps with ai & agent building tasks.
About
map-generator is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- map-generator
- AI & Agent Building
- AI-coding skill
Map Generator by the numbers
- 13 all-time installs (skills.sh)
- +1 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #11,355 of 16,556 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/vishalsachdev/claude-skills --skill map-generatorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 13 |
|---|---|
| repo stars | ★ 2 |
| Last updated | August 1, 2026 |
| Repository | vishalsachdev/claude-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Map Generator Skill
This skill creates interactive Leaflet maps as MicroSims for intelligent textbooks built with MkDocs Material theme.
When to Use This Skill
Use this skill when users request:
- Geographic visualizations (regions, countries, cities)
- Location-based data displays (historical sites, landmarks)
- Campus or facility maps
- Travel route visualizations
- Custom maps with markers, layers, or highlighted borders
- Educational geography content
Workflow
Step 1: Gather Map Requirements
Ask the user for the following information:
1. Map Purpose: What geographic data are we visualizing? 2. Geographic Region: Region name, country, city, or coordinates 3. Markers/Points: What locations need markers? (names, coordinates, descriptions) 4. Map Layers: Do you need multiple layers (satellite, terrain, street map)? 5. Borders/Regions: Do any borders or regions need to be highlighted? 6. Zoom Level: Initial zoom level (1-18, where 1 is world view, 18 is building level) 7. Interactive Features: Popups, custom markers, layer controls? 8. Educational Context: Related concepts, Bloom's taxonomy level, target audience
Example user input: "Create a map showing major universities in California with markers for each campus"
Step 2: Create Directory Structure
Create the MicroSim directory:
docs/sims/[map-name]/Naming convention: Use kebab-case (e.g., california-universities, ancient-rome-map, world-capitals)
Step 3: Create map-data.json (Optional)
If the map includes markers or GeoJSON data, create a map-data.json file:
{
"center": {
"lat": 37.7749,
"lng": -122.4194
},
"zoom": 10,
"title": "Map Title",
"subtitle": "Map Subtitle",
"markers": [
{
"lat": 37.7749,
"lng": -122.4194,
"title": "Location Name",
"description": "Location description",
"category": "category-name"
}
]
}For borders/regions: Use GeoJSON format for complex geometries.
Step 4: Create main.html
Create main.html using the template from assets/template-iframe-main.html:
Key elements:
- Leaflet CDN links (CSS and JS)
- Map container div with id="map"
- Optional controls section for layer toggles
- Script reference to script.js
- Minimal padding/margins for iframe embedding
Replace placeholders:
{{TITLE}}- Map title{{SUBTITLE}}- Map subtitle{{MAP_HEIGHT}}- Map container height (default: 400px)
Step 5: Create style.css
Create style.css using the template from assets/template-iframe-style.css:
Critical requirements for iframe embedding:
body { margin: 0; padding: 0; }- No body margins- Minimal margins throughout (2px max for headings)
- Fixed height for #map container
- Responsive breakpoints for mobile
- aliceblue background (repository standard)
Customization options:
- Map height (adjust based on content needs)
- Control button styling
- Marker popup styling
Step 6: Create script.js
Create script.js using the template from assets/template-script.js:
Core functionality:
1. Initialize Leaflet map with center coordinates and zoom level 2. Add tile layer (OpenStreetMap default, or custom) 3. Add markers with popups 4. Optional: Add GeoJSON layers for borders/regions 5. Optional: Add layer controls for toggling map types
Replace placeholders:
{{CENTER_LAT}},{{CENTER_LNG}}- Map center coordinates{{ZOOM}}- Initial zoom level{{MARKERS}}- Marker data array{{TILE_LAYER}}- Tile layer URL (OpenStreetMap, satellite, etc.)
Common tile layers:
- OpenStreetMap:
https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png - Satellite:
https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x} - Terrain:
https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png
Step 7: Create index.md
Create index.md using the template from assets/template-index.md:
Structure:
- Title and overview
- iframe embed (width="100%", height="700", frameborder="0")
- Link to fullscreen view
- Features section (interactive elements)
- Customization guide (how to modify the map)
- Technical details (library version, dependencies)
- Use cases
- References
iframe embed format:
<iframe src="main.html" width="100%" height="700" frameborder="0"></iframe>
[View Fullscreen](main.html){:target="_blank"}Step 8: Create metadata.json
Create metadata.json using the template from assets/template-metadata.json:
Dublin Core fields:
- title, description, subject, creator, date, type, format, language
- coverage, rights, audience
Map-specific fields:
map_type: "interactive", "choropleth", "route", etc.center_lat,center_lng: Center coordinateszoom_level: Initial zoom levelmarker_count: Number of markersconcepts: Array of related conceptsbloom_taxonomy: Cognitive level (Remember, Understand, Apply, etc.)
Step 9: Update mkdocs.yml Navigation
Add the new map to the navigation in mkdocs.yml:
nav:
- MicroSims:
- Introduction: sims/index.md
- [Map Name]: sims/[map-name]/index.mdNaming: Use Title Case for navigation labels
Step 10: Test and Validate
Perform these validation steps:
1. Direct HTML test: Open docs/sims/[map-name]/main.html in browser
- Verify map loads correctly
- Test zoom and pan controls
- Click markers to verify popups
- Test responsive behavior (resize window)
2. MkDocs test: Run mkdocs serve and navigate to the map page
- Verify iframe embedding works
- Check margins/padding (should be minimal)
- Test fullscreen link
- Verify navigation link works
3. Browser compatibility: Test in Chrome, Firefox, Safari
4. Mobile test: Verify responsive behavior on mobile devices
Common Map Patterns
Simple Marker Map
Basic map with multiple markers:
const markers = [
{ lat: 40.7128, lng: -74.0060, title: "New York", description: "The Big Apple" },
{ lat: 34.0522, lng: -118.2437, title: "Los Angeles", description: "City of Angels" }
];
markers.forEach(marker => {
L.marker([marker.lat, marker.lng])
.bindPopup(`<b>${marker.title}</b><br>${marker.description}`)
.addTo(map);
});Highlighted Region (GeoJSON)
Show a highlighted border or region:
const region = {
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[...]]
}
};
L.geoJSON(region, {
style: { color: 'red', weight: 3, fillOpacity: 0.2 }
}).addTo(map);Layer Controls
Toggle between map types:
const street = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png');
const satellite = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}');
const baseMaps = {
"Street": street,
"Satellite": satellite
};
L.control.layers(baseMaps).addTo(map);
street.addTo(map); // Default layerCustom Marker Icons
Use custom icons for different categories:
const universityIcon = L.icon({
iconUrl: 'university-icon.png',
iconSize: [32, 32],
iconAnchor: [16, 32],
popupAnchor: [0, -32]
});
L.marker([lat, lng], { icon: universityIcon }).addTo(map);Educational Considerations
Bloom's Taxonomy Alignment
- Remember: Identify locations on a map
- Understand: Explain geographic relationships
- Apply: Use maps for problem-solving (routes, distances)
- Analyze: Compare geographic patterns
- Evaluate: Assess geographic data quality
- Create: Design custom maps for specific purposes
Accessibility
- Ensure marker popups have descriptive text
- Provide text alternatives for visual information
- Use high-contrast colors for highlighted regions
- Include keyboard navigation support
Performance
- Limit markers to <100 for optimal performance
- Use marker clustering for large datasets:
const markers = L.markerClusterGroup();
markers.addLayer(L.marker([lat, lng]));
map.addLayer(markers);Troubleshooting
Map not displaying
- Check that Leaflet CDN links are correct
- Verify
#mapdiv has a fixed height in CSS - Ensure coordinates are in decimal format (not DMS)
Markers not appearing
- Verify latitude/longitude order (lat first, lng second)
- Check that coordinates are within valid ranges (-90 to 90 lat, -180 to 180 lng)
- Ensure markers are added after map initialization
Iframe not fitting properly
- Verify
body { margin: 0; padding: 0; }in CSS - Check iframe height in index.md (adjust if needed)
- Ensure container has minimal margins
References
Version History
- v1.0 (2025-01-16): Initial release with basic marker maps, layer controls, and GeoJSON support
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{TITLE}}</title>
<link rel="stylesheet" href="style.css">
<!-- Leaflet CSS -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
crossorigin=""/>
<!-- Leaflet JavaScript -->
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
crossorigin=""></script>
</head>
<body>
<div class="container">
<h1>{{TITLE}}</h1>
<p class="subtitle">{{SUBTITLE}}</p>
<!-- Map container - MUST have a fixed height -->
<div id="map"></div>
<!-- Optional: Controls for layer toggles, etc. -->
<div class="controls">
<!-- Add control buttons here if needed -->
</div>
</div>
<!-- Map initialization script -->
<script src="script.js"></script>
</body>
</html>
/*
* Leaflet Map Styles
* Designed for iframe embedding with minimal padding and margins
* Target: <iframe src="main.html" height="700pt" width="100%" scrolling="no"></iframe>
* Optimized for narrow MkDocs pages with navbar (left) and TOC (right)
*/
/* Critical: Remove all body margins for iframe embedding */
body {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica', 'Arial', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* Container with minimal margins */
.container {
max-width: 1200px;
margin: 0 auto;
padding: 5px;
background: aliceblue;
border: solid blue 2px;
}
/* Title with minimal spacing */
h1 {
text-align: center;
color: black;
margin-top: 5px;
margin-bottom: 2px; /* MINIMAL MARGIN */
font-size: 1.5em;
font-weight: 600;
}
/* Subtitle with minimal spacing */
.subtitle {
text-align: center;
color: #333;
margin-top: 0;
margin-bottom: 5px; /* MINIMAL MARGIN */
font-size: 0.9em;
font-style: italic;
}
/* Map container - MUST have fixed height for Leaflet */
#map {
height: 400px;
width: 100%;
border: 1px solid #ddd;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
/* Controls section (for layer toggles, buttons, etc.) */
.controls {
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
margin-top: 10px;
margin-bottom: 5px; /* MINIMAL MARGIN */
flex-wrap: wrap;
}
.controls button {
padding: 8px 16px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: background-color 0.3s;
}
.controls button:hover {
background-color: #45a049;
}
.controls button:active {
background-color: #3d8b40;
}
.controls button.active {
background-color: #2196F3;
}
/* Leaflet popup customization */
.leaflet-popup-content-wrapper {
border-radius: 8px;
padding: 0;
}
.leaflet-popup-content {
margin: 12px;
font-size: 14px;
line-height: 1.5;
}
.leaflet-popup-content h3 {
margin: 0 0 8px 0;
font-size: 16px;
color: #2196F3;
}
.leaflet-popup-content p {
margin: 4px 0;
}
/* Custom marker icon styles (if using custom markers) */
.custom-marker {
background-color: #2196F3;
border: 2px solid white;
border-radius: 50%;
width: 20px;
height: 20px;
}
/* Responsive design for mobile devices */
@media (max-width: 768px) {
.container {
padding: 3px;
}
h1 {
font-size: 1.2em;
margin-top: 3px;
margin-bottom: 2px;
}
.subtitle {
font-size: 0.8em;
margin-bottom: 3px;
}
#map {
height: 300px;
}
.controls {
margin-top: 8px;
margin-bottom: 3px;
}
.controls button {
padding: 6px 12px;
font-size: 12px;
}
}
/* Extra small devices */
@media (max-width: 480px) {
.container {
padding: 2px;
}
h1 {
font-size: 1em;
margin-top: 2px;
margin-bottom: 1px;
}
.subtitle {
font-size: 0.75em;
margin-bottom: 2px;
}
#map {
height: 250px;
}
.controls {
gap: 5px;
margin-top: 5px;
margin-bottom: 2px;
}
.controls button {
padding: 5px 10px;
font-size: 11px;
}
}
{{TITLE}}
{{DESCRIPTION}}
Interactive Map
<iframe src="main.html" width="100%" height="700" frameborder="0"></iframe>
View Fullscreen{:target="_blank"}
Overview
{{OVERVIEW_TEXT}}
Features
Interactive Elements
- Zoom and Pan - Use mouse wheel or touch gestures to zoom, click and drag to pan
- Marker Popups - Click on markers to view detailed information
- Layer Controls - Toggle between different map views (street, satellite, terrain)
- Reset View - Return to the initial map position and zoom level
Visual Design
- Color-coded markers for different categories
- Clear, informative popups with titles and descriptions
- Responsive layout that adapts to different screen sizes
- Minimal padding optimized for textbook integration
Map Details
Center Coordinates: {{CENTER_LAT}}, {{CENTER_LNG}}
Initial Zoom Level: {{ZOOM}}
Number of Markers: {{MARKER_COUNT}}
Base Map: {{BASE_MAP_TYPE}}
Customization Guide
This map can be customized by editing the files in the sims/{{MAP_NAME}}/ directory.
Adding Markers
To add new markers, edit the markers array in script.js:
const markers = [
{
lat: 40.7128,
lng: -74.0060,
title: "New York City",
description: "The largest city in the United States",
link: "https://en.wikipedia.org/wiki/New_York_City"
},
// Add more markers here
];Fields:
lat- Latitude (-90 to 90)lng- Longitude (-180 to 180)title- Marker title (shown in popup)description- Detailed description (optional)link- External link for more information (optional)
Changing the Base Map
Modify the tile layer URL in script.js:
OpenStreetMap (default):
const tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
});Satellite Imagery:
const tileLayer = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
attribution: '© Esri'
});Terrain Map:
const tileLayer = L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', {
attribution: '© OpenTopoMap contributors'
});Adjusting Map Height
Edit style.css to change the map container height:
#map {
height: 500px; /* Change this value */
width: 100%;
}Also update the iframe height in this index.md file to match.
Custom Marker Icons
Replace the default marker icons by adding custom icons in script.js:
const customIcon = L.icon({
iconUrl: 'custom-marker.png',
iconSize: [32, 32],
iconAnchor: [16, 32],
popupAnchor: [0, -32]
});
L.marker([lat, lng], { icon: customIcon }).addTo(map);Adding GeoJSON Layers
To highlight regions or borders, add GeoJSON data:
const regionData = {
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[...]]
},
"properties": {
"name": "Region Name"
}
};
L.geoJSON(regionData, {
style: { color: 'red', weight: 3, fillOpacity: 0.2 }
}).addTo(map);Technical Details
- Library: Leaflet 1.9.4
- CDN: unpkg.com (with SRI integrity checks)
- Browser Compatibility: All modern browsers (Chrome, Firefox, Safari, Edge)
- Dependencies: Leaflet CSS and JavaScript (loaded from CDN)
- Responsive: Yes - adapts to mobile, tablet, and desktop screens
- Performance: Optimized for up to 100 markers (use clustering for more)
Educational Applications
This map pattern can be adapted for various educational contexts:
Geography and History
- Historical event locations and timelines
- Ancient civilization sites
- Exploration routes and trade networks
- Geographic feature identification
Science
- Biodiversity hotspots
- Climate zones and weather patterns
- Geological formations
- Ecological regions
Social Studies
- Cultural landmarks
- Population centers
- Economic activity zones
- Political boundaries
Campus and Facility Maps
- University campus buildings
- Museum floor plans
- Park trails and facilities
- City infrastructure
Bloom's Taxonomy Alignment
This map supports multiple cognitive levels:
- Remember: Identify and locate specific places on the map
- Understand: Explain spatial relationships between locations
- Apply: Use the map to solve problems (distances, routes)
- Analyze: Compare and contrast geographic patterns
- Evaluate: Assess the significance of location-based data
- Create: Design custom maps for specific educational purposes
Accessibility Considerations
- All markers include descriptive text in popups
- Keyboard navigation supported through Leaflet controls
- High-contrast colors used for visibility
- Text alternatives provided for geographic information
References
- Leaflet Official Documentation - Complete API reference
- Leaflet Tutorials - Step-by-step guides
- OpenStreetMap Tile Usage Policy - Terms of service
- GeoJSON Format Specification - Standard for geographic data
- Map Projections - Understanding coordinate systems
Version History
- v1.0 ({{DATE}}): Initial map created with {{MARKER_COUNT}} markers
---
Generated using the map-generator skill for intelligent textbooks
{
"title": "{{TITLE}}",
"description": "{{DESCRIPTION}}",
"subject": "{{SUBJECT}}",
"creator": "Claude AI with Map Generator Skill",
"date": "{{DATE}}",
"type": "Interactive Map Visualization",
"format": "text/html",
"language": "en-US",
"coverage": "{{COVERAGE}}",
"rights": "Educational Use",
"audience": "{{AUDIENCE}}",
"map_type": "{{MAP_TYPE}}",
"center_lat": "{{CENTER_LAT}}",
"center_lng": "{{CENTER_LNG}}",
"zoom_level": {{ZOOM}},
"marker_count": {{MARKER_COUNT}},
"base_map": "{{BASE_MAP}}",
"has_layers": {{HAS_LAYERS}},
"has_geojson": {{HAS_GEOJSON}},
"concepts": [
{{CONCEPTS_LIST}}
],
"bloom_taxonomy": "{{BLOOM_LEVEL}}",
"difficulty": "{{DIFFICULTY}}",
"prerequisites": [
{{PREREQUISITES}}
],
"learning_objectives": [
{{LEARNING_OBJECTIVES}}
],
"tags": [
{{TAGS}}
],
"version": "1.0",
"library": "Leaflet",
"library_version": "1.9.4"
}
/**
* Leaflet Map Script Template
* Replace placeholders with actual values when generating a map
*/
// Map configuration
const mapConfig = {
center: [{{CENTER_LAT}}, {{CENTER_LNG}}], // [latitude, longitude]
zoom: {{ZOOM}}, // Zoom level (1-18)
minZoom: 2,
maxZoom: 18
};
// Initialize the map
const map = L.map('map', {
center: mapConfig.center,
zoom: mapConfig.zoom,
minZoom: mapConfig.minZoom,
maxZoom: mapConfig.maxZoom,
zoomControl: true,
scrollWheelZoom: true
});
// Add tile layer (base map)
// Options: OpenStreetMap, Satellite, Terrain
const tileLayer = L.tileLayer('{{TILE_LAYER_URL}}', {
attribution: '{{ATTRIBUTION}}',
maxZoom: 18,
tileSize: 256
}).addTo(map);
// ===== MARKERS =====
// Define markers with popups
const markers = {{MARKERS_JSON}};
// Add markers to the map
markers.forEach(markerData => {
const marker = L.marker([markerData.lat, markerData.lng]);
// Create popup content
let popupContent = `<h3>${markerData.title}</h3>`;
if (markerData.description) {
popupContent += `<p>${markerData.description}</p>`;
}
if (markerData.link) {
popupContent += `<p><a href="${markerData.link}" target="_blank">Learn more</a></p>`;
}
marker.bindPopup(popupContent);
marker.addTo(map);
});
// ===== OPTIONAL: CUSTOM MARKER ICONS =====
// Uncomment and modify to use custom icons
/*
const customIcon = L.icon({
iconUrl: 'marker-icon.png',
iconSize: [32, 32],
iconAnchor: [16, 32],
popupAnchor: [0, -32]
});
L.marker([lat, lng], { icon: customIcon }).addTo(map);
*/
// ===== OPTIONAL: GEOJSON LAYERS =====
// Uncomment to add GeoJSON polygons (borders, regions, etc.)
/*
const geoJsonData = {{GEOJSON_DATA}};
L.geoJSON(geoJsonData, {
style: {
color: '#ff0000',
weight: 3,
opacity: 0.8,
fillOpacity: 0.2
},
onEachFeature: function(feature, layer) {
if (feature.properties && feature.properties.name) {
layer.bindPopup(`<h3>${feature.properties.name}</h3>`);
}
}
}).addTo(map);
*/
// ===== OPTIONAL: LAYER CONTROLS =====
// Uncomment to add multiple base layers with toggle controls
/*
const streetMap = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
});
const satelliteMap = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
attribution: '© Esri'
});
const terrainMap = L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', {
attribution: '© OpenTopoMap contributors'
});
const baseMaps = {
"Street": streetMap,
"Satellite": satelliteMap,
"Terrain": terrainMap
};
// Add the first layer by default
streetMap.addTo(map);
// Add layer control
L.control.layers(baseMaps).addTo(map);
*/
// ===== OPTIONAL: MARKER CLUSTERING =====
// For maps with many markers, use clustering for better performance
// Requires: https://unpkg.com/leaflet.markercluster/dist/leaflet.markercluster.js
/*
const markerCluster = L.markerClusterGroup();
markers.forEach(markerData => {
const marker = L.marker([markerData.lat, markerData.lng]);
marker.bindPopup(`<b>${markerData.title}</b><br>${markerData.description}`);
markerCluster.addLayer(marker);
});
map.addLayer(markerCluster);
*/
// ===== OPTIONAL: CUSTOM CONTROLS =====
// Add custom buttons for user interactions
/*
function addCustomControl(label, onClick) {
const button = document.createElement('button');
button.textContent = label;
button.onclick = onClick;
document.querySelector('.controls').appendChild(button);
}
// Example: Add a "Reset View" button
addCustomControl('Reset View', function() {
map.setView(mapConfig.center, mapConfig.zoom);
});
// Example: Add a "Toggle Markers" button
let markersVisible = true;
addCustomControl('Toggle Markers', function() {
if (markersVisible) {
map.eachLayer(layer => {
if (layer instanceof L.Marker) {
map.removeLayer(layer);
}
});
markersVisible = false;
} else {
markers.forEach(markerData => {
L.marker([markerData.lat, markerData.lng])
.bindPopup(`<b>${markerData.title}</b><br>${markerData.description}`)
.addTo(map);
});
markersVisible = true;
}
});
*/
// ===== OPTIONAL: FIT BOUNDS =====
// Automatically adjust zoom to fit all markers
/*
if (markers.length > 0) {
const bounds = L.latLngBounds(markers.map(m => [m.lat, m.lng]));
map.fitBounds(bounds, { padding: [50, 50] });
}
*/
// ===== EVENT LISTENERS =====
// Add custom event handlers
/*
map.on('click', function(e) {
console.log('Map clicked at:', e.latlng);
});
map.on('zoomend', function() {
console.log('Current zoom level:', map.getZoom());
});
*/