Skip to content

πŸ—ΊοΈ Navigation System Overview

The WebXR Gallery navigation system allows users to navigate between stages using interactive maps or floor plans, providing geographic context to immersive experiences.


Features

πŸ—ΊοΈ Interactive Maps

  • OpenStreetMap Integration - Free, open-source maps
  • Multiple Tile Layers - Streets, satellite, terrain views
  • Search & Geocoding - Find locations by address
  • Drag-to-Place - Click and drag to position stages
  • Auto-Centering - Focuses on current stage location

🏒 Floor Plans

  • SVG-Based Markers - Lightweight and scalable
  • Multi-Floor Support - Switch between building levels
  • Custom Images - Upload your own floor plan images
  • Clickable Markers - Navigate by clicking stage locations
  • Minimap Mode - Always-visible corner widget

πŸ“ Unified Minimap

  • 100x100px Widget - Fixed bottom-left corner
  • Click-to-Expand - Opens full stage selector
  • Current Stage Indicator - Pulsing marker animation
  • Graceful Degradation - Hidden if no location data

Architecture

NavigationManager
β”œβ”€β”€ type: "map" | "floorplan" | "none"
β”œβ”€β”€ MapOverlay
β”‚   β”œβ”€β”€ Leaflet integration
β”‚   β”œβ”€β”€ Tile layer rendering
β”‚   β”œβ”€β”€ Marker placement
β”‚   └── Geocoding service
└── FloorPlanOverlay
    β”œβ”€β”€ SVG marker rendering
    β”œβ”€β”€ Image loading
    β”œβ”€β”€ Floor switching
    └── Tooltip system

Configuration

Quick Start

// In your ExperienceConfig
{
  "navigation": {
    "type": "map",              // or "floorplan" or "none"
    "showMinimap": true,        // Show corner widget
    "markers": [
      {
        "stageId": "stage-1",
        "label": "Lobby",
        "geoPosition": {        // For maps
          "lat": 40.7128,
          "lng": -74.0060
        },
        "floorPlanPosition": {  // For floor plans
          "x": 0.5,             // 0-1 normalized
          "y": 0.3
        }
      }
    ]
  },
  "stages": [
    {
      "id": "stage-1",
      "name": "Lobby",
      "location": {             // Stage-level location (fallback)
        "lat": 40.7128,
        "lng": -74.0060
      }
    }
  ]
}

1. Map Navigation

Best for: - Outdoor locations - City tours - Multi-building campuses - Geographic experiences

Configuration:

{
  "navigation": {
    "type": "map",
    "showMinimap": true,
    "mapConfig": {
      "tileLayer": "streets",     // streets, satellite, outdoors, dark
      "initialZoom": 15,
      "maxZoom": 18,
      "minZoom": 10
    },
    "markers": [
      {
        "stageId": "times-square",
        "label": "Times Square",
        "icon": "star",           // default, star, info, camera, etc.
        "color": "#FF0000",       // Custom marker color
        "geoPosition": {
          "lat": 40.7580,
          "lng": -73.9855
        }
      }
    ]
  }
}

Tile Layer Options: - streets - Default road map - satellite - Aerial imagery - outdoors - Topographic with trails - dark - Dark mode map - light - Minimal light theme

2. Floor Plan Navigation

Best for: - Indoor experiences - Museums and galleries - Office buildings - Multi-floor venues

Configuration:

{
  "navigation": {
    "type": "floorplan",
    "showMinimap": true,
    "floorPlans": [              // Multi-floor support
      {
        "floor": 1,
        "name": "Ground Floor",
        "imageUrl": "https://cdn.com/floor1.png"
      },
      {
        "floor": 2,
        "name": "Second Floor",
        "imageUrl": "https://cdn.com/floor2.png"
      }
    ],
    "markers": [
      {
        "stageId": "lobby",
        "label": "Main Lobby",
        "floor": 1,              // Which floor plan?
        "floorPlanPosition": {
          "x": 0.5,              // Normalized 0-1 (50% from left)
          "y": 0.3               // Normalized 0-1 (30% from top)
        }
      }
    ]
  }
}

Floor Plan Image Requirements: - Format: PNG, JPG, or SVG - Aspect Ratio: Any (will scale to fit) - Resolution: 1920x1080+ recommended - File Size: <5MB for best performance

3. No Navigation

Disables geographic navigation entirely:

{
  "navigation": {
    "type": "none"
  }
}

Marker Configuration

Each marker connects a stage to a geographic or floor plan location:

interface NavigationMarker {
  stageId: string;              // Which stage?
  label?: string;               // Display name (defaults to stage name)

  // Geographic (for maps)
  geoPosition?: {
    lat: number;                // Latitude (-90 to 90)
    lng: number;                // Longitude (-180 to 180)
  };

  // Floor plan (for floor plans)
  floorPlanPosition?: {
    x: number;                  // 0-1 (0=left, 1=right)
    y: number;                  // 0-1 (0=top, 1=bottom)
  };
  floor?: number;               // Which floor? (1-indexed)

  // Visual customization
  icon?: 'default' | 'star' | 'info' | 'camera' | 'video' | 'audio';
  customIconUrl?: string;       // URL to custom PNG icon
  color?: string;               // Hex color (e.g., "#FF0000")

  // Metadata
  placeName?: string;           // Auto-filled by geocoding
}

Geocoding

The GeocodingService automatically converts addresses to coordinates and vice versa.

Reverse Geocoding (Coordinates β†’ Address)

Automatically triggered when you set a stage location in the editor:

// User drags marker to (40.7128, -74.0060)
// Geocoding service automatically calls Nominatim API
// Result: "New York, NY, USA"
// Stored in marker.placeName

Forward Geocoding (Address β†’ Coordinates)

Available in the Map Location Picker:

  1. User types "Empire State Building"
  2. Search suggestions appear in <300ms
  3. User clicks suggestion
  4. Map centers on location
  5. Marker placed automatically

Caching & Rate Limiting

To respect Nominatim's usage policy: - 15-minute cache for repeated lookups - 1 request/second rate limiting - 100-entry LRU cache to prevent memory bloat


Minimap Behavior

Visibility Rules

The minimap is shown when: - βœ… navigation.showMinimap === true (explicit) - βœ… navigation.type !== 'none' - βœ… At least one marker has valid location data

Hidden when: - ❌ navigation.showMinimap === false - ❌ All markers at (0, 0) or undefined - ❌ Navigation type is 'none'

Interaction

  • Click minimap: Opens full stage selector
  • Hover marker: Shows tooltip with stage name
  • Current stage: Pulsing animation
  • Other stages: Static markers

Styling

Fixed at 100x100px, bottom-left corner:

.floor-plan-minimap {
  position: fixed;
  bottom: 80px;
  left: 20px;
  width: 100px;
  height: 100px;
  border-radius: 12px;
  box-shadow: 0 4px 12px rgba(0,0,0,0.3);
  cursor: pointer;
}

Editor Integration

Map Location Picker

Click "Set Location" in the stage editor to open:

  1. Search Bar - Type address or landmark
  2. Interactive Map - Drag to fine-tune position
  3. Coordinates Display - Lat/lng shown in real-time
  4. Place Name - Auto-filled from geocoding
  5. Confirm Button - Saves to stage config

Keyboard Shortcuts: - Enter - Confirm selection - Escape - Cancel and close - Tab - Focus next input

Floor Plan Editor

Position markers visually:

  1. Upload floor plan image
  2. Click on floor plan to place marker
  3. Drag to adjust position
  4. Coordinates auto-normalized (0-1 range)

Advanced Features

Multi-Floor Buildings

Support for complex venues with multiple floors:

{
  "navigation": {
    "type": "floorplan",
    "floorPlans": [
      { "floor": 0, "name": "Basement", "imageUrl": "..." },
      { "floor": 1, "name": "Ground Floor", "imageUrl": "..." },
      { "floor": 2, "name": "Mezzanine", "imageUrl": "..." },
      { "floor": 3, "name": "Rooftop", "imageUrl": "..." }
    ]
  }
}

Floor Switcher UI: - Appears in expanded floor plan view - Tabs for each floor - Current floor highlighted - Click to switch views

Custom Map Tiles

For enterprise customers, custom tile servers can be configured. Contact support for setup assistance.


Performance Considerations

Maps

  • Leaflet CDN: Loaded on-demand (~40KB gzipped)
  • Tile Caching: Browser caches tiles automatically
  • Lazy Loading: Only loads visible tiles

Floor Plans

  • Image Optimization: Compress images to <1MB
  • SVG Markers: Lightweight vector graphics
  • Debounced Rendering: Minimizes redraws

Troubleshooting

Map Not Showing

Check: 1. βœ… navigation.type === "map" 2. βœ… Markers have valid geoPosition (not 0,0) 3. βœ… Network allows access to unpkg.com (Leaflet CDN) 4. βœ… Network allows access to tile server (OpenStreetMap) 5. βœ… Browser console for errors

Common Fix:

// Ensure coordinates are numbers, not strings
"geoPosition": {
  "lat": 40.7128,      // βœ… number
  "lng": -74.0060      // βœ… number
}

// NOT:
"geoPosition": {
  "lat": "40.7128",    // ❌ string
  "lng": "-74.0060"    // ❌ string
}

Floor Plan Not Showing

Check: 1. βœ… Floor plan image URL is publicly accessible 2. βœ… CORS headers allow loading from your domain 3. βœ… Image format is PNG or JPG (SVG not recommended for floor plans) 4. βœ… Markers have floorPlanPosition with values 0-1

Test Image:

curl -I https://your-cdn.com/floorplan.png
# Should return 200 OK
# Should include: Access-Control-Allow-Origin: *

Geocoding Not Working

Check: 1. βœ… Internet connection allows access to nominatim.openstreetmap.org 2. βœ… Rate limit not exceeded (max 1 req/second) 3. βœ… Search query is valid (not empty, not too short)

Fallback: If geocoding fails, you can manually set coordinates:

{
  "geoPosition": { "lat": 40.7128, "lng": -74.0060 },
  "placeName": "New York, NY" // Manually set
}

Next Steps


Questions? Open an issue on GitHub or check the FAQ.