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:
- Map Purpose: What geographic data are we visualizing?
- Geographic Region: Region name, country, city, or coordinates
- Markers/Points: What locations need markers? (names, coordinates, descriptions)
- Map Layers: Do you need multiple layers (satellite, terrain, street map)?
- Borders/Regions: Do any borders or regions need to be highlighted?
- Zoom Level: Initial zoom level (1-18, where 1 is world view, 18 is building level)
- Interactive Features: Popups, custom markers, layer controls?
- 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:
- Initialize Leaflet map with center coordinates and zoom level
- Add tile layer (OpenStreetMap default, or custom)
- Add markers with popups
- Optional: Add GeoJSON layers for borders/regions
- 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.md
Naming: Use Title Case for navigation labels
Step 10: Test and Validate
Perform these validation steps:
-
Direct HTML test: Open
docs/sims/[map-name]/main.htmlin browser- Verify map loads correctly
- Test zoom and pan controls
- Click markers to verify popups
- Test responsive behavior (resize window)
-
MkDocs test: Run
mkdocs serveand navigate to the map page- Verify iframe embedding works
- Check margins/padding (should be minimal)
- Test fullscreen link
- Verify navigation link works
-
Browser compatibility: Test in Chrome, Firefox, Safari
-
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 layer
Custom 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
- Leaflet Documentation
- Leaflet Tutorials
- OpenStreetMap Tile Usage Policy
- GeoJSON Format Specification
Version History
- v1.0 (2025-01-16): Initial release with basic marker maps, layer controls, and GeoJSON support