diff --git a/skills/README.md b/skills/README.md index a368976..51b4c49 100644 --- a/skills/README.md +++ b/skills/README.md @@ -1,115 +1,51 @@ # Mapbox Agent Skills -This directory contains [Agent Skills](https://agentskills.io) that provide domain expertise and best practices for building maps with Mapbox. These skills complement the MCP server by teaching AI assistants how to make better decisions about map design, security, and implementation patterns. +> **Note:** Mapbox Agent Skills have moved to a dedicated repository for better maintenance and discoverability. -## What are Agent Skills? +## π¦ Install Skills from the Official Repository -Agent Skills are folders containing instructions, scripts, and resources that AI agents can discover and use to perform tasks more effectively. Unlike MCP tools (which provide actions) or prompts (which provide workflows), skills provide **domain expertise** - the "know-how" that helps agents make informed decisions. +All Mapbox Agent Skills are now maintained in the official **[mapbox-agent-skills](https://github.com/mapbox/mapbox-agent-skills)** repository. -Think of skills as giving Claude a specialized education in cartography, security, and Mapbox development best practices. +### Quick Install -## Available Skills - -### π¨ mapbox-cartography - -**Expert guidance on map design principles, color theory, visual hierarchy, typography, and cartographic best practices.** - -Use this skill when: - -- Designing a new map style -- Choosing colors for map elements -- Making decisions about visual hierarchy -- Optimizing for specific use cases -- Ensuring accessibility -- Creating themed maps (dark mode, vintage, etc.) - -**Key topics:** - -- Core cartographic principles (visual hierarchy, color theory) -- Typography best practices for maps -- Map context considerations (audience, platform, use case) -- Zoom level strategies -- Color palette templates -- Common mapping scenarios (restaurant finders, real estate, etc.) - -[View skill β](./mapbox-cartography/SKILL.md) - -### π mapbox-token-security - -**Security best practices for Mapbox access tokens, including scope management, URL restrictions, and rotation strategies.** - -Use this skill when: - -- Creating new tokens -- Deciding between public vs secret tokens -- Setting up token restrictions -- Implementing token rotation -- Investigating security incidents -- Conducting security audits - -**Key topics:** - -- Token types and when to use them (public, secret, temporary) -- Scope management (principle of least privilege) -- URL restrictions and patterns -- Token storage and handling -- Rotation strategies -- Monitoring and auditing -- Incident response plans - -[View skill β](./mapbox-token-security/SKILL.md) - -### π mapbox-style-patterns - -**Common style patterns, layer configurations, and recipes for typical mapping scenarios.** +```bash +# Install all Mapbox skills +npx add-skill mapbox/mapbox-agent-skills -Use this skill when: +# Install specific skills +npx add-skill mapbox/mapbox-agent-skills --skill mapbox-web-performance-patterns +npx add-skill mapbox/mapbox-agent-skills --skill mapbox-token-security +npx add-skill mapbox/mapbox-agent-skills --skill mapbox-cartography +``` -- Starting a new map style for a specific use case -- Looking for layer configuration examples -- Implementing common mapping patterns -- Optimizing existing styles -- Need proven recipes for typical scenarios +### Available Skills -**Key topics:** +The mapbox-agent-skills repository includes **10 comprehensive skills**: -- Restaurant/POI finder pattern -- Real estate map pattern -- Data visualization base map pattern -- Navigation/routing map pattern -- Dark mode / night theme pattern -- Layer optimization patterns -- Common modifications (3D buildings, terrain, custom markers) +**Migration & Platform:** -[View skill β](./mapbox-style-patterns/SKILL.md) +- `mapbox-google-maps-migration` - Migrate from Google Maps to Mapbox GL JS +- `mapbox-maplibre-migration` - Migrate from MapLibre GL JS to Mapbox -### π§ mapbox-integration-patterns +**Performance & Integration:** -**Official integration patterns for Mapbox GL JS across popular web frameworks including React, Vue, Svelte, Angular, and vanilla JavaScript.** +- `mapbox-web-performance-patterns` - Performance optimization for Mapbox GL JS +- `mapbox-web-integration-patterns` - Framework integration (React, Vue, Svelte, Angular, Next.js) -Use this skill when: +**Design & Styling:** -- Setting up Mapbox GL JS in a new project -- Integrating Mapbox into a specific framework -- Adding Mapbox Search functionality -- Implementing proper cleanup and lifecycle management -- Debugging map initialization issues -- Converting between frameworks -- Reviewing code for integration best practices +- `mapbox-cartography` - Map design principles and best practices +- `mapbox-style-patterns` - Common style patterns and layer configurations +- `mapbox-style-quality` - Style validation, accessibility, and testing -**Key topics:** +**Security:** -- Framework-specific patterns (React, Vue, Svelte, Angular, Next.js) -- Token management (environment variables across frameworks) -- Lifecycle management and cleanup (preventing memory leaks) -- Mapbox Search JS integration -- Common mistakes and how to avoid them -- SSR handling (Angular Universal, Next.js) -- Testing patterns for maps +- `mapbox-token-security` - Access token security and best practices -**Based on:** Mapbox's official `create-web-app` scaffolding tool +**Mobile:** -[View skill β](./mapbox-integration-patterns/SKILL.md) +- `mapbox-ios-patterns` - iOS integration with Swift, SwiftUI, UIKit +- `mapbox-android-patterns` - Android integration with Kotlin, Jetpack Compose ## How Skills Work with the MCP Server @@ -126,144 +62,32 @@ The Mapbox MCP DevKit Server and Agent Skills work together: ``` User: "Create a map for my restaurant finder app" -Without Skills: -Claude β Uses create_style_tool with basic styling - -With Skills: -Claude β -1. [mapbox-cartography skill] Understands restaurant maps need: - - High contrast for restaurant markers - - Muted background (food photos will overlay) - - Clear street labels for navigation - - Mobile-optimized design - -2. [mapbox-token-security skill] Knows to create public token with: - - Only styles:read scope (principle of least privilege) - - URL restrictions to app domain - -3. [mapbox-style-patterns skill] Applies POI Finder pattern: - - Desaturated base map - - Orange markers (#FF6B35) for visibility - - White roads on light gray background - -4. β Uses style_builder_tool with informed design decisions -5. β Uses create_style_tool with optimized configuration -6. β Uses create_token_tool with secure settings -7. β Uses preview_style_tool to generate shareable link -``` - -## Using Skills - -### With Claude Code - -Skills in this directory are automatically discovered by Claude Code when placed in: - -- Project-level: `.claude/skills/` (recommended for this repository) -- Global: `~/.claude/skills/` (available across all projects) - -To use these skills in Claude Code: - -```bash -# Option 1: Symlink from project root (recommended) -mkdir -p .claude -ln -s ../skills .claude/skills - -# Option 2: Copy to global skills directory -cp -r skills/* ~/.claude/skills/ +With MCP Server + Skills: +1. [mapbox-cartography skill] Understands restaurant map design principles +2. [mapbox-style-patterns skill] Applies POI Finder pattern +3. [mapbox-token-security skill] Knows secure token configuration +4. β Uses MCP tools (style_builder_tool, create_style_tool, etc.) +5. β Creates optimized, secure map ``` -For more information, see [Claude Code Skills documentation](https://code.claude.com/docs/en/skills). - -### With Claude API - -Upload skills via the Skills API: - -```bash -# Create a zip of the skill directory -cd skills/mapbox-cartography -zip -r mapbox-cartography.zip . - -# Upload via API -curl https://api.anthropic.com/v1/skills \ - -H "anthropic-version: 2025-08-25" \ - -H "x-api-key: $ANTHROPIC_API_KEY" \ - -H "anthropic-beta: skills-2025-10-02" \ - -F file=@mapbox-cartography.zip -``` +## Why Skills Moved to a Separate Repository -For more information, see [Claude API Skills guide](https://docs.anthropic.com/en/build-with-claude/skills-guide). +**Benefits:** -### With Claude.ai - -1. Go to Settings β Features -2. Upload skill as a zip file -3. Claude will automatically use the skill when relevant - -For more information, see [Using Skills in Claude](https://support.claude.com/en/articles/12512180-using-skills-in-claude). - -## Skill Structure - -Each skill follows the Agent Skills specification: - -``` -skill-name/ -βββ SKILL.md # Main skill file (required) -β βββ YAML frontmatter # name, description -β βββ Markdown content # Instructions and guidance -βββ [optional files] # Additional resources -``` - -**SKILL.md format:** - -```yaml ---- -name: skill-name -description: What the skill does and when to use it ---- -# Skill Name - -[Instructions and guidance for Claude to follow] -``` - -## Creating Custom Skills - -To create your own Mapbox-related skill: - -1. **Create a new directory** in `skills/` -2. **Create SKILL.md** with YAML frontmatter and instructions -3. **Add reference materials** (optional) -4. **Test with Claude Code** or upload to API -5. **Share with team** via git or Skills API - -**Guidelines:** - -- Keep instructions clear and actionable -- Provide concrete examples -- Include decision trees when applicable -- Reference official Mapbox documentation -- Test with real scenarios - -For more best practices, see [Agent Skills authoring guide](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices). - -## License - -These skills are provided under the same license as the Mapbox MCP DevKit Server (MIT License). +- β **Dedicated maintenance**: Skills can be updated independently +- β **Better discoverability**: Easier to find and install via `npx add-skill` +- β **Comprehensive collection**: 10 skills covering web, mobile, and migration +- β **Community contributions**: Easier for community to contribute new skills +- β **Versioning**: Skills can be versioned independently from MCP server ## Resources -- [Agent Skills Overview](https://agentskills.io) -- [Agent Skills Specification](https://github.com/anthropics/skills) -- [Claude Skills Documentation](https://docs.anthropic.com/en/agents-and-tools/agent-skills/overview) -- [Mapbox Documentation](https://docs.mapbox.com) -- [Mapbox Style Specification](https://docs.mapbox.com/style-spec/) - -## Contributing - -We welcome contributions of new skills or improvements to existing ones! Please: +- **[Mapbox Agent Skills Repository](https://github.com/mapbox/mapbox-agent-skills)** - Official skills repository +- [Agent Skills Overview](https://agentskills.io) - Learn about Agent Skills +- [Agent Skills Specification](https://github.com/anthropics/skills) - Technical specification +- [Mapbox Documentation](https://docs.mapbox.com) - Official Mapbox docs -1. Follow the existing skill structure -2. Test your skill thoroughly -3. Include clear examples -4. Submit a pull request with description +## Need Help? -For questions or suggestions, please open an issue. +- Skills-related issues: [mapbox-agent-skills issues](https://github.com/mapbox/mapbox-agent-skills/issues) +- MCP Server issues: [mcp-devkit-server issues](https://github.com/mapbox/mcp-devkit-server/issues) diff --git a/skills/mapbox-cartography/SKILL.md b/skills/mapbox-cartography/SKILL.md deleted file mode 100644 index 4b843e3..0000000 --- a/skills/mapbox-cartography/SKILL.md +++ /dev/null @@ -1,323 +0,0 @@ ---- -name: mapbox-cartography -description: Expert guidance on map design principles, color theory, visual hierarchy, typography, and cartographic best practices for creating effective and beautiful maps with Mapbox. Use when designing map styles, choosing colors, or making cartographic decisions. ---- - -# Mapbox Cartography Skill - -This skill provides expert cartographic knowledge to help you design effective, beautiful, and functional maps using Mapbox. - -## Core Cartographic Principles - -### Visual Hierarchy - -Maps must guide the viewer's attention to what matters most: - -- **Most important**: POIs, user location, route highlights -- **Secondary**: Major roads, city labels, landmarks -- **Tertiary**: Minor streets, administrative boundaries -- **Background**: Water, land use, terrain - -**Implementation:** - -- Use size, color intensity, and contrast to establish hierarchy -- Primary features: high contrast, larger symbols, bold colors -- Background features: low contrast, muted colors, smaller text - -### Color Theory for Maps - -**Color Harmony:** - -- **Analogous colors**: Use colors next to each other on color wheel (blue-green-teal) for cohesive designs -- **Complementary colors**: Use opposite colors (blue/orange, red/green) for high contrast emphasis -- **Monochromatic**: Single hue with varying saturation/brightness for elegant, minimal designs - -**Color Psychology:** - -- **Blue**: Water, trust, calm, professional (default for water bodies) -- **Green**: Parks, nature, growth, eco-friendly (vegetation, parks) -- **Red/Orange**: Urgent, important, dining (alerts, restaurants) -- **Yellow**: Caution, highlight, attention (warnings, selected items) -- **Gray**: Neutral, background, roads (infrastructure) - -**Accessibility:** - -- Ensure 4.5:1 contrast ratio for text (WCAG AA) -- Don't rely solely on color to convey information -- Test designs with colorblind simulators -- Avoid red/green combinations for critical distinctions - -### Typography Best Practices - -**Font Selection:** - -- **Sans-serif** (Roboto, Open Sans): Modern, clean, high legibility at small sizes - use for labels -- **Serif** (Noto Serif): Traditional, formal - use sparingly for titles or historic maps -- **Monospace**: Technical data, coordinates - -**Text Sizing:** - -``` -Place labels (cities, POIs): 11-14px -Street labels: 9-11px -Feature labels (parks): 10-12px -Map title: 16-20px -Attribution: 8-9px -``` - -**Label Placement:** - -- Point labels: Center or slightly offset (avoid overlap with symbol) -- Line labels: Follow line curve, repeat for long features -- Area labels: Center in polygon, sized appropriately -- Prioritize: Major features get labels first, minor features labeled if space allows - -### Map Context Considerations - -**Know Your Audience:** - -- **General public**: Simplify, use familiar patterns (Google/Apple style) -- **Technical users**: Include more detail, technical layers, data precision -- **Domain experts**: Show specialized data, use domain-specific symbology - -**Use Case Optimization:** - -- **Navigation**: Emphasize roads, clear hierarchy, route visibility -- **Data visualization**: Muted base map, let data stand out -- **Storytelling**: Guide viewer attention, establish mood with colors -- **Location selection**: Show POIs clearly, provide context -- **Analysis**: Include relevant layers, maintain clarity at different zooms - -**Platform Considerations:** - -- **Mobile**: Larger touch targets (44x44px minimum), simpler designs, readable at arm's length -- **Desktop**: Can include more detail, hover interactions, complex overlays -- **Print**: Higher contrast, larger text, consider CMYK color space -- **Outdoor/Bright**: Higher contrast, avoid subtle grays - -## Mapbox-Specific Guidance - -### Style Layer Best Practices - -**Layer Ordering (bottom to top):** - -1. Background (solid color or pattern) -2. Landuse (parks, residential, commercial) -3. Water bodies (oceans, lakes, rivers) -4. Terrain/hillshade (if using elevation) -5. Buildings (3D or 2D footprints) -6. Roads (highways β local streets) -7. Borders (country, state lines) -8. Labels (place names, street names) -9. POI symbols -10. User-generated content (routes, markers) - -### Zoom Level Strategy - -**Zoom 0-4** (World to Continent): - -- Major country boundaries -- Ocean and sea labels -- Capital cities only - -**Zoom 5-8** (Country to State): - -- State/province boundaries -- Major cities -- Major highways -- Large water bodies - -**Zoom 9-11** (Metro Area): - -- City boundaries -- Neighborhoods -- All highways and major roads -- Parks and landmarks - -**Zoom 12-15** (Neighborhood): - -- All streets -- Building footprints -- POIs (restaurants, shops) -- Street names - -**Zoom 16-22** (Street Level): - -- All detail -- House numbers -- Parking lots -- Fine-grained POIs - -### Color Palette Templates - -**Light Theme (Day/Professional):** - -```json -{ - "background": "#f5f5f5", - "water": "#a0c8f0", - "parks": "#d4e7c5", - "roads": "#ffffff", - "buildings": "#e0e0e0", - "text": "#333333" -} -``` - -**Dark Theme (Night Mode):** - -```json -{ - "background": "#1a1a1a", - "water": "#0d47a1", - "parks": "#2e7d32", - "roads": "#3a3a3a", - "buildings": "#2d2d2d", - "text": "#ffffff" -} -``` - -**High Contrast (Accessibility):** - -```json -{ - "background": "#000000", - "water": "#0066ff", - "parks": "#00ff00", - "roads": "#ffffff", - "buildings": "#808080", - "text": "#ffffff" -} -``` - -**Vintage/Retro:** - -```json -{ - "background": "#f4e8d0", - "water": "#b8d4d4", - "parks": "#c8d4a4", - "roads": "#d4c4a8", - "buildings": "#e4d4c4", - "text": "#4a3828" -} -``` - -## Common Mapping Scenarios - -### Scenario: Restaurant Finder App - -**Requirements:** - -- Restaurants must be highly visible -- Street context for navigation -- Muted background (food photos overlay) - -**Recommendations:** - -- Use bold, warm colors for restaurant markers (red, orange) -- Gray out background (low saturation) -- Keep street labels clear but not dominant -- High contrast for selected restaurant -- Mobile-optimized touch targets - -### Scenario: Real Estate Map - -**Requirements:** - -- Property boundaries clearly visible -- Neighborhood context -- Price differentiation - -**Recommendations:** - -- Use color scale for price ranges (green=affordable, red=expensive) -- Show parks and amenities prominently -- Include school zones if relevant -- Label neighborhoods clearly -- Show transit access - -### Scenario: Data Visualization Overlay - -**Requirements:** - -- Data layer is primary focus -- Base map provides context only -- Multiple data points may cluster - -**Recommendations:** - -- Monochromatic, low-contrast base map -- Use data-ink ratio principle (minimize non-data elements) -- Base map grayscale or single muted hue -- Remove unnecessary labels -- Consider using light base for dark data, vice versa - -### Scenario: Navigation/Routing - -**Requirements:** - -- Route must be unmissable -- Turn-by-turn clarity -- Current location always visible - -**Recommendations:** - -- Route in high-contrast color (blue or purple) -- Animate route line or use dashed pattern -- Large, clear turn indicators -- Dim unrelated features -- User location: pulsing blue dot -- Next turn: prominent arrow/icon - -## Performance Optimization - -**Style Performance:** - -- Minimize layer count (combine similar layers) -- Use expressions instead of multiple layers for variants -- Simplify complex geometries at lower zooms -- Use sprite sheets for repeated icons -- Leverage tileset simplification - -**Loading Speed:** - -- Preload critical zoom levels -- Use style optimization tools -- Minimize external resource calls -- Compress images in sprite sheets - -## Testing Your Design - -**Checklist:** - -- [ ] View at all relevant zoom levels -- [ ] Test in different lighting conditions -- [ ] Check on actual devices (mobile, desktop) -- [ ] Verify color accessibility (colorblind.org) -- [ ] Review with target users -- [ ] Test with real data density -- [ ] Check label collision/overlap -- [ ] Verify performance on slower devices - -## Common Mistakes to Avoid - -1. **Too many colors**: Stick to 5-7 main colors maximum -2. **Insufficient contrast**: Text must be readable -3. **Overcrowding**: Not everything needs a label -4. **Ignoring zoom levels**: Show appropriate detail for scale -5. **Poor label hierarchy**: Organize by importance -6. **Inconsistent styling**: Maintain visual consistency -7. **Neglecting performance**: Complex styles slow rendering -8. **Forgetting mobile**: Test on actual devices - -## When to Use This Skill - -Invoke this skill when: - -- Designing a new map style -- Choosing colors for map elements -- Making decisions about visual hierarchy -- Optimizing for specific use cases -- Troubleshooting visibility issues -- Ensuring accessibility -- Creating themed maps (dark mode, vintage, etc.) diff --git a/skills/mapbox-integration-patterns/SKILL.md b/skills/mapbox-integration-patterns/SKILL.md deleted file mode 100644 index 097512f..0000000 --- a/skills/mapbox-integration-patterns/SKILL.md +++ /dev/null @@ -1,969 +0,0 @@ ---- -name: mapbox-integration-patterns -description: Official integration patterns for Mapbox GL JS across popular web frameworks. Covers setup, lifecycle management, token handling, search integration, and common pitfalls. Based on Mapbox's create-web-app scaffolding tool. ---- - -# Mapbox Integration Patterns Skill - -This skill provides official patterns for integrating Mapbox GL JS into web applications across different frameworks. These patterns are based on Mapbox's `create-web-app` scaffolding tool and represent production-ready best practices. - -## Version Requirements - -### Mapbox GL JS - -**Recommended:** v3.x (latest) - -- **Minimum:** v3.0.0 -- **Why v3.x:** Modern API, improved performance, active development -- **v2.x:** Still supported but deprecated patterns (see migration notes below) - -**Installing via npm (recommended for production):** - -```bash -npm install mapbox-gl@^3.0.0 # Installs latest v3.x -``` - -**CDN (for prototyping only):** - -```html - - - -``` - -β οΈ **Production apps should use npm, not CDN** - ensures consistent versions and offline builds. - -### Framework Requirements - -**React:** - -- Minimum: 19+ (current implementation in create-web-app) -- Recommended: Latest 19.x - -**Vue:** - -- Minimum: 3.x (Composition API recommended) -- Vue 2.x: Use Options API pattern (mounted/unmounted hooks) - -**Svelte:** - -- Minimum: 5+ (current implementation in create-web-app) -- Recommended: Latest 5.x - -**Angular:** - -- Minimum: 19+ (current implementation in create-web-app) -- Recommended: Latest 19.x - -**Next.js:** - -- Minimum: 13.x (App Router) -- Pages Router: 12.x+ - -### Mapbox Search JS - -**Required for search integration:** - -```bash -npm install @mapbox/search-js-react@^1.0.0 # React -npm install @mapbox/search-js-web@^1.0.0 # Other frameworks -``` - -### Version Migration Notes - -**Migrating from v2.x to v3.x:** - -- `accessToken` can now be passed to Map constructor (preferred) -- Improved TypeScript types -- Better tree-shaking support -- No breaking changes to core initialization patterns - -**Example:** - -```javascript -const token = import.meta.env.VITE_MAPBOX_ACCESS_TOKEN; // Use env vars in production - -// v2.x pattern (still works in v3.x) -mapboxgl.accessToken = token; -const map = new mapboxgl.Map({ container: '...' }); - -// v3.x pattern (preferred) -const map = new mapboxgl.Map({ - accessToken: token, - container: '...' -}); -``` - -## Core Principles - -**Every Mapbox GL JS integration must:** - -1. Initialize the map in the correct lifecycle hook -2. Store map instance in component state (not recreate on every render) -3. **Always call `map.remove()` on cleanup** to prevent memory leaks -4. Handle token management securely (environment variables) -5. Import CSS: `import 'mapbox-gl/dist/mapbox-gl.css'` - -## Framework-Specific Patterns - -### React Integration - -**Pattern: useRef + useEffect with cleanup** - -> **Note:** These examples use **Vite** (the bundler used in `create-web-app`). If using Create React App, replace `import.meta.env.VITE_MAPBOX_ACCESS_TOKEN` with `process.env.REACT_APP_MAPBOX_TOKEN`. See the [Token Management Patterns](#token-management-patterns) section for other bundlers. - -```jsx -import { useRef, useEffect } from 'react'; -import mapboxgl from 'mapbox-gl'; -import 'mapbox-gl/dist/mapbox-gl.css'; - -function MapComponent() { - const mapRef = useRef(null); // Store map instance - const mapContainerRef = useRef(null); // Store DOM reference - - useEffect(() => { - mapboxgl.accessToken = import.meta.env.VITE_MAPBOX_ACCESS_TOKEN; - - mapRef.current = new mapboxgl.Map({ - container: mapContainerRef.current, - center: [-71.05953, 42.3629], - zoom: 13 - }); - - // CRITICAL: Cleanup to prevent memory leaks - return () => { - mapRef.current.remove(); - }; - }, []); // Empty dependency array = run once on mount - - return
; -} -``` - -**Key points:** - -- Use `useRef` for both map instance and container -- Initialize in `useEffect` with empty deps `[]` -- **Always return cleanup function** that calls `map.remove()` -- Never initialize map in render (causes infinite loops) - -**React + Search JS:** - -```jsx -import { useRef, useEffect, useState } from 'react'; -import mapboxgl from 'mapbox-gl'; -import { SearchBox } from '@mapbox/search-js-react'; -import 'mapbox-gl/dist/mapbox-gl.css'; - -const accessToken = import.meta.env.VITE_MAPBOX_ACCESS_TOKEN; -const center = [-71.05953, 42.3629]; - -function MapWithSearch() { - const mapRef = useRef(null); - const mapContainerRef = useRef(null); - const [inputValue, setInputValue] = useState(''); - - useEffect(() => { - mapboxgl.accessToken = accessToken; - - mapRef.current = new mapboxgl.Map({ - container: mapContainerRef.current, - center: center, - zoom: 13 - }); - - return () => { - mapRef.current.remove(); - }; - }, []); - - return ( - <> -Loading map...
-}) - -export default function HomePage() { - return -} -``` - -**Key points:** - -- Use `dynamic` import with `ssr: false` -- Provide loading state -- Map component itself follows standard React pattern - ---- - -## Style Configuration - -### Default Center and Zoom Guidelines - -**Recommended defaults:** - -- **Center**: `[-71.05953, 42.36290]` (Boston, MA) - Mapbox HQ -- **Zoom**: `13` for city-level view - -**Zoom level guide:** - -- `0-2`: World view -- `3-5`: Continent/country -- `6-9`: Region/state -- `10-12`: City view -- `13-15`: Neighborhood -- `16-18`: Street level -- `19-22`: Building level - -**Customizing for user location:** - -```javascript -// Use browser geolocation -if (navigator.geolocation) { - navigator.geolocation.getCurrentPosition((position) => { - map.setCenter([position.coords.longitude, position.coords.latitude]); - map.setZoom(13); - }); -} -``` - ---- - -## Testing Patterns - -### Unit Testing Maps - -**Mock mapbox-gl:** - -```javascript -// vitest.config.js or jest.config.js -export default { - setupFiles: ['./test/setup.js'] -}; -``` - -```javascript -// test/setup.js -vi.mock('mapbox-gl', () => ({ - default: { - Map: vi.fn(() => ({ - on: vi.fn(), - remove: vi.fn(), - setCenter: vi.fn(), - setZoom: vi.fn() - })), - accessToken: '' - } -})); -``` - -**Why:** Mapbox GL JS requires WebGL and browser APIs that don't exist in test environments. Mock the library to test component logic. - ---- - -## When to Use This Skill - -Invoke this skill when: - -- Setting up Mapbox GL JS in a new project -- Integrating Mapbox into a specific framework -- Debugging map initialization issues -- Adding Mapbox Search functionality -- Implementing proper cleanup and lifecycle management -- Converting between frameworks (e.g., React to Vue) -- Reviewing code for Mapbox integration best practices - -## Related Skills - -- **mapbox-cartography**: Map design principles and styling -- **mapbox-token-security**: Token management and security -- **mapbox-style-patterns**: Common map style patterns - -## Resources - -- [Mapbox GL JS Documentation](https://docs.mapbox.com/mapbox-gl-js/) -- [Mapbox Search JS Documentation](https://docs.mapbox.com/mapbox-search-js/) -- [create-web-app GitHub](https://github.com/mapbox/create-web-app) diff --git a/skills/mapbox-style-patterns/SKILL.md b/skills/mapbox-style-patterns/SKILL.md deleted file mode 100644 index fdae7b2..0000000 --- a/skills/mapbox-style-patterns/SKILL.md +++ /dev/null @@ -1,902 +0,0 @@ ---- -name: mapbox-style-patterns -description: Common style patterns, layer configurations, and recipes for typical mapping scenarios including restaurant finders, real estate, data visualization, navigation, and more. Use when implementing specific map use cases or looking for proven style patterns. ---- - -# Mapbox Style Patterns Skill - -This skill provides battle-tested style patterns and layer configurations for common mapping scenarios. - -## Pattern Library - -### Pattern 1: Restaurant/POI Finder - -**Use case:** Consumer app showing restaurants, cafes, bars, or other points of interest - -**Visual requirements:** - -- POIs must be immediately visible -- Street context for navigation -- Neutral background (photos/content overlay) -- Mobile-optimized - -**Recommended layers:** - -```json -{ - "layers": [ - { - "id": "background", - "type": "background", - "paint": { - "background-color": "#f5f5f5" - } - }, - { - "id": "water", - "type": "fill", - "source": "mapbox-streets", - "source-layer": "water", - "paint": { - "fill-color": "#d4e4f7", - "fill-opacity": 0.6 - } - }, - { - "id": "landuse-parks", - "type": "fill", - "source": "mapbox-streets", - "source-layer": "landuse", - "filter": ["==", "class", "park"], - "paint": { - "fill-color": "#e8f5e8", - "fill-opacity": 0.5 - } - }, - { - "id": "roads-minor", - "type": "line", - "source": "mapbox-streets", - "source-layer": "road", - "filter": ["in", "class", "street", "street_limited"], - "paint": { - "line-color": "#e0e0e0", - "line-width": { - "base": 1.5, - "stops": [ - [12, 0.5], - [15, 2], - [18, 6] - ] - } - } - }, - { - "id": "roads-major", - "type": "line", - "source": "mapbox-streets", - "source-layer": "road", - "filter": ["in", "class", "primary", "secondary", "tertiary"], - "paint": { - "line-color": "#ffffff", - "line-width": { - "base": 1.5, - "stops": [ - [10, 1], - [15, 4], - [18, 12] - ] - } - } - }, - { - "id": "restaurant-markers", - "type": "symbol", - "source": "restaurants", - "layout": { - "icon-image": "restaurant-15", - "icon-size": 1.5, - "icon-allow-overlap": false, - "text-field": ["get", "name"], - "text-offset": [0, 1.5], - "text-size": 12, - "text-allow-overlap": false - }, - "paint": { - "icon-color": "#FF6B35", - "text-color": "#333333", - "text-halo-color": "#ffffff", - "text-halo-width": 2 - } - } - ] -} -``` - -**Key features:** - -- Desaturated base map (doesn't compete with photos) -- High-contrast markers (#FF6B35 orange stands out) -- Clear road network (white on light gray) -- Parks visible but subtle -- Text halos for readability - -### Pattern 2: Real Estate Map - -**Use case:** Property search, neighborhood exploration, real estate listings - -**Visual requirements:** - -- Property boundaries clear -- Neighborhood context visible -- Amenities highlighted (schools, parks, transit) -- Price/property data display - -**Recommended layers:** - -```json -{ - "layers": [ - { - "id": "background", - "type": "background", - "paint": { - "background-color": "#fafafa" - } - }, - { - "id": "parks-green-spaces", - "type": "fill", - "source": "mapbox-streets", - "source-layer": "landuse", - "filter": ["in", "class", "park", "pitch", "playground"], - "paint": { - "fill-color": "#7cb342", - "fill-opacity": 0.3 - } - }, - { - "id": "water", - "type": "fill", - "source": "mapbox-streets", - "source-layer": "water", - "paint": { - "fill-color": "#42a5f5", - "fill-opacity": 0.4 - } - }, - { - "id": "roads", - "type": "line", - "source": "mapbox-streets", - "source-layer": "road", - "paint": { - "line-color": "#e0e0e0", - "line-width": { - "base": 1.2, - "stops": [ - [10, 0.5], - [15, 2], - [18, 6] - ] - } - } - }, - { - "id": "property-boundaries", - "type": "line", - "source": "properties", - "paint": { - "line-color": "#7e57c2", - "line-width": 2, - "line-opacity": 0.8 - } - }, - { - "id": "property-fills", - "type": "fill", - "source": "properties", - "paint": { - "fill-color": [ - "interpolate", - ["linear"], - ["get", "price"], - 200000, - "#4caf50", - 500000, - "#ffc107", - 1000000, - "#f44336" - ], - "fill-opacity": 0.3 - } - }, - { - "id": "school-icons", - "type": "symbol", - "source": "composite", - "source-layer": "poi_label", - "filter": ["==", "class", "school"], - "layout": { - "icon-image": "school-15", - "icon-size": 1.2 - }, - "paint": { - "icon-opacity": 0.8 - } - }, - { - "id": "transit-stops", - "type": "circle", - "source": "transit", - "paint": { - "circle-radius": 6, - "circle-color": "#2196f3", - "circle-stroke-color": "#ffffff", - "circle-stroke-width": 2 - } - } - ] -} -``` - -**Key features:** - -- Properties color-coded by price (greenβyellowβred) -- Parks prominently visible (important for home buyers) -- Schools and transit clearly marked -- Property boundaries visible -- Clean, professional aesthetic - -### Pattern 3: Data Visualization Base Map - -**Use case:** Choropleth maps, heatmaps, data overlays, analytics dashboards - -**Visual requirements:** - -- Minimal base map (data is the focus) -- Context without distraction -- Works with various data overlay colors -- High contrast optional for dark data - -**Recommended layers:** - -```json -{ - "layers": [ - { - "id": "background", - "type": "background", - "paint": { - "background-color": "#f0f0f0" - } - }, - { - "id": "water", - "type": "fill", - "source": "mapbox-streets", - "source-layer": "water", - "paint": { - "fill-color": "#d8d8d8", - "fill-opacity": 0.5 - } - }, - { - "id": "admin-boundaries", - "type": "line", - "source": "mapbox-streets", - "source-layer": "admin", - "filter": ["in", "admin_level", 0, 1, 2], - "paint": { - "line-color": "#999999", - "line-width": { - "base": 1, - "stops": [ - [0, 0.5], - [10, 1], - [15, 2] - ] - }, - "line-dasharray": [3, 2] - } - }, - { - "id": "roads-major-simplified", - "type": "line", - "source": "mapbox-streets", - "source-layer": "road", - "filter": ["in", "class", "motorway", "primary"], - "minzoom": 6, - "paint": { - "line-color": "#cccccc", - "line-width": { - "base": 1.2, - "stops": [ - [6, 0.5], - [10, 1], - [15, 2] - ] - }, - "line-opacity": 0.5 - } - }, - { - "id": "place-labels-major", - "type": "symbol", - "source": "mapbox-streets", - "source-layer": "place_label", - "filter": ["in", "type", "city", "capital"], - "layout": { - "text-field": ["get", "name"], - "text-size": { - "base": 1, - "stops": [ - [4, 10], - [10, 14] - ] - }, - "text-font": ["Open Sans Semibold"] - }, - "paint": { - "text-color": "#666666", - "text-halo-color": "#ffffff", - "text-halo-width": 2 - } - } - ] -} -``` - -**Key features:** - -- Grayscale palette (doesn't interfere with data colors) -- Minimal detail (roads, borders only) -- Major cities labeled for orientation -- Low opacity throughout -- Perfect for overlay data - -### Pattern 4: Navigation/Routing Map - -**Use case:** Turn-by-turn directions, route planning, delivery apps - -**Visual requirements:** - -- Route highly visible -- Current location always clear -- Turn points obvious -- Street names readable -- Performance optimized - -**Recommended layers:** - -```json -{ - "layers": [ - { - "id": "background", - "type": "background", - "paint": { - "background-color": "#ffffff" - } - }, - { - "id": "water", - "type": "fill", - "source": "mapbox-streets", - "source-layer": "water", - "paint": { - "fill-color": "#a8d8ea" - } - }, - { - "id": "landuse", - "type": "fill", - "source": "mapbox-streets", - "source-layer": "landuse", - "paint": { - "fill-color": [ - "match", - ["get", "class"], - "park", - "#d4edda", - "hospital", - "#f8d7da", - "school", - "#fff3cd", - "#e9ecef" - ], - "fill-opacity": 0.5 - } - }, - { - "id": "roads-background", - "type": "line", - "source": "mapbox-streets", - "source-layer": "road", - "paint": { - "line-color": "#333333", - "line-width": { - "base": 1.5, - "stops": [ - [10, 2], - [15, 8], - [18, 20] - ] - }, - "line-opacity": 0.3 - } - }, - { - "id": "roads-foreground", - "type": "line", - "source": "mapbox-streets", - "source-layer": "road", - "paint": { - "line-color": "#ffffff", - "line-width": { - "base": 1.5, - "stops": [ - [10, 1], - [15, 6], - [18, 16] - ] - } - } - }, - { - "id": "route-casing", - "type": "line", - "source": "route", - "paint": { - "line-color": "#0d47a1", - "line-width": { - "base": 1.5, - "stops": [ - [10, 8], - [15, 16], - [18, 32] - ] - }, - "line-opacity": 0.4 - } - }, - { - "id": "route-line", - "type": "line", - "source": "route", - "paint": { - "line-color": "#2196f3", - "line-width": { - "base": 1.5, - "stops": [ - [10, 6], - [15, 12], - [18, 24] - ] - } - } - }, - { - "id": "user-location", - "type": "circle", - "source": "user-location", - "paint": { - "circle-radius": 8, - "circle-color": "#2196f3", - "circle-stroke-color": "#ffffff", - "circle-stroke-width": 3 - } - }, - { - "id": "user-location-pulse", - "type": "circle", - "source": "user-location", - "paint": { - "circle-radius": { - "base": 1, - "stops": [ - [0, 16], - [1, 24] - ] - }, - "circle-color": "#2196f3", - "circle-opacity": { - "base": 1, - "stops": [ - [0, 0.4], - [1, 0] - ] - } - } - }, - { - "id": "turn-arrows", - "type": "symbol", - "source": "route-maneuvers", - "layout": { - "icon-image": ["get", "arrow-type"], - "icon-size": 1.5, - "icon-rotation-alignment": "map", - "icon-rotate": ["get", "bearing"] - } - } - ] -} -``` - -**Key features:** - -- Thick, high-contrast route (blue on white) -- Pulsing user location indicator -- Turn arrows at maneuver points -- Simplified background (focus on route) -- Color-coded land use for context - -### Pattern 5: Dark Mode / Night Theme - -**Use case:** Reduced eye strain, night use, modern aesthetic, battery saving (OLED) - -**Visual requirements:** - -- Dark background -- Reduced brightness -- Maintained contrast -- Readable text -- Comfortable viewing - -**Recommended layers:** - -```json -{ - "layers": [ - { - "id": "background", - "type": "background", - "paint": { - "background-color": "#0a0a0a" - } - }, - { - "id": "water", - "type": "fill", - "source": "mapbox-streets", - "source-layer": "water", - "paint": { - "fill-color": "#1a237e", - "fill-opacity": 0.5 - } - }, - { - "id": "parks", - "type": "fill", - "source": "mapbox-streets", - "source-layer": "landuse", - "filter": ["==", "class", "park"], - "paint": { - "fill-color": "#1b5e20", - "fill-opacity": 0.4 - } - }, - { - "id": "buildings", - "type": "fill", - "source": "mapbox-streets", - "source-layer": "building", - "paint": { - "fill-color": "#1a1a1a", - "fill-opacity": 0.8, - "fill-outline-color": "#2a2a2a" - } - }, - { - "id": "roads-minor", - "type": "line", - "source": "mapbox-streets", - "source-layer": "road", - "filter": ["in", "class", "street", "street_limited"], - "paint": { - "line-color": "#2a2a2a", - "line-width": { - "base": 1.5, - "stops": [ - [12, 0.5], - [15, 2], - [18, 6] - ] - } - } - }, - { - "id": "roads-major", - "type": "line", - "source": "mapbox-streets", - "source-layer": "road", - "filter": ["in", "class", "primary", "secondary", "motorway"], - "paint": { - "line-color": "#3a3a3a", - "line-width": { - "base": 1.5, - "stops": [ - [10, 1], - [15, 4], - [18, 12] - ] - } - } - }, - { - "id": "labels", - "type": "symbol", - "source": "mapbox-streets", - "source-layer": "place_label", - "layout": { - "text-field": ["get", "name"], - "text-size": 12 - }, - "paint": { - "text-color": "#e0e0e0", - "text-halo-color": "#0a0a0a", - "text-halo-width": 2 - } - } - ] -} -``` - -**Key features:** - -- Very dark background (#0a0a0a near-black) -- Subtle color differentiation (deep blues, greens) -- Light text (#e0e0e0) with dark halos -- Reduced opacity throughout -- Easy on eyes in low light - -## Pattern Selection Guide - -### Decision Tree - -**Question 1: What is the primary content?** - -- User-generated markers/pins β **POI Finder Pattern** -- Property data/boundaries β **Real Estate Pattern** -- Statistical/analytical data β **Data Visualization Pattern** -- Routes/directions β **Navigation Pattern** - -**Question 2: What is the viewing environment?** - -- Daytime/office β Light theme -- Night/dark environment β **Dark Mode Pattern** -- Variable β Provide theme toggle - -**Question 3: What is the user's primary action?** - -- Browse/explore β Focus on POIs, rich detail -- Navigate β Focus on roads, route visibility -- Analyze data β Minimize base map, maximize data -- Select location β Clear boundaries, context - -**Question 4: What is the platform?** - -- Mobile β Simplified, larger touch targets, less detail -- Desktop β Can include more detail and complexity -- Both β Design mobile-first, enhance for desktop - -## Layer Optimization Patterns - -### Performance Pattern: Simplified by Zoom - -```json -{ - "id": "roads", - "type": "line", - "source": "mapbox-streets", - "source-layer": "road", - "filter": [ - "step", - ["zoom"], - ["in", "class", "motorway", "trunk"], - 8, - ["in", "class", "motorway", "trunk", "primary"], - 12, - ["in", "class", "motorway", "trunk", "primary", "secondary"], - 14, - true - ], - "paint": { - "line-width": { - "base": 1.5, - "stops": [ - [4, 0.5], - [10, 1], - [15, 4], - [18, 12] - ] - } - } -} -``` - -### Expression Pattern: Data-Driven Styling - -```json -{ - "paint": { - "circle-radius": [ - "interpolate", - ["linear"], - ["get", "population"], - 0, - 3, - 1000, - 5, - 10000, - 8, - 100000, - 12, - 1000000, - 20 - ], - "circle-color": [ - "case", - ["<", ["get", "temperature"], 0], - "#2196f3", - ["<", ["get", "temperature"], 20], - "#4caf50", - ["<", ["get", "temperature"], 30], - "#ffc107", - "#f44336" - ] - } -} -``` - -### Clustering Pattern: Handle Dense POIs - -```json -{ - "id": "clusters", - "type": "circle", - "source": "pois", - "filter": ["has", "point_count"], - "paint": { - "circle-color": [ - "step", - ["get", "point_count"], - "#51bbd6", 10, - "#f1f075", 30, - "#f28cb1" - ], - "circle-radius": [ - "step", - ["get", "point_count"], - 15, 10, - 20, 30, - 25 - ] - } -}, -{ - "id": "cluster-count", - "type": "symbol", - "source": "pois", - "filter": ["has", "point_count"], - "layout": { - "text-field": ["get", "point_count_abbreviated"], - "text-size": 12 - } -} -``` - -## Common Modifications - -### Add 3D Buildings - -```json -{ - "id": "3d-buildings", - "type": "fill-extrusion", - "source": "composite", - "source-layer": "building", - "minzoom": 15, - "paint": { - "fill-extrusion-color": "#aaa", - "fill-extrusion-height": [ - "interpolate", - ["linear"], - ["zoom"], - 15, - 0, - 15.05, - ["get", "height"] - ], - "fill-extrusion-base": [ - "interpolate", - ["linear"], - ["zoom"], - 15, - 0, - 15.05, - ["get", "min_height"] - ], - "fill-extrusion-opacity": 0.6 - } -} -``` - -### Add Terrain/Hillshade - -```json -{ - "sources": { - "mapbox-dem": { - "type": "raster-dem", - "url": "mapbox://mapbox.mapbox-terrain-dem-v1" - } - }, - "layers": [ - { - "id": "hillshade", - "type": "hillshade", - "source": "mapbox-dem", - "paint": { - "hillshade-exaggeration": 0.5, - "hillshade-shadow-color": "#000000" - } - } - ], - "terrain": { - "source": "mapbox-dem", - "exaggeration": 1.5 - } -} -``` - -### Add Custom Markers - -```json -{ - "id": "custom-markers", - "type": "symbol", - "source": "markers", - "layout": { - "icon-image": "custom-marker", - "icon-size": 0.8, - "icon-anchor": "bottom", - "icon-allow-overlap": true, - "text-field": ["get", "name"], - "text-offset": [0, -2], - "text-anchor": "top", - "text-size": 12 - }, - "paint": { - "text-color": "#ffffff", - "text-halo-color": "#000000", - "text-halo-width": 2 - } -} -``` - -## Testing Patterns - -### Visual Regression Checklist - -- [ ] Test at zoom levels: 4, 8, 12, 16, 20 -- [ ] Verify on mobile (375px width) -- [ ] Verify on desktop (1920px width) -- [ ] Test with dense data -- [ ] Test with sparse data -- [ ] Check label collision -- [ ] Verify color contrast (WCAG) -- [ ] Test loading performance - -## When to Use This Skill - -Invoke this skill when: - -- Starting a new map style for a specific use case -- Looking for layer configuration examples -- Implementing common mapping patterns -- Optimizing existing styles -- Need proven recipes for typical scenarios -- Debugging style issues -- Learning Mapbox style best practices diff --git a/skills/mapbox-style-quality/SKILL.md b/skills/mapbox-style-quality/SKILL.md deleted file mode 100644 index c4846c0..0000000 --- a/skills/mapbox-style-quality/SKILL.md +++ /dev/null @@ -1,420 +0,0 @@ ---- -name: mapbox-style-quality -description: Expert guidance on validating, optimizing, and ensuring quality of Mapbox styles through validation, accessibility checks, and optimization. Use when preparing styles for production, debugging issues, or ensuring map quality standards. ---- - -# Mapbox Style Quality Skill - -This skill provides expert guidance on ensuring Mapbox style quality through validation, accessibility, and optimization tools. - -## When to Use Quality Tools - -### Pre-Production Checklist - -Before deploying any Mapbox style to production: - -1. **Validate all expressions** - Catch syntax errors before runtime -2. **Check color contrast** - Ensure text is readable (WCAG compliance) -3. **Validate GeoJSON sources** - Ensure data integrity -4. **Optimize style** - Reduce file size and improve performance -5. **Compare versions** - Understand what changed - -### During Development - -**When adding GeoJSON data:** - -- Always validate external GeoJSON with `validate_geojson_tool` before using as a source - -**When writing expressions:** - -- Validate expressions with `validate_expression_tool` as you write them -- Catch type mismatches early (e.g., using string operator on number) -- Verify operator availability in your Mapbox GL JS version -- Test expressions with expected data types - -**When styling text/labels:** - -- Check foreground/background contrast with `check_color_contrast_tool` -- Aim for WCAG AA minimum (4.5:1 for normal text, 3:1 for large text) -- Use AAA standard (7:1 for normal text) for better accessibility -- Consider different background scenarios (map tiles, overlays) - -### Before Committing Changes - -**Compare style versions:** - -- Use `compare_styles_tool` to generate a diff report -- Review all layer changes, source modifications, and expression updates -- Understand the impact of your changes -- Document significant changes in commit messages - -### Before Deployment - -**Optimize the style:** - -- Run `optimize_style_tool` to reduce file size -- Remove unused sources that reference deleted layers -- Eliminate duplicate layers with identical properties -- Simplify boolean expressions for better performance -- Remove empty layers that serve no purpose - -## Validation Best Practices - -### GeoJSON Validation - -**Always validate when:** - -- Loading GeoJSON from user uploads -- Fetching GeoJSON from external APIs -- Processing GeoJSON from third-party sources -- Converting between data formats - -**Common GeoJSON errors:** - -- Invalid coordinate ranges (longitude > 180 or < -180) -- Unclosed polygon rings (first and last coordinates must match) -- Wrong coordinate order (should be [longitude, latitude], not [latitude, longitude]) -- Missing required properties (type, coordinates, geometry) -- Invalid geometry types or nesting - -**Example workflow:** - -``` -1. Receive GeoJSON data -2. Validate with validate_geojson_tool -3. If valid: Add as source to style -4. If invalid: Fix errors, re-validate -``` - -### Expression Validation - -**Validate expressions for:** - -- Filter conditions (`filter` property on layers) -- Data-driven styling (`paint` and `layout` properties) -- Feature state expressions -- Dynamic property calculations - -**Common expression errors:** - -- Type mismatches (string operators on numbers) -- Invalid operator names or wrong syntax -- Wrong number of arguments for operators -- Nested expression errors -- Using unavailable operators for your GL JS version - -**Prevention strategies:** - -- Validate as you write expressions, not at runtime -- Test expressions with representative data -- Use type checking (expectedType parameter) -- Validate in context (layer, filter, paint, layout) - -### Accessibility Validation - -**WCAG Levels:** - -- **AA** (minimum): 4.5:1 for normal text, 3:1 for large text -- **AAA** (enhanced): 7:1 for normal text, 4.5:1 for large text - -**Text size categories:** - -- **Normal**: < 18pt or < 14pt bold -- **Large**: β₯ 18pt or β₯ 14pt bold - -**Common scenarios to check:** - -- Text labels on map tiles -- POI labels with background colors -- Custom markers with text -- UI overlays on maps -- Legend text and symbols -- Attribution text - -**Testing strategy:** - -- Test against both light and dark map tiles -- Consider overlay backgrounds (popups, modals) -- Test in different lighting conditions (mobile outdoor use) -- Verify contrast at different zoom levels - -## Optimization Best Practices - -### When to Optimize - -**Before production deployment:** - -- After all development changes are complete -- After merging multiple feature branches -- When style has grown significantly over time -- Before major releases or launches - -**Benefits of optimization:** - -- Faster initial load times -- Reduced bandwidth usage -- Better runtime performance -- Cleaner, more maintainable code - -### Optimization Types - -**Remove unused sources:** - -- Automatically identifies sources not referenced by any layer -- Safe to remove without affecting functionality -- Common after deleting layers or refactoring - -**Remove duplicate layers:** - -- Finds layers with identical properties (excluding ID) -- Can occur when copying/pasting layers -- Reduces style complexity and file size - -**Simplify expressions:** - -- Converts `["all", true]` β `true` -- Converts `["any", false]` β `false` -- Converts `["!", false]` β `true` -- Converts `["!", true]` β `false` -- Improves expression evaluation performance - -**Remove empty layers:** - -- Removes layers with no paint or layout properties -- Preserves background layers (valid even when empty) -- Cleans up incomplete or placeholder layers - -**Consolidate filters:** - -- Identifies groups of layers with identical filter expressions -- Highlights opportunities for layer consolidation -- Doesn't automatically consolidate (informational only) - -### Optimization Strategy - -**Recommended order:** - -1. Remove unused sources first (reduces noise for other checks) -2. Remove duplicate layers (eliminates redundancy) -3. Simplify expressions (improves readability and performance) -4. Remove empty layers (final cleanup) -5. Review consolidation opportunities (manual step) - -**Selective optimization:** - -``` -// All optimizations (recommended for production) -optimize_style_tool({ style }) - -// Specific optimizations only -optimize_style_tool({ - style, - optimizations: ['remove-unused-sources', 'simplify-expressions'] -}) -``` - -**Review before deploying:** - -- Check the optimization report -- Verify size savings (percentReduction) -- Review the list of changes (optimizations array) -- Test the optimized style before deployment - -## Style Comparison Workflow - -### When to Compare Styles - -**Before merging changes:** - -- Review what changed in your feature branch -- Ensure no unintended modifications -- Generate change summary for PR description - -**When investigating issues:** - -- Compare working version vs. broken version -- Identify what changed between versions -- Narrow down root cause of problems - -**During migrations:** - -- Compare old format vs. new format -- Verify data integrity after conversion -- Document transformation differences - -### Comparison Best Practices - -**Use ignoreMetadata flag:** - -``` -// Ignore metadata differences (id, owner, created, modified) -compare_styles_tool({ - styleA: oldStyle, - styleB: newStyle, - ignoreMetadata: true -}) -``` - -**Focus on meaningful changes:** - -- Layer additions/removals -- Source changes -- Expression modifications -- Paint/layout property updates - -**Document significant changes:** - -- Note breaking changes in documentation -- Update style version numbers -- Communicate changes to team/users - -## Quality Workflow Examples - -### Basic Quality Check - -``` -1. Validate expressions in style -2. Check color contrast for text layers -3. Optimize if needed -``` - -### Full Pre-Production Workflow - -``` -1. Validate all GeoJSON sources -2. Validate all expressions (filters, paint, layout) -3. Check color contrast for all text layers -4. Compare with previous production version -5. Optimize style -6. Test optimized style -7. Deploy -``` - -### Troubleshooting Workflow - -``` -1. Compare working vs. broken style -2. Identify differences -3. Validate suspicious expressions -4. Check GeoJSON data if source-related -5. Verify color contrast if visibility issue -``` - -### Refactoring Workflow - -``` -1. Create backup of current style -2. Make refactoring changes -3. Compare before vs. after -4. Validate all modified expressions -5. Optimize to clean up -6. Review size impact -``` - -## Common Issues and Solutions - -### Runtime Expression Errors - -**Problem:** Map throws expression errors at runtime -**Solution:** Validate expressions with `validate_expression_tool` during development -**Prevention:** Add expression validation to pre-commit hooks or CI/CD - -### Poor Text Readability - -**Problem:** Text labels are hard to read on map -**Solution:** Check contrast with `check_color_contrast_tool`, adjust colors to meet WCAG AA -**Prevention:** Test text on both light and dark backgrounds, check at different zoom levels - -### Large Style File Size - -**Problem:** Style takes long to load or transfer -**Solution:** Run `optimize_style_tool` to remove redundancies and simplify -**Prevention:** Regularly optimize during development, remove unused sources immediately - -### Invalid GeoJSON Source - -**Problem:** GeoJSON source fails to load or render -**Solution:** Validate with `validate_geojson_tool`, fix coordinate issues, verify structure -**Prevention:** Validate all external GeoJSON before adding to style - -### Unexpected Style Changes - -**Problem:** Style changed but unsure what modified -**Solution:** Use `compare_styles_tool` to generate diff report -**Prevention:** Compare before/after for all significant changes, document modifications - -## Integration with Development Workflow - -### Git Pre-Commit Hook - -```bash -# Validate expressions before commit -npm run validate-style - -# Optimize before commit (optional) -npm run optimize-style -``` - -### CI/CD Pipeline - -``` -1. Validate all expressions -2. Check accessibility compliance -3. Run optimization (warning if significant savings) -4. Compare with production version -5. Generate quality report -``` - -### Code Review Checklist - -- [ ] All expressions validated -- [ ] Text contrast meets WCAG AA -- [ ] GeoJSON sources validated -- [ ] Style optimized for production -- [ ] Changes documented in comparison report - -## Best Practices Summary - -**During Development:** - -- Validate expressions as you write them -- Check GeoJSON data when adding sources -- Test color contrast for new text layers - -**Before Committing:** - -- Compare with previous version -- Document significant changes -- Validate modified expressions - -**Before Production:** - -- Run full validation suite -- Check accessibility compliance -- Optimize style -- Test optimized version -- Generate quality report - -**Regular Maintenance:** - -- Periodically optimize to prevent bloat -- Review and consolidate similar layers -- Update expressions to use simpler forms -- Remove deprecated or unused code - -## Tool Quick Reference - -| Tool | Use When | Output | -| --------------------------- | ---------------------- | -------------------------- | -| `validate_geojson_tool` | Adding GeoJSON sources | Valid/invalid + error list | -| `validate_expression_tool` | Writing expressions | Valid/invalid + error list | -| `check_color_contrast_tool` | Styling text labels | Passes/fails + WCAG levels | -| `compare_styles_tool` | Reviewing changes | Diff report with paths | -| `optimize_style_tool` | Before deployment | Optimized style + savings | - -## Additional Resources - -- [Mapbox Style Specification](https://docs.mapbox.com/mapbox-gl-js/style-spec/) -- [WCAG 2.1 Guidelines](https://www.w3.org/WAI/WCAG21/quickref/) -- [GeoJSON Specification (RFC 7946)](https://tools.ietf.org/html/rfc7946) -- [Mapbox Expression Reference](https://docs.mapbox.com/mapbox-gl-js/style-spec/expressions/) diff --git a/skills/mapbox-token-security/SKILL.md b/skills/mapbox-token-security/SKILL.md deleted file mode 100644 index 339b116..0000000 --- a/skills/mapbox-token-security/SKILL.md +++ /dev/null @@ -1,500 +0,0 @@ ---- -name: mapbox-token-security -description: Security best practices for Mapbox access tokens, including scope management, URL restrictions, rotation strategies, and protecting sensitive data. Use when creating, managing, or advising on Mapbox token security. ---- - -# Mapbox Token Security Skill - -This skill provides security expertise for managing Mapbox access tokens safely and effectively. - -## Token Types and When to Use Them - -### Public Tokens (pk.\*) - -**Characteristics:** - -- Can be safely exposed in client-side code -- Limited to specific public scopes only -- Can have URL restrictions -- Cannot access sensitive APIs - -**When to use:** - -- Client-side web applications -- Mobile apps -- Public-facing demos -- Embedded maps on websites - -**Allowed scopes:** - -- `styles:tiles` - Display style tiles (raster) -- `styles:read` - Read style specifications -- `fonts:read` - Access Mapbox fonts -- `datasets:read` - Read dataset data -- `vision:read` - Vision API access - -### Secret Tokens (sk.\*) - -**Characteristics:** - -- **NEVER expose in client-side code** -- Full API access with any scopes -- Server-side use only -- Can create/manage other tokens - -**When to use:** - -- Server-side applications -- Backend services -- CI/CD pipelines -- Administrative tasks -- Token management - -**Common scopes:** - -- `styles:write` - Create/modify styles -- `styles:list` - List all styles -- `tokens:read` - View token information -- `tokens:write` - Create/modify tokens -- User feedback management scopes - -### Temporary Tokens (tk.\*) - -**Characteristics:** - -- Short-lived (max 1 hour) -- Created by secret tokens -- Single-purpose use -- Automatically expire - -**When to use:** - -- One-time operations -- Temporary delegated access -- Short-lived demos -- Security-conscious workflows - -## Scope Management Best Practices - -### Principle of Least Privilege - -**Always grant the minimum scopes needed:** - -β **Bad:** - -```javascript -// Overly permissive - don't do this -{ - scopes: [ - 'styles:read', - 'styles:write', - 'styles:list', - 'styles:delete', - 'tokens:read', - 'tokens:write' - ]; -} -``` - -β **Good:** - -```javascript -// Only what's needed for displaying a map -{ - scopes: ['styles:read', 'fonts:read']; -} -``` - -### Scope Combinations by Use Case - -**Public Map Display (client-side):** - -```json -{ - "scopes": ["styles:read", "fonts:read", "styles:tiles"], - "note": "Public token for map display", - "allowedUrls": ["https://myapp.com/*"] -} -``` - -**Style Management (server-side):** - -```json -{ - "scopes": ["styles:read", "styles:write", "styles:list"], - "note": "Backend style management - SECRET TOKEN" -} -``` - -**Token Administration (server-side):** - -```json -{ - "scopes": ["tokens:read", "tokens:write"], - "note": "Token management only - SECRET TOKEN" -} -``` - -**Read-Only Access:** - -```json -{ - "scopes": ["styles:list", "styles:read", "tokens:read"], - "note": "Auditing/monitoring - SECRET TOKEN" -} -``` - -## URL Restrictions - -### Why URL Restrictions Matter - -URL restrictions limit where a public token can be used, preventing unauthorized usage if the token is exposed. - -### Effective URL Patterns - -β **Recommended patterns:** - -``` -https://myapp.com/* # Production domain -https://*.myapp.com/* # All subdomains -https://staging.myapp.com/* # Staging environment -http://localhost:* # Local development -``` - -β **Avoid these:** - -``` -* # No restriction (insecure) -http://* # Any HTTP site (insecure) -*.com/* # Too broad -``` - -### Multiple Environment Strategy - -Create separate tokens for each environment: - -```javascript -// Production -{ - note: "Production - myapp.com", - scopes: ["styles:read", "fonts:read"], - allowedUrls: ["https://myapp.com/*", "https://www.myapp.com/*"] -} - -// Staging -{ - note: "Staging - staging.myapp.com", - scopes: ["styles:read", "fonts:read"], - allowedUrls: ["https://staging.myapp.com/*"] -} - -// Development -{ - note: "Development - localhost", - scopes: ["styles:read", "fonts:read"], - allowedUrls: ["http://localhost:*", "http://127.0.0.1:*"] -} -``` - -## Token Storage and Handling - -### Server-Side (Secret Tokens) - -β **DO:** - -- Store in environment variables -- Use secret management services (AWS Secrets Manager, HashiCorp Vault) -- Encrypt at rest -- Limit access via IAM policies -- Log token usage - -β **DON'T:** - -- Hardcode in source code -- Commit to version control -- Store in plaintext configuration files -- Share via email or Slack -- Reuse across multiple services - -**Example: Secure Environment Variable:** - -```bash -# .env (NEVER commit this file) -MAPBOX_SECRET_TOKEN=sk.ey... - -# .gitignore (ALWAYS include .env) -.env -.env.local -.env.*.local -``` - -### Client-Side (Public Tokens) - -β **DO:** - -- Use public tokens only -- Apply URL restrictions -- Use different tokens per app -- Rotate periodically -- Monitor usage - -β **DON'T:** - -- Expose secret tokens -- Use tokens without URL restrictions -- Share tokens between unrelated apps -- Use tokens with excessive scopes - -**Example: Safe Client Usage:** - -```javascript -// Public token with URL restrictions - SAFE -const mapboxToken = 'pk.eyJ1IjoiZXhhbXBsZSIsImEiOiJjbGV4YW1wbGUifQ.example'; - -// This token is restricted to your domain -// and only has styles:read scope -mapboxgl.accessToken = mapboxToken; -``` - -## Token Rotation Strategy - -### When to Rotate Tokens - -**Mandatory rotation:** - -- Token exposed in public repository -- Team member leaves with token access -- Suspected compromise or breach -- Service decommissioning -- Compliance requirements - -**Scheduled rotation:** - -- Every 90 days (recommended for production) -- Every 30 days (high-security environments) -- After major deployments -- During security audits - -### Rotation Process - -**Zero-downtime rotation:** - -1. **Create new token** with same scopes -2. **Deploy new token** to canary/staging environment -3. **Verify functionality** with new token -4. **Gradually roll out** to production -5. **Monitor for issues** for 24-48 hours -6. **Revoke old token** after confirmation -7. **Update documentation** with rotation date - -**Emergency rotation:** - -1. **Immediately revoke** compromised token -2. **Create replacement** token -3. **Deploy emergency update** to all services -4. **Notify team** of incident -5. **Investigate** how compromise occurred -6. **Update procedures** to prevent recurrence - -## Monitoring and Auditing - -### Track Token Usage - -**Metrics to monitor:** - -- API request volume per token -- Geographic distribution of requests -- Error rates by token -- Unexpected spike patterns -- Requests from unauthorized domains - -**Alert on:** - -- Usage from unexpected IPs/regions -- Sudden traffic spikes (>200% normal) -- High error rates (>10%) -- Requests outside allowed URLs -- Off-hours access patterns - -### Regular Security Audits - -**Monthly checklist:** - -- [ ] Review all active tokens -- [ ] Verify token scopes are still appropriate -- [ ] Check for unused tokens (revoke if inactive >30 days) -- [ ] Confirm URL restrictions are current -- [ ] Review team member access -- [ ] Check for tokens in public repositories (GitHub scan) -- [ ] Verify documentation is up-to-date - -**Quarterly checklist:** - -- [ ] Rotate production tokens -- [ ] Full token inventory -- [ ] Access control review -- [ ] Update incident response procedures -- [ ] Security training for team - -## Common Security Mistakes - -### 1. Exposing Secret Tokens in Client Code - -β **CRITICAL ERROR:** - -```javascript -// NEVER DO THIS - Secret token in client code -const map = new mapboxgl.Map({ - accessToken: 'sk.eyJ1IjoiZXhhbXBsZSIsI...' // SECRET TOKEN -}); -``` - -β **Correct:** - -```javascript -// Public token only in client code -const map = new mapboxgl.Map({ - accessToken: 'pk.eyJ1IjoiZXhhbXBsZSIsI...' // PUBLIC TOKEN -}); -``` - -### 2. Overly Permissive Scopes - -β **Too broad:** - -```json -{ - "scopes": ["styles:*", "tokens:*"] -} -``` - -β **Specific:** - -```json -{ - "scopes": ["styles:read"] -} -``` - -### 3. Missing URL Restrictions - -β **No restrictions:** - -```json -{ - "scopes": ["styles:read"], - "allowedUrls": [] // Token works anywhere -} -``` - -β **Domain restricted:** - -```json -{ - "scopes": ["styles:read"], - "allowedUrls": ["https://myapp.com/*"] -} -``` - -### 4. Long-Lived Tokens Without Rotation - -β **Never rotated:** - -``` -Token created: Jan 2020 -Last rotation: Never -Still in production: Yes -``` - -β **Regular rotation:** - -``` -Token created: Dec 2024 -Last rotation: Dec 2024 -Next rotation: Mar 2025 -``` - -### 5. Tokens in Version Control - -β **Committed to Git:** - -```javascript -// config.js (committed to repo) -export const MAPBOX_TOKEN = 'sk.eyJ1IjoiZXhhbXBsZSI...'; -``` - -β **Environment variables:** - -```javascript -// config.js -export const MAPBOX_TOKEN = process.env.MAPBOX_SECRET_TOKEN; -``` - -```bash -# .env (in .gitignore) -MAPBOX_SECRET_TOKEN=sk.eyJ1IjoiZXhhbXBsZSI... -``` - -## Incident Response Plan - -### If a Token is Compromised - -**Immediate actions (first 15 minutes):** - -1. **Revoke the token** via Mapbox dashboard or API -2. **Create replacement token** with different scopes/restrictions if needed -3. **Update all services** using the compromised token -4. **Notify team** via incident channel - -**Investigation (within 24 hours):** 5. **Review access logs** to understand exposure 6. **Check for unauthorized usage** in Mapbox dashboard 7. **Identify root cause** (how was it exposed?) 8. **Document incident** with timeline and impact - -**Prevention (within 1 week):** 9. **Update procedures** to prevent recurrence 10. **Implement additional safeguards** (CI checks, secret scanning) 11. **Train team** on lessons learned 12. **Update documentation** with new security measures - -## Best Practices Summary - -### Security Checklist - -**Token Creation:** - -- [ ] Use public tokens for client-side, secret for server-side -- [ ] Apply principle of least privilege for scopes -- [ ] Add URL restrictions to public tokens -- [ ] Use descriptive names/notes for token identification -- [ ] Document intended use and environment - -**Token Management:** - -- [ ] Store secret tokens in environment variables or secret managers -- [ ] Never commit tokens to version control -- [ ] Rotate tokens every 90 days (or per policy) -- [ ] Remove unused tokens promptly -- [ ] Separate tokens by environment (dev/staging/prod) - -**Monitoring:** - -- [ ] Track token usage patterns -- [ ] Set up alerts for unusual activity -- [ ] Regular security audits (monthly) -- [ ] Review team access quarterly -- [ ] Scan repositories for exposed tokens - -**Incident Response:** - -- [ ] Documented revocation procedure -- [ ] Emergency contact list -- [ ] Rotation process documented -- [ ] Post-incident review template -- [ ] Team training on security procedures - -## When to Use This Skill - -Invoke this skill when: - -- Creating new tokens -- Deciding between public vs secret tokens -- Setting up token restrictions -- Implementing token rotation -- Investigating security incidents -- Conducting security audits -- Training team on token security -- Reviewing code for token exposure